Loading packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt +9 −3 Original line number Diff line number Diff line Loading @@ -424,15 +424,16 @@ constructor( newKeyguardOccludedState: Boolean? ) { super.onTransitionAnimationCancelled(newKeyguardOccludedState) cleanUp() onDispose() } override fun onTransitionAnimationEnd(isExpandingFullyAbove: Boolean) { super.onTransitionAnimationEnd(isExpandingFullyAbove) cleanUp() onDispose() } private fun cleanUp() { override fun onDispose() { super.onDispose() cleanUpRunnable?.run() } } Loading Loading @@ -560,6 +561,7 @@ constructor( cookie: TransitionCookie? = null, component: ComponentName? = null, returnCujType: Int? = null, isEphemeral: Boolean = true, ): Controller? { // Make sure the View we launch from implements LaunchableView to avoid visibility // issues. Loading Loading @@ -587,6 +589,7 @@ constructor( cookie, component, returnCujType, isEphemeral, ) } } Loading Loading @@ -647,6 +650,9 @@ constructor( * appropriately. */ fun onTransitionAnimationCancelled(newKeyguardOccludedState: Boolean? = null) {} /** The controller will not be used again. Clean up the relevant internal state. */ fun onDispose() {} } /** Loading packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt +8 −4 Original line number Diff line number Diff line Loading @@ -39,7 +39,8 @@ interface Expandable { launchCujType: Int? = null, cookie: ActivityTransitionAnimator.TransitionCookie? = null, component: ComponentName? = null, returnCujType: Int? = null returnCujType: Int? = null, isEphemeral: Boolean = true, ): ActivityTransitionAnimator.Controller? /** Loading @@ -55,7 +56,8 @@ interface Expandable { launchCujType, cookie = null, component = null, returnCujType = null returnCujType = null, isEphemeral = true, ) } Loading @@ -80,14 +82,16 @@ interface Expandable { launchCujType: Int?, cookie: ActivityTransitionAnimator.TransitionCookie?, component: ComponentName?, returnCujType: Int? returnCujType: Int?, isEphemeral: Boolean, ): ActivityTransitionAnimator.Controller? { return ActivityTransitionAnimator.Controller.fromView( view, launchCujType, cookie, component, returnCujType returnCujType, isEphemeral, ) } Loading packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt +35 −6 Original line number Diff line number Diff line Loading @@ -67,6 +67,12 @@ constructor( /** The [CujType] associated to this return animation. */ private val returnCujType: Int? = null, /** * Whether this controller should be invalidated after its first use, and whenever [ghostedView] * is detached. */ private val isEphemeral: Boolean = false, private var interactionJankMonitor: InteractionJankMonitor = InteractionJankMonitor.getInstance(), ) : ActivityTransitionAnimator.Controller { Loading Loading @@ -119,6 +125,19 @@ constructor( returnCujType } /** * Used to automatically clean up the internal state once [ghostedView] is detached from the * hierarchy. */ private val detachListener = object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View) {} override fun onViewDetachedFromWindow(v: View) { onDispose() } } init { // Make sure the View we launch from implements LaunchableView to avoid visibility issues. if (ghostedView !is LaunchableView) { Loading Loading @@ -155,6 +174,16 @@ constructor( } background = findBackground(ghostedView) if (TransitionAnimator.returnAnimationsEnabled() && isEphemeral) { ghostedView.addOnAttachStateChangeListener(detachListener) } } override fun onDispose() { if (TransitionAnimator.returnAnimationsEnabled()) { ghostedView.removeOnAttachStateChangeListener(detachListener) } } /** Loading @@ -164,7 +193,7 @@ constructor( protected open fun setBackgroundCornerRadius( background: Drawable, topCornerRadius: Float, bottomCornerRadius: Float bottomCornerRadius: Float, ) { // By default, we rely on WrappedDrawable to set/restore the background radii before/after // each draw. Loading Loading @@ -195,7 +224,7 @@ constructor( val state = TransitionAnimator.State( topCornerRadius = getCurrentTopCornerRadius(), bottomCornerRadius = getCurrentBottomCornerRadius() bottomCornerRadius = getCurrentBottomCornerRadius(), ) fillGhostedViewState(state) return state Loading Loading @@ -269,7 +298,7 @@ constructor( override fun onTransitionAnimationProgress( state: TransitionAnimator.State, progress: Float, linearProgress: Float linearProgress: Float, ) { val ghostView = this.ghostView ?: return val backgroundView = this.backgroundView!! Loading Loading @@ -317,11 +346,11 @@ constructor( scale, scale, ghostedViewState.centerX - transitionContainerLocation[0], ghostedViewState.centerY - transitionContainerLocation[1] ghostedViewState.centerY - transitionContainerLocation[1], ) ghostViewMatrix.postTranslate( (leftChange + rightChange) / 2f, (topChange + bottomChange) / 2f (topChange + bottomChange) / 2f, ) ghostView.animationMatrix = ghostViewMatrix Loading Loading @@ -462,7 +491,7 @@ constructor( private fun updateRadii( radii: FloatArray, topCornerRadius: Float, bottomCornerRadius: Float bottomCornerRadius: Float, ) { radii[0] = topCornerRadius radii[1] = topCornerRadius Loading packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt +52 −23 Original line number Diff line number Diff line Loading @@ -52,6 +52,9 @@ import kotlin.math.roundToInt interface ExpandableController { /** The [Expandable] controlled by this controller. */ val expandable: Expandable /** Called when the [Expandable] stop being included in the composition. */ fun onDispose() } /** Loading Loading @@ -88,9 +91,9 @@ fun rememberExpandableController( // Whether this composable is still composed. We only do the dialog exit animation if this is // true. val isComposed = remember { mutableStateOf(true) } DisposableEffect(Unit) { onDispose { isComposed.value = false } } return remember( val controller = remember( color, contentColor, shape, Loading @@ -115,6 +118,17 @@ fun rememberExpandableController( isComposed, ) } DisposableEffect(Unit) { onDispose { isComposed.value = false if (TransitionAnimator.returnAnimationsEnabled()) { controller.onDispose() } } } return controller } internal class ExpandableControllerImpl( Loading @@ -132,19 +146,29 @@ internal class ExpandableControllerImpl( private val layoutDirection: LayoutDirection, private val isComposed: State<Boolean>, ) : ExpandableController { /** The [ActivityTransitionAnimator.Controller] to be cleaned up [onDispose]. */ private var activityControllerForDisposal: ActivityTransitionAnimator.Controller? = null override val expandable: Expandable = object : Expandable { override fun activityTransitionController( launchCujType: Int?, cookie: ActivityTransitionAnimator.TransitionCookie?, component: ComponentName?, returnCujType: Int? returnCujType: Int?, isEphemeral: Boolean, ): ActivityTransitionAnimator.Controller? { if (!isComposed.value) { return null } return activityController(launchCujType, cookie, component, returnCujType) val controller = activityController(launchCujType, cookie, component, returnCujType) if (TransitionAnimator.returnAnimationsEnabled() && isEphemeral) { activityControllerForDisposal?.onDispose() activityControllerForDisposal = controller } return controller } override fun dialogTransitionController( Loading @@ -158,6 +182,11 @@ internal class ExpandableControllerImpl( } } override fun onDispose() { activityControllerForDisposal?.onDispose() activityControllerForDisposal = null } /** * Create a [TransitionAnimator.Controller] that is going to be used to drive an activity or * dialog animation. This controller will: Loading @@ -181,7 +210,7 @@ internal class ExpandableControllerImpl( override fun onTransitionAnimationProgress( state: TransitionAnimator.State, progress: Float, linearProgress: Float linearProgress: Float, ) { // We copy state given that it's always the same object that is mutated by // ActivityTransitionAnimator. Loading Loading @@ -269,7 +298,7 @@ internal class ExpandableControllerImpl( launchCujType: Int?, cookie: ActivityTransitionAnimator.TransitionCookie?, component: ComponentName?, returnCujType: Int? returnCujType: Int?, ): ActivityTransitionAnimator.Controller { val delegate = transitionController() return object : Loading packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/StateAwareExpandable.kt +8 −1 Original line number Diff line number Diff line Loading @@ -78,9 +78,16 @@ fun Expandable.withStateAwareness( cookie: ActivityTransitionAnimator.TransitionCookie?, component: ComponentName?, returnCujType: Int?, isEphemeral: Boolean, ): ActivityTransitionAnimator.Controller? = delegate .activityTransitionController(launchCujType, cookie, component, returnCujType) .activityTransitionController( launchCujType, cookie, component, returnCujType, isEphemeral, ) ?.withStateAwareness(onActivityLaunchTransitionStart, onActivityLaunchTransitionEnd) override fun dialogTransitionController( Loading Loading
packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt +9 −3 Original line number Diff line number Diff line Loading @@ -424,15 +424,16 @@ constructor( newKeyguardOccludedState: Boolean? ) { super.onTransitionAnimationCancelled(newKeyguardOccludedState) cleanUp() onDispose() } override fun onTransitionAnimationEnd(isExpandingFullyAbove: Boolean) { super.onTransitionAnimationEnd(isExpandingFullyAbove) cleanUp() onDispose() } private fun cleanUp() { override fun onDispose() { super.onDispose() cleanUpRunnable?.run() } } Loading Loading @@ -560,6 +561,7 @@ constructor( cookie: TransitionCookie? = null, component: ComponentName? = null, returnCujType: Int? = null, isEphemeral: Boolean = true, ): Controller? { // Make sure the View we launch from implements LaunchableView to avoid visibility // issues. Loading Loading @@ -587,6 +589,7 @@ constructor( cookie, component, returnCujType, isEphemeral, ) } } Loading Loading @@ -647,6 +650,9 @@ constructor( * appropriately. */ fun onTransitionAnimationCancelled(newKeyguardOccludedState: Boolean? = null) {} /** The controller will not be used again. Clean up the relevant internal state. */ fun onDispose() {} } /** Loading
packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt +8 −4 Original line number Diff line number Diff line Loading @@ -39,7 +39,8 @@ interface Expandable { launchCujType: Int? = null, cookie: ActivityTransitionAnimator.TransitionCookie? = null, component: ComponentName? = null, returnCujType: Int? = null returnCujType: Int? = null, isEphemeral: Boolean = true, ): ActivityTransitionAnimator.Controller? /** Loading @@ -55,7 +56,8 @@ interface Expandable { launchCujType, cookie = null, component = null, returnCujType = null returnCujType = null, isEphemeral = true, ) } Loading @@ -80,14 +82,16 @@ interface Expandable { launchCujType: Int?, cookie: ActivityTransitionAnimator.TransitionCookie?, component: ComponentName?, returnCujType: Int? returnCujType: Int?, isEphemeral: Boolean, ): ActivityTransitionAnimator.Controller? { return ActivityTransitionAnimator.Controller.fromView( view, launchCujType, cookie, component, returnCujType returnCujType, isEphemeral, ) } Loading
packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt +35 −6 Original line number Diff line number Diff line Loading @@ -67,6 +67,12 @@ constructor( /** The [CujType] associated to this return animation. */ private val returnCujType: Int? = null, /** * Whether this controller should be invalidated after its first use, and whenever [ghostedView] * is detached. */ private val isEphemeral: Boolean = false, private var interactionJankMonitor: InteractionJankMonitor = InteractionJankMonitor.getInstance(), ) : ActivityTransitionAnimator.Controller { Loading Loading @@ -119,6 +125,19 @@ constructor( returnCujType } /** * Used to automatically clean up the internal state once [ghostedView] is detached from the * hierarchy. */ private val detachListener = object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View) {} override fun onViewDetachedFromWindow(v: View) { onDispose() } } init { // Make sure the View we launch from implements LaunchableView to avoid visibility issues. if (ghostedView !is LaunchableView) { Loading Loading @@ -155,6 +174,16 @@ constructor( } background = findBackground(ghostedView) if (TransitionAnimator.returnAnimationsEnabled() && isEphemeral) { ghostedView.addOnAttachStateChangeListener(detachListener) } } override fun onDispose() { if (TransitionAnimator.returnAnimationsEnabled()) { ghostedView.removeOnAttachStateChangeListener(detachListener) } } /** Loading @@ -164,7 +193,7 @@ constructor( protected open fun setBackgroundCornerRadius( background: Drawable, topCornerRadius: Float, bottomCornerRadius: Float bottomCornerRadius: Float, ) { // By default, we rely on WrappedDrawable to set/restore the background radii before/after // each draw. Loading Loading @@ -195,7 +224,7 @@ constructor( val state = TransitionAnimator.State( topCornerRadius = getCurrentTopCornerRadius(), bottomCornerRadius = getCurrentBottomCornerRadius() bottomCornerRadius = getCurrentBottomCornerRadius(), ) fillGhostedViewState(state) return state Loading Loading @@ -269,7 +298,7 @@ constructor( override fun onTransitionAnimationProgress( state: TransitionAnimator.State, progress: Float, linearProgress: Float linearProgress: Float, ) { val ghostView = this.ghostView ?: return val backgroundView = this.backgroundView!! Loading Loading @@ -317,11 +346,11 @@ constructor( scale, scale, ghostedViewState.centerX - transitionContainerLocation[0], ghostedViewState.centerY - transitionContainerLocation[1] ghostedViewState.centerY - transitionContainerLocation[1], ) ghostViewMatrix.postTranslate( (leftChange + rightChange) / 2f, (topChange + bottomChange) / 2f (topChange + bottomChange) / 2f, ) ghostView.animationMatrix = ghostViewMatrix Loading Loading @@ -462,7 +491,7 @@ constructor( private fun updateRadii( radii: FloatArray, topCornerRadius: Float, bottomCornerRadius: Float bottomCornerRadius: Float, ) { radii[0] = topCornerRadius radii[1] = topCornerRadius Loading
packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt +52 −23 Original line number Diff line number Diff line Loading @@ -52,6 +52,9 @@ import kotlin.math.roundToInt interface ExpandableController { /** The [Expandable] controlled by this controller. */ val expandable: Expandable /** Called when the [Expandable] stop being included in the composition. */ fun onDispose() } /** Loading Loading @@ -88,9 +91,9 @@ fun rememberExpandableController( // Whether this composable is still composed. We only do the dialog exit animation if this is // true. val isComposed = remember { mutableStateOf(true) } DisposableEffect(Unit) { onDispose { isComposed.value = false } } return remember( val controller = remember( color, contentColor, shape, Loading @@ -115,6 +118,17 @@ fun rememberExpandableController( isComposed, ) } DisposableEffect(Unit) { onDispose { isComposed.value = false if (TransitionAnimator.returnAnimationsEnabled()) { controller.onDispose() } } } return controller } internal class ExpandableControllerImpl( Loading @@ -132,19 +146,29 @@ internal class ExpandableControllerImpl( private val layoutDirection: LayoutDirection, private val isComposed: State<Boolean>, ) : ExpandableController { /** The [ActivityTransitionAnimator.Controller] to be cleaned up [onDispose]. */ private var activityControllerForDisposal: ActivityTransitionAnimator.Controller? = null override val expandable: Expandable = object : Expandable { override fun activityTransitionController( launchCujType: Int?, cookie: ActivityTransitionAnimator.TransitionCookie?, component: ComponentName?, returnCujType: Int? returnCujType: Int?, isEphemeral: Boolean, ): ActivityTransitionAnimator.Controller? { if (!isComposed.value) { return null } return activityController(launchCujType, cookie, component, returnCujType) val controller = activityController(launchCujType, cookie, component, returnCujType) if (TransitionAnimator.returnAnimationsEnabled() && isEphemeral) { activityControllerForDisposal?.onDispose() activityControllerForDisposal = controller } return controller } override fun dialogTransitionController( Loading @@ -158,6 +182,11 @@ internal class ExpandableControllerImpl( } } override fun onDispose() { activityControllerForDisposal?.onDispose() activityControllerForDisposal = null } /** * Create a [TransitionAnimator.Controller] that is going to be used to drive an activity or * dialog animation. This controller will: Loading @@ -181,7 +210,7 @@ internal class ExpandableControllerImpl( override fun onTransitionAnimationProgress( state: TransitionAnimator.State, progress: Float, linearProgress: Float linearProgress: Float, ) { // We copy state given that it's always the same object that is mutated by // ActivityTransitionAnimator. Loading Loading @@ -269,7 +298,7 @@ internal class ExpandableControllerImpl( launchCujType: Int?, cookie: ActivityTransitionAnimator.TransitionCookie?, component: ComponentName?, returnCujType: Int? returnCujType: Int?, ): ActivityTransitionAnimator.Controller { val delegate = transitionController() return object : Loading
packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/StateAwareExpandable.kt +8 −1 Original line number Diff line number Diff line Loading @@ -78,9 +78,16 @@ fun Expandable.withStateAwareness( cookie: ActivityTransitionAnimator.TransitionCookie?, component: ComponentName?, returnCujType: Int?, isEphemeral: Boolean, ): ActivityTransitionAnimator.Controller? = delegate .activityTransitionController(launchCujType, cookie, component, returnCujType) .activityTransitionController( launchCujType, cookie, component, returnCujType, isEphemeral, ) ?.withStateAwareness(onActivityLaunchTransitionStart, onActivityLaunchTransitionEnd) override fun dialogTransitionController( Loading