diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml old mode 100644 new mode 100755 index 077193be3..4d9507ff7 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -22,6 +22,7 @@ + diff --git a/app/src/main/java/com/hippo/ehviewer/Settings.java b/app/src/main/java/com/hippo/ehviewer/Settings.java old mode 100644 new mode 100755 index 12f20231e..f41b95bcf --- a/app/src/main/java/com/hippo/ehviewer/Settings.java +++ b/app/src/main/java/com/hippo/ehviewer/Settings.java @@ -911,6 +911,16 @@ public class Settings { putString(KEY_SECURITY, value); } + public static final String KEY_ENABLE_FINGERPRINT = "enable_fingerprint"; + + public static boolean getEnableFingerprint() { + return getBoolean(KEY_ENABLE_FINGERPRINT, false); + } + + public static void putEnableFingerprint(boolean value) { + putBoolean(KEY_ENABLE_FINGERPRINT, value); + } + public static final String KEY_READ_CACHE_SIZE = "read_cache_size"; public static final int DEFAULT_READ_CACHE_SIZE = 160; diff --git a/app/src/main/java/com/hippo/ehviewer/ui/SetSecurityActivity.java b/app/src/main/java/com/hippo/ehviewer/ui/SetSecurityActivity.java old mode 100644 new mode 100755 index ebc9b3954..e17ca11a0 --- a/app/src/main/java/com/hippo/ehviewer/ui/SetSecurityActivity.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/SetSecurityActivity.java @@ -16,11 +16,13 @@ package com.hippo.ehviewer.ui; +import android.hardware.fingerprint.FingerprintManager; import android.os.Bundle; import android.support.annotation.Nullable; import android.text.TextUtils; import android.view.MenuItem; import android.view.View; +import android.widget.CheckBox; import com.hippo.ehviewer.R; import com.hippo.ehviewer.Settings; @@ -36,6 +38,8 @@ public class SetSecurityActivity extends ToolbarActivity implements View.OnClick private View mCancel; @Nullable private View mSet; + @Nullable + private CheckBox mFingerprint; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -46,6 +50,7 @@ public class SetSecurityActivity extends ToolbarActivity implements View.OnClick mPatternView = (LockPatternView) ViewUtils.$$(this, R.id.pattern_view); mCancel = ViewUtils.$$(this, R.id.cancel); mSet = ViewUtils.$$(this, R.id.set); + mFingerprint = (CheckBox) ViewUtils.$$(this, R.id.fingerprint_checkbox); String pattern = Settings.getSecurity(); if (!TextUtils.isEmpty(pattern)) { @@ -53,6 +58,16 @@ public class SetSecurityActivity extends ToolbarActivity implements View.OnClick LockPatternUtils.stringToPattern(pattern)); } + 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.hasEnrolledFingerprints()) { + mFingerprint.setVisibility(View.VISIBLE); + mFingerprint.setChecked(Settings.getEnableFingerprint()); + } + } + mCancel.setOnClickListener(this); mSet.setOnClickListener(this); } @@ -79,7 +94,7 @@ public class SetSecurityActivity extends ToolbarActivity implements View.OnClick if (v == mCancel) { finish(); } else if (v == mSet) { - if (null != mPatternView) { + if (null != mPatternView && null != mFingerprint) { String security; if (mPatternView.getCellSize() <= 1) { security = ""; @@ -87,6 +102,8 @@ public class SetSecurityActivity extends ToolbarActivity implements View.OnClick security = mPatternView.getPatternString(); } Settings.putSecurity(security); + Settings.putEnableFingerprint(mFingerprint.getVisibility() == View.VISIBLE && + mFingerprint.isChecked() && !security.isEmpty()); } finish(); } 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-land/activity_set_security.xml b/app/src/main/res/layout-land/activity_set_security.xml old mode 100644 new mode 100755 index 6f4b4e0bb..3ed310944 --- a/app/src/main/res/layout-land/activity_set_security.xml +++ b/app/src/main/res/layout-land/activity_set_security.xml @@ -40,6 +40,15 @@ android:layout_height="0dp" android:layout_weight="1"/> + + + + + app:maxHeight="360dp"> - + android:layout_height="wrap_content" + android:orientation="vertical"> + + + + + + diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml old mode 100644 new mode 100755 index 57e3cdc9d..277101195 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -334,6 +334,7 @@ Establecer Proteccion po Patrón Dibujar un patrón para establecer la proteccion por patrón. \nDejar en blanco para quitar la proteccion por patrón. Establecer + Permitir desbloquear con huella dactilar Pagina %d diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml old mode 100644 new mode 100755 index 2f3cc1dae..24a2cc72a --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -341,6 +341,7 @@ 设置图案保护 绘制图案来设置图案保护\n留空来取消图案保护 设置 + 允许使用指纹解锁 第 %d 页 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml old mode 100644 new mode 100755 index cfa29a93f..2d8f9f074 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -341,6 +341,7 @@ 設置圖案保護 繪製圖案來設置圖案保護\n留空來取消圖案保護 設置 + 允許使用指紋解鎖 第 %d 頁 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml old mode 100644 new mode 100755 index ca372446a..a48608cc6 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -341,6 +341,7 @@ 設定圖案保護 繪製圖案來設定圖案保護\n留空來取消圖案保護 設定 + 允許使用指紋解鎖 第 %d 頁 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml old mode 100644 new mode 100755 index 7e4d1e43a..27437f2bb --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -385,6 +385,7 @@ Set pattern protection Draw a pattern to set pattern protection\nLeave blank to clear pattern protection Set + Also allow unlock with fingerprint Page %d