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

Commit d991f01a authored by Matt Pietal's avatar Matt Pietal
Browse files

[DO NOT MERGE] Transitions: LOCKSCREEN->DREAMING

Add general support for lockscren->occluded/dreaming transitions,
including improved support for camera gesture occlusion. Double-tap
power will send various signals, so capture the double-tap as soon as
possible to cancel a transition in favor of the occlusion transition.

For LOCKSCREEN->DREAMING only, delay call to setOccluded, as it causes
jank when done too early. Also absorb touches while this transition is
running to prevent strange artifacts from popping in if the display is
touched.

Test: atest KeyguardRepositoryImplTest
KeyguardTransitionRepositoryTest
NotificationShadeWindowViewControllerTest
LockscreenToDreamingTransitionViewModelTest
LockscreenToOccludedTransitionViewModelTest
NotificationShadeWindowViewTest NotificationPanelViewControllerTest
Bug: 260637747

Change-Id: Ie2593706f2848ca715e557c8d4dfc129d93a29f1
parent 06da15b3
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -1279,6 +1279,12 @@
    <!-- OCCLUDED -> LOCKSCREEN transition: Amount to shift lockscreen content on entering -->
    <dimen name="occluded_to_lockscreen_transition_lockscreen_translation_y">40dp</dimen>

    <!-- LOCKSCREEN -> DREAMING transition: Amount to shift lockscreen content on entering -->
    <dimen name="lockscreen_to_dreaming_transition_lockscreen_translation_y">-40dp</dimen>

    <!-- LOCKSCREEN -> OCCLUDED transition: Amount to shift lockscreen content on entering -->
    <dimen name="lockscreen_to_occluded_transition_lockscreen_translation_y">-40dp</dimen>

    <!-- The amount of vertical offset for the keyguard during the full shade transition. -->
    <dimen name="lockscreen_shade_keyguard_transition_vertical_offset">0dp</dimen>

