diff --git a/app/build.gradle b/app/build.gradle index 417c60195..764934617 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -78,6 +78,7 @@ tasks.withType(JavaCompile) { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'androidx.appcompat:appcompat:1.2.0-alpha03' + implementation 'androidx.biometric:biometric:1.0.1' implementation 'androidx.cardview:cardview:1.0.0' implementation 'com.google.android.gms:play-services-oss-licenses:17.0.0' implementation 'com.google.android.material:material:1.1.0' diff --git a/app/src/main/java/com/hippo/ehviewer/ui/SetSecurityActivity.java b/app/src/main/java/com/hippo/ehviewer/ui/SetSecurityActivity.java index 3202e8dc1..d863e5c75 100755 --- a/app/src/main/java/com/hippo/ehviewer/ui/SetSecurityActivity.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/SetSecurityActivity.java @@ -16,8 +16,6 @@ package com.hippo.ehviewer.ui; -import android.hardware.fingerprint.FingerprintManager; -import android.os.Build; import android.os.Bundle; import android.text.TextUtils; import android.view.MenuItem; @@ -25,7 +23,7 @@ import android.view.View; import android.widget.CheckBox; import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; +import androidx.biometric.BiometricManager; import com.hippo.ehviewer.R; import com.hippo.ehviewer.Settings; @@ -44,16 +42,6 @@ public class SetSecurityActivity extends ToolbarActivity implements View.OnClick @Nullable private CheckBox mFingerprint; - @RequiresApi(api = Build.VERSION_CODES.M) - public static boolean hasEnrolledFingerprints(FingerprintManager fingerprintManager) { - try { - return fingerprintManager.isHardwareDetected() - && fingerprintManager.hasEnrolledFingerprints(); - } catch (Throwable e) { - return false; - } - } - @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -72,10 +60,7 @@ public class SetSecurityActivity extends ToolbarActivity implements View.OnClick } if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { - FingerprintManager fingerprintManager = getSystemService(FingerprintManager.class); - // The line below prevents the false positive inspection from Android Studio - // noinspection ResourceType - if (fingerprintManager != null && hasEnrolledFingerprints(fingerprintManager)) { + if (BiometricManager.from(this).canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS) { mFingerprint.setVisibility(View.VISIBLE); mFingerprint.setChecked(Settings.getEnableFingerprint()); } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/SecurityScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/SecurityScene.java index 5261b0af8..0a98139c8 100755 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/SecurityScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/SecurityScene.java @@ -19,59 +19,43 @@ package com.hippo.ehviewer.ui.scene; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorManager; -import android.hardware.fingerprint.FingerprintManager; import android.os.Build; import android.os.Bundle; -import android.os.CancellationSignal; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageView; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.biometric.BiometricManager; +import androidx.biometric.BiometricPrompt; import com.hippo.ehviewer.R; import com.hippo.ehviewer.Settings; import com.hippo.ehviewer.ui.MainActivity; -import com.hippo.ehviewer.ui.SetSecurityActivity; import com.hippo.hardware.ShakeDetector; import com.hippo.widget.lockpattern.LockPatternUtils; import com.hippo.widget.lockpattern.LockPatternView; -import com.hippo.yorozuya.AssertUtils; import com.hippo.yorozuya.ObjectUtils; import com.hippo.yorozuya.ViewUtils; import java.util.List; +import java.util.concurrent.Executors; public class SecurityScene extends SolidScene implements LockPatternView.OnPatternListener, ShakeDetector.OnShakeListener { private static final int MAX_RETRY_TIMES = 5; - private static final long ERROR_TIMEOUT_MILLIS = 1200; - private static final long SUCCESS_DELAY_MILLIS = 100; - private static final String KEY_RETRY_TIMES = "retry_times"; @Nullable private LockPatternView mPatternView; - private ImageView mFingerprintIcon; private SensorManager mSensorManager; private Sensor mAccelerometer; private ShakeDetector mShakeDetector; - @Nullable - private FingerprintManager mFingerprintManager; - - private CancellationSignal mFingerprintCancellationSignal; private int mRetryTimes; - private Runnable mResetFingerprintRunnable = new Runnable() { - @Override - public void run() { - if (mFingerprintIcon != null) - mFingerprintIcon.setImageResource(R.drawable.ic_fp_40px); - } - }; @Override public boolean needShowLeftDrawer() { @@ -82,8 +66,7 @@ public class SecurityScene extends SolidScene implements public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Context context = getContext2(); - AssertUtils.assertNotNull(context); + Context context = requireContext(); mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); if (null != mSensorManager) { mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); @@ -92,9 +75,6 @@ public class SecurityScene extends SolidScene implements mShakeDetector.setOnShakeListener(this); } } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - mFingerprintManager = context.getSystemService(FingerprintManager.class); - } if (null == savedInstanceState) { mRetryTimes = MAX_RETRY_TIMES; @@ -121,35 +101,29 @@ public class SecurityScene extends SolidScene implements } if (isFingerprintAuthAvailable()) { - mFingerprintCancellationSignal = new CancellationSignal(); - // The line below prevents the false positive inspection from Android Studio - // noinspection ResourceType - mFingerprintManager.authenticate(null, mFingerprintCancellationSignal, 0, - new FingerprintManager.AuthenticationCallback() { - @Override - public void onAuthenticationError(int errMsgId, CharSequence errString) { - fingerprintError(true); - } + BiometricPrompt biometricPrompt = new BiometricPrompt(this, Executors.newSingleThreadExecutor(), new BiometricPrompt.AuthenticationCallback() { + @Override + public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) { + super.onAuthenticationError(errorCode, errString); + } - @Override - public void onAuthenticationFailed() { - fingerprintError(false); - } + @Override + public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) { + startSceneForCheckStep(CHECK_STEP_SECURITY, getArguments()); + finish(); + super.onAuthenticationSucceeded(result); + } - @Override - public void onAuthenticationSucceeded( - FingerprintManager.AuthenticationResult result) { - mFingerprintIcon.setImageResource(R.drawable.fingerprint_success); - mFingerprintIcon.postDelayed(new Runnable() { - @Override - public void run() { - startSceneForCheckStep(CHECK_STEP_SECURITY, getArguments()); - finish(); - } - }, SUCCESS_DELAY_MILLIS); - - } - }, null); + @Override + public void onAuthenticationFailed() { + super.onAuthenticationFailed(); + } + }); + BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder() + .setTitle(getString(R.string.app_name)) + .setNegativeButtonText(getString(android.R.string.cancel)) + .build(); + biometricPrompt.authenticate(promptInfo); } } @@ -160,10 +134,6 @@ public class SecurityScene extends SolidScene implements if (null != mShakeDetector) { mSensorManager.unregisterListener(mShakeDetector); } - if (isFingerprintAuthAvailable() && mFingerprintCancellationSignal != null) { - mFingerprintCancellationSignal.cancel(); - mFingerprintCancellationSignal = null; - } } @Override @@ -180,12 +150,6 @@ public class SecurityScene extends SolidScene implements mPatternView = (LockPatternView) ViewUtils.$$(view, R.id.pattern_view); mPatternView.setOnPatternListener(this); - - mFingerprintIcon = (ImageView) ViewUtils.$$(view, R.id.fingerprint_icon); - if (Settings.getEnableFingerprint() && isFingerprintAuthAvailable()) { - mFingerprintIcon.setVisibility(View.VISIBLE); - mFingerprintIcon.setImageResource(R.drawable.ic_fp_40px); - } return view; } @@ -244,27 +208,8 @@ public class SecurityScene extends SolidScene implements } private boolean isFingerprintAuthAvailable() { - // The line below prevents the false positive inspection from Android Studio - // noinspection ResourceType return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.getEnableFingerprint() - && mFingerprintManager != null - && SetSecurityActivity.hasEnrolledFingerprints(mFingerprintManager); - } - - private void fingerprintError(boolean unrecoverable) { - // Do not decrease mRetryTimes here since Android system will handle it :) - mFingerprintIcon.setImageResource(R.drawable.fingerprint_error); - mFingerprintIcon.removeCallbacks(mResetFingerprintRunnable); - if (unrecoverable) { - mFingerprintIcon.postDelayed(new Runnable() { - @Override - public void run() { - mFingerprintIcon.setVisibility(View.INVISIBLE); - } - }, ERROR_TIMEOUT_MILLIS); - } else { - mFingerprintIcon.postDelayed(mResetFingerprintRunnable, ERROR_TIMEOUT_MILLIS); - } + && BiometricManager.from(requireContext()).canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS; } } diff --git a/app/src/main/res/layout-land/activity_set_security.xml b/app/src/main/res/layout-land/activity_set_security.xml index 3ed310944..84bec4338 100755 --- a/app/src/main/res/layout-land/activity_set_security.xml +++ b/app/src/main/res/layout-land/activity_set_security.xml @@ -50,11 +50,10 @@ android:text="@string/enable_fingerprint" /> -