diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java
index 4ec5e1b67c5ddee191f4db5cd4763658c4ca83b0..6404c4bc33d65c90d8eb32754861355cffa839fb 100644
--- a/keystore/java/android/security/Authorization.java
+++ b/keystore/java/android/security/Authorization.java
@@ -100,12 +100,14 @@ public class Authorization {
      *
      * @param userId - the user's Android user ID
      * @param unlockingSids - list of biometric SIDs with which the device may be unlocked again
+     * @param weakUnlockEnabled - true if non-strong biometric or trust agent unlock is enabled
      * @return 0 if successful or a {@code ResponseCode}.
      */
-    public static int onDeviceLocked(int userId, @NonNull long[] unlockingSids) {
+    public static int onDeviceLocked(int userId, @NonNull long[] unlockingSids,
+            boolean weakUnlockEnabled) {
         StrictMode.noteDiskWrite();
         try {
-            getService().onDeviceLocked(userId, unlockingSids);
+            getService().onDeviceLocked(userId, unlockingSids, weakUnlockEnabled);
             return 0;
         } catch (RemoteException | NullPointerException e) {
             Log.w(TAG, "Can not connect to keystore", e);
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index ed9445c267404803513ea9ba80f9ff539b3e7056..ba8a76c9dddea842a7e4045cd2c2a79ee42e5edd 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -44,6 +44,9 @@ import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricSourceType;
+import android.hardware.biometrics.SensorProperties;
+import android.hardware.face.FaceManager;
+import android.hardware.fingerprint.FingerprintManager;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -157,6 +160,8 @@ public class TrustManagerService extends SystemService {
     private final LockPatternUtils mLockPatternUtils;
     private final UserManager mUserManager;
     private final ActivityManager mActivityManager;
+    private FingerprintManager mFingerprintManager;
+    private FaceManager mFaceManager;
     private VirtualDeviceManagerInternal mVirtualDeviceManager;
 
     private enum TrustState {
@@ -294,6 +299,8 @@ public class TrustManagerService extends SystemService {
             mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
             mReceiver.register(mContext);
             mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker);
+            mFingerprintManager = mContext.getSystemService(FingerprintManager.class);
+            mFaceManager = mContext.getSystemService(FaceManager.class);
         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             mTrustAgentsCanRun = true;
             refreshAgentList(UserHandle.USER_ALL);
@@ -895,7 +902,19 @@ public class TrustManagerService extends SystemService {
 
     private void notifyKeystoreOfDeviceLockState(int userId, boolean isLocked) {
         if (isLocked) {
-            Authorization.onDeviceLocked(userId, getBiometricSids(userId));
+            if (android.security.Flags.fixUnlockedDeviceRequiredKeysV2()) {
+                // A profile with unified challenge is unlockable not by its own biometrics and
+                // trust agents, but rather by those of the parent user.  Therefore, when protecting
+                // the profile's UnlockedDeviceRequired keys, we must use the parent's list of
+                // biometric SIDs and weak unlock methods, not the profile's.
+                int authUserId = mLockPatternUtils.isProfileWithUnifiedChallenge(userId)
+                        ? resolveProfileParent(userId) : userId;
+
+                Authorization.onDeviceLocked(userId, getBiometricSids(authUserId),
+                        isWeakUnlockMethodEnabled(authUserId));
+            } else {
+                Authorization.onDeviceLocked(userId, getBiometricSids(userId), false);
+            }
         } else {
             // Notify Keystore that the device is now unlocked for the user.  Note that for unlocks
             // with LSKF, this is redundant with the call from LockSettingsService which provides
@@ -1442,16 +1461,59 @@ public class TrustManagerService extends SystemService {
         if (biometricManager == null) {
             return new long[0];
         }
-        if (android.security.Flags.fixUnlockedDeviceRequiredKeysV2()
-                && mLockPatternUtils.isProfileWithUnifiedChallenge(userId)) {
-            // Profiles with unified challenge have their own set of biometrics, but the device
-            // unlock happens via the parent user.  In this case Keystore needs to be given the list
-            // of biometric SIDs from the parent user, not the profile.
-            userId = resolveProfileParent(userId);
-        }
         return biometricManager.getAuthenticatorIds(userId);
     }
 
+    // Returns whether the device can become unlocked for the specified user via one of that user's
+    // non-strong biometrics or trust agents.  This assumes that the device is currently locked, or
+    // is becoming locked, for the user.
+    private boolean isWeakUnlockMethodEnabled(int userId) {
+
+        // Check whether the system currently allows the use of non-strong biometrics for the user,
+        // *and* the user actually has a non-strong biometric enrolled.
+        //
+        // The biometrics framework ostensibly supports multiple sensors per modality.  However,
+        // that feature is unused and untested.  So, we simply consider one sensor per modality.
+        //
+        // Also, currently we just consider fingerprint and face, matching Keyguard.  If Keyguard
+        // starts supporting other biometric modalities, this will need to be updated.
+        if (mStrongAuthTracker.isBiometricAllowedForUser(/* isStrongBiometric= */ false, userId)) {
+            DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
+            int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, userId);
+
+            if (mFingerprintManager != null
+                    && (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) == 0
+                    && mFingerprintManager.hasEnrolledTemplates(userId)
+                    && isWeakOrConvenienceSensor(
+                            mFingerprintManager.getSensorProperties().get(0))) {
+                Slog.i(TAG, "User is unlockable by non-strong fingerprint auth");
+                return true;
+            }
+
+            if (mFaceManager != null
+                    && (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_FACE) == 0
+                    && mFaceManager.hasEnrolledTemplates(userId)
+                    && isWeakOrConvenienceSensor(mFaceManager.getSensorProperties().get(0))) {
+                Slog.i(TAG, "User is unlockable by non-strong face auth");
+                return true;
+            }
+        }
+
+        // Check whether it's possible for the device to be actively unlocked by a trust agent.
+        if (getUserTrustStateInner(userId) == TrustState.TRUSTABLE
+                || (isAutomotive() && isTrustUsuallyManagedInternal(userId))) {
+            Slog.i(TAG, "User is unlockable by trust agent");
+            return true;
+        }
+
+        return false;
+    }
+
+    private static boolean isWeakOrConvenienceSensor(SensorProperties sensor) {
+        return sensor.getSensorStrength() == SensorProperties.STRENGTH_WEAK
+                || sensor.getSensorStrength() == SensorProperties.STRENGTH_CONVENIENCE;
+    }
+
     // User lifecycle
 
     @Override
diff --git a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
index 37ca09d9fa2707cb120433317b829ed643c5b054..b41568298dbc1c32ff11d1cfc4d1364f07f767ca 100644
--- a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
@@ -47,6 +47,10 @@ import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
 import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.SensorProperties;
+import android.hardware.face.FaceManager;
+import android.hardware.face.FaceSensorProperties;
+import android.hardware.fingerprint.FingerprintManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -69,6 +73,7 @@ import android.view.WindowManagerGlobal;
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
 import com.android.modules.utils.testing.ExtendedMockitoRule;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -105,6 +110,8 @@ public class TrustManagerServiceTest {
 
     private static final String URI_SCHEME_PACKAGE = "package";
     private static final int TEST_USER_ID = 50;
+    private static final UserInfo TEST_USER =
+            new UserInfo(TEST_USER_ID, "user", UserInfo.FLAG_FULL);
     private static final int PARENT_USER_ID = 60;
     private static final int PROFILE_USER_ID = 70;
     private static final long[] PARENT_BIOMETRIC_SIDS = new long[] { 600L, 601L };
@@ -117,6 +124,8 @@ public class TrustManagerServiceTest {
     private @Mock ActivityManager mActivityManager;
     private @Mock BiometricManager mBiometricManager;
     private @Mock DevicePolicyManager mDevicePolicyManager;
+    private @Mock FaceManager mFaceManager;
+    private @Mock FingerprintManager mFingerprintManager;
     private @Mock IKeystoreAuthorization mKeystoreAuthorization;
     private @Mock LockPatternUtils mLockPatternUtils;
     private @Mock PackageManager mPackageManager;
@@ -133,6 +142,9 @@ public class TrustManagerServiceTest {
         when(mActivityManager.isUserRunning(TEST_USER_ID)).thenReturn(true);
         doReturn(mock(IActivityManager.class)).when(() -> ActivityManager.getService());
 
+        when(mFaceManager.getSensorProperties()).thenReturn(List.of());
+        when(mFingerprintManager.getSensorProperties()).thenReturn(List.of());
+
         doReturn(mKeystoreAuthorization).when(() -> Authorization.getService());
 
         when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager);
@@ -161,13 +173,16 @@ public class TrustManagerServiceTest {
         when(mPackageManager.checkPermission(any(), any())).thenReturn(
                 PackageManager.PERMISSION_GRANTED);
 
-        when(mUserManager.getAliveUsers()).thenReturn(
-                List.of(new UserInfo(TEST_USER_ID, "user", UserInfo.FLAG_FULL)));
+        when(mUserManager.getAliveUsers()).thenReturn(List.of(TEST_USER));
+        when(mUserManager.getEnabledProfileIds(TEST_USER_ID)).thenReturn(new int[0]);
+        when(mUserManager.getUserInfo(TEST_USER_ID)).thenReturn(TEST_USER);
 
         when(mWindowManager.isKeyguardLocked()).thenReturn(true);
 
         mMockContext.addMockSystemService(ActivityManager.class, mActivityManager);
         mMockContext.addMockSystemService(BiometricManager.class, mBiometricManager);
+        mMockContext.addMockSystemService(FaceManager.class, mFaceManager);
+        mMockContext.addMockSystemService(FingerprintManager.class, mFingerprintManager);
         mMockContext.setMockPackageManager(mPackageManager);
         mMockContext.addMockSystemService(UserManager.class, mUserManager);
         doReturn(mWindowManager).when(() -> WindowManagerGlobal.getWindowManagerService());
@@ -362,9 +377,9 @@ public class TrustManagerServiceTest {
         when(mWindowManager.isKeyguardLocked()).thenReturn(true);
         mTrustManager.reportKeyguardShowingChanged();
         verify(mKeystoreAuthorization)
-                .onDeviceLocked(eq(PARENT_USER_ID), eq(PARENT_BIOMETRIC_SIDS));
+                .onDeviceLocked(eq(PARENT_USER_ID), eq(PARENT_BIOMETRIC_SIDS), eq(false));
         verify(mKeystoreAuthorization)
-                .onDeviceLocked(eq(PROFILE_USER_ID), eq(PARENT_BIOMETRIC_SIDS));
+                .onDeviceLocked(eq(PROFILE_USER_ID), eq(PARENT_BIOMETRIC_SIDS), eq(false));
     }
 
     // Tests that when the device is locked for a managed profile with a *separate* challenge, the
@@ -381,7 +396,188 @@ public class TrustManagerServiceTest {
 
         mTrustManager.setDeviceLockedForUser(PROFILE_USER_ID, true);
         verify(mKeystoreAuthorization)
-                .onDeviceLocked(eq(PROFILE_USER_ID), eq(PROFILE_BIOMETRIC_SIDS));
+                .onDeviceLocked(eq(PROFILE_USER_ID), eq(PROFILE_BIOMETRIC_SIDS), eq(false));
+    }
+
+    @Test
+    @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
+    public void testKeystoreWeakUnlockEnabled_whenWeakFingerprintIsSetupAndAllowed()
+            throws Exception {
+        setupStrongAuthTrackerToAllowEverything();
+        setupFingerprint(SensorProperties.STRENGTH_WEAK);
+        verifyWeakUnlockEnabled();
+    }
+
+    @Test
+    @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
+    public void testKeystoreWeakUnlockEnabled_whenWeakFaceIsSetupAndAllowed() throws Exception {
+        setupStrongAuthTrackerToAllowEverything();
+        setupFace(SensorProperties.STRENGTH_WEAK);
+        verifyWeakUnlockEnabled();
+    }
+
+    @Test
+    @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
+    public void testKeystoreWeakUnlockEnabled_whenConvenienceFingerprintIsSetupAndAllowed()
+            throws Exception {
+        setupStrongAuthTrackerToAllowEverything();
+        setupFingerprint(SensorProperties.STRENGTH_CONVENIENCE);
+        verifyWeakUnlockEnabled();
+    }
+
+    @Test
+    @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
+    public void testKeystoreWeakUnlockEnabled_whenConvenienceFaceIsSetupAndAllowed()
+            throws Exception {
+        setupStrongAuthTrackerToAllowEverything();
+        setupFace(SensorProperties.STRENGTH_CONVENIENCE);
+        verifyWeakUnlockEnabled();
+    }
+
+    @Test
+    @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
+    public void testKeystoreWeakUnlockDisabled_whenStrongAuthRequired() throws Exception {
+        setupStrongAuthTracker(StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, true);
+        setupFace(SensorProperties.STRENGTH_WEAK);
+        verifyWeakUnlockDisabled();
+    }
+
+    @Test
+    @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
+    public void testKeystoreWeakUnlockDisabled_whenNonStrongBiometricNotAllowed() throws Exception {
+        setupStrongAuthTracker(StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED,
+                /* isNonStrongBiometricAllowed= */ false);
+        setupFace(SensorProperties.STRENGTH_WEAK);
+        verifyWeakUnlockDisabled();
+    }
+
+    @Test
+    @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
+    public void testKeystoreWeakUnlockDisabled_whenWeakFingerprintSensorIsPresentButNotEnrolled()
+            throws Exception {
+        setupStrongAuthTrackerToAllowEverything();
+        setupFingerprint(SensorProperties.STRENGTH_WEAK, /* enrolled= */ false);
+        verifyWeakUnlockDisabled();
+    }
+
+    @Test
+    @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
+    public void testKeystoreWeakUnlockDisabled_whenWeakFaceSensorIsPresentButNotEnrolled()
+            throws Exception {
+        setupStrongAuthTrackerToAllowEverything();
+        setupFace(SensorProperties.STRENGTH_WEAK, /* enrolled= */ false);
+        verifyWeakUnlockDisabled();
+    }
+
+    @Test
+    @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
+    public void
+            testKeystoreWeakUnlockDisabled_whenWeakFingerprintIsSetupButForbiddenByDevicePolicy()
+            throws Exception {
+        setupStrongAuthTrackerToAllowEverything();
+        setupFingerprint(SensorProperties.STRENGTH_WEAK);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(null, TEST_USER_ID))
+                .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
+        verifyWeakUnlockDisabled();
+    }
+
+    @Test
+    @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
+    public void testKeystoreWeakUnlockDisabled_whenWeakFaceIsSetupButForbiddenByDevicePolicy()
+            throws Exception {
+        setupStrongAuthTrackerToAllowEverything();
+        setupFace(SensorProperties.STRENGTH_WEAK);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(null, TEST_USER_ID))
+                .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE);
+        verifyWeakUnlockDisabled();
+    }
+
+    @Test
+    @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
+    public void testKeystoreWeakUnlockDisabled_whenOnlyStrongFingerprintIsSetup() throws Exception {
+        setupStrongAuthTrackerToAllowEverything();
+        setupFingerprint(SensorProperties.STRENGTH_STRONG);
+        verifyWeakUnlockDisabled();
+    }
+
+    @Test
+    @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
+    public void testKeystoreWeakUnlockDisabled_whenOnlyStrongFaceIsSetup() throws Exception {
+        setupStrongAuthTrackerToAllowEverything();
+        setupFace(SensorProperties.STRENGTH_STRONG);
+        verifyWeakUnlockDisabled();
+    }
+
+    @Test
+    @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
+    public void testKeystoreWeakUnlockDisabled_whenNoBiometricsAreSetup() throws Exception {
+        setupStrongAuthTrackerToAllowEverything();
+        verifyWeakUnlockDisabled();
+    }
+
+    private void setupStrongAuthTrackerToAllowEverything() throws Exception {
+        setupStrongAuthTracker(StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED, true);
+    }
+
+    private void setupStrongAuthTracker(int strongAuthFlags, boolean isNonStrongBiometricAllowed)
+            throws Exception {
+        bootService();
+        mService.onUserSwitching(null, new SystemService.TargetUser(TEST_USER));
+
+        ArgumentCaptor<StrongAuthTracker> strongAuthTracker =
+                ArgumentCaptor.forClass(StrongAuthTracker.class);
+        verify(mLockPatternUtils).registerStrongAuthTracker(strongAuthTracker.capture());
+        strongAuthTracker.getValue().getStub().onStrongAuthRequiredChanged(
+                strongAuthFlags, TEST_USER_ID);
+        strongAuthTracker.getValue().getStub().onIsNonStrongBiometricAllowedChanged(
+                isNonStrongBiometricAllowed, TEST_USER_ID);
+        mService.waitForIdle();
+    }
+
+    private void setupFingerprint(int strength) {
+        setupFingerprint(strength, /* enrolled= */ true);
+    }
+
+    private void setupFingerprint(int strength, boolean enrolled) {
+        int sensorId = 100;
+        List<SensorProperties.ComponentInfo> componentInfo = List.of();
+        SensorProperties sensor = new SensorProperties(sensorId, strength, componentInfo);
+        when(mFingerprintManager.getSensorProperties()).thenReturn(List.of(sensor));
+        when(mFingerprintManager.hasEnrolledTemplates(TEST_USER_ID)).thenReturn(enrolled);
+    }
+
+    private void setupFace(int strength) {
+        setupFace(strength, /* enrolled= */ true);
+    }
+
+    private void setupFace(int strength, boolean enrolled) {
+        int sensorId = 100;
+        List<SensorProperties.ComponentInfo> componentInfo = List.of();
+        FaceSensorProperties sensor = new FaceSensorProperties(
+                sensorId, strength, componentInfo, FaceSensorProperties.TYPE_RGB);
+        when(mFaceManager.getSensorProperties()).thenReturn(List.of(sensor));
+        when(mFaceManager.hasEnrolledTemplates(TEST_USER_ID)).thenReturn(enrolled);
+    }
+
+    private void verifyWeakUnlockEnabled() throws Exception {
+        verifyWeakUnlockValue(true);
+    }
+
+    private void verifyWeakUnlockDisabled() throws Exception {
+        verifyWeakUnlockValue(false);
+    }
+
+    // Simulates a device unlock and a device lock, then verifies that the expected
+    // weakUnlockEnabled flag was passed to Keystore's onDeviceLocked method.
+    private void verifyWeakUnlockValue(boolean expectedWeakUnlockEnabled) throws Exception {
+        when(mWindowManager.isKeyguardLocked()).thenReturn(false);
+        mTrustManager.reportKeyguardShowingChanged();
+        verify(mKeystoreAuthorization).onDeviceUnlocked(TEST_USER_ID, null);
+
+        when(mWindowManager.isKeyguardLocked()).thenReturn(true);
+        mTrustManager.reportKeyguardShowingChanged();
+        verify(mKeystoreAuthorization).onDeviceLocked(eq(TEST_USER_ID), any(),
+                eq(expectedWeakUnlockEnabled));
     }
 
     private void setupMocksForProfile(boolean unifiedChallenge) {