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

Commit 47c91b21 authored by Winson Chung's avatar Winson Chung
Browse files

Bring the task forward when it consumes a cross-window global drag

- Send a notification when a successful cross-window drag occurs over a
  task so that we can bring it forward

Bug: 320797628
Test: atest DragDropTest DragDropControllerTests CrossAppDragAndDropTests
Test: atest WMShellUnitTests
Change-Id: Id2d2258a1e71b6dbc9a57e2f58ef43825cfc18c7
parent b4d9b79e
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.window;

import android.app.ActivityManager;
import android.view.DragEvent;
import android.window.IUnhandledDragCallback;

@@ -24,6 +25,12 @@ import android.window.IUnhandledDragCallback;
 * {@hide}
 */
oneway interface IGlobalDragListener {
    /**
     * Called when a cross-window drag is handled by another window.
     * @param taskInfo the task containing the window that consumed the drop
     */
    void onCrossWindowDrop(in ActivityManager.RunningTaskInfo taskInfo);

    /**
     * Called when the user finishes the drag gesture but no windows have reported handling the
     * drop.  The DragEvent is populated with the drag surface for the listener to animate.  The
+0 −13
Original line number Diff line number Diff line
@@ -643,19 +643,6 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
        }
    }

    /** Helper to set int metadata on the Surface corresponding to the task id. */
    public void setSurfaceMetadata(int taskId, int key, int value) {
        synchronized (mLock) {
            final TaskAppearedInfo info = mTasks.get(taskId);
            if (info == null || info.getLeash() == null) {
                return;
            }
            SurfaceControl.Transaction t = new SurfaceControl.Transaction();
            t.setMetadata(info.getLeash(), key, value);
            t.apply();
        }
    }

    private boolean updateTaskListenerIfNeeded(RunningTaskInfo taskInfo, SurfaceControl leash,
            TaskListener oldListener, TaskListener newListener) {
        if (oldListener == newListener) return false;
+5 −2
Original line number Diff line number Diff line
@@ -577,9 +577,12 @@ public abstract class WMShellModule {
            DisplayController displayController,
            UiEventLogger uiEventLogger,
            IconProvider iconProvider,
            GlobalDragListener globalDragListener,
            Transitions transitions,
            @ShellMainThread ShellExecutor mainExecutor) {
        return new DragAndDropController(context, shellInit, shellController,
                shellCommandHandler, displayController, uiEventLogger, iconProvider, mainExecutor);
        return new DragAndDropController(context, shellInit, shellController, shellCommandHandler,
                displayController, uiEventLogger, iconProvider, globalDragListener, transitions,
                mainExecutor);
    }

    //
+19 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DRAG_AND_DROP;

import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.content.ClipDescription;
import android.content.ComponentCallbacks2;
@@ -51,6 +52,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.window.WindowContainerTransaction;

import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
@@ -71,6 +73,7 @@ import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;

import java.io.PrintWriter;
import java.util.ArrayList;
@@ -79,6 +82,7 @@ import java.util.ArrayList;
 * Handles the global drag and drop handling for the Shell.
 */
public class DragAndDropController implements RemoteCallable<DragAndDropController>,
        GlobalDragListener.GlobalDragListenerCallback,
        DisplayController.OnDisplaysChangedListener,
        View.OnDragListener, ComponentCallbacks2 {

@@ -90,6 +94,8 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
    private final DisplayController mDisplayController;
    private final DragAndDropEventLogger mLogger;
    private final IconProvider mIconProvider;
    private final GlobalDragListener mGlobalDragListener;
    private final Transitions mTransitions;
    private SplitScreenController mSplitScreen;
    private ShellExecutor mMainExecutor;
    private ArrayList<DragAndDropListener> mListeners = new ArrayList<>();
@@ -112,6 +118,8 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
            DisplayController displayController,
            UiEventLogger uiEventLogger,
            IconProvider iconProvider,
            GlobalDragListener globalDragListener,
            Transitions transitions,
            ShellExecutor mainExecutor) {
        mContext = context;
        mShellController = shellController;
@@ -119,6 +127,8 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
        mDisplayController = displayController;
        mLogger = new DragAndDropEventLogger(uiEventLogger);
        mIconProvider = iconProvider;
        mGlobalDragListener = globalDragListener;
        mTransitions = transitions;
        mMainExecutor = mainExecutor;
        shellInit.addInitCallback(this::onInit, this);
    }
@@ -136,6 +146,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
        mShellController.addExternalInterface(KEY_EXTRA_SHELL_DRAG_AND_DROP,
                this::createExternalInterface, this);
        mShellCommandHandler.addDumpCallback(this::dump, this);
        mGlobalDragListener.setListener(this);
    }

    private ExternalInterfaceBinder createExternalInterface() {
@@ -322,6 +333,14 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
        return true;
    }

    @Override
    public void onCrossWindowDrop(@NonNull ActivityManager.RunningTaskInfo taskInfo) {
        // Bring the task forward when an item is dropped on it
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        wct.reorder(taskInfo.token, true /* onTop */);
        mTransitions.startTransition(WindowManager.TRANSIT_TO_FRONT, wct, null);
    }

    /**
     * Handles dropping on the drop target.
     */
+22 −2
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package com.android.wm.shell.draganddrop

import android.app.ActivityManager
import android.os.RemoteException
import android.util.Log
import android.view.DragEvent
@@ -31,13 +32,19 @@ import java.util.function.Consumer
 * Manages the listener and callbacks for unhandled global drags.
 */
class GlobalDragListener(
    val wmService: IWindowManager,
    mainExecutor: ShellExecutor
    private val wmService: IWindowManager,
    private val mainExecutor: ShellExecutor
) {
    private var callback: GlobalDragListenerCallback? = null

    private val globalDragListener: IGlobalDragListener =
        object : IGlobalDragListener.Stub() {
            override fun onCrossWindowDrop(taskInfo: ActivityManager.RunningTaskInfo) {
                mainExecutor.execute() {
                    this@GlobalDragListener.onCrossWindowDrop(taskInfo)
                }
            }

            override fun onUnhandledDrop(event: DragEvent, callback: IUnhandledDragCallback) {
                mainExecutor.execute() {
                    this@GlobalDragListener.onUnhandledDrop(event, callback)
@@ -49,6 +56,11 @@ class GlobalDragListener(
     * Callbacks for global drag events.
     */
    interface GlobalDragListenerCallback {
        /**
         * Called when a global drag is successfully handled by another window.
         */
        fun onCrossWindowDrop(taskInfo: ActivityManager.RunningTaskInfo) {}

        /**
         * Called when a global drag is unhandled (ie. dropped outside of all visible windows, or
         * dropped on a window that does not want to handle it).
@@ -79,12 +91,20 @@ class GlobalDragListener(
        }
    }

    @VisibleForTesting
    fun onCrossWindowDrop(taskInfo: ActivityManager.RunningTaskInfo) {
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
            "onCrossWindowDrop: %s", taskInfo)
        callback?.onCrossWindowDrop(taskInfo)
    }

    @VisibleForTesting
    fun onUnhandledDrop(dragEvent: DragEvent, wmCallback: IUnhandledDragCallback) {
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
            "onUnhandledDrop: %s", dragEvent)
        if (callback == null) {
            wmCallback.notifyUnhandledDropComplete(false)
            return
        }

        callback?.onUnhandledDrop(dragEvent) {
Loading