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

Commit d0930e9f authored by Liran Binyamin's avatar Liran Binyamin
Browse files

Clean up the preparing transition

Currently the preparing transition in some of the transitions
is cleaned up after the continueExpand signal is sent. With
bubble bar, the expand signal comes from launcher and it is
possible to swipe back while the animation is still running and
collapse the bubble bar. In that case the expand signal will
never be sent and the preparing transition will never get
cleared from the bubble. That would cause crashes the next time
we try to expand the bubble bar.

This change clears the preparing transition from the bubble as
part of the clean up step.

Bug: 415925442
Flag: com.android.wm.shell.enable_create_any_bubble
Test: atest BubbleTransitionsTest
Change-Id: Icd82ddbec6eaf322bf661eec84a9dbbb43373d0d
parent 962cf28b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -724,6 +724,7 @@ public class BubbleTransitions {
            ProtoLog.d(WM_SHELL_BUBBLES_NOISY, "LaunchNewTaskBubble.cleanup()");
            mFinishCb.onTransitionFinished(mFinishWct);
            mFinishCb = null;
            mBubble.setPreparingTransition(null);
        }
    }

@@ -1070,6 +1071,7 @@ public class BubbleTransitions {
            mFinishCb = null;
            mPendingEnterTransitions.remove(mLaunchCookie.binder);
            mEnterTransitions.remove(mPlayingTransition);
            mBubble.setPreparingTransition(null);
        }
    }

+84 −0
Original line number Diff line number Diff line
@@ -783,6 +783,90 @@ public class BubbleTransitionsTest extends ShellTestCase {
                bt.mLaunchCookie.binder);
    }

    @Test
    public void testLaunchOrConvert_convertTaskToBubble_collapseWhileExpanding() {
        final ActivityManager.RunningTaskInfo taskInfo = setupAppBubble();

        when(mLayerView.canExpandView(mBubble)).thenReturn(true);

        final BubbleTransitions.LaunchOrConvertToBubble bt =
                (BubbleTransitions.LaunchOrConvertToBubble) mBubbleTransitions
                        .startLaunchIntoOrConvertToBubble(
                                mBubble, mExpandedViewManager, mTaskViewFactory, mBubblePositioner,
                                mStackView, mLayerView, mIconFactory, false /* inflateSync */,
                                BubbleBarLocation.RIGHT);

        bt.onInflated(mBubble);

        verify(mBubble).setPreparingTransition(bt);

        // Check that an external transition was enqueued, and a launch cookie was set.
        assertThat(mTaskViewTransitions.hasPending()).isTrue();
        assertThat(bt.mLaunchCookie).isNotNull();

        // Prepare for startAnimation call
        final SurfaceControl taskLeash = new SurfaceControl.Builder().setName("taskLeash").build();
        final SurfaceControl snapshot = new SurfaceControl.Builder().setName("snapshot").build();
        final TransitionInfo info = setupConvertTransition(taskInfo, taskLeash, snapshot,
                bt.mLaunchCookie.binder);

        final IBinder transitionToken = mock(IBinder.class);
        bt.mPlayingTransition = transitionToken;

        final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
        final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
        final boolean[] finishCalled = new boolean[] { false };
        final Transitions.TransitionFinishCallback finishCb = wct -> {
            assertThat(finishCalled[0]).isFalse();
            finishCalled[0] = true;
        };

        // Start playing the transition
        bt.startAnimation(transitionToken, info, startT, finishT, finishCb);

        assertThat(mTaskViewTransitions.hasPending()).isFalse();
        // Verify startT modifications (position, snapshot handling)
        verify(startT).setPosition(taskLeash, 0, 0);
        verify(startT).show(snapshot);
        verify(startT).reparent(eq(snapshot), any(SurfaceControl.class));
        verify(startT).setPosition(snapshot, 0 , 0);
        verify(startT).setLayer(snapshot, Integer.MAX_VALUE);

        // Bubble data gets updated with the correct bubble bar location
        verify(mBubbleData).notificationEntryUpdated(eq(mBubble), anyBoolean(), anyBoolean(),
                eq(BubbleBarLocation.RIGHT));

        // Simulate surfaceCreated so the animation can start but don't call continueExpand
        bt.surfaceCreated();

        // Verify preparingTransition is not cleared yet
        verify(mBubble, never()).setPreparingTransition(null);

        // Verify animateConvert is called due to TRANSIT_CHANGE and snapshot exists
        ArgumentCaptor<Runnable> animCb = ArgumentCaptor.forClass(Runnable.class);
        verify(mLayerView).animateConvert(
                any(),
                // Check that task bounds are passed in as the initial bounds
                eq(new Rect(0, 0, FULLSCREEN_TASK_WIDTH, FULLSCREEN_TASK_HEIGHT)),
                eq(1f),
                eq(snapshot),
                eq(taskLeash),
                animCb.capture()
        );

        // Trigger animation callback to finish
        assertThat(finishCalled[0]).isFalse();
        animCb.getValue().run();
        assertThat(finishCalled[0]).isTrue();

        // Verify that the playing transition and pending cookie are removed
        assertThat(mBubbleTransitions.mEnterTransitions).doesNotContainKey(transitionToken);
        assertThat(mBubbleTransitions.mPendingEnterTransitions).doesNotContainKey(
                bt.mLaunchCookie.binder);
        // Verify we cleared the preparing transition after the animation finished
        verify(mBubble).setPreparingTransition(null);
    }

    @Test
    public void testLaunchOrConvert_convertTaskToBubble_noSnapshot() {
        final ActivityManager.RunningTaskInfo taskInfo = setupAppBubble();