Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f36a816a authored by Beverly's avatar Beverly Committed by Beverly Tai
Browse files

Show directional face auth feedback when unfolded

Bug: 319377982
Flag: NONE bugfix
Test: atest KeyguardIndicationControllerTest
Change-Id: I10c6d938ae0124663997477b7ddc8e369e69ed42
Merged-In: I10c6d938ae0124663997477b7ddc8e369e69ed42
parent 4fccc4e1
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -718,6 +718,20 @@
        <item>26</item> <!-- MOUTH_COVERING_DETECTED -->
    </integer-array>

    <!-- Which face help messages to surface when fingerprint is enrolled and device is unfolded.
     Message ids correspond with the acquired ids in BiometricFaceConstants -->
    <integer-array name="config_face_help_msgs_when_fingerprint_enrolled_unfolded">
        <item>3</item> <!-- TOO_DARK -->
        <item>4</item> <!-- TOO_CLOSE -->
        <item>5</item> <!-- TOO_FAR -->
        <item>6</item> <!-- TOO_HIGH -->
        <item>7</item> <!-- TOO_LOW -->
        <item>8</item> <!-- TOO_RIGHT -->
        <item>9</item> <!-- TOO_LEFT -->
        <item>25</item> <!-- DARK_GLASSES -->
        <item>26</item> <!-- MOUTH_COVERING_DETECTED -->
    </integer-array>

    <!-- Which device wake-ups will trigger passive auth. These values correspond with
         PowerManager#WakeReason. -->
    <integer-array name="config_face_auth_wake_up_triggers">
+52 −15
Original line number Diff line number Diff line
@@ -30,17 +30,20 @@ import com.android.systemui.deviceentry.shared.model.FingerprintFailureMessage
import com.android.systemui.deviceentry.shared.model.FingerprintLockoutMessage
import com.android.systemui.deviceentry.shared.model.FingerprintMessage
import com.android.systemui.deviceentry.shared.model.HelpFaceAuthenticationStatus
import com.android.systemui.keyguard.domain.interactor.DevicePostureInteractor
import com.android.systemui.keyguard.shared.model.DevicePosture
import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus
import com.android.systemui.res.R
import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.filterNot
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge

