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

Commit 99b0eef1 authored by Winson Chung's avatar Winson Chung
Browse files

Handle bubble transitions if the launch is collected into another transition

- In this particular flow, the opening of the next bubble task is
  collected into the transition for the closing of the trampoline task
  so we don't get a chance to handle the transition at request time.
  In this case, we should check during startAnimation() for the launch
  of the next bubble task, and handle the transition if possible.

Bug: 428855873
Flag: com.android.wm.shell.enable_create_any_bubble
Test: atest DefaultMixedHandlerTest

Change-Id: I880ed7110bffa67011d6966e9e0ddf7359cffcf7
parent 5a077e1a
Loading
Loading
Loading
Loading
+5 −6
Original line number Diff line number Diff line
@@ -3370,16 +3370,15 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        }
    }

    /** @return whether the transition-request implies entering bubbles from split. */
    public boolean requestImpliesSplitToBubble(TransitionRequestInfo request) {
        final TaskInfo triggerTask = request.getTriggerTask();
    /** @return whether the opening task implies entering bubbles from split. */
    public boolean requestImpliesSplitToBubble(TaskInfo openingTask) {
        if (!isSplitActive()
                || triggerTask == null
                || triggerTask.displayId != mDisplayId) {
                || openingTask == null
                || openingTask.displayId != mDisplayId) {
            return false;
        }

        int stageForTask = getStageOfTask(triggerTask.taskId);
        int stageForTask = getStageOfTask(openingTask.taskId);
        if (stageForTask == STAGE_TYPE_UNDEFINED) {
            return false;
        }
+32 −2
Original line number Diff line number Diff line
@@ -331,7 +331,7 @@ public class DefaultMixedHandler implements MixedTransitionHandler,
        if (requestHasBubbleEnter(request)) {
            consumeRemoteTransitionIfNecessary(transition, request.getRemoteTransition());

            if (mSplitHandler.requestImpliesSplitToBubble(request)) {
            if (mSplitHandler.requestImpliesSplitToBubble(request.getTriggerTask())) {
                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
                        " Got a Bubble-enter request from a split task");
                mBubbleTransitions.storePendingEnterTransition(transition, request);
@@ -361,7 +361,7 @@ public class DefaultMixedHandler implements MixedTransitionHandler,
        } else if (requestHasBubbleEnterFromAppBubbleOrExistingBubble(request)) {
            consumeRemoteTransitionIfNecessary(transition, request.getRemoteTransition());

            if (mSplitHandler.requestImpliesSplitToBubble(request)) {
            if (mSplitHandler.requestImpliesSplitToBubble(request.getTriggerTask())) {
                // TODO: Handle from split
            } else {
                // Note: This will currently "intercept" launches even while the bubble is collapsed
@@ -581,6 +581,24 @@ public class DefaultMixedHandler implements MixedTransitionHandler,
            break;
        }

        // If there was no requested transition but the transition includes an opening bubble task
        // then handle it here now
        TransitionInfo.Change bubbleChange =
                transitionHasBubbleEnterFromAppBubbleOrExistingBubble(info);
        if (mixed == null && bubbleChange != null) {
            if (mSplitHandler.requestImpliesSplitToBubble(bubbleChange.getTaskInfo())) {
                // TODO: Handle from split
            } else {
                // Add a mixed transition
                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a Bubble-enter "
                        + "transition from an app bubble or for an existing bubble");
                mixed = createDefaultMixedTransition(
                        MixedTransition.TYPE_LAUNCH_OR_CONVERT_TO_BUBBLE_FROM_EXISTING_BUBBLE,
                        transition);
                mActiveTransitions.add(mixed);
            }
        }

        // Offer Keyguard the opportunity to take over lock transitions - ideally we could know by
        // the time of handleRequest, but we need more information than is available at that time.
        if (KeyguardTransitionHandler.handles(info)) {
@@ -836,6 +854,18 @@ public class DefaultMixedHandler implements MixedTransitionHandler,
                && mBubbleTransitions.shouldBeAppBubble(request.getTriggerTask());
    }

    /**
     * Returns the associated change for the bubbled task in the given started transition if it is
     * from an app bubble or for an existing bubble and should be handled by the bubbles transition
     */
    public TransitionInfo.Change transitionHasBubbleEnterFromAppBubbleOrExistingBubble(
            @NonNull TransitionInfo info) {
        if (!BubbleAnythingFlagHelper.enableCreateAnyBubble()) {
            return null;
        }
        return DefaultMixedTransition.getChangeForBubblingTask(info, mBubbleTransitions);
    }

    /**
     * Notifies the remote transition that it will not be played and is consumed by another
     * transition (and it can clean up accordingly).
+1 −1
Original line number Diff line number Diff line
@@ -453,7 +453,7 @@ class DefaultMixedTransition extends DefaultMixedHandler.MixedTransition {
        return true;
    }

    private static @Nullable TransitionInfo.Change getChangeForBubblingTask(
    static @Nullable TransitionInfo.Change getChangeForBubblingTask(
            @NonNull TransitionInfo info, BubbleTransitions bubbleTransitions) {
        for (int i = 0; i < info.getChanges().size(); i++) {
            final TransitionInfo.Change chg = info.getChanges().get(i);
+44 −0
Original line number Diff line number Diff line
@@ -17,12 +17,16 @@
package com.android.wm.shell.transition

import android.app.ActivityManager.RunningTaskInfo
import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
import android.os.Binder
import android.platform.test.annotations.EnableFlags
import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_OPEN
import android.window.IRemoteTransition
import android.window.RemoteTransition
import android.window.TransitionInfo
import android.window.TransitionRequestInfo
import android.window.WindowContainerToken
import androidx.test.filters.SmallTest
import com.android.wm.shell.Flags.FLAG_ENABLE_CREATE_ANY_BUBBLE
import com.android.wm.shell.ShellTestCase
@@ -45,6 +49,7 @@ import org.mockito.kotlin.any
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.stub
import org.mockito.kotlin.verify

@@ -218,6 +223,44 @@ class DefaultMixedHandlerTest : ShellTestCase() {
        verify(remoteTransition).onTransitionConsumed(any(), eq(false))
    }

    @Test
    @EnableFlags(FLAG_ENABLE_CREATE_ANY_BUBBLE)
    fun test_startAnimation_NoBubbleEnterFromAppBubble() {
        val info = TransitionInfo(TRANSIT_OPEN, 0)

        bubbleTransitions.stub {
            on { isShowingAsBubbleBar } doReturn true
            on { shouldBeAppBubble(any()) } doReturn true
        }

        mixedHandler.startAnimation(Binder(), info, mock<SurfaceControl.Transaction>(),
            mock<SurfaceControl.Transaction>(), mock<Transitions.TransitionFinishCallback>())

        verify(bubbleTransitions, never()).startBubbleToBubbleLaunchOrExistingBubbleConvert(
            any(), any(), any());
    }

    @Test
    @EnableFlags(FLAG_ENABLE_CREATE_ANY_BUBBLE)
    fun test_startAnimation_bubbleEnterFromAppBubble() {
        val change = TransitionInfo.Change(mock<WindowContainerToken>(), mock<SurfaceControl>())
        change.mode = TRANSIT_OPEN
        change.taskInfo = createRunningTask()
        val info = TransitionInfo(TRANSIT_OPEN, 0)
        info.addChange(change)

        bubbleTransitions.stub {
            on { isShowingAsBubbleBar } doReturn true
            on { shouldBeAppBubble(any()) } doReturn true
        }

        mixedHandler.startAnimation(Binder(), info, mock<SurfaceControl.Transaction>(),
            mock<SurfaceControl.Transaction>(), mock<Transitions.TransitionFinishCallback>())

        verify(bubbleTransitions).startBubbleToBubbleLaunchOrExistingBubbleConvert(
            any(), any(), any());
    }

    private fun createTransitionRequestInfo(
        runningTask: RunningTaskInfo? = null,
        remote: RemoteTransition? = null,
@@ -228,6 +271,7 @@ class DefaultMixedHandlerTest : ShellTestCase() {
    private fun createRunningTask(taskId: Int = 0): RunningTaskInfo {
        return RunningTaskInfo().apply {
            this.taskId = taskId
            this.configuration.windowConfiguration.activityType = ACTIVITY_TYPE_STANDARD
        }
    }
}