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

Commit 2264eab0 authored by Beverly Tai's avatar Beverly Tai Committed by Android (Google) Code Review
Browse files

Merge "Don't add the UdfpsView until after the device is finishedGoingToSleep" into main

parents 198545c4 cd5ef0a3
Loading
Loading
Loading
Loading
+85 −0
Original line number Diff line number Diff line
@@ -44,12 +44,18 @@ import com.android.systemui.biometrics.ui.viewmodel.DefaultUdfpsTouchOverlayView
import com.android.systemui.biometrics.ui.viewmodel.DeviceEntryUdfpsTouchOverlayViewModel
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.data.repository.FakePowerRepository
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.power.shared.model.WakefulnessState
import com.android.systemui.res.R
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController
@@ -58,6 +64,10 @@ import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -68,6 +78,7 @@ import org.mockito.ArgumentMatchers.eq
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
@@ -120,6 +131,9 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
    @Mock private lateinit var shadeInteractor: ShadeInteractor
    @Captor private lateinit var layoutParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams>
    @Mock private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor
    private lateinit var powerRepository: FakePowerRepository
    private lateinit var powerInteractor: PowerInteractor
    private lateinit var testScope: TestScope

    private val onTouch = { _: View, _: MotionEvent, _: Boolean -> true }
    private var overlayParams: UdfpsOverlayParams = UdfpsOverlayParams()
@@ -127,6 +141,15 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {

    @Before
    fun setup() {
        testScope = TestScope(StandardTestDispatcher())
        powerRepository = FakePowerRepository()
        powerInteractor =
            PowerInteractor(
                powerRepository,
                mock(FalsingCollector::class.java),
                mock(ScreenOffAnimationController::class.java),
                statusBarStateController,
            )
        whenever(inflater.inflate(R.layout.udfps_view, null, false)).thenReturn(udfpsView)
        whenever(inflater.inflate(R.layout.udfps_bp_view, null))
            .thenReturn(mock(UdfpsBpView::class.java))
@@ -178,6 +201,8 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
                { defaultUdfpsTouchOverlayViewModel },
                shadeInteractor,
                udfpsOverlayInteractor,
                powerInteractor,
                testScope,
            )
        block()
    }