@@ -59,6 +62,7 @@ constructor(
    faceAuthInteractor: DeviceEntryFaceAuthInteractor,
    private val biometricSettingsInteractor: DeviceEntryBiometricSettingsInteractor,
    faceHelpMessageDeferralInteractor: FaceHelpMessageDeferralInteractor,
    devicePostureInteractor: DevicePostureInteractor,
) {
    private val faceHelp: Flow<HelpFaceAuthenticationStatus> =
        faceAuthInteractor.authenticationStatus.filterIsInstance<HelpFaceAuthenticationStatus>()
@@ -71,9 +75,18 @@ constructor(
     * The acquisition message ids to show message when both fingerprint and face are enrolled and
     * enabled for device entry.
     */
    private val coExFaceAcquisitionMsgIdsToShow: Set<Int> =
    private val coExFaceAcquisitionMsgIdsToShowDefault: Set<Int> =
        resources.getIntArray(R.array.config_face_help_msgs_when_fingerprint_enrolled).toSet()

    /**
     * The acquisition message ids to show message when both fingerprint and face are enrolled and
     * enabled for device entry and the device is unfolded.
     */
    private val coExFaceAcquisitionMsgIdsToShowUnfolded: Set<Int> =
        resources
            .getIntArray(R.array.config_face_help_msgs_when_fingerprint_enrolled_unfolded)
            .toSet()

    private fun ErrorFingerprintAuthenticationStatus.shouldSuppressError(): Boolean {
        return isCancellationError() || isPowerPressedError()
    }
@@ -122,6 +135,17 @@ constructor(
                }
        }

    val coExFaceAcquisitionMsgIdsToShow: Flow<Set<Int>> =
        devicePostureInteractor.posture.map { devicePosture ->
            when (devicePosture) {
                DevicePosture.OPENED -> coExFaceAcquisitionMsgIdsToShowUnfolded
                DevicePosture.UNKNOWN, // Devices without posture support (non-foldable) use UNKNOWN
                DevicePosture.CLOSED,
                DevicePosture.HALF_OPENED,
                DevicePosture.FLIPPED -> coExFaceAcquisitionMsgIdsToShowDefault
            }
        }

    val fingerprintMessage: Flow<FingerprintMessage> =
        merge(
            fingerprintErrorMessage,
@@ -129,25 +153,38 @@ constructor(
            fingerprintHelpMessage,
        )

    private val filterConditionForFaceHelpMessages:
        Flow<(HelpFaceAuthenticationStatus) -> Boolean> =
        combine(
                biometricSettingsInteractor.isFingerprintAuthEnrolledAndEnabled,
                biometricSettingsInteractor.faceAuthCurrentlyAllowed,
                ::Pair
            )
            .flatMapLatest { (fingerprintEnrolled, faceAuthCurrentlyAllowed) ->
                if (fingerprintEnrolled && faceAuthCurrentlyAllowed) {
                    // Show only some face help messages if fingerprint is also enrolled
                    coExFaceAcquisitionMsgIdsToShow.map { msgIdsToShow ->
                        { helpStatus: HelpFaceAuthenticationStatus ->
                            msgIdsToShow.contains(helpStatus.msgId)
                        }
                    }
                } else if (faceAuthCurrentlyAllowed) {
                    // Show all face help messages if only face is enrolled and currently allowed
                    flowOf { _: HelpFaceAuthenticationStatus -> true }
                } else {
                    flowOf { _: HelpFaceAuthenticationStatus -> false }
                }
            }

    private val faceHelpMessage: Flow<FaceMessage> =
        faceHelp
            .filterNot {
                // Message deferred to potentially show at face timeout error instead
                faceHelpMessageDeferralInteractor.shouldDefer(it.msgId)
            }
            .sample(biometricSettingsInteractor.fingerprintAndFaceEnrolledAndEnabled, ::Pair)
            .filter { (faceAuthHelpStatus, fingerprintAndFaceEnrolledAndEnabled) ->
                if (fingerprintAndFaceEnrolledAndEnabled) {
                    // Show only some face help messages if fingerprint is also enrolled
                    coExFaceAcquisitionMsgIdsToShow.contains(faceAuthHelpStatus.msgId)
                } else {
                    // Show all face help messages if only face is enrolled
                    true
                }
            }
            .sample(biometricSettingsInteractor.faceAuthCurrentlyAllowed, ::toTriple)
            .filter { (_, _, faceAuthCurrentlyAllowed) -> faceAuthCurrentlyAllowed }
            .map { (status, _, _) -> FaceMessage(status.msg) }
            .sample(filterConditionForFaceHelpMessages, ::Pair)
            .filter { (helpMessage, filterCondition) -> filterCondition(helpMessage) }
            .map { (status, _) -> FaceMessage(status.msg) }

    private val faceFailureMessage: Flow<FaceMessage> =
        faceFailure
+31 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.keyguard.domain.interactor

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.DevicePostureRepository
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi

/** DevicePosture business logic. */
@ExperimentalCoroutinesApi
@SysUISingleton
class DevicePostureInteractor
@Inject
constructor(devicePostureRepository: DevicePostureRepository) {
    val posture = devicePostureRepository.currentDevicePosture
}
+15 −10
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.deviceentry.domain.interactor.BiometricMessageInteractor;
import com.android.systemui.dock.DockManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardIndication;
@@ -120,7 +121,6 @@ import com.android.systemui.util.wakelock.WakeLock;

import java.io.PrintWriter;
import java.text.NumberFormat;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;

@@ -181,6 +181,7 @@ public class KeyguardIndicationController {
    private BroadcastReceiver mBroadcastReceiver;
    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
    private KeyguardInteractor mKeyguardInteractor;
    private final BiometricMessageInteractor mBiometricMessageInteractor;
    private String mPersistentUnlockMessage;
    private String mAlignmentIndication;
    private boolean mForceIsDismissible;
@@ -209,7 +210,7 @@ public class KeyguardIndicationController {
    private boolean mBatteryPresent = true;
    protected long mChargingTimeRemaining;
    private Pair<String, BiometricSourceType> mBiometricErrorMessageToShowOnScreenOn;
    private final Set<Integer> mCoExFaceAcquisitionMsgIdsToShow;
    private Set<Integer> mCoExFaceAcquisitionMsgIdsToShow;
    private final FaceHelpMessageDeferral mFaceAcquiredMessageDeferral;
    private boolean mInited;

@@ -227,6 +228,10 @@ public class KeyguardIndicationController {
                mIsActiveDreamLockscreenHosted = isLockscreenHosted;
                updateDeviceEntryIndication(false);
            };
    @VisibleForTesting
    final Consumer<Set<Integer>> mCoExAcquisitionMsgIdsToShowCallback =
            (Set<Integer> coExFaceAcquisitionMsgIdsToShow) -> mCoExFaceAcquisitionMsgIdsToShow =
                    coExFaceAcquisitionMsgIdsToShow;
    private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
        @Override
        public void onScreenTurnedOn() {
@@ -286,7 +291,8 @@ public class KeyguardIndicationController {
            BouncerMessageInteractor bouncerMessageInteractor,
            FeatureFlags flags,
            IndicationHelper indicationHelper,
            KeyguardInteractor keyguardInteractor
            KeyguardInteractor keyguardInteractor,
            BiometricMessageInteractor biometricMessageInteractor
    ) {
        mContext = context;
        mBroadcastDispatcher = broadcastDispatcher;
@@ -315,14 +321,9 @@ public class KeyguardIndicationController {
        mFeatureFlags = flags;
        mIndicationHelper = indicationHelper;
        mKeyguardInteractor = keyguardInteractor;
        mBiometricMessageInteractor = biometricMessageInteractor;

        mFaceAcquiredMessageDeferral = faceHelpMessageDeferral.create();
        mCoExFaceAcquisitionMsgIdsToShow = new HashSet<>();
        int[] msgIds = context.getResources().getIntArray(
                com.android.systemui.res.R.array.config_face_help_msgs_when_fingerprint_enrolled);
        for (int msgId : msgIds) {
            mCoExFaceAcquisitionMsgIdsToShow.add(msgId);
        }

        mHandler = new Handler(mainLooper) {
            @Override
@@ -401,6 +402,10 @@ public class KeyguardIndicationController {
            collectFlow(mIndicationArea, mKeyguardInteractor.isActiveDreamLockscreenHosted(),
                    mIsActiveDreamLockscreenHostedCallback);
        }

        collectFlow(mIndicationArea,
                mBiometricMessageInteractor.getCoExFaceAcquisitionMsgIdsToShow(),
                mCoExAcquisitionMsgIdsToShowCallback);
    }

    /**
+2 −0
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@ class Utils {
        fun <A, B, C, D> toQuad(a: A, b: B, c: C, d: D) = Quad(a, b, c, d)
        fun <A, B, C, D> toQuad(a: A, bcd: Triple<B, C, D>) =
            Quad(a, bcd.first, bcd.second, bcd.third)
        fun <A, B, C, D> toQuad(abc: Triple<A, B, C>, d: D) =
            Quad(abc.first, abc.second, abc.third, d)

        fun <A, B, C, D, E> toQuint(a: A, b: B, c: C, d: D, e: E) = Quint(a, b, c, d, e)
        fun <A, B, C, D, E> toQuint(a: A, bcde: Quad<B, C, D, E>) =
Loading