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

Commit a190f5ad authored by Ats Jenk's avatar Ats Jenk Committed by Android (Google) Code Review
Browse files

Merge changes I62acfff0,Ic2b1cd09 into main

* changes:
  Create a custom transition type for convert to bubble
  Start to bubble transition when releasing task in bubble area
parents ce93717f 5a8864ee
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.service.notification.NotificationListenerService.REASON_CA
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.TRANSIT_CHANGE;

import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -1590,20 +1591,26 @@ public class BubbleController implements ConfigurationChangeListener,
     * Expands and selects a bubble created from a running task in a different mode.
     *
     * @param taskInfo the task.
     * @param dragData optional information about the task when it is being dragged into a bubble
     */
    public void expandStackAndSelectBubble(ActivityManager.RunningTaskInfo taskInfo) {
    public void expandStackAndSelectBubble(ActivityManager.RunningTaskInfo taskInfo,
            @Nullable BubbleTransitions.DragData dragData) {
        if (!BubbleAnythingFlagHelper.enableBubbleToFullscreen()) return;
        Bubble b = mBubbleData.getOrCreateBubble(taskInfo); // Removes from overflow
        ProtoLog.v(WM_SHELL_BUBBLES, "expandStackAndSelectBubble - intent=%s", taskInfo.taskId);
        if (b.isInflated()) {
            mBubbleData.setSelectedBubbleAndExpandStack(b);
            if (dragData != null && dragData.getPendingWct() != null) {
                mTransitions.startTransition(TRANSIT_CHANGE,
                        dragData.getPendingWct(), /* handler= */ null);
            }
        } else {
            b.enable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE);
            // Lazy init stack view when a bubble is created
            ensureBubbleViewsAndWindowCreated();
            mBubbleTransitions.startConvertToBubble(b, taskInfo, mExpandedViewManager,
                    mBubbleTaskViewFactory, mBubblePositioner, mStackView, mLayerView,
                    mBubbleIconFactory, mInflateSynchronously);
                    mBubbleIconFactory, dragData, mInflateSynchronously);
        }
    }

+57 −4
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.View.INVISIBLE;
import static android.view.WindowManager.TRANSIT_CHANGE;

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

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -92,10 +94,10 @@ public class BubbleTransitions {
            BubbleExpandedViewManager expandedViewManager, BubbleTaskViewFactory factory,
            BubblePositioner positioner, BubbleStackView stackView,
            BubbleBarLayerView layerView, BubbleIconFactory iconFactory,
            boolean inflateSync) {
            DragData dragData, boolean inflateSync) {
        return new ConvertToBubble(bubble, taskInfo, mContext,
                expandedViewManager, factory, positioner, stackView, layerView, iconFactory,
                inflateSync);
                dragData, inflateSync);
    }

    /**
@@ -148,6 +150,39 @@ public class BubbleTransitions {
        default void continueCollapse() {}
    }

    /**
     * Information about the task when it is being dragged to a bubble
     */
    public static class DragData {
        private final Rect mBounds;
        private final WindowContainerTransaction mPendingWct;

        /**
         * @param bounds bounds of the dragged task when the drag was released
         * @param wct pending operations to be applied when finishing the drag
         */
        public DragData(@Nullable Rect bounds, @Nullable WindowContainerTransaction wct) {
            mBounds = bounds;
            mPendingWct = wct;
        }

        /**
         * @return bounds of the dragged task when the drag was released
         */
        @Nullable
        public Rect getBounds() {
            return mBounds;
        }

        /**
         * @return pending operations to be applied when finishing the drag
         */
        @Nullable
        public WindowContainerTransaction getPendingWct() {
            return mPendingWct;
        }
    }

    /**
     * BubbleTransition that coordinates the process of a non-bubble task becoming a bubble. The
     * steps are as follows:
@@ -167,6 +202,7 @@ public class BubbleTransitions {
    class ConvertToBubble implements Transitions.TransitionHandler, BubbleTransition {
        final BubbleBarLayerView mLayerView;
        Bubble mBubble;
        @Nullable DragData mDragData;
        IBinder mTransition;
        Transitions.TransitionFinishCallback mFinishCb;
        WindowContainerTransaction mFinishWct = null;
@@ -182,10 +218,12 @@ public class BubbleTransitions {
        ConvertToBubble(Bubble bubble, TaskInfo taskInfo, Context context,
                BubbleExpandedViewManager expandedViewManager, BubbleTaskViewFactory factory,
                BubblePositioner positioner, BubbleStackView stackView,
                BubbleBarLayerView layerView, BubbleIconFactory iconFactory, boolean inflateSync) {
                BubbleBarLayerView layerView, BubbleIconFactory iconFactory,
                @Nullable DragData dragData, boolean inflateSync) {
            mBubble = bubble;
            mTaskInfo = taskInfo;
            mLayerView = layerView;
            mDragData = dragData;
            mBubble.setInflateSynchronously(inflateSync);
            mBubble.setPreparingTransition(this);
            mBubble.inflate(
@@ -208,6 +246,9 @@ public class BubbleTransitions {
            final Rect launchBounds = new Rect();
            mLayerView.getExpandedViewRestBounds(launchBounds);
            WindowContainerTransaction wct = new WindowContainerTransaction();
            if (mDragData != null && mDragData.getPendingWct() != null) {
                wct.merge(mDragData.getPendingWct(), true);
            }
            if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) {
                if (mTaskInfo.getParentTaskId() != INVALID_TASK_ID) {
                    wct.reparent(mTaskInfo.token, null, true);
@@ -226,7 +267,7 @@ public class BubbleTransitions {
                state.mVisible = true;
            }
            mTaskViewTransitions.enqueueExternal(tv.getController(), () -> {
                mTransition = mTransitions.startTransition(TRANSIT_CHANGE, wct, this);
                mTransition = mTransitions.startTransition(TRANSIT_CONVERT_TO_BUBBLE, wct, this);
                return mTransition;
            });
        }
@@ -292,6 +333,11 @@ public class BubbleTransitions {
            }
            mFinishCb = finishCallback;

            if (mDragData != null && mDragData.getBounds() != null) {
                // Override start bounds with the dragged task bounds
                mStartBounds.set(mDragData.getBounds());
            }

            // Now update state (and talk to launcher) in parallel with snapshot stuff
            mBubbleData.notificationEntryUpdated(mBubble, /* suppressFlyout= */ true,
                    /* showInShade= */ false);
