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

Commit 2fa7a24c authored by Liran Binyamin's avatar Liran Binyamin
Browse files

Move dragged bubble to full screen

Adds a bubble transition for a dragged bubble to a full screen window.

Currently the transition shows the full screen window without animation.

Flag: com.android.wm.shell.enable_bubble_to_fullscreen
Bug: 388858013
Test: atest BubbleTransitionsTest
Test: manual
       - create bubble in bubble bar
       - drag bubble to full screen drag zone
       - observe bubble moved to full screen window
Change-Id: I692ff1fdf95f09e07bf3c273bd54097ddf139a1e
parent 2d731e06
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -2644,7 +2644,8 @@ public class BubbleController implements ConfigurationChangeListener,
    }

    private void moveBubbleToFullscreen(String key) {
        // TODO b/388858013: convert the bubble to full screen
        Bubble b = mBubbleData.getBubbleInStackWithKey(key);
        mBubbleTransitions.startDraggedBubbleIconToFullscreen(b);
    }

    private boolean isDeviceLocked() {
+116 −0
Original line number Diff line number Diff line
@@ -113,6 +113,11 @@ public class BubbleTransitions {
        return convert;
    }

    /** Starts a transition that converts a dragged bubble icon to a full screen task. */
    public BubbleTransition startDraggedBubbleIconToFullscreen(Bubble bubble) {
        return new DraggedBubbleIconToFullscreen(bubble);
    }

    /**
     * Plucks the task-surface out of an ancestor view while making the view invisible. This helper
     * attempts to do this seamlessly (ie. view becomes invisible in sync with task reparent).
@@ -645,4 +650,115 @@ public class BubbleTransitions {
            t.apply();
        }
    }

    /**
     * A transition that converts a dragged bubble icon to a full screen window.
     *
     * <p>This transition assumes that the bubble is invisible so it is simply sent to front.
     */
    class DraggedBubbleIconToFullscreen implements Transitions.TransitionHandler, BubbleTransition {

        IBinder mTransition;
        final Bubble mBubble;

        DraggedBubbleIconToFullscreen(Bubble bubble) {
            mBubble = bubble;
            bubble.setPreparingTransition(this);
            WindowContainerToken token = bubble.getTaskView().getTaskInfo().getToken();
            WindowContainerTransaction wct = new WindowContainerTransaction();
            wct.setAlwaysOnTop(token, false);
            wct.setWindowingMode(token, WINDOWING_MODE_UNDEFINED);
            wct.reorder(token, /* onTop= */ true);
            wct.setHidden(token, false);
            mTaskOrganizer.setInterceptBackPressedOnTaskRoot(token, false);
            mTaskViewTransitions.enqueueExternal(bubble.getTaskView().getController(), () -> {
                mTransition = mTransitions.startTransition(TRANSIT_TO_FRONT, wct, this);
                return mTransition;
            });
        }

        @Override
        public void skip() {
            mBubble.setPreparingTransition(null);
        }

        @Override
        public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
                @NonNull SurfaceControl.Transaction startTransaction,
                @NonNull SurfaceControl.Transaction finishTransaction,
                @NonNull Transitions.TransitionFinishCallback finishCallback) {
            if (mTransition != transition) {
                return false;
            }

            final TaskViewTaskController taskViewTaskController =
                    mBubble.getTaskView().getController();
            if (taskViewTaskController == null) {
                mTaskViewTransitions.onExternalDone(transition);
                finishCallback.onTransitionFinished(null);
                return true;
            }

            TransitionInfo.Change change = findTransitionChange(info);
            if (change == null) {
                Slog.w(TAG, "Expected a TaskView transition to front but didn't find "
                        + "one, cleaning up the task view");
                taskViewTaskController.setTaskNotFound();
                mTaskViewTransitions.onExternalDone(transition);
                finishCallback.onTransitionFinished(null);
                return true;
            }
            mRepository.remove(taskViewTaskController);

            startTransaction.apply();
            finishCallback.onTransitionFinished(null);
            taskViewTaskController.notifyTaskRemovalStarted(mBubble.getTaskView().getTaskInfo());
            mTaskViewTransitions.onExternalDone(transition);
            return true;
        }

        private TransitionInfo.Change findTransitionChange(TransitionInfo info) {
            TransitionInfo.Change result = null;
            WindowContainerToken token = mBubble.getTaskView().getTaskInfo().getToken();
            for (int i = 0; i < info.getChanges().size(); ++i) {
                final TransitionInfo.Change change = info.getChanges().get(i);
                if (change.getTaskInfo() == null) {
                    continue;
                }
                if (change.getMode() != TRANSIT_TO_FRONT) {
                    continue;
                }
                if (!token.equals(change.getTaskInfo().token)) {
                    continue;
                }
                result = change;
                break;
            }
            return result;
        }

        @Override
        public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
                @NonNull SurfaceControl.Transaction startTransaction,
                @NonNull SurfaceControl.Transaction finishTransaction,
                @NonNull IBinder mergeTarget,
                @NonNull Transitions.TransitionFinishCallback finishCallback) {
        }

        @Override
        public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
                @NonNull TransitionRequestInfo request) {
            return null;
        }

        @Override
        public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted,
                @Nullable SurfaceControl.Transaction finishTransaction) {
            if (!aborted) {
                return;
            }
            mTransition = null;
            mTaskViewTransitions.onExternalDone(transition);
        }
    }
}
+26 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
package com.android.wm.shell.bubbles;

import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_TO_FRONT;

import static com.android.wm.shell.transition.Transitions.TRANSIT_CONVERT_TO_BUBBLE;

@@ -52,6 +53,7 @@ import com.android.launcher3.icons.BubbleIconFactory;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestSyncExecutor;
import com.android.wm.shell.bubbles.BubbleTransitions.DraggedBubbleIconToFullscreen;
import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
import com.android.wm.shell.common.ShellExecutor;
@@ -136,6 +138,7 @@ public class BubbleTransitionsTest extends ShellTestCase {
        when(tvtc.getTaskInfo()).thenReturn(taskInfo);
        when(tv.getController()).thenReturn(tvtc);
        when(mBubble.getTaskView()).thenReturn(tv);
        when(tv.getTaskInfo()).thenReturn(taskInfo);
        mRepository.add(tvtc);
        return taskInfo;
    }
@@ -285,4 +288,27 @@ public class BubbleTransitionsTest extends ShellTestCase {
        // directly tested.
        assertFalse(mTaskViewTransitions.hasPending());
    }

    @Test
    public void convertDraggedBubbleToFullscreen() {
        ActivityManager.RunningTaskInfo taskInfo = setupBubble();
        final DraggedBubbleIconToFullscreen bt =
                (DraggedBubbleIconToFullscreen) mBubbleTransitions
                        .startDraggedBubbleIconToFullscreen(mBubble);
        verify(mTransitions).startTransition(anyInt(), any(), eq(bt));

        final TransitionInfo info = new TransitionInfo(TRANSIT_TO_FRONT, 0);
        final TransitionInfo.Change chg = new TransitionInfo.Change(taskInfo.token,
                mock(SurfaceControl.class));
        chg.setMode(TRANSIT_TO_FRONT);
        chg.setTaskInfo(taskInfo);
        info.addChange(chg);
        info.addRoot(new TransitionInfo.Root(0, mock(SurfaceControl.class), 0, 0));
        SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
        SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
        Transitions.TransitionFinishCallback finishCb = wct -> {};
        bt.startAnimation(bt.mTransition, info, startT, finishT, finishCb);
        verify(startT).apply();
        assertFalse(mTaskViewTransitions.hasPending());
    }
}