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 old mode 100644 new mode 100755 index 79736a93e..57ce348cd --- 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,11 +19,15 @@ 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.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageView; import com.hippo.ehviewer.R; import com.hippo.ehviewer.Settings; @@ -42,15 +46,21 @@ 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; + private FingerprintManager mFingerprintManager; + + private CancellationSignal mFingerprintCancellationSignal; private int mRetryTimes; @@ -73,6 +83,9 @@ 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; @@ -97,6 +110,38 @@ public class SecurityScene extends SolidScene implements if (null != mShakeDetector) { mSensorManager.registerListener(mShakeDetector, mAccelerometer, SensorManager.SENSOR_DELAY_UI); } + + 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); + } + + @Override + public void onAuthenticationFailed() { + fingerprintError(false); + } + + @Override + public void onAuthenticationSucceeded( + FingerprintManager.AuthenticationResult result) { + mFingerprintIcon.setImageResource(R.drawable.ic_fingerprint_success); + mFingerprintIcon.postDelayed(new Runnable() { + @Override + public void run() { + startSceneForCheckStep(CHECK_STEP_SECURITY, getArguments()); + finish(); + } + }, SUCCESS_DELAY_MILLIS); + + } + }, null); + } } @Override @@ -106,6 +151,10 @@ public class SecurityScene extends SolidScene implements if (null != mShakeDetector) { mSensorManager.unregisterListener(mShakeDetector); } + if (isFingerprintAuthAvailable() && mFingerprintCancellationSignal != null) { + mFingerprintCancellationSignal.cancel(); + mFingerprintCancellationSignal = null; + } } @Override @@ -123,6 +172,11 @@ 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; } @@ -176,4 +230,38 @@ public class SecurityScene extends SolidScene implements finish(); } } + + 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 + && mFingerprintManager.isHardwareDetected() + && mFingerprintManager.hasEnrolledFingerprints(); + } + + private Runnable mResetFingerprintRunnable = new Runnable() { + @Override + public void run() { + if (mFingerprintIcon != null) + mFingerprintIcon.setImageResource(R.drawable.ic_fp_40px); + } + }; + + private void fingerprintError(boolean unrecoverable) { + // Do not decrease mRetryTimes here since Android system will handle it :) + mFingerprintIcon.setImageResource(R.drawable.ic_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); + } + } } diff --git a/app/src/main/res/drawable-hdpi/ic_fp_40px.png b/app/src/main/res/drawable-hdpi/ic_fp_40px.png new file mode 100755 index 000000000..48ebd8ad7 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_fp_40px.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_fingerprint_error.xml b/app/src/main/res/drawable-mdpi/ic_fingerprint_error.xml new file mode 100755 index 000000000..be46116da --- /dev/null +++ b/app/src/main/res/drawable-mdpi/ic_fingerprint_error.xml @@ -0,0 +1,28 @@ + + + + + + diff --git a/app/src/main/res/drawable-mdpi/ic_fingerprint_success.xml b/app/src/main/res/drawable-mdpi/ic_fingerprint_success.xml new file mode 100755 index 000000000..261f3e7fb --- /dev/null +++ b/app/src/main/res/drawable-mdpi/ic_fingerprint_success.xml @@ -0,0 +1,28 @@ + + + + + + diff --git a/app/src/main/res/drawable-mdpi/ic_fp_40px.png b/app/src/main/res/drawable-mdpi/ic_fp_40px.png new file mode 100755 index 000000000..122f44257 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_fp_40px.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_fp_40px.png b/app/src/main/res/drawable-xhdpi/ic_fp_40px.png new file mode 100755 index 000000000..e1c9590bb Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_fp_40px.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_fp_40px.png b/app/src/main/res/drawable-xxhdpi/ic_fp_40px.png new file mode 100755 index 000000000..0fb854524 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_fp_40px.png differ diff --git a/app/src/main/res/layout/scene_security.xml b/app/src/main/res/layout/scene_security.xml old mode 100644 new mode 100755 index b488a17c5..f18817944 --- a/app/src/main/res/layout/scene_security.xml +++ b/app/src/main/res/layout/scene_security.xml @@ -27,12 +27,27 @@ android:layout_gravity="center" android:layout_margin="32dp" app:maxWidth="320dp" - app:maxHeight="320dp"> + app:maxHeight="360dp"> - + android:layout_height="wrap_content" + android:orientation="vertical"> + + + + + +