@@ -303,6 +349,13 @@ public class BubbleTransitions {
                    mStartBounds.left - info.getRoot(0).getOffset().x,
                    mStartBounds.top - info.getRoot(0).getOffset().y);
            startTransaction.setLayer(mSnapshot, Integer.MAX_VALUE);

            BubbleBarExpandedView bbev = mBubble.getBubbleBarExpandedView();
            if (bbev != null) {
                // Corners get reset during the animation. Add them back
                startTransaction.setCornerRadius(mSnapshot, bbev.getRestingCornerRadius());
            }

            startTransaction.apply();

            mTaskViewTransitions.onExternalDone(transition);
+4 −3
Original line number Diff line number Diff line
@@ -915,14 +915,15 @@ public abstract class WMShellModule {
            Transitions transitions,
            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
            @DynamicOverride DesktopUserRepositories desktopUserRepositories,
            InteractionJankMonitor interactionJankMonitor) {
            InteractionJankMonitor interactionJankMonitor,
            Optional<BubbleController> bubbleController) {
        return ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS_BUGFIX.isTrue()
                ? new SpringDragToDesktopTransitionHandler(
                context, transitions, rootTaskDisplayAreaOrganizer, desktopUserRepositories,
                interactionJankMonitor)
                interactionJankMonitor, bubbleController)
                : new DefaultDragToDesktopTransitionHandler(
                        context, transitions, rootTaskDisplayAreaOrganizer, desktopUserRepositories,
                        interactionJankMonitor);
                        interactionJankMonitor, bubbleController);
    }

    @WMSingleton
