Require authentication to toggle fingerprint settings

Close #474
This commit is contained in:
topjohnwu 2018-08-22 17:49:51 -04:00
parent d56e1b2cc5
commit 3948e67c8f
6 changed files with 128 additions and 60 deletions

View File

@ -5,6 +5,7 @@ import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.Xml; import android.util.Xml;
import com.topjohnwu.magisk.utils.FingerprintHelper;
import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils; 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); 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); suNamespaceMode = mm.mDB.getSettings(Const.Key.SU_MNT_NS, Const.Value.NAMESPACE_MODE_REQUESTER);
suFingerprint = mm.mDB.getSettings(Const.Key.SU_FINGERPRINT, 0) != 0; 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 // config
isDarkTheme = mm.prefs.getBoolean(Const.Key.DARK_THEME, false); isDarkTheme = mm.prefs.getBoolean(Const.Key.DARK_THEME, false);

View File

@ -10,7 +10,6 @@ import android.support.annotation.Nullable;
import android.support.annotation.StringRes; import android.support.annotation.StringRes;
import android.support.v4.widget.SwipeRefreshLayout; import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.CardView; import android.support.v7.widget.CardView;
import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;

View File

@ -2,6 +2,9 @@ package com.topjohnwu.magisk;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.hardware.fingerprint.FingerprintManager;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; 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.PreferenceFragmentCompat;
import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.PreferenceScreen;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -23,11 +28,11 @@ import android.widget.Toast;
import com.topjohnwu.magisk.asyncs.CheckUpdates; import com.topjohnwu.magisk.asyncs.CheckUpdates;
import com.topjohnwu.magisk.asyncs.PatchAPK; import com.topjohnwu.magisk.asyncs.PatchAPK;
import com.topjohnwu.magisk.components.BaseActivity; import com.topjohnwu.magisk.components.BaseActivity;
import com.topjohnwu.magisk.components.CustomAlertDialog;
import com.topjohnwu.magisk.receivers.DownloadReceiver; import com.topjohnwu.magisk.receivers.DownloadReceiver;
import com.topjohnwu.magisk.utils.Download; import com.topjohnwu.magisk.utils.Download;
import com.topjohnwu.magisk.utils.FingerprintHelper; import com.topjohnwu.magisk.utils.FingerprintHelper;
import com.topjohnwu.magisk.utils.LocaleManager; import com.topjohnwu.magisk.utils.LocaleManager;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.RootUtils; import com.topjohnwu.magisk.utils.RootUtils;
import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.Utils;
@ -308,7 +313,55 @@ public class SettingsActivity extends BaseActivity implements Topic.Subscriber {
String key = preference.getKey(); String key = preference.getKey();
switch (key) { switch (key) {
case Const.Key.SU_FINGERPRINT: 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; break;
} }
return true; return true;

View File

@ -20,29 +20,37 @@ import butterknife.ButterKnife;
public class CustomAlertDialog extends AlertDialog.Builder { 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 positiveListener;
private DialogInterface.OnClickListener negativeListener; private DialogInterface.OnClickListener negativeListener;
private DialogInterface.OnClickListener neutralListener; private DialogInterface.OnClickListener neutralListener;
private AlertDialog dialog; 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); View v = LayoutInflater.from(getContext()).inflate(R.layout.alert_dialog, null);
ButterKnife.bind(this, v); vh = new ViewHolder(v);
super.setView(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) { public CustomAlertDialog(@NonNull Activity context) {
@ -53,31 +61,35 @@ public class CustomAlertDialog extends AlertDialog.Builder {
super(context, themeResId); super(context, themeResId);
} }
@Override public ViewHolder getViewHolder() {
public AlertDialog.Builder setView(int layoutResId) { return this; } return vh;
}
@Override @Override
public AlertDialog.Builder setView(View view) { return this; } public CustomAlertDialog setView(int layoutResId) { return this; }
@Override @Override
public AlertDialog.Builder setMessage(@Nullable CharSequence message) { public CustomAlertDialog setView(View view) { return this; }
messageView.setText(message);
messagePanel.setVisibility(View.VISIBLE); @Override
public CustomAlertDialog setMessage(@Nullable CharSequence message) {
vh.messageView.setVisibility(View.VISIBLE);
vh.messageView.setText(message);
return this; return this;
} }
@Override @Override
public AlertDialog.Builder setMessage(@StringRes int messageId) { public CustomAlertDialog setMessage(@StringRes int messageId) {
return setMessage(getContext().getString(messageId)); return setMessage(getContext().getString(messageId));
} }
@Override @Override
public AlertDialog.Builder setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) { public CustomAlertDialog setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) {
buttons.setVisibility(View.VISIBLE); vh.buttons.setVisibility(View.VISIBLE);
positive.setVisibility(View.VISIBLE); vh.positive.setVisibility(View.VISIBLE);
positive.setText(text); vh.positive.setText(text);
positiveListener = listener; positiveListener = listener;
positive.setOnClickListener((v) -> { vh.positive.setOnClickListener((v) -> {
if (positiveListener != null) { if (positiveListener != null) {
positiveListener.onClick(dialog, DialogInterface.BUTTON_POSITIVE); positiveListener.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
} }
@ -87,17 +99,17 @@ public class CustomAlertDialog extends AlertDialog.Builder {
} }
@Override @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); return setPositiveButton(getContext().getString(textId), listener);
} }
@Override @Override
public AlertDialog.Builder setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) { public CustomAlertDialog setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) {
buttons.setVisibility(View.VISIBLE); vh.buttons.setVisibility(View.VISIBLE);
negative.setVisibility(View.VISIBLE); vh.negative.setVisibility(View.VISIBLE);
negative.setText(text); vh.negative.setText(text);
negativeListener = listener; negativeListener = listener;
negative.setOnClickListener((v) -> { vh.negative.setOnClickListener((v) -> {
if (negativeListener != null) { if (negativeListener != null) {
negativeListener.onClick(dialog, DialogInterface.BUTTON_NEGATIVE); negativeListener.onClick(dialog, DialogInterface.BUTTON_NEGATIVE);
} }
@ -107,17 +119,17 @@ public class CustomAlertDialog extends AlertDialog.Builder {
} }
@Override @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); return setNegativeButton(getContext().getString(textId), listener);
} }
@Override @Override
public AlertDialog.Builder setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener) { public CustomAlertDialog setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener) {
buttons.setVisibility(View.VISIBLE); vh.buttons.setVisibility(View.VISIBLE);
neutral.setVisibility(View.VISIBLE); vh.neutral.setVisibility(View.VISIBLE);
neutral.setText(text); vh.neutral.setText(text);
neutralListener = listener; neutralListener = listener;
neutral.setOnClickListener((v) -> { vh.neutral.setOnClickListener((v) -> {
if (neutralListener != null) { if (neutralListener != null) {
neutralListener.onClick(dialog, DialogInterface.BUTTON_NEUTRAL); neutralListener.onClick(dialog, DialogInterface.BUTTON_NEUTRAL);
} }
@ -127,7 +139,7 @@ public class CustomAlertDialog extends AlertDialog.Builder {
} }
@Override @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); return setNeutralButton(getContext().getString(textId), listener);
} }
@ -143,4 +155,8 @@ public class CustomAlertDialog extends AlertDialog.Builder {
dialog.show(); dialog.show();
return dialog; return dialog;
} }
public void dismiss() {
dialog.dismiss();
}
} }