@@ -277,6 +302,66 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
            }
        }

    @Test
    fun showUdfpsOverlay_awake() =
        testScope.runTest {
            withReason(REASON_AUTH_KEYGUARD) {
                mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE)
                powerRepository.updateWakefulness(
                    rawState = WakefulnessState.AWAKE,
                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
                    lastSleepReason = WakeSleepReason.OTHER,
                )
                controllerOverlay.show(udfpsController, overlayParams)
                runCurrent()
                verify(windowManager).addView(any(), any())
            }
        }

    @Test
    fun showUdfpsOverlay_whileGoingToSleep() =
        testScope.runTest {
            withReason(REASON_AUTH_KEYGUARD) {
                mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE)
                powerRepository.updateWakefulness(
                    rawState = WakefulnessState.STARTING_TO_SLEEP,
                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
                    lastSleepReason = WakeSleepReason.OTHER,
                )
                controllerOverlay.show(udfpsController, overlayParams)
                runCurrent()
                verify(windowManager, never()).addView(any(), any())

                // we hide to end the job that listens for the finishedGoingToSleep signal
                controllerOverlay.hide()
            }
        }

    @Test
    fun showUdfpsOverlay_afterFinishedGoingToSleep() =
        testScope.runTest {
            withReason(REASON_AUTH_KEYGUARD) {
                mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE)
                powerRepository.updateWakefulness(
                    rawState = WakefulnessState.STARTING_TO_SLEEP,
                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
                    lastSleepReason = WakeSleepReason.OTHER,
                )
                controllerOverlay.show(udfpsController, overlayParams)
                runCurrent()
                verify(windowManager, never()).addView(any(), any())

                powerRepository.updateWakefulness(
                    rawState = WakefulnessState.ASLEEP,
                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
                    lastSleepReason = WakeSleepReason.OTHER,
                )
                runCurrent()
                verify(windowManager)
                    .addView(eq(controllerOverlay.getTouchOverlay()), layoutParamsCaptor.capture())
            }
        }

    private fun showUdfpsOverlay() {
        val didShow = controllerOverlay.show(udfpsController, overlayParams)

+26 −1
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ import com.android.systemui.biometrics.ui.viewmodel.DefaultUdfpsTouchOverlayView
import com.android.systemui.biometrics.ui.viewmodel.DeviceEntryUdfpsTouchOverlayViewModel;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
@@ -94,10 +95,15 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.data.repository.FakePowerRepository;
import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.power.shared.model.WakeSleepReason;
import com.android.systemui.power.shared.model.WakefulnessState;
import com.android.systemui.res.R;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
@@ -125,6 +131,8 @@ import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
import java.util.List;

import kotlinx.coroutines.CoroutineScope;

@SmallTest
@RunWith(AndroidJUnit4.class)
@RunWithLooper(setAsMainLooper = true)
@@ -238,6 +246,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
    private ScreenLifecycle.Observer mScreenObserver;
    private FingerprintSensorPropertiesInternal mOpticalProps;
    private FingerprintSensorPropertiesInternal mUltrasonicProps;
    private PowerInteractor mPowerInteractor;
    private FakePowerRepository mPowerRepository;
    @Mock
    private InputManager mInputManager;
    @Mock
@@ -253,6 +263,19 @@ public class UdfpsControllerTest extends SysuiTestCase {

    @Before
    public void setUp() {
        mPowerRepository = new FakePowerRepository();
        mPowerInteractor = new PowerInteractor(
                mPowerRepository,
                mock(FalsingCollector.class),
                mock(ScreenOffAnimationController.class),
                mStatusBarStateController
        );
        mPowerRepository.updateWakefulness(
                WakefulnessState.AWAKE,
                WakeSleepReason.POWER_BUTTON,
                WakeSleepReason.OTHER,
                /* powerButtonLaunchGestureTriggered */ false
        );
        mContext.getOrCreateTestableResources()
                .addOverride(com.android.internal.R.bool.config_ignoreUdfpsVote, false);

@@ -346,7 +369,9 @@ public class UdfpsControllerTest extends SysuiTestCase {
                mKeyguardTransitionInteractor,
                mDeviceEntryUdfpsTouchOverlayViewModel,
                mDefaultUdfpsTouchOverlayViewModel,
                mUdfpsOverlayInteractor
                mUdfpsOverlayInteractor,
                mPowerInteractor,
                mock(CoroutineScope.class)
        );
        verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
        mOverlayController = mOverlayCaptor.getValue();
+13 −2
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@ import com.android.systemui.biometrics.ui.viewmodel.DeviceEntryUdfpsTouchOverlay
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor;
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor;
@@ -90,6 +91,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -116,6 +118,7 @@ import java.util.concurrent.Executor;

import javax.inject.Inject;

import kotlinx.coroutines.CoroutineScope;
import kotlinx.coroutines.ExperimentalCoroutinesApi;

/**
@@ -173,6 +176,8 @@ public class UdfpsController implements DozeReceiver, Dumpable {
            mDefaultUdfpsTouchOverlayViewModel;
    @NonNull private final AlternateBouncerInteractor mAlternateBouncerInteractor;
    @NonNull private final UdfpsOverlayInteractor mUdfpsOverlayInteractor;
    @NonNull private final PowerInteractor mPowerInteractor;
    @NonNull private final CoroutineScope mScope;
    @NonNull private final InputManager mInputManager;
    @NonNull private final UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate;
    @NonNull private final SelectedUserInteractor mSelectedUserInteractor;
@@ -296,7 +301,9 @@ public class UdfpsController implements DozeReceiver, Dumpable {
                        mDeviceEntryUdfpsTouchOverlayViewModel,
                        mDefaultUdfpsTouchOverlayViewModel,
                        mShadeInteractor,
                        mUdfpsOverlayInteractor
                        mUdfpsOverlayInteractor,
                        mPowerInteractor,
                        mScope
                    )));
        }

@@ -678,7 +685,9 @@ public class UdfpsController implements DozeReceiver, Dumpable {
            @NonNull KeyguardTransitionInteractor keyguardTransitionInteractor,
            Lazy<DeviceEntryUdfpsTouchOverlayViewModel> deviceEntryUdfpsTouchOverlayViewModel,
            Lazy<DefaultUdfpsTouchOverlayViewModel> defaultUdfpsTouchOverlayViewModel,
            @NonNull UdfpsOverlayInteractor udfpsOverlayInteractor) {
            @NonNull UdfpsOverlayInteractor udfpsOverlayInteractor,
            @NonNull PowerInteractor powerInteractor,
            @Application CoroutineScope scope) {
        mContext = context;
        mExecution = execution;
        mVibrator = vibrator;
@@ -720,6 +729,8 @@ public class UdfpsController implements DozeReceiver, Dumpable {
        mShadeInteractor = shadeInteractor;
        mAlternateBouncerInteractor = alternateBouncerInteractor;
        mUdfpsOverlayInteractor = udfpsOverlayInteractor;
        mPowerInteractor = powerInteractor;
        mScope = scope;
        mInputManager = inputManager;
        mUdfpsKeyguardAccessibilityDelegate = udfpsKeyguardAccessibilityDelegate;
        mSelectedUserInteractor = selectedUserInteractor;
+89 −32
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import android.view.accessibility.AccessibilityManager.TouchExplorationStateChan
import androidx.annotation.LayoutRes
import androidx.annotation.VisibleForTesting
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.Flags.udfpsViewPerformance
import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
@@ -53,10 +54,13 @@ import com.android.systemui.biometrics.ui.viewmodel.DefaultUdfpsTouchOverlayView
import com.android.systemui.biometrics.ui.viewmodel.DeviceEntryUdfpsTouchOverlayViewModel
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.shared.model.WakefulnessState
import com.android.systemui.res.R
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.LockscreenShadeTransitionController
@@ -67,7 +71,13 @@ import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import dagger.Lazy
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch

private const val TAG = "UdfpsControllerOverlay"

@@ -107,11 +117,20 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
        private val udfpsKeyguardAccessibilityDelegate: UdfpsKeyguardAccessibilityDelegate,
        private val transitionInteractor: KeyguardTransitionInteractor,
        private val selectedUserInteractor: SelectedUserInteractor,
    private val deviceEntryUdfpsTouchOverlayViewModel: Lazy<DeviceEntryUdfpsTouchOverlayViewModel>,
        private val deviceEntryUdfpsTouchOverlayViewModel:
            Lazy<DeviceEntryUdfpsTouchOverlayViewModel>,
        private val defaultUdfpsTouchOverlayViewModel: Lazy<DefaultUdfpsTouchOverlayViewModel>,
        private val shadeInteractor: ShadeInteractor,
        private val udfpsOverlayInteractor: UdfpsOverlayInteractor,
        private val powerInteractor: PowerInteractor,
        @Application private val scope: CoroutineScope,
) {
    private val isFinishedGoingToSleep: Flow<Unit> =
        powerInteractor.detailedWakefulness
            .filter { it.internalWakefulnessState == WakefulnessState.ASLEEP }
            .map { } // map to Unit
    private var listenForAsleepJob: Job? = null
    private var addViewRunnable: Runnable? = null
    private var overlayViewLegacy: UdfpsView? = null
        private set
    private var overlayTouchView: UdfpsTouchOverlay? = null
@@ -192,7 +211,8 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
                        if (requestReason.isImportantForAccessibility()) {
                            importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
                        }
                        windowManager.addView(this, coreLayoutParams.updateDimensions(null))

                        addViewNowOrLater(this, null)
                        when (requestReason) {
                            REASON_AUTH_KEYGUARD ->
                                UdfpsTouchOverlayBinder.bind(
@@ -225,7 +245,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
                            importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
                        }

                        windowManager.addView(this, coreLayoutParams.updateDimensions(animation))
                        addViewNowOrLater(this, animation)
                        sensorRect = sensorBounds
                    }
                }
@@ -257,6 +277,41 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
        return false
    }

    private fun addViewNowOrLater(view: View, animation: UdfpsAnimationViewController<*>?) {
        if (udfpsViewPerformance()) {
            addViewRunnable = kotlinx.coroutines.Runnable {
                windowManager.addView(
                        view,
                        coreLayoutParams.updateDimensions(animation)
                )
            }
            if (powerInteractor.detailedWakefulness.value.internalWakefulnessState
                    != WakefulnessState.STARTING_TO_SLEEP) {
                addViewIfPending()
            } else {
                listenForAsleepJob?.cancel()
                listenForAsleepJob = scope.launch {
                    isFinishedGoingToSleep.collect {
                        addViewIfPending()
                    }
                }
            }
        } else {
            windowManager.addView(
                    view,
                    coreLayoutParams.updateDimensions(animation)
            )
        }
    }

    private fun addViewIfPending() {
        addViewRunnable?.let {
            listenForAsleepJob?.cancel()
            it.run()
        }
        addViewRunnable = null
    }

    fun inflateUdfpsAnimation(
        view: UdfpsView,
        controller: UdfpsController
@@ -368,6 +423,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
        overlayViewLegacy = null
        overlayTouchView = null
        overlayTouchListener = null
        listenForAsleepJob?.cancel()

        return wasShowing
    }
@@ -412,7 +468,8 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
        if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
            if (!shouldRotate(animation)) {
                Log.v(
                    TAG, "Skip rotating UDFPS bounds " + Surface.rotationToString(rot) +
                    TAG,
                    "Skip rotating UDFPS bounds " + Surface.rotationToString(rot) +
                        " animation=$animation" +
                        " isGoingToSleep=${keyguardUpdateMonitor.isGoingToSleep}" +
                        " isOccluded=${keyguardStateController.isOccluded}"