diff --git a/app/src/full/java/com/topjohnwu/magisk/Data.java b/app/src/full/java/com/topjohnwu/magisk/Data.java index 100d8b4e4..316babc0c 100644 --- a/app/src/full/java/com/topjohnwu/magisk/Data.java +++ b/app/src/full/java/com/topjohnwu/magisk/Data.java @@ -5,6 +5,7 @@ import android.os.Handler; import android.os.Looper; import android.util.Xml; +import com.topjohnwu.magisk.utils.FingerprintHelper; import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.ShellUtils; @@ -153,6 +154,11 @@ public class Data { multiuserMode = mm.mDB.getSettings(Const.Key.SU_MULTIUSER_MODE, Const.Value.MULTIUSER_MODE_OWNER_ONLY); suNamespaceMode = mm.mDB.getSettings(Const.Key.SU_MNT_NS, Const.Value.NAMESPACE_MODE_REQUESTER); suFingerprint = mm.mDB.getSettings(Const.Key.SU_FINGERPRINT, 0) != 0; + if (suFingerprint && !FingerprintHelper.canUseFingerprint()) { + // User revoked the fingerprint + mm.mDB.setSettings(Const.Key.SU_FINGERPRINT, 0); + suFingerprint = false; + } // config isDarkTheme = mm.prefs.getBoolean(Const.Key.DARK_THEME, false); diff --git a/app/src/full/java/com/topjohnwu/magisk/MagiskFragment.java b/app/src/full/java/com/topjohnwu/magisk/MagiskFragment.java index 0171d56a2..2fce1032f 100644 --- a/app/src/full/java/com/topjohnwu/magisk/MagiskFragment.java +++ b/app/src/full/java/com/topjohnwu/magisk/MagiskFragment.java @@ -10,7 +10,6 @@ import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.CardView; -import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/app/src/full/java/com/topjohnwu/magisk/SettingsActivity.java b/app/src/full/java/com/topjohnwu/magisk/SettingsActivity.java index b464831cf..4958db0db 100644 --- a/app/src/full/java/com/topjohnwu/magisk/SettingsActivity.java +++ b/app/src/full/java/com/topjohnwu/magisk/SettingsActivity.java @@ -2,6 +2,9 @@ package com.topjohnwu.magisk; import android.content.Context; import android.content.SharedPreferences; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.hardware.fingerprint.FingerprintManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -14,6 +17,8 @@ import android.support.v7.preference.PreferenceCategory; import android.support.v7.preference.PreferenceFragmentCompat; import android.support.v7.preference.PreferenceScreen; import android.support.v7.widget.Toolbar; +import android.util.TypedValue; +import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -23,11 +28,11 @@ import android.widget.Toast; import com.topjohnwu.magisk.asyncs.CheckUpdates; import com.topjohnwu.magisk.asyncs.PatchAPK; import com.topjohnwu.magisk.components.BaseActivity; +import com.topjohnwu.magisk.components.CustomAlertDialog; import com.topjohnwu.magisk.receivers.DownloadReceiver; import com.topjohnwu.magisk.utils.Download; import com.topjohnwu.magisk.utils.FingerprintHelper; import com.topjohnwu.magisk.utils.LocaleManager; -import com.topjohnwu.magisk.utils.Logger; import com.topjohnwu.magisk.utils.RootUtils; import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.magisk.utils.Utils; @@ -308,7 +313,55 @@ public class SettingsActivity extends BaseActivity implements Topic.Subscriber { String key = preference.getKey(); switch (key) { case Const.Key.SU_FINGERPRINT: - mm.mDB.setSettings(key, mm.prefs.getBoolean(key, false) ? 1 : 0); + boolean checked = ((SwitchPreference) preference).isChecked(); + ((SwitchPreference) preference).setChecked(!checked); + CustomAlertDialog dialog = new CustomAlertDialog(requireActivity()); + CustomAlertDialog.ViewHolder vh = dialog.getViewHolder(); + Drawable fingerprint = getResources().getDrawable(R.drawable.ic_fingerprint); + fingerprint.setBounds(0, 0, Utils.dpInPx(50), Utils.dpInPx(50)); + TypedValue tint = new TypedValue(); + requireActivity().getTheme().resolveAttribute(R.attr.imageColorTint, tint, true); + fingerprint.setTint(tint.data); + vh.messageView.setCompoundDrawables(null, null, null, fingerprint); + vh.messageView.setCompoundDrawablePadding(Utils.dpInPx(20)); + vh.messageView.setGravity(Gravity.CENTER); + try { + FingerprintHelper helper = new FingerprintHelper() { + @Override + public void onAuthenticationError(int errorCode, CharSequence errString) { + vh.messageView.setTextColor(Color.RED); + vh.messageView.setText(errString); + } + + @Override + public void onAuthenticationHelp(int helpCode, CharSequence helpString) { + vh.messageView.setTextColor(Color.RED); + vh.messageView.setText(helpString); + } + + @Override + public void onAuthenticationFailed() { + vh.messageView.setTextColor(Color.RED); + vh.messageView.setText(R.string.auth_fail); + } + + @Override + public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) { + dialog.dismiss(); + ((SwitchPreference) preference).setChecked(checked); + mm.mDB.setSettings(key, checked ? 1 : 0); + + } + }; + dialog.setMessage(R.string.auth_fingerprint) + .setNegativeButton(R.string.close, (d, w) -> helper.cancel()) + .setOnCancelListener(d -> helper.cancel()) + .show(); + helper.authenticate(); + } catch (Exception e) { + e.printStackTrace(); + Utils.toast(R.string.auth_fail, Toast.LENGTH_SHORT); + } break; } return true; diff --git a/app/src/full/java/com/topjohnwu/magisk/components/CustomAlertDialog.java b/app/src/full/java/com/topjohnwu/magisk/components/CustomAlertDialog.java index c4ad30251..2c6d064aa 100644 --- a/app/src/full/java/com/topjohnwu/magisk/components/CustomAlertDialog.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/CustomAlertDialog.java @@ -20,29 +20,37 @@ import butterknife.ButterKnife; public class CustomAlertDialog extends AlertDialog.Builder { - @BindView(R.id.button_panel) LinearLayout buttons; - @BindView(R.id.message_panel) LinearLayout messagePanel; - - @BindView(R.id.negative) Button negative; - @BindView(R.id.positive) Button positive; - @BindView(R.id.neutral) Button neutral; - @BindView(R.id.message) TextView messageView; - private DialogInterface.OnClickListener positiveListener; private DialogInterface.OnClickListener negativeListener; private DialogInterface.OnClickListener neutralListener; - private AlertDialog dialog; + private ViewHolder vh; + + public class ViewHolder { + @BindView(R.id.dialog_layout) public LinearLayout dialogLayout; + @BindView(R.id.button_panel) public LinearLayout buttons; + + @BindView(R.id.message) public TextView messageView; + @BindView(R.id.negative) public Button negative; + @BindView(R.id.positive) public Button positive; + @BindView(R.id.neutral) public Button neutral; + + ViewHolder(View v) { + ButterKnife.bind(this, v); + messageView.setVisibility(View.GONE); + negative.setVisibility(View.GONE); + positive.setVisibility(View.GONE); + neutral.setVisibility(View.GONE); + buttons.setVisibility(View.GONE); + } + } + { View v = LayoutInflater.from(getContext()).inflate(R.layout.alert_dialog, null); - ButterKnife.bind(this, v); + vh = new ViewHolder(v); super.setView(v); - negative.setVisibility(View.GONE); - positive.setVisibility(View.GONE); - neutral.setVisibility(View.GONE); - buttons.setVisibility(View.GONE); - messagePanel.setVisibility(View.GONE); + } public CustomAlertDialog(@NonNull Activity context) { @@ -53,31 +61,35 @@ public class CustomAlertDialog extends AlertDialog.Builder { super(context, themeResId); } - @Override - public AlertDialog.Builder setView(int layoutResId) { return this; } + public ViewHolder getViewHolder() { + return vh; + } @Override - public AlertDialog.Builder setView(View view) { return this; } + public CustomAlertDialog setView(int layoutResId) { return this; } @Override - public AlertDialog.Builder setMessage(@Nullable CharSequence message) { - messageView.setText(message); - messagePanel.setVisibility(View.VISIBLE); + public CustomAlertDialog setView(View view) { return this; } + + @Override + public CustomAlertDialog setMessage(@Nullable CharSequence message) { + vh.messageView.setVisibility(View.VISIBLE); + vh.messageView.setText(message); return this; } @Override - public AlertDialog.Builder setMessage(@StringRes int messageId) { + public CustomAlertDialog setMessage(@StringRes int messageId) { return setMessage(getContext().getString(messageId)); } @Override - public AlertDialog.Builder setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) { - buttons.setVisibility(View.VISIBLE); - positive.setVisibility(View.VISIBLE); - positive.setText(text); + public CustomAlertDialog setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) { + vh.buttons.setVisibility(View.VISIBLE); + vh.positive.setVisibility(View.VISIBLE); + vh.positive.setText(text); positiveListener = listener; - positive.setOnClickListener((v) -> { + vh.positive.setOnClickListener((v) -> { if (positiveListener != null) { positiveListener.onClick(dialog, DialogInterface.BUTTON_POSITIVE); } @@ -87,17 +99,17 @@ public class CustomAlertDialog extends AlertDialog.Builder { } @Override - public AlertDialog.Builder setPositiveButton(@StringRes int textId, DialogInterface.OnClickListener listener) { + public CustomAlertDialog setPositiveButton(@StringRes int textId, DialogInterface.OnClickListener listener) { return setPositiveButton(getContext().getString(textId), listener); } @Override - public AlertDialog.Builder setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) { - buttons.setVisibility(View.VISIBLE); - negative.setVisibility(View.VISIBLE); - negative.setText(text); + public CustomAlertDialog setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) { + vh.buttons.setVisibility(View.VISIBLE); + vh.negative.setVisibility(View.VISIBLE); + vh.negative.setText(text); negativeListener = listener; - negative.setOnClickListener((v) -> { + vh.negative.setOnClickListener((v) -> { if (negativeListener != null) { negativeListener.onClick(dialog, DialogInterface.BUTTON_NEGATIVE); } @@ -107,17 +119,17 @@ public class CustomAlertDialog extends AlertDialog.Builder { } @Override - public AlertDialog.Builder setNegativeButton(@StringRes int textId, DialogInterface.OnClickListener listener) { + public CustomAlertDialog setNegativeButton(@StringRes int textId, DialogInterface.OnClickListener listener) { return setNegativeButton(getContext().getString(textId), listener); } @Override - public AlertDialog.Builder setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener) { - buttons.setVisibility(View.VISIBLE); - neutral.setVisibility(View.VISIBLE); - neutral.setText(text); + public CustomAlertDialog setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener) { + vh.buttons.setVisibility(View.VISIBLE); + vh.neutral.setVisibility(View.VISIBLE); + vh.neutral.setText(text); neutralListener = listener; - neutral.setOnClickListener((v) -> { + vh.neutral.setOnClickListener((v) -> { if (neutralListener != null) { neutralListener.onClick(dialog, DialogInterface.BUTTON_NEUTRAL); } @@ -127,7 +139,7 @@ public class CustomAlertDialog extends AlertDialog.Builder { } @Override - public AlertDialog.Builder setNeutralButton(@StringRes int textId, DialogInterface.OnClickListener listener) { + public CustomAlertDialog setNeutralButton(@StringRes int textId, DialogInterface.OnClickListener listener) { return setNeutralButton(getContext().getString(textId), listener); } @@ -143,4 +155,8 @@ public class CustomAlertDialog extends AlertDialog.Builder { dialog.show(); return dialog; } + + public void dismiss() { + dialog.dismiss(); + } } diff --git a/app/src/full/res/layout/alert_dialog.xml b/app/src/full/res/layout/alert_dialog.xml index 91b8c4779..e0037ec22 100644 --- a/app/src/full/res/layout/alert_dialog.xml +++ b/app/src/full/res/layout/alert_dialog.xml @@ -1,29 +1,22 @@ - - - - - + android:paddingBottom="12dp" + android:paddingEnd="25dp" + android:paddingStart="25dp" + android:paddingTop="12dp" /> Re-authenticate superuser permissions after an application upgrades Enable Fingerprint Authentication Use fingerprint scanner to allow superuser requests + Authenticate Fingerprint Multiuser Mode Device Owner Only