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">
+
+
+
+
+
+