View File

@ -1,29 +1,22 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dialog_layout"
android:orientation="vertical" android:orientation="vertical"
android:paddingTop="5dp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<LinearLayout <TextView
android:id="@+id/message_panel" android:id="@+id/message"
style="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:paddingBottom="12dp"
android:paddingBottom="12dip" android:paddingEnd="25dp"
android:paddingEnd="20dip" android:paddingStart="25dp"
android:paddingStart="20dip" android:paddingTop="12dp" />
android:paddingTop="12dip">
<TextView
android:id="@+id/message"
style="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dip" />
</LinearLayout>
<LinearLayout <LinearLayout
style="?android:attr/buttonBarStyle" style="?android:attr/buttonBarStyle"

View File

@ -164,6 +164,7 @@
<string name="settings_su_reauth_summary">Re-authenticate superuser permissions after an application upgrades</string> <string name="settings_su_reauth_summary">Re-authenticate superuser permissions after an application upgrades</string>
<string name="settings_su_fingerprint_title">Enable Fingerprint Authentication</string> <string name="settings_su_fingerprint_title">Enable Fingerprint Authentication</string>
<string name="settings_su_fingerprint_summary">Use fingerprint scanner to allow superuser requests</string> <string name="settings_su_fingerprint_summary">Use fingerprint scanner to allow superuser requests</string>
<string name="auth_fingerprint">Authenticate Fingerprint</string>
<string name="multiuser_mode">Multiuser Mode</string> <string name="multiuser_mode">Multiuser Mode</string>
<string name="settings_owner_only">Device Owner Only</string> <string name="settings_owner_only">Device Owner Only</string>