From c5d374af04aa1c110037c35674e353a34bd82870 Mon Sep 17 00:00:00 2001
From: Torsten Grote <t@grobox.de>
Date: Tue, 7 Aug 2018 18:33:11 -0300
Subject: [PATCH 1/4] ScreenLock: Implement fingerprint unlocking with
 BiometricPromptCompat

---
 briar-android/build.gradle                    |  5 +-
 briar-android/src/main/AndroidManifest.xml    |  7 +-
 .../briar/android/login/UnlockActivity.java   | 80 ++++++++++++++++++-
 .../briar/android/util/UiUtils.java           | 11 +++
 .../src/main/res/layout/activity_unlock.xml   | 18 +----
 briar-android/src/main/res/values/strings.xml |  2 +
 briar-android/witness.gradle                  |  1 +
 7 files changed, 103 insertions(+), 21 deletions(-)

diff --git a/briar-android/build.gradle b/briar-android/build.gradle
index bb4988e825..9f7e35b066 100644
--- a/briar-android/build.gradle
+++ b/briar-android/build.gradle
@@ -33,6 +33,7 @@ dependencies {
 	implementation 'com.google.zxing:core:3.3.0'
 	implementation 'uk.co.samuelwall:material-tap-target-prompt:2.8.0'
 	implementation 'com.vanniktech:emoji-google:0.5.1'
+	implementation 'moe.feng.support.biometricprompt:library:1.0.1'
 
 	annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
 
@@ -75,8 +76,8 @@ def getStdout = { command, defaultValue ->
 }
 
 android {
-	compileSdkVersion 27
-	buildToolsVersion '27.0.3'
+	compileSdkVersion 28
+	buildToolsVersion '28.0.2'
 
 	defaultConfig {
 		minSdkVersion 15
diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml
index 82d4b83cfc..722f3ff160 100644
--- a/briar-android/src/main/AndroidManifest.xml
+++ b/briar-android/src/main/AndroidManifest.xml
@@ -1,7 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest
 	package="org.briarproject.briar"
-	xmlns:android="http://schemas.android.com/apk/res/android">
+	xmlns:android="http://schemas.android.com/apk/res/android"
+	xmlns:tools="http://schemas.android.com/tools">
+
+	<uses-sdk tools:overrideLibrary="moe.feng.support.biometricprompt"/>
 
 	<uses-feature android:name="android.hardware.bluetooth" android:required="false"/>
 	<uses-feature android:name="android.hardware.camera" android:required="false"/>
@@ -17,6 +20,8 @@
 	<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_FINGERPRINT" />
+	<uses-permission-sdk-23 android:name="android.permission.USE_BIOMETRIC" />
 
 	<application
 		android:name="org.briarproject.briar.android.BriarApplicationImpl"
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java
index 49286c21f9..76eff79505 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java
@@ -3,9 +3,12 @@ package org.briarproject.briar.android.login;
 import android.app.KeyguardManager;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.support.annotation.NonNull;
 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 +21,19 @@ import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
+import moe.feng.support.biometricprompt.BiometricPromptCompat;
+import moe.feng.support.biometricprompt.BiometricPromptCompat.Builder;
+import moe.feng.support.biometricprompt.BiometricPromptCompat.IAuthenticationCallback;
+import moe.feng.support.biometricprompt.BiometricPromptCompat.IAuthenticationResult;
+
 import static android.os.Build.VERSION.SDK_INT;
+import static moe.feng.support.biometricprompt.BiometricPromptCompat.BIOMETRIC_ERROR_CANCELED;
+import static moe.feng.support.biometricprompt.BiometricPromptCompat.BIOMETRIC_ERROR_LOCKOUT;
+import static moe.feng.support.biometricprompt.BiometricPromptCompat.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
+import static moe.feng.support.biometricprompt.BiometricPromptCompat.BIOMETRIC_ERROR_USER_CANCELED;
 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
@@ -46,7 +60,7 @@ public class UnlockActivity extends BaseActivity {
 		setContentView(R.layout.activity_unlock);
 
 		Button button = findViewById(R.id.unlock);
-		button.setOnClickListener(view -> requestKeyguardUnlock());
+		button.setOnClickListener(view -> requestUnlock());
 
 		keyguardShown = state != null && state.getBoolean(KEYGUARD_SHOWN);
 	}
@@ -83,18 +97,80 @@ 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 (hasUsableFingerprint(this)) {
+			requestFingerprintUnlock();
+		} else {
+			requestKeyguardUnlock();
+		}
+	}
+
 	@Override
 	public void onBackPressed() {
 		moveTaskToBack(true);
 	}
 
+	private void requestFingerprintUnlock() {
+		BiometricPromptCompat biometricPrompt = new Builder(this)
+				.setTitle(R.string.lock_unlock)
+				.setDescription(R.string.lock_unlock_fingerprint_description)
+				.setNegativeButton(R.string.lock_unlock_password,
+						(dialog, which) -> {
+							requestKeyguardUnlock();
+						})
+				.build();
+		CancellationSignal signal = new CancellationSignal();
+		biometricPrompt.authenticate(signal, new IAuthenticationCallback() {
+			@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();
+				}
+				// locked out due to 5 failed attempts, lasts for 30 seconds
+				else if (errorCode == BIOMETRIC_ERROR_LOCKOUT ||
+						errorCode == BIOMETRIC_ERROR_LOCKOUT_PERMANENT) {
+					if (hasKeyguardLock(UnlockActivity.this)) {
+						requestKeyguardUnlock();
+					} else {
+						// normally fingerprints require a screen lock, but
+						// who knows if that's true for all devices out there
+						Toast.makeText(UnlockActivity.this, errString,
+								Toast.LENGTH_LONG).show();
+						finish();
+					}
+				} else {
+					Toast.makeText(UnlockActivity.this, errString,
+							Toast.LENGTH_LONG).show();
+				}
+			}
+
+			@Override
+			public void onAuthenticationHelp(int helpCode,
+					@Nullable CharSequence helpString) {
+			}
+
+			@Override
+			public void onAuthenticationSucceeded(
+					@NonNull IAuthenticationResult result) {
+				unlock();
+			}
+
+			@Override
+			public void onAuthenticationFailed() {
+			}
+		});
+	}
+
 	private void requestKeyguardUnlock() {
 		KeyguardManager keyguardManager =
 				(KeyguardManager) getSystemService(KEYGUARD_SERVICE);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
index 7fb316a622..7eb04eb8a7 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
@@ -59,6 +59,8 @@ import static android.text.format.DateUtils.FORMAT_ABBREV_TIME;
 import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
+import static moe.feng.support.biometricprompt.BiometricPromptCompat.hasEnrolledFingerprints;
+import static moe.feng.support.biometricprompt.BiometricPromptCompat.isHardwareDetected;
 import static org.briarproject.briar.BuildConfig.APPLICATION_ID;
 import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE;
 
@@ -261,6 +263,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 +277,11 @@ public class UiUtils {
 				(SDK_INT >= 23 && keyguardManager.isDeviceSecure());
 	}
 
+	public static boolean hasUsableFingerprint(Context ctx) {
+		return SDK_INT >= 23 && isHardwareDetected(ctx) &&
+				hasEnrolledFingerprints(ctx);
+	}
+
 	public static void triggerFeedback(AndroidExecutor androidExecutor) {
 		androidExecutor.runOnBackgroundThread(
 				() -> ACRA.getErrorReporter()
diff --git a/briar-android/src/main/res/layout/activity_unlock.xml b/briar-android/src/main/res/layout/activity_unlock.xml
index 48413a1982..32e87ad55f 100644
--- a/briar-android/src/main/res/layout/activity_unlock.xml
+++ b/briar-android/src/main/res/layout/activity_unlock.xml
@@ -14,27 +14,13 @@
 		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_toTopOf="@+id/unlock"
 		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"
diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml
index bdc04d7926..722a2f50d1 100644
--- a/briar-android/src/main/res/values/strings.xml
+++ b/briar-android/src/main/res/values/strings.xml
@@ -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>
 
diff --git a/briar-android/witness.gradle b/briar-android/witness.gradle
index e262ffb0cb..ae5feada30 100644
--- a/briar-android/witness.gradle
+++ b/briar-android/witness.gradle
@@ -100,6 +100,7 @@ dependencyVerification {
         'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
         'javax.xml.bind:jaxb-api:2.2.12-b140109.1041:jaxb-api-2.2.12-b140109.1041.jar:b5e60cd8b7b5ff01ce4a74c5dd008f4fbd14ced3495d0b47b85cfedc182211f2',
         'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
+        'moe.feng.support.biometricprompt:library:1.0.1:library-1.0.1.aar:2cf011abdc9c51a505b35f421197b4fbeba79af792e9ea1ca973f1aef087dacd',
         'nekohtml:nekohtml:1.9.6.2:nekohtml-1.9.6.2.jar:fdff6cfa9ed9cc911c842a5d2395f209ec621ef1239d46810e9e495809d3ae09',
         'nekohtml:xercesMinimal:1.9.6.2:xercesMinimal-1.9.6.2.jar:95b8b357d19f63797dd7d67622fd3f18374d64acbc6584faba1c7759a31e8438',
         'net.bytebuddy:byte-buddy-agent:1.7.9:byte-buddy-agent-1.7.9.jar:ac1a993befb528c3271a83a9ad9c42d363d399e9deb26e0470e3c4962066c550',
-- 
GitLab


From 57841be4479cae89e2b66caa3a4579dca64480e6 Mon Sep 17 00:00:00 2001
From: Torsten Grote <t@grobox.de>
Date: Thu, 30 Aug 2018 11:50:55 -0300
Subject: [PATCH 2/4] Remove BiometricPromptCompat library and limit feature to
 API 28

---
 briar-android/build.gradle                    |  1 -
 briar-android/src/main/AndroidManifest.xml    |  6 +--
 .../briar/android/login/UnlockActivity.java   | 43 +++++++++----------
 .../briar/android/util/UiUtils.java           |  8 ++--
 briar-android/witness.gradle                  |  1 -
 5 files changed, 26 insertions(+), 33 deletions(-)

diff --git a/briar-android/build.gradle b/briar-android/build.gradle
index 9f7e35b066..ef9427921f 100644
--- a/briar-android/build.gradle
+++ b/briar-android/build.gradle
@@ -33,7 +33,6 @@ dependencies {
 	implementation 'com.google.zxing:core:3.3.0'
 	implementation 'uk.co.samuelwall:material-tap-target-prompt:2.8.0'
 	implementation 'com.vanniktech:emoji-google:0.5.1'
-	implementation 'moe.feng.support.biometricprompt:library:1.0.1'
 
 	annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
 
diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml
index 722f3ff160..79eb8b41a5 100644
--- a/briar-android/src/main/AndroidManifest.xml
+++ b/briar-android/src/main/AndroidManifest.xml
@@ -1,10 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest
 	package="org.briarproject.briar"
-	xmlns:android="http://schemas.android.com/apk/res/android"
-	xmlns:tools="http://schemas.android.com/tools">
-
-	<uses-sdk tools:overrideLibrary="moe.feng.support.biometricprompt"/>
+	xmlns:android="http://schemas.android.com/apk/res/android">
 
 	<uses-feature android:name="android.hardware.bluetooth" android:required="false"/>
 	<uses-feature android:name="android.hardware.camera" android:required="false"/>
@@ -20,7 +17,6 @@
 	<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_FINGERPRINT" />
 	<uses-permission-sdk-23 android:name="android.permission.USE_BIOMETRIC" />
 
 	<application
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java
index 76eff79505..29155a7266 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java
@@ -2,9 +2,12 @@ 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.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RequiresApi;
 import android.widget.Button;
@@ -21,16 +24,11 @@ import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
-import moe.feng.support.biometricprompt.BiometricPromptCompat;
-import moe.feng.support.biometricprompt.BiometricPromptCompat.Builder;
-import moe.feng.support.biometricprompt.BiometricPromptCompat.IAuthenticationCallback;
-import moe.feng.support.biometricprompt.BiometricPromptCompat.IAuthenticationResult;
-
+import static android.hardware.biometrics.BiometricPrompt.BIOMETRIC_ERROR_CANCELED;
+import static android.hardware.biometrics.BiometricPrompt.BIOMETRIC_ERROR_LOCKOUT;
+import static android.hardware.biometrics.BiometricPrompt.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
+import static android.hardware.biometrics.BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED;
 import static android.os.Build.VERSION.SDK_INT;
-import static moe.feng.support.biometricprompt.BiometricPromptCompat.BIOMETRIC_ERROR_CANCELED;
-import static moe.feng.support.biometricprompt.BiometricPromptCompat.BIOMETRIC_ERROR_LOCKOUT;
-import static moe.feng.support.biometricprompt.BiometricPromptCompat.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
-import static moe.feng.support.biometricprompt.BiometricPromptCompat.BIOMETRIC_ERROR_USER_CANCELED;
 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;
@@ -105,7 +103,7 @@ public class UnlockActivity extends BaseActivity {
 	}
 
 	private void requestUnlock() {
-		if (hasUsableFingerprint(this)) {
+		if (SDK_INT >= 28 && hasUsableFingerprint(this)) {
 			requestFingerprintUnlock();
 		} else {
 			requestKeyguardUnlock();
@@ -117,17 +115,18 @@ public class UnlockActivity extends BaseActivity {
 		moveTaskToBack(true);
 	}
 
+	@RequiresApi(api = 28)
 	private void requestFingerprintUnlock() {
-		BiometricPromptCompat biometricPrompt = new Builder(this)
-				.setTitle(R.string.lock_unlock)
-				.setDescription(R.string.lock_unlock_fingerprint_description)
-				.setNegativeButton(R.string.lock_unlock_password,
-						(dialog, which) -> {
-							requestKeyguardUnlock();
-						})
+		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();
-		biometricPrompt.authenticate(signal, new IAuthenticationCallback() {
+		AuthenticationCallback callback = new AuthenticationCallback() {
 			@Override
 			public void onAuthenticationError(int errorCode,
 					@Nullable CharSequence errString) {
@@ -160,15 +159,15 @@ public class UnlockActivity extends BaseActivity {
 			}
 
 			@Override
-			public void onAuthenticationSucceeded(
-					@NonNull IAuthenticationResult result) {
+			public void onAuthenticationSucceeded(AuthenticationResult result) {
 				unlock();
 			}
 
 			@Override
 			public void onAuthenticationFailed() {
 			}
-		});
+		};
+		biometricPrompt.authenticate(signal, getMainExecutor(), callback);
 	}
 
 	private void requestKeyguardUnlock() {
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
index 7eb04eb8a7..4cb49aac5d 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
@@ -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;
@@ -59,8 +60,6 @@ import static android.text.format.DateUtils.FORMAT_ABBREV_TIME;
 import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
-import static moe.feng.support.biometricprompt.BiometricPromptCompat.hasEnrolledFingerprints;
-import static moe.feng.support.biometricprompt.BiometricPromptCompat.isHardwareDetected;
 import static org.briarproject.briar.BuildConfig.APPLICATION_ID;
 import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE;
 
@@ -278,8 +277,9 @@ public class UiUtils {
 	}
 
 	public static boolean hasUsableFingerprint(Context ctx) {
-		return SDK_INT >= 23 && isHardwareDetected(ctx) &&
-				hasEnrolledFingerprints(ctx);
+		if (SDK_INT < 28) return false;
+		FingerprintManagerCompat fm = FingerprintManagerCompat.from(ctx);
+		return fm.hasEnrolledFingerprints() && fm.isHardwareDetected();
 	}
 
 	public static void triggerFeedback(AndroidExecutor androidExecutor) {
diff --git a/briar-android/witness.gradle b/briar-android/witness.gradle
index ae5feada30..e262ffb0cb 100644
--- a/briar-android/witness.gradle
+++ b/briar-android/witness.gradle
@@ -100,7 +100,6 @@ dependencyVerification {
         'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
         'javax.xml.bind:jaxb-api:2.2.12-b140109.1041:jaxb-api-2.2.12-b140109.1041.jar:b5e60cd8b7b5ff01ce4a74c5dd008f4fbd14ced3495d0b47b85cfedc182211f2',
         'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
-        'moe.feng.support.biometricprompt:library:1.0.1:library-1.0.1.aar:2cf011abdc9c51a505b35f421197b4fbeba79af792e9ea1ca973f1aef087dacd',
         'nekohtml:nekohtml:1.9.6.2:nekohtml-1.9.6.2.jar:fdff6cfa9ed9cc911c842a5d2395f209ec621ef1239d46810e9e495809d3ae09',
         'nekohtml:xercesMinimal:1.9.6.2:xercesMinimal-1.9.6.2.jar:95b8b357d19f63797dd7d67622fd3f18374d64acbc6584faba1c7759a31e8438',
         'net.bytebuddy:byte-buddy-agent:1.7.9:byte-buddy-agent-1.7.9.jar:ac1a993befb528c3271a83a9ad9c42d363d399e9deb26e0470e3c4962066c550',
-- 
GitLab


From a3fa15e90e14c5a1f33d280384cdf39b3b5c84ef Mon Sep 17 00:00:00 2001
From: Torsten Grote <t@grobox.de>
Date: Thu, 30 Aug 2018 12:14:02 -0300
Subject: [PATCH 3/4] Blank UnlockActivity when not using fingerprint unlock

---
 .../briar/android/login/UnlockActivity.java           | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java
index 29155a7266..4bbd3d1d0f 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java
@@ -29,6 +29,7 @@ import static android.hardware.biometrics.BiometricPrompt.BIOMETRIC_ERROR_LOCKOU
 import static android.hardware.biometrics.BiometricPrompt.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
 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;
@@ -60,6 +61,12 @@ public class UnlockActivity extends BaseActivity {
 		Button button = findViewById(R.id.unlock);
 		button.setOnClickListener(view -> requestUnlock());
 
+		if (!hasUsableFingerprint(this)) {
+			getWindow().setBackgroundDrawable(null);
+			button.setVisibility(INVISIBLE);
+			findViewById(R.id.image).setVisibility(INVISIBLE);
+		}
+
 		keyguardShown = state != null && state.getBoolean(KEYGUARD_SHOWN);
 	}
 
@@ -140,14 +147,14 @@ public class UnlockActivity extends BaseActivity {
 						errorCode == BIOMETRIC_ERROR_LOCKOUT_PERMANENT) {
 					if (hasKeyguardLock(UnlockActivity.this)) {
 						requestKeyguardUnlock();
-					} else {
+					} else if (errString != null) {
 						// normally fingerprints require a screen lock, but
 						// who knows if that's true for all devices out there
 						Toast.makeText(UnlockActivity.this, errString,
 								Toast.LENGTH_LONG).show();
 						finish();
 					}
-				} else {
+				} else if (errString != null) {
 					Toast.makeText(UnlockActivity.this, errString,
 							Toast.LENGTH_LONG).show();
 				}
-- 
GitLab


From 24c030f06f78387da1c85d6b398c4ca1e67be2c5 Mon Sep 17 00:00:00 2001
From: Torsten Grote <t@grobox.de>
Date: Tue, 4 Sep 2018 09:32:24 -0300
Subject: [PATCH 4/4] Remove button from UnlockActivity

---
 .../briar/android/login/UnlockActivity.java   | 24 ++++++-------------
 .../src/main/res/layout/activity_unlock.xml   | 13 +---------
 2 files changed, 8 insertions(+), 29 deletions(-)

diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java
index 4bbd3d1d0f..2842ecb3e5 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java
@@ -10,7 +10,6 @@ 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;
@@ -25,8 +24,6 @@ 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_LOCKOUT;
-import static android.hardware.biometrics.BiometricPrompt.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
 import static android.hardware.biometrics.BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED;
 import static android.os.Build.VERSION.SDK_INT;
 import static android.view.View.INVISIBLE;
@@ -58,15 +55,10 @@ public class UnlockActivity extends BaseActivity {
 		overridePendingTransition(0, 0);
 		setContentView(R.layout.activity_unlock);
 
-		Button button = findViewById(R.id.unlock);
-		button.setOnClickListener(view -> requestUnlock());
-
 		if (!hasUsableFingerprint(this)) {
 			getWindow().setBackgroundDrawable(null);
-			button.setVisibility(INVISIBLE);
 			findViewById(R.id.image).setVisibility(INVISIBLE);
 		}
-
 		keyguardShown = state != null && state.getBoolean(KEYGUARD_SHOWN);
 	}
 
@@ -142,21 +134,19 @@ public class UnlockActivity extends BaseActivity {
 						errorCode == BIOMETRIC_ERROR_USER_CANCELED) {
 					finish();
 				}
-				// locked out due to 5 failed attempts, lasts for 30 seconds
-				else if (errorCode == BIOMETRIC_ERROR_LOCKOUT ||
-						errorCode == BIOMETRIC_ERROR_LOCKOUT_PERMANENT) {
+				// e.g. 5 failed attempts
+				else {
 					if (hasKeyguardLock(UnlockActivity.this)) {
 						requestKeyguardUnlock();
-					} else if (errString != null) {
+					} else {
 						// normally fingerprints require a screen lock, but
 						// who knows if that's true for all devices out there
-						Toast.makeText(UnlockActivity.this, errString,
-								Toast.LENGTH_LONG).show();
+						if (errString != null) {
+							Toast.makeText(UnlockActivity.this, errString,
+									Toast.LENGTH_LONG).show();
+						}
 						finish();
 					}
-				} else if (errString != null) {
-					Toast.makeText(UnlockActivity.this, errString,
-							Toast.LENGTH_LONG).show();
 				}
 			}
 
diff --git a/briar-android/src/main/res/layout/activity_unlock.xml b/briar-android/src/main/res/layout/activity_unlock.xml
index 32e87ad55f..83c8d594b1 100644
--- a/briar-android/src/main/res/layout/activity_unlock.xml
+++ b/briar-android/src/main/res/layout/activity_unlock.xml
@@ -14,22 +14,11 @@
 		android:layout_height="150dp"
 		android:layout_margin="@dimen/margin_large"
 		android:src="@drawable/splash_screen"
-		app:layout_constraintBottom_toTopOf="@+id/unlock"
+		app:layout_constraintBottom_toBottomOf="parent"
 		app:layout_constraintEnd_toEndOf="parent"
 		app:layout_constraintStart_toStartOf="parent"
 		app:layout_constraintTop_toTopOf="parent"
 		app:layout_constraintVertical_bias="0.1"
 		app:tint="?attr/colorControlNormal"/>
 
-	<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>
\ No newline at end of file
-- 
GitLab