diff --git a/briar-android/build.gradle b/briar-android/build.gradle
index bb4988e825110c3dd3de940a1a6a73311c485924..ef9427921fe63c69a84009ffda49f91078a66808 100644
--- a/briar-android/build.gradle
+++ b/briar-android/build.gradle
@@ -75,8 +75,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 82d4b83cfca31940105b2a64a3b4b57544bba5b8..79eb8b41a5dd723babfa06d22499a193d1e3865f 100644
--- a/briar-android/src/main/AndroidManifest.xml
+++ b/briar-android/src/main/AndroidManifest.xml
@@ -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"
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 49286c21f9e48bfb858be32868b4955e80935736..2842ecb3e5bdbf9f8d32be6c2cba19ccf6a9ebf7 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,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);
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 7fb316a622e387df0c0b837f2a2ee857f96196ce..4cb49aac5d7a00752ef32e646fd0c32d8f10504f 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;
@@ -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()
diff --git a/briar-android/src/main/res/layout/activity_unlock.xml b/briar-android/src/main/res/layout/activity_unlock.xml
index 48413a19820d5251e01c1418ffd54fb48aedcb09..83c8d594b103d7bfd9d57dc849240888a07e9f19 100644
--- a/briar-android/src/main/res/layout/activity_unlock.xml
+++ b/briar-android/src/main/res/layout/activity_unlock.xml
@@ -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>
\ No newline at end of file
diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml
index bdc04d7926923e84b0577bdc1b982e347dbfe1dc..722a2f50d1903ab75a89271ff9e36e967e755b5b 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>