+13 −5
Original line number Diff line number Diff line
@@ -2689,15 +2689,22 @@ class DesktopTasksController(
    }

    /** Requests a task be transitioned from whatever mode it's in to a bubble. */
    fun requestFloat(taskInfo: RunningTaskInfo) {
    @JvmOverloads
    fun requestFloat(taskInfo: RunningTaskInfo, left: Boolean? = null) {
        val isDragging = dragToDesktopTransitionHandler.inProgress
        val shouldRequestFloat =
            taskInfo.isFullscreen || taskInfo.isFreeform || isDragging || taskInfo.isMultiWindow
        if (!shouldRequestFloat) return
        if (isDragging) {
            releaseVisualIndicator()
            val cancelState =
                if (left == true) DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_LEFT
                else DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_RIGHT
            dragToDesktopTransitionHandler.cancelDragToDesktopTransition(cancelState)
        } else {
            bubbleController.ifPresent { it.expandStackAndSelectBubble(taskInfo) }
            bubbleController.ifPresent {
                it.expandStackAndSelectBubble(taskInfo, /* dragData= */ null)
            }
        }
    }

@@ -2975,10 +2982,11 @@ class DesktopTasksController(
                )
                requestSplit(taskInfo, leftOrTop = false)
            }
            IndicatorType.TO_BUBBLE_LEFT_INDICATOR,
            IndicatorType.TO_BUBBLE_LEFT_INDICATOR -> {
                requestFloat(taskInfo, left = true)
            }
            IndicatorType.TO_BUBBLE_RIGHT_INDICATOR -> {
                // TODO(b/388851898): move to bubble
                cancelDragToDesktop(taskInfo)
                requestFloat(taskInfo, left = false)
            }
        }
        return indicatorType
+76 −8
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@ import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.animation.FloatProperties
import com.android.wm.shell.bubbles.BubbleController
import com.android.wm.shell.bubbles.BubbleTransitions
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP
@@ -49,10 +51,12 @@ import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UND
import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition
import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.transition.Transitions.TRANSIT_CONVERT_TO_BUBBLE
import com.android.wm.shell.transition.Transitions.TransitionHandler
import com.android.wm.shell.windowdecor.MoveToDesktopAnimator
import com.android.wm.shell.windowdecor.MoveToDesktopAnimator.Companion.DRAG_FREEFORM_SCALE
import com.android.wm.shell.windowdecor.OnTaskResizeAnimationListener
import java.util.Optional
import java.util.function.Supplier
import kotlin.math.max

