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

Commit df0d9ea9 authored by Hawkwood Glazier's avatar Hawkwood Glazier Committed by Android (Google) Code Review
Browse files

Merge "Execute fold animation using clock interactor" into main

parents 28b92c63 5fb8f031
Loading
Loading
Loading
Loading
+8 −5
Original line number Diff line number Diff line
@@ -29,8 +29,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow

private val TAG = KeyguardClockInteractor::class.simpleName
/** Manages keyguard clock for the lockscreen root view. */
/** Encapsulates business-logic related to the keyguard clock. */
/** Manages and ecapsulates the clock components of the lockscreen root view. */
@SysUISingleton
class KeyguardClockInteractor
@Inject
@@ -46,6 +45,8 @@ constructor(

    val previewClock: Flow<ClockController> = keyguardClockRepository.previewClock

    val clockEventController: ClockEventController by keyguardClockRepository::clockEventController

    var clock: ClockController? by keyguardClockRepository.clockEventController::clock

    val clockSize: StateFlow<Int> = keyguardClockRepository.clockSize
@@ -53,8 +54,10 @@ constructor(
        keyguardClockRepository.setClockSize(size)
    }

    val clockEventController: ClockEventController
        get() {
            return keyguardClockRepository.clockEventController
    fun animateFoldToAod(foldFraction: Float) {
        clock?.let { clock ->
            clock.smallClock.animations.fold(foldFraction)
            clock.largeClock.animations.fold(foldFraction)
        }
    }
}
+99 −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 android.animation.ValueAnimator
import android.view.ViewGroup
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.shade.NotificationPanelViewController
import com.android.systemui.shade.ShadeFoldAnimator
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch

@SysUISingleton
class ToAodFoldTransitionInteractor
@Inject
constructor(
    private val keyguardClockInteractor: KeyguardClockInteractor,
    private val transitionInteractor: KeyguardTransitionInteractor,
    private val transitionRepository: KeyguardTransitionRepository,
    @Application private val mainScope: CoroutineScope,
    @Main private val mainDispatcher: CoroutineDispatcher,
) {
    private var parentAnimator: NotificationPanelViewController.ShadeFoldAnimatorImpl? = null

    // TODO(b/331770313): Migrate to PowerInteractor; Deprecate ShadeFoldAnimator again
    val foldAnimator =
        object : ShadeFoldAnimator {
            override val view: ViewGroup?
                get() = throw NotImplementedError("Deprecated. Do not call.")

            override fun prepareFoldToAodAnimation() {
                forceToAod()
                parentAnimator?.prepareFoldToAodAnimation()
            }

            override fun startFoldToAodAnimation(
                startAction: Runnable,
                endAction: Runnable,
                cancelAction: Runnable
            ) {
                parentAnimator?.let {
                    it.buildViewAnimator(startAction, endAction, cancelAction)
                        .setUpdateListener {
                            keyguardClockInteractor.animateFoldToAod(it.animatedFraction)
                        }
                        .start()
                }
            }

            override fun cancelFoldToAodAnimation() {
                parentAnimator?.cancelFoldToAodAnimation()
            }
        }

    fun initialize(parentAnimator: ShadeFoldAnimator) {
        this.parentAnimator =
            parentAnimator as NotificationPanelViewController.ShadeFoldAnimatorImpl?
    }

    /** Forces the keyguard into AOD or Doze */
    private fun forceToAod() {
        mainScope.launch(mainDispatcher) {
            transitionRepository.startTransition(
                TransitionInfo(
                    "$TAG (Fold transition triggered)",
                    transitionInteractor.getCurrentState(),
                    transitionInteractor.asleepKeyguardState.value,
                    ValueAnimator().apply { duration = 0 },
                    TransitionModeOnCanceled.LAST_VALUE,
                )
            )
        }
    }

    companion object {
        private val TAG = ToAodFoldTransitionInteractor::class.simpleName!!
    }
}
+26 −18
Original line number Diff line number Diff line
@@ -437,7 +437,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
    private final FalsingManager mFalsingManager;
    private final FalsingCollector mFalsingCollector;
    private final ShadeHeadsUpTrackerImpl mShadeHeadsUpTracker = new ShadeHeadsUpTrackerImpl();
    private final ShadeFoldAnimator mShadeFoldAnimator = new ShadeFoldAnimatorImpl();
    private final ShadeFoldAnimatorImpl mShadeFoldAnimator = new ShadeFoldAnimatorImpl();

    private boolean mShowIconsWhenExpanded;
    private int mIndicationBottomPadding;
@@ -3311,19 +3311,19 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
    }

    @Override
    public ShadeFoldAnimator getShadeFoldAnimator() {
    public ShadeFoldAnimatorImpl getShadeFoldAnimator() {
        return mShadeFoldAnimator;
    }

    private final class ShadeFoldAnimatorImpl implements ShadeFoldAnimator {
    @Deprecated
    public final class ShadeFoldAnimatorImpl implements ShadeFoldAnimator {
        /** Updates the views to the initial state for the fold to AOD animation. */
        @Override
        public void prepareFoldToAodAnimation() {
            if (MigrateClocksToBlueprint.isEnabled()) {
                return;
            }
            if (!MigrateClocksToBlueprint.isEnabled()) {
                // Force show AOD UI even if we are not locked
                showAodUi();
            }

            // Move the content of the AOD all the way to the left
            // so we can animate to the initial position
@@ -3341,14 +3341,29 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
         * @param cancelAction invoked when the animation is cancelled, before endAction.
         */
        @Override
        public void startFoldToAodAnimation(Runnable startAction, Runnable endAction,
                Runnable cancelAction) {
        public void startFoldToAodAnimation(
                Runnable startAction, Runnable endAction, Runnable cancelAction) {
            if (MigrateClocksToBlueprint.isEnabled()) {
                return;
            }

            buildViewAnimator(startAction, endAction, cancelAction)
                    .setUpdateListener(anim -> mKeyguardStatusViewController
                            .animateFoldToAod(anim.getAnimatedFraction()))
                    .start();
        }

        /**
         * Builds the default NPVC fold animator
         *
         * @deprecated Temporary stop-gap. Do not use outside of keyguard fold transition.
         */
        @Deprecated
        public ViewPropertyAnimator buildViewAnimator(
                Runnable startAction, Runnable endAction, Runnable cancelAction) {
            final ViewPropertyAnimator viewAnimator = mView.animate();
            viewAnimator.cancel();
            viewAnimator
            return viewAnimator
                    .translationX(0)
                    .alpha(1f)
                    .setDuration(ANIMATION_DURATION_FOLD_TO_AOD)
@@ -3371,19 +3386,12 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
                            viewAnimator.setListener(null);
                            viewAnimator.setUpdateListener(null);
                        }
                    })
                    .setUpdateListener(anim ->
                            mKeyguardStatusViewController.animateFoldToAod(
                                    anim.getAnimatedFraction()))
                    .start();
                    });
        }

        /** Cancels fold to AOD transition and resets view state. */
        @Override
        public void cancelFoldToAodAnimation() {
            if (MigrateClocksToBlueprint.isEnabled()) {
                return;
            }
            cancelAnimation();
            resetAlpha();
            resetTranslation();
+7 −5
Original line number Diff line number Diff line
@@ -144,10 +144,11 @@ interface ShadeHeadsUpTracker {
}

/** Handles the lifecycle of the shade's animation that happens when folding a foldable. */
@Deprecated("This interface should not be used in scene container.")
@Deprecated("This interface should not be used in scene container. Needs flexiglass equivalent.")
interface ShadeFoldAnimator {
    /** Updates the views to the initial state for the fold to AOD animation. */
    @Deprecated("Not used when migrateClocksToBlueprint enabled") fun prepareFoldToAodAnimation()
    @Deprecated("Used by the Keyguard Fold Transition. Needs flexiglass equivalent.")
    fun prepareFoldToAodAnimation()

    /**
     * Starts fold to AOD animation.
@@ -156,14 +157,15 @@ interface ShadeFoldAnimator {
     * @param endAction invoked when the animation finishes, also if it was cancelled.
     * @param cancelAction invoked when the animation is cancelled, before endAction.
     */
    @Deprecated("Not used when migrateClocksToBlueprint enabled")
    @Deprecated("Not used when migrateClocksToBlueprint enabled.")
    fun startFoldToAodAnimation(startAction: Runnable, endAction: Runnable, cancelAction: Runnable)

    /** Cancels fold to AOD transition and resets view state. */
    @Deprecated("Not used when migrateClocksToBlueprint enabled") fun cancelFoldToAodAnimation()
    @Deprecated("Used by the Keyguard Fold Transition. Needs flexiglass equivalent.")
    fun cancelFoldToAodAnimation()

    /** Returns the main view of the shade. */
    @Deprecated("Not used in Scene Container") val view: ViewGroup?
    @Deprecated("Not used when migrateClocksToBlueprint enabled.") val view: ViewGroup?
}

/**
+65 −54
Original line number Diff line number Diff line
@@ -23,10 +23,11 @@ import android.os.PowerManager
import android.provider.Settings
import androidx.core.view.OneShotPreDrawListener
import com.android.internal.util.LatencyTracker
import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.ToAodFoldTransitionInteractor
import com.android.systemui.shade.ShadeFoldAnimator
import com.android.systemui.shade.ShadeViewController
import com.android.systemui.statusbar.LightRevealScrim
@@ -55,6 +56,7 @@ constructor(
    private val globalSettings: GlobalSettings,
    private val latencyTracker: LatencyTracker,
    private val keyguardInteractor: Lazy<KeyguardInteractor>,
    private val foldTransitionInteractor: Lazy<ToAodFoldTransitionInteractor>,
) : CallbackController<FoldAodAnimationStatus>, ScreenOffAnimation, WakefulnessLifecycle.Observer {

    private lateinit var shadeViewController: ShadeViewController
@@ -74,7 +76,7 @@ constructor(
    private val foldToAodLatencyTracker = FoldToAodLatencyTracker()

    private val startAnimationRunnable = Runnable {
        getShadeFoldAnimator().startFoldToAodAnimation(
        shadeFoldAnimator.startFoldToAodAnimation(
            /* startAction= */ { foldToAodLatencyTracker.onAnimationStarted() },
            /* endAction= */ { setAnimationState(playing = false) },
            /* cancelAction= */ { setAnimationState(playing = false) },
@@ -87,6 +89,7 @@ constructor(
        lightRevealScrim: LightRevealScrim,
    ) {
        this.shadeViewController = shadeViewController
        foldTransitionInteractor.get().initialize(shadeViewController.shadeFoldAnimator)

        deviceStateManager.registerCallback(mainExecutor, FoldListener())
        wakefulnessLifecycle.addObserver(this)
@@ -103,7 +106,7 @@ constructor(
    override fun startAnimation(): Boolean =
        if (shouldStartAnimation()) {
            setAnimationState(playing = true)
            getShadeFoldAnimator().prepareFoldToAodAnimation()
            shadeFoldAnimator.prepareFoldToAodAnimation()
            true
        } else {
            setAnimationState(playing = false)
@@ -114,14 +117,20 @@ constructor(
        if (isAnimationPlaying) {
            foldToAodLatencyTracker.cancel()
            cancelAnimation?.run()
            getShadeFoldAnimator().cancelFoldToAodAnimation()
            shadeFoldAnimator.cancelFoldToAodAnimation()
        }

        setAnimationState(playing = false)
    }

    private fun getShadeFoldAnimator(): ShadeFoldAnimator =
    private val shadeFoldAnimator: ShadeFoldAnimator
        get() {
            return if (MigrateClocksToBlueprint.isEnabled) {
                foldTransitionInteractor.get().foldAnimator
            } else {
                shadeViewController.shadeFoldAnimator
            }
        }

    private fun setAnimationState(playing: Boolean) {
        shouldPlayAnimation = playing
@@ -137,28 +146,32 @@ constructor(
     * @see [com.android.systemui.keyguard.KeyguardViewMediator]
     */
    @BinderThread
    fun onScreenTurningOn(onReady: Runnable) = mainExecutor.execute {
    fun onScreenTurningOn(onReady: Runnable) =
        mainExecutor.execute {
            if (shouldPlayAnimation) {
                // The device was not dozing and going to sleep after folding, play the animation

                if (isScrimOpaque) {
                    onReady.run()
                } else {
                    pendingScrimReadyCallback = onReady
                }
        } else if (isFolded && !isFoldHandled && alwaysOnEnabled &&
                keyguardInteractor.get().isDozing.value) {
            } else if (
                isFolded &&
                    !isFoldHandled &&
                    alwaysOnEnabled &&
                    keyguardInteractor.get().isDozing.value
            ) {
                setAnimationState(playing = true)
            getShadeFoldAnimator().prepareFoldToAodAnimation()
                shadeFoldAnimator.prepareFoldToAodAnimation()

                // We don't need to wait for the scrim as it is already displayed
                // but we should wait for the initial animation preparations to be drawn
                // (setting initial alpha/translation)
                // TODO(b/254878364): remove this call to NPVC.getView()
            if (!migrateClocksToBlueprint()) {
                getShadeFoldAnimator().view?.let {
                    OneShotPreDrawListener.add(it, onReady)
                }
                if (!MigrateClocksToBlueprint.isEnabled) {
                    shadeFoldAnimator.view?.let { OneShotPreDrawListener.add(it, onReady) }
                } else {
                    onReady.run()
                }
            } else {
                // No animation, call ready callback immediately
@@ -184,15 +197,14 @@ constructor(
    }

    @BinderThread
    fun onScreenTurnedOn() = mainExecutor.execute {
    fun onScreenTurnedOn() =
        mainExecutor.execute {
            if (shouldPlayAnimation) {
                cancelAnimation?.run()

                // Post starting the animation to the next frame to avoid junk due to inset changes
            cancelAnimation = mainExecutor.executeDelayed(
                startAnimationRunnable,
                /* delayMillis= */ 0
            )
                cancelAnimation =
                    mainExecutor.executeDelayed(startAnimationRunnable, /* delayMillis= */ 0)
                shouldPlayAnimation = false
            }
        }
@@ -247,7 +259,6 @@ constructor(
     * Tracks the latency of fold to AOD using [LatencyTracker].
     *
     * Events that trigger start and end are:
     *
     * - Start: Once [DeviceStateManager] sends the folded signal [FoldToAodLatencyTracker.onFolded]
     *   is called and latency tracking starts.
     * - End: Once the fold -> AOD animation starts, [FoldToAodLatencyTracker.onAnimationStarted] is
Loading