+24 −5
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel.LOCKSCREEN_ANIMATION_DURATION_MS;
import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -122,6 +123,8 @@ import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.dagger.KeyguardModule;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -507,6 +510,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,

    private CentralSurfaces mCentralSurfaces;

    private boolean mUnocclusionTransitionFlagEnabled = false;

    private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
            new DeviceConfig.OnPropertiesChangedListener() {
            @Override
@@ -958,8 +963,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
                public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
                        RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
                        IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
                    if (!mUnocclusionTransitionFlagEnabled) {
                        setOccluded(true /* isOccluded */, true /* animate */);

                    }
                    if (apps == null || apps.length == 0 || apps[0] == null) {
                        if (DEBUG) {
                            Log.d(TAG, "No apps provided to the OccludeByDream runner; "
@@ -1001,9 +1007,20 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
                                    applier.scheduleApply(paramsBuilder.build());
                                });
                        mOccludeByDreamAnimator.addListener(new AnimatorListenerAdapter() {
                            private boolean mIsCancelled = false;
                            @Override
                            public void onAnimationCancel(Animator animation) {
                                mIsCancelled = true;
                            }

                            @Override
                            public void onAnimationEnd(Animator animation) {
                                try {
                                    if (!mIsCancelled && mUnocclusionTransitionFlagEnabled) {
                                        // We're already on the main thread, don't queue this call
                                        handleSetOccluded(true /* isOccluded */,
                                                false /* animate */);
                                    }
                                    finishedCallback.onAnimationFinished();
                                    mOccludeByDreamAnimator = null;
                                } catch (RemoteException e) {
@@ -1176,6 +1193,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
            ScreenOnCoordinator screenOnCoordinator,
            InteractionJankMonitor interactionJankMonitor,
            DreamOverlayStateController dreamOverlayStateController,
            FeatureFlags featureFlags,
            Lazy<ShadeController> shadeControllerLazy,
            Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy,
            Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
@@ -1230,9 +1248,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
                R.dimen.physical_power_button_center_screen_location_y);
        mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);

        mDreamOpenAnimationDuration = context.getResources().getInteger(
                com.android.internal.R.integer.config_dreamOpenAnimationDuration);
        mDreamOpenAnimationDuration = (int) DREAMING_ANIMATION_DURATION_MS;
        mDreamCloseAnimationDuration = (int) LOCKSCREEN_ANIMATION_DURATION_MS;
        mUnocclusionTransitionFlagEnabled = featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION);
    }

    public void userActivity() {
@@ -1792,7 +1810,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,

        Trace.beginSection("KeyguardViewMediator#setOccluded");
        if (DEBUG) Log.d(TAG, "setOccluded " + isOccluded);
        mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD);
        mHandler.removeMessages(SET_OCCLUDED);
        Message msg = mHandler.obtainMessage(SET_OCCLUDED, isOccluded ? 1 : 0, animate ? 1 : 0);
        mHandler.sendMessage(msg);
@@ -1825,6 +1842,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
    private void handleSetOccluded(boolean isOccluded, boolean animate) {
        Trace.beginSection("KeyguardViewMediator#handleSetOccluded");
        Log.d(TAG, "handleSetOccluded(" + isOccluded + ")");
        mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD);

        synchronized (KeyguardViewMediator.this) {
            if (mHiding && isOccluded) {
                // We're in the process of going away but WindowManager wants to show a
+3 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -112,6 +113,7 @@ public class KeyguardModule {
            ScreenOnCoordinator screenOnCoordinator,
            InteractionJankMonitor interactionJankMonitor,
            DreamOverlayStateController dreamOverlayStateController,
            FeatureFlags featureFlags,
            Lazy<ShadeController> shadeController,
            Lazy<NotificationShadeWindowController> notificationShadeWindowController,
            Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
@@ -142,6 +144,7 @@ public class KeyguardModule {
                screenOnCoordinator,
                interactionJankMonitor,
                dreamOverlayStateController,
                featureFlags,
                shadeController,
                notificationShadeWindowController,
                activityLaunchAnimator,
+7 −4
Original line number Diff line number Diff line
@@ -135,11 +135,14 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
            Log.i(TAG, "Duplicate call to start the transition, rejecting: $info")
            return null
        }
        val startingValue =
            if (lastStep.transitionState != TransitionState.FINISHED) {
                Log.i(TAG, "Transition still active: $lastStep, canceling")
                lastStep.value
            } else {
                0f
            }

        val startingValue = 1f - lastStep.value
        lastAnimator?.cancel()
        lastAnimator = info.animator

+40 −10
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.util.kotlin.sample
import java.util.UUID
import javax.inject.Inject
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
@@ -51,6 +53,7 @@ constructor(
    override fun start() {
        listenForLockscreenToGone()
        listenForLockscreenToOccluded()
        listenForLockscreenToCamera()
        listenForLockscreenToAod()
        listenForLockscreenToBouncer()
        listenForLockscreenToDreaming()
@@ -69,7 +72,7 @@ constructor(
                                name,
                                KeyguardState.LOCKSCREEN,
                                KeyguardState.DREAMING,
                                getAnimator(),
                                getAnimator(TO_DREAMING_DURATION),
                            )
                        )
                    }
@@ -184,17 +187,42 @@ constructor(
                    ),
                    ::toTriple
                )
                .collect { triple ->
                    val (isOccluded, keyguardState, isDreaming) = triple
                    // Occlusion signals come from the framework, and should interrupt any
                    // existing transition
                    if (isOccluded && !isDreaming) {
                .collect { (isOccluded, keyguardState, isDreaming) ->
                    if (isOccluded && !isDreaming && keyguardState == KeyguardState.LOCKSCREEN) {
                        keyguardTransitionRepository.startTransition(
                            TransitionInfo(
                                name,
                                keyguardState,
                                KeyguardState.OCCLUDED,
                                getAnimator(),
                                getAnimator(TO_OCCLUDED_DURATION),
                            )
                        )
                    }
                }
        }
    }

    /** This signal may come in before the occlusion signal, and can provide a custom transition */
    private fun listenForLockscreenToCamera() {
        scope.launch {
            keyguardInteractor.onCameraLaunchDetected
                .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
                .collect { (_, lastStartedStep) ->
                    // DREAMING/AOD/OFF may trigger on the first power button push, so include this
                    // state in order to cancel and correct the transition
                    if (
                        lastStartedStep.to == KeyguardState.LOCKSCREEN ||
                            lastStartedStep.to == KeyguardState.DREAMING ||
                            lastStartedStep.to == KeyguardState.DOZING ||
                            lastStartedStep.to == KeyguardState.AOD ||
                            lastStartedStep.to == KeyguardState.OFF
                    ) {
                        keyguardTransitionRepository.startTransition(
                            TransitionInfo(
                                name,
                                KeyguardState.LOCKSCREEN,
                                KeyguardState.OCCLUDED,
                                getAnimator(TO_OCCLUDED_DURATION),
                            )
                        )
                    }
@@ -223,14 +251,16 @@ constructor(
        }
    }

    private fun getAnimator(): ValueAnimator {
    private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
        return ValueAnimator().apply {
            setInterpolator(Interpolators.LINEAR)
            setDuration(TRANSITION_DURATION_MS)
            setDuration(duration.inWholeMilliseconds)
        }
    }

    companion object {
        private const val TRANSITION_DURATION_MS = 500L
        private val DEFAULT_DURATION = 500.milliseconds
        val TO_DREAMING_DURATION = 933.milliseconds
        val TO_OCCLUDED_DURATION = 450.milliseconds
    }
}
Loading