@@ -72,6 +76,7 @@ sealed class DragToDesktopTransitionHandler(
    private val taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
    private val desktopUserRepositories: DesktopUserRepositories,
    protected val interactionJankMonitor: InteractionJankMonitor,
    private val bubbleController: Optional<BubbleController>,
    protected val transactionSupplier: Supplier<SurfaceControl.Transaction>,
) : TransitionHandler {

@@ -241,6 +246,20 @@ sealed class DragToDesktopTransitionHandler(
            state.startTransitionFinishCb?.onTransitionFinished(/* wct= */ null)
            requestSplitFromScaledTask(splitPosition, wct)
            clearState()
        } else if (
            state.draggedTaskChange != null &&
                (cancelState == CancelState.CANCEL_BUBBLE_LEFT ||
                    cancelState == CancelState.CANCEL_BUBBLE_RIGHT)
        ) {
            if (!bubbleController.isPresent) {
                startCancelAnimation()
            } else {
                // Animation is handled by BubbleController
                val wct = WindowContainerTransaction()
                restoreWindowOrder(wct, state)
                // TODO(b/388851898): pass along information about left or right side
                requestBubbleFromScaledTask(wct)
            }
        } else {
            // There's no dragged task, this can happen when the "cancel" happened too quickly
            // before the "start" transition is even ready (like on a fling gesture). The
@@ -256,6 +275,13 @@ sealed class DragToDesktopTransitionHandler(
        @SplitPosition splitPosition: Int,
        wct: WindowContainerTransaction,
    ) {
        val state = requireTransitionState()
        val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo")
        val animatedTaskBounds = getAnimatedTaskBounds()
        requestSplitSelect(wct, taskInfo, splitPosition, animatedTaskBounds)
    }

    private fun getAnimatedTaskBounds(): Rect {
        val state = requireTransitionState()
        val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo")
        val taskBounds = Rect(taskInfo.configuration.windowConfiguration.bounds)
@@ -264,14 +290,12 @@ sealed class DragToDesktopTransitionHandler(
        val scaledHeight = taskBounds.height() * taskScale
        val dragPosition = PointF(state.dragAnimator.position)
        state.dragAnimator.cancelAnimator()
        val animatedTaskBounds =
            Rect(
        return Rect(
            dragPosition.x.toInt(),
            dragPosition.y.toInt(),
            (dragPosition.x + scaledWidth).toInt(),
            (dragPosition.y + scaledHeight).toInt(),
        )
        requestSplitSelect(wct, taskInfo, splitPosition, animatedTaskBounds)
    }

    private fun requestSplitSelect(
@@ -294,6 +318,25 @@ sealed class DragToDesktopTransitionHandler(
        splitScreenController.requestEnterSplitSelect(taskInfo, wct, splitPosition, taskBounds)
    }

    private fun requestBubbleFromScaledTask(wct: WindowContainerTransaction) {
        // TODO(b/391928049): update density once we can drag from desktop to bubble
        val state = requireTransitionState()
        val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo")
        val taskBounds = getAnimatedTaskBounds()
        state.dragAnimator.cancelAnimator()
        requestBubble(wct, taskInfo, taskBounds)
    }

    private fun requestBubble(
        wct: WindowContainerTransaction,
        taskInfo: RunningTaskInfo,
        taskBounds: Rect = Rect(taskInfo.configuration.windowConfiguration.bounds),
    ) {
        val controller =
            bubbleController.orElseThrow { IllegalStateException("BubbleController not set") }
        controller.expandStackAndSelectBubble(taskInfo, BubbleTransitions.DragData(taskBounds, wct))
    }

    override fun startAnimation(
        transition: IBinder,
        info: TransitionInfo,
@@ -446,6 +489,16 @@ sealed class DragToDesktopTransitionHandler(
            state.startTransitionFinishTransaction?.apply()
            state.startTransitionFinishCb?.onTransitionFinished(/* wct= */ null)
            requestSplitSelect(wct, taskInfo, splitPosition)
        } else if (
            state.cancelState == CancelState.CANCEL_BUBBLE_LEFT ||
                state.cancelState == CancelState.CANCEL_BUBBLE_RIGHT
        ) {
            val taskInfo =
                state.draggedTaskChange?.taskInfo ?: error("Expected non-null task info.")
            val wct = WindowContainerTransaction()
            restoreWindowOrder(wct)
            // TODO(b/388851898): pass along information about left or right side
            requestBubble(wct, taskInfo)
        }
        return true
    }
@@ -476,6 +529,13 @@ sealed class DragToDesktopTransitionHandler(
            clearState()
            return
        }
        // In case of bubble animation, finish the initial desktop drag animation, but keep the
        // current animation running and have bubbles take over
        if (info.type == TRANSIT_CONVERT_TO_BUBBLE) {
            state.startTransitionFinishCb?.onTransitionFinished(/* wct= */ null)
            clearState()
            return
        }
        val isCancelTransition =
            info.type == TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP &&
                transition == state.cancelTransitionToken &&
@@ -869,6 +929,10 @@ sealed class DragToDesktopTransitionHandler(
        CANCEL_SPLIT_LEFT,
        /** A cancel event where the task will request to enter split on the right side. */
        CANCEL_SPLIT_RIGHT,
        /** A cancel event where the task will request to bubble on the left side. */
        CANCEL_BUBBLE_LEFT,
        /** A cancel event where the task will request to bubble on the right side. */
        CANCEL_BUBBLE_RIGHT,
    }

    companion object {
@@ -887,6 +951,7 @@ constructor(
    taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
    desktopUserRepositories: DesktopUserRepositories,
    interactionJankMonitor: InteractionJankMonitor,
    bubbleController: Optional<BubbleController>,
    transactionSupplier: Supplier<SurfaceControl.Transaction> = Supplier {
        SurfaceControl.Transaction()
    },
@@ -897,6 +962,7 @@ constructor(
        taskDisplayAreaOrganizer,
        desktopUserRepositories,
        interactionJankMonitor,
        bubbleController,
        transactionSupplier,
    ) {

@@ -925,6 +991,7 @@ constructor(
    taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
    desktopUserRepositories: DesktopUserRepositories,
    interactionJankMonitor: InteractionJankMonitor,
    bubbleController: Optional<BubbleController>,
    transactionSupplier: Supplier<SurfaceControl.Transaction> = Supplier {
        SurfaceControl.Transaction()
    },
@@ -935,6 +1002,7 @@ constructor(
        taskDisplayAreaOrganizer,
        desktopUserRepositories,
        interactionJankMonitor,
        bubbleController,
        transactionSupplier,
    ) {

Loading