mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Merge branch '1247-pin-lock-fingerprint' into 'master'
Implement fingerprint unlocking with BiometricPromptCompat See merge request briar/briar!882
This commit is contained in:
@@ -75,8 +75,8 @@ def getStdout = { command, defaultValue ->
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 27
|
||||
buildToolsVersion '27.0.3'
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion '28.0.2'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 15
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
||||
<uses-permission-sdk-23 android:name="android.permission.USE_BIOMETRIC" />
|
||||
|
||||
<application
|
||||
android:name="org.briarproject.briar.android.BriarApplicationImpl"
|
||||
|
||||
@@ -2,10 +2,15 @@ package org.briarproject.briar.android.login;
|
||||
|
||||
import android.app.KeyguardManager;
|
||||
import android.content.Intent;
|
||||
import android.hardware.biometrics.BiometricPrompt;
|
||||
import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback;
|
||||
import android.hardware.biometrics.BiometricPrompt.AuthenticationResult;
|
||||
import android.hardware.biometrics.BiometricPrompt.Builder;
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.widget.Button;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
@@ -18,8 +23,13 @@ import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.hardware.biometrics.BiometricPrompt.BIOMETRIC_ERROR_CANCELED;
|
||||
import static android.hardware.biometrics.BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED;
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static android.view.View.INVISIBLE;
|
||||
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_KEYGUARD_UNLOCK;
|
||||
import static org.briarproject.briar.android.util.UiUtils.hasKeyguardLock;
|
||||
import static org.briarproject.briar.android.util.UiUtils.hasUsableFingerprint;
|
||||
|
||||
@RequiresApi(21)
|
||||
@MethodsNotNullByDefault
|
||||
@@ -45,9 +55,10 @@ public class UnlockActivity extends BaseActivity {
|
||||
overridePendingTransition(0, 0);
|
||||
setContentView(R.layout.activity_unlock);
|
||||
|
||||
Button button = findViewById(R.id.unlock);
|
||||
button.setOnClickListener(view -> requestKeyguardUnlock());
|
||||
|
||||
if (!hasUsableFingerprint(this)) {
|
||||
getWindow().setBackgroundDrawable(null);
|
||||
findViewById(R.id.image).setVisibility(INVISIBLE);
|
||||
}
|
||||
keyguardShown = state != null && state.getBoolean(KEYGUARD_SHOWN);
|
||||
}
|
||||
|
||||
@@ -83,18 +94,79 @@ public class UnlockActivity extends BaseActivity {
|
||||
// Check if app is still locked, lockable
|
||||
// and not finishing (which is possible if recreated)
|
||||
if (!keyguardShown && lockManager.isLocked() && !isFinishing()) {
|
||||
requestKeyguardUnlock();
|
||||
requestUnlock();
|
||||
} else if (!lockManager.isLocked()) {
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void requestUnlock() {
|
||||
if (SDK_INT >= 28 && hasUsableFingerprint(this)) {
|
||||
requestFingerprintUnlock();
|
||||
} else {
|
||||
requestKeyguardUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
moveTaskToBack(true);
|
||||
}
|
||||
|
||||
@RequiresApi(api = 28)
|
||||
private void requestFingerprintUnlock() {
|
||||
BiometricPrompt biometricPrompt = new Builder(this)
|
||||
.setTitle(getString(R.string.lock_unlock))
|
||||
.setDescription(
|
||||
getString(R.string.lock_unlock_fingerprint_description))
|
||||
.setNegativeButton(getString(R.string.lock_unlock_password),
|
||||
getMainExecutor(),
|
||||
(dialog, which) -> requestKeyguardUnlock())
|
||||
.build();
|
||||
CancellationSignal signal = new CancellationSignal();
|
||||
AuthenticationCallback callback = new AuthenticationCallback() {
|
||||
@Override
|
||||
public void onAuthenticationError(int errorCode,
|
||||
@Nullable CharSequence errString) {
|
||||
// when back button is pressed while fingerprint dialog shows
|
||||
if (errorCode == BIOMETRIC_ERROR_CANCELED ||
|
||||
errorCode == BIOMETRIC_ERROR_USER_CANCELED) {
|
||||
finish();
|
||||
}
|
||||
// e.g. 5 failed attempts
|
||||
else {
|
||||
if (hasKeyguardLock(UnlockActivity.this)) {
|
||||
requestKeyguardUnlock();
|
||||
} else {
|
||||
// normally fingerprints require a screen lock, but
|
||||
// who knows if that's true for all devices out there
|
||||
if (errString != null) {
|
||||
Toast.makeText(UnlockActivity.this, errString,
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationHelp(int helpCode,
|
||||
@Nullable CharSequence helpString) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(AuthenticationResult result) {
|
||||
unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed() {
|
||||
}
|
||||
};
|
||||
biometricPrompt.authenticate(signal, getMainExecutor(), callback);
|
||||
}
|
||||
|
||||
private void requestKeyguardUnlock() {
|
||||
KeyguardManager keyguardManager =
|
||||
(KeyguardManager) getSystemService(KEYGUARD_SERVICE);
|
||||
|
||||
@@ -14,6 +14,7 @@ import android.support.annotation.ColorRes;
|
||||
import android.support.design.widget.TextInputLayout;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.Html;
|
||||
import android.text.Spannable;
|
||||
@@ -261,6 +262,10 @@ public class UiUtils {
|
||||
}
|
||||
|
||||
public static boolean hasScreenLock(Context ctx) {
|
||||
return hasKeyguardLock(ctx) || hasUsableFingerprint(ctx);
|
||||
}
|
||||
|
||||
public static boolean hasKeyguardLock(Context ctx) {
|
||||
if (SDK_INT < 21) return false;
|
||||
KeyguardManager keyguardManager =
|
||||
(KeyguardManager) ctx.getSystemService(KEYGUARD_SERVICE);
|
||||
@@ -271,6 +276,12 @@ public class UiUtils {
|
||||
(SDK_INT >= 23 && keyguardManager.isDeviceSecure());
|
||||
}
|
||||
|
||||
public static boolean hasUsableFingerprint(Context ctx) {
|
||||
if (SDK_INT < 28) return false;
|
||||
FingerprintManagerCompat fm = FingerprintManagerCompat.from(ctx);
|
||||
return fm.hasEnrolledFingerprints() && fm.isHardwareDetected();
|
||||
}
|
||||
|
||||
public static void triggerFeedback(AndroidExecutor androidExecutor) {
|
||||
androidExecutor.runOnBackgroundThread(
|
||||
() -> ACRA.getErrorReporter()
|
||||
|
||||
@@ -14,36 +14,11 @@
|
||||
android:layout_height="150dp"
|
||||
android:layout_margin="@dimen/margin_large"
|
||||
android:src="@drawable/splash_screen"
|
||||
app:layout_constraintBottom_toTopOf="@+id/is_locked"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="spread"
|
||||
app:layout_constraintVertical_bias="0.1"
|
||||
app:tint="?attr/colorControlNormal"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/is_locked"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/margin_large"
|
||||
android:gravity="center"
|
||||
android:text="@string/lock_is_locked"
|
||||
android:textSize="@dimen/text_size_xlarge"
|
||||
app:layout_constraintBottom_toTopOf="@+id/unlock"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/image"
|
||||
app:layout_constraintVertical_chainStyle="spread"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/unlock"
|
||||
style="@style/BriarButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/margin_large"
|
||||
android:text="@string/lock_unlock"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
@@ -475,6 +475,8 @@
|
||||
<!-- App Locking -->
|
||||
<string name="lock_unlock">Unlock Briar</string>
|
||||
<string name="lock_unlock_verbose">Enter your device PIN, pattern or password to unlock Briar</string>
|
||||
<string name="lock_unlock_fingerprint_description">Touch your fingerprint sensor with the registered finger to continue</string>
|
||||
<string name="lock_unlock_password">Use Password</string>
|
||||
<string name="lock_is_locked">Briar is locked</string>
|
||||
<string name="lock_tap_to_unlock">Tap to unlock</string>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user