Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java +56 −15 Original line number Original line Diff line number Diff line Loading @@ -189,14 +189,16 @@ public class BubbleTransitions { * * * 1. Start inflating the bubble view * 1. Start inflating the bubble view * 2. Once inflated (but not-yet visible), tell WM to do the shell-transition. * 2. Once inflated (but not-yet visible), tell WM to do the shell-transition. * 3. Transition becomes ready, so notify Launcher * 3. When the transition becomes ready, notify Launcher in parallel * 4. Launcher responds with showExpandedView which calls continueExpand() to make view visible * 4. Wait for surface to be created * 5. Surface is created which kicks off actual animation * 5. Once surface is ready, animate the task to a bubble * * * So, constructor -> onInflated -> startAnimation -> continueExpand -> surfaceCreated. * While the animation is pending, we keep a reference to the pending transition in the bubble. * This allows us to check in other parts of the code that this bubble will be shown via the * transition animation. * * * continueExpand and surfaceCreated are set-up to happen in either order, though, to support * startAnimation, continueExpand and surfaceCreated are set-up to happen in either order, * UX/timing adjustments. * to support UX/timing adjustments. */ */ @VisibleForTesting @VisibleForTesting class ConvertToBubble implements Transitions.TransitionHandler, BubbleTransition { class ConvertToBubble implements Transitions.TransitionHandler, BubbleTransition { Loading @@ -209,9 +211,9 @@ public class BubbleTransitions { final Rect mStartBounds = new Rect(); final Rect mStartBounds = new Rect(); SurfaceControl mSnapshot = null; SurfaceControl mSnapshot = null; TaskInfo mTaskInfo; TaskInfo mTaskInfo; boolean mFinishedExpand = false; BubbleViewProvider mPriorBubble = null; BubbleViewProvider mPriorBubble = null; private final TransitionProgress mTransitionProgress = new TransitionProgress(); private SurfaceControl.Transaction mFinishT; private SurfaceControl.Transaction mFinishT; private SurfaceControl mTaskLeash; private SurfaceControl mTaskLeash; Loading Loading @@ -359,12 +361,12 @@ public class BubbleTransitions { startTransaction.apply(); startTransaction.apply(); mTaskViewTransitions.onExternalDone(transition); mTaskViewTransitions.onExternalDone(transition); mTransitionProgress.setTransitionReady(); startExpandAnim(); return true; return true; } } @Override private void startExpandAnim() { public void continueExpand() { mFinishedExpand = true; final boolean animate = mLayerView.canExpandView(mBubble); final boolean animate = mLayerView.canExpandView(mBubble); if (animate) { if (animate) { mPriorBubble = mLayerView.prepareConvertedView(mBubble); mPriorBubble = mLayerView.prepareConvertedView(mBubble); Loading @@ -375,19 +377,25 @@ public class BubbleTransitions { mLayerView.removeView(priorView); mLayerView.removeView(priorView); mPriorBubble = null; mPriorBubble = null; } } if (!animate || mBubble.getTaskView().getSurfaceControl() != null) { if (!animate || mTransitionProgress.isReadyToAnimate()) { playAnimation(animate); playAnimation(animate); } } } } @Override public void continueExpand() { mTransitionProgress.setReadyToExpand(); } @Override @Override public void surfaceCreated() { public void surfaceCreated() { mTransitionProgress.setSurfaceReady(); mMainExecutor.execute(() -> { mMainExecutor.execute(() -> { final TaskViewTaskController tvc = mBubble.getTaskView().getController(); final TaskViewTaskController tvc = mBubble.getTaskView().getController(); final TaskViewRepository.TaskViewState state = mRepository.byTaskView(tvc); final TaskViewRepository.TaskViewState state = mRepository.byTaskView(tvc); if (state == null) return; if (state == null) return; state.mVisible = true; state.mVisible = true; if (mFinishedExpand) { if (mTransitionProgress.isReadyToAnimate()) { playAnimation(true /* animate */); playAnimation(true /* animate */); } } }); }); Loading @@ -403,9 +411,6 @@ public class BubbleTransitions { mFinishWct = null; mFinishWct = null; } } // Preparation is complete. mBubble.setPreparingTransition(null); if (animate) { if (animate) { mLayerView.animateConvert(startT, mStartBounds, mSnapshot, mTaskLeash, () -> { mLayerView.animateConvert(startT, mStartBounds, mSnapshot, mTaskLeash, () -> { mFinishCb.onTransitionFinished(mFinishWct); mFinishCb.onTransitionFinished(mFinishWct); Loading @@ -417,6 +422,42 @@ public class BubbleTransitions { mFinishCb = null; mFinishCb = null; } } } } /** * Keeps track of internal state of different steps of this BubbleTransition. */ private class TransitionProgress { private boolean mTransitionReady; private boolean mReadyToExpand; private boolean mSurfaceReady; void setTransitionReady() { mTransitionReady = true; onUpdate(); } void setReadyToExpand() { mReadyToExpand = true; onUpdate(); } void setSurfaceReady() { mSurfaceReady = true; onUpdate(); } boolean isReadyToAnimate() { // Animation only depends on transition and surface state return mTransitionReady && mSurfaceReady; } private void onUpdate() { if (mTransitionReady && mReadyToExpand && mSurfaceReady) { // Clear the transition from bubble when all the steps are ready mBubble.setPreparingTransition(null); } } } } } /** /** Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java +7 −2 Original line number Original line Diff line number Diff line Loading @@ -186,15 +186,20 @@ public class BubbleTransitionsTest extends ShellTestCase { verify(startT).setPosition(any(), eq(0f), eq(0f)); verify(startT).setPosition(any(), eq(0f), eq(0f)); verify(mBubbleData).notificationEntryUpdated(eq(mBubble), anyBoolean(), anyBoolean()); verify(mBubbleData).notificationEntryUpdated(eq(mBubble), anyBoolean(), anyBoolean()); ctb.continueExpand(); clearInvocations(mBubble); clearInvocations(mBubble); verify(mBubble, never()).setPreparingTransition(any()); verify(mBubble, never()).setPreparingTransition(any()); ctb.surfaceCreated(); ctb.surfaceCreated(); verify(mBubble).setPreparingTransition(isNull()); // Check that preparing transition is not reset before continueExpand is called verify(mBubble, never()).setPreparingTransition(any()); ArgumentCaptor<Runnable> animCb = ArgumentCaptor.forClass(Runnable.class); ArgumentCaptor<Runnable> animCb = ArgumentCaptor.forClass(Runnable.class); verify(mLayerView).animateConvert(any(), any(), any(), any(), animCb.capture()); verify(mLayerView).animateConvert(any(), any(), any(), any(), animCb.capture()); // continueExpand is now called, check that preparing transition is cleared ctb.continueExpand(); verify(mBubble).setPreparingTransition(isNull()); assertFalse(finishCalled[0]); assertFalse(finishCalled[0]); animCb.getValue().run(); animCb.getValue().run(); assertTrue(finishCalled[0]); assertTrue(finishCalled[0]); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java +56 −15 Original line number Original line Diff line number Diff line Loading @@ -189,14 +189,16 @@ public class BubbleTransitions { * * * 1. Start inflating the bubble view * 1. Start inflating the bubble view * 2. Once inflated (but not-yet visible), tell WM to do the shell-transition. * 2. Once inflated (but not-yet visible), tell WM to do the shell-transition. * 3. Transition becomes ready, so notify Launcher * 3. When the transition becomes ready, notify Launcher in parallel * 4. Launcher responds with showExpandedView which calls continueExpand() to make view visible * 4. Wait for surface to be created * 5. Surface is created which kicks off actual animation * 5. Once surface is ready, animate the task to a bubble * * * So, constructor -> onInflated -> startAnimation -> continueExpand -> surfaceCreated. * While the animation is pending, we keep a reference to the pending transition in the bubble. * This allows us to check in other parts of the code that this bubble will be shown via the * transition animation. * * * continueExpand and surfaceCreated are set-up to happen in either order, though, to support * startAnimation, continueExpand and surfaceCreated are set-up to happen in either order, * UX/timing adjustments. * to support UX/timing adjustments. */ */ @VisibleForTesting @VisibleForTesting class ConvertToBubble implements Transitions.TransitionHandler, BubbleTransition { class ConvertToBubble implements Transitions.TransitionHandler, BubbleTransition { Loading @@ -209,9 +211,9 @@ public class BubbleTransitions { final Rect mStartBounds = new Rect(); final Rect mStartBounds = new Rect(); SurfaceControl mSnapshot = null; SurfaceControl mSnapshot = null; TaskInfo mTaskInfo; TaskInfo mTaskInfo; boolean mFinishedExpand = false; BubbleViewProvider mPriorBubble = null; BubbleViewProvider mPriorBubble = null; private final TransitionProgress mTransitionProgress = new TransitionProgress(); private SurfaceControl.Transaction mFinishT; private SurfaceControl.Transaction mFinishT; private SurfaceControl mTaskLeash; private SurfaceControl mTaskLeash; Loading Loading @@ -359,12 +361,12 @@ public class BubbleTransitions { startTransaction.apply(); startTransaction.apply(); mTaskViewTransitions.onExternalDone(transition); mTaskViewTransitions.onExternalDone(transition); mTransitionProgress.setTransitionReady(); startExpandAnim(); return true; return true; } } @Override private void startExpandAnim() { public void continueExpand() { mFinishedExpand = true; final boolean animate = mLayerView.canExpandView(mBubble); final boolean animate = mLayerView.canExpandView(mBubble); if (animate) { if (animate) { mPriorBubble = mLayerView.prepareConvertedView(mBubble); mPriorBubble = mLayerView.prepareConvertedView(mBubble); Loading @@ -375,19 +377,25 @@ public class BubbleTransitions { mLayerView.removeView(priorView); mLayerView.removeView(priorView); mPriorBubble = null; mPriorBubble = null; } } if (!animate || mBubble.getTaskView().getSurfaceControl() != null) { if (!animate || mTransitionProgress.isReadyToAnimate()) { playAnimation(animate); playAnimation(animate); } } } } @Override public void continueExpand() { mTransitionProgress.setReadyToExpand(); } @Override @Override public void surfaceCreated() { public void surfaceCreated() { mTransitionProgress.setSurfaceReady(); mMainExecutor.execute(() -> { mMainExecutor.execute(() -> { final TaskViewTaskController tvc = mBubble.getTaskView().getController(); final TaskViewTaskController tvc = mBubble.getTaskView().getController(); final TaskViewRepository.TaskViewState state = mRepository.byTaskView(tvc); final TaskViewRepository.TaskViewState state = mRepository.byTaskView(tvc); if (state == null) return; if (state == null) return; state.mVisible = true; state.mVisible = true; if (mFinishedExpand) { if (mTransitionProgress.isReadyToAnimate()) { playAnimation(true /* animate */); playAnimation(true /* animate */); } } }); }); Loading @@ -403,9 +411,6 @@ public class BubbleTransitions { mFinishWct = null; mFinishWct = null; } } // Preparation is complete. mBubble.setPreparingTransition(null); if (animate) { if (animate) { mLayerView.animateConvert(startT, mStartBounds, mSnapshot, mTaskLeash, () -> { mLayerView.animateConvert(startT, mStartBounds, mSnapshot, mTaskLeash, () -> { mFinishCb.onTransitionFinished(mFinishWct); mFinishCb.onTransitionFinished(mFinishWct); Loading @@ -417,6 +422,42 @@ public class BubbleTransitions { mFinishCb = null; mFinishCb = null; } } } } /** * Keeps track of internal state of different steps of this BubbleTransition. */ private class TransitionProgress { private boolean mTransitionReady; private boolean mReadyToExpand; private boolean mSurfaceReady; void setTransitionReady() { mTransitionReady = true; onUpdate(); } void setReadyToExpand() { mReadyToExpand = true; onUpdate(); } void setSurfaceReady() { mSurfaceReady = true; onUpdate(); } boolean isReadyToAnimate() { // Animation only depends on transition and surface state return mTransitionReady && mSurfaceReady; } private void onUpdate() { if (mTransitionReady && mReadyToExpand && mSurfaceReady) { // Clear the transition from bubble when all the steps are ready mBubble.setPreparingTransition(null); } } } } } /** /** Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java +7 −2 Original line number Original line Diff line number Diff line Loading @@ -186,15 +186,20 @@ public class BubbleTransitionsTest extends ShellTestCase { verify(startT).setPosition(any(), eq(0f), eq(0f)); verify(startT).setPosition(any(), eq(0f), eq(0f)); verify(mBubbleData).notificationEntryUpdated(eq(mBubble), anyBoolean(), anyBoolean()); verify(mBubbleData).notificationEntryUpdated(eq(mBubble), anyBoolean(), anyBoolean()); ctb.continueExpand(); clearInvocations(mBubble); clearInvocations(mBubble); verify(mBubble, never()).setPreparingTransition(any()); verify(mBubble, never()).setPreparingTransition(any()); ctb.surfaceCreated(); ctb.surfaceCreated(); verify(mBubble).setPreparingTransition(isNull()); // Check that preparing transition is not reset before continueExpand is called verify(mBubble, never()).setPreparingTransition(any()); ArgumentCaptor<Runnable> animCb = ArgumentCaptor.forClass(Runnable.class); ArgumentCaptor<Runnable> animCb = ArgumentCaptor.forClass(Runnable.class); verify(mLayerView).animateConvert(any(), any(), any(), any(), animCb.capture()); verify(mLayerView).animateConvert(any(), any(), any(), any(), animCb.capture()); // continueExpand is now called, check that preparing transition is cleared ctb.continueExpand(); verify(mBubble).setPreparingTransition(isNull()); assertFalse(finishCalled[0]); assertFalse(finishCalled[0]); animCb.getValue().run(); animCb.getValue().run(); assertTrue(finishCalled[0]); assertTrue(finishCalled[0]); Loading