diff options
5 files changed, 149 insertions, 15 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index 80e920fefe5f..28368ef37061 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -189,12 +189,13 @@ public abstract class WMShellBaseModule { static Optional<DragAndDropController> provideDragAndDropController(Context context, ShellInit shellInit, ShellController shellController, + ShellCommandHandler shellCommandHandler, DisplayController displayController, UiEventLogger uiEventLogger, IconProvider iconProvider, @ShellMainThread ShellExecutor mainExecutor) { return Optional.ofNullable(DragAndDropController.create(context, shellInit, shellController, - displayController, uiEventLogger, iconProvider, mainExecutor)); + shellCommandHandler, displayController, uiEventLogger, iconProvider, mainExecutor)); } @WMSingleton diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java index 091de3a86461..be2489da3628 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java @@ -35,10 +35,14 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; 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.content.ClipDescription; import android.content.ComponentCallbacks2; import android.content.Context; import android.content.res.Configuration; +import android.graphics.HardwareRenderer; import android.graphics.PixelFormat; import android.util.Slog; import android.util.SparseArray; @@ -50,6 +54,8 @@ import android.view.ViewGroup; import android.view.WindowManager; import android.widget.FrameLayout; +import androidx.annotation.BinderThread; +import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import com.android.internal.logging.InstanceId; @@ -58,25 +64,31 @@ import com.android.internal.protolog.common.ProtoLog; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.ExternalInterfaceBinder; +import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.annotations.ExternalMainThread; import com.android.wm.shell.protolog.ShellProtoLogGroup; 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 java.io.PrintWriter; import java.util.ArrayList; /** * Handles the global drag and drop handling for the Shell. */ -public class DragAndDropController implements DisplayController.OnDisplaysChangedListener, +public class DragAndDropController implements RemoteCallable<DragAndDropController>, + DisplayController.OnDisplaysChangedListener, View.OnDragListener, ComponentCallbacks2 { private static final String TAG = DragAndDropController.class.getSimpleName(); private final Context mContext; private final ShellController mShellController; + private final ShellCommandHandler mShellCommandHandler; private final DisplayController mDisplayController; private final DragAndDropEventLogger mLogger; private final IconProvider mIconProvider; @@ -100,6 +112,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange public static DragAndDropController create(Context context, ShellInit shellInit, ShellController shellController, + ShellCommandHandler shellCommandHandler, DisplayController displayController, UiEventLogger uiEventLogger, IconProvider iconProvider, @@ -107,19 +120,21 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange if (!context.getResources().getBoolean(R.bool.config_enableShellDragDrop)) { return null; } - return new DragAndDropController(context, shellInit, shellController, displayController, - uiEventLogger, iconProvider, mainExecutor); + return new DragAndDropController(context, shellInit, shellController, shellCommandHandler, + displayController, uiEventLogger, iconProvider, mainExecutor); } DragAndDropController(Context context, ShellInit shellInit, ShellController shellController, + ShellCommandHandler shellCommandHandler, DisplayController displayController, UiEventLogger uiEventLogger, IconProvider iconProvider, ShellExecutor mainExecutor) { mContext = context; mShellController = shellController; + mShellCommandHandler = shellCommandHandler; mDisplayController = displayController; mLogger = new DragAndDropEventLogger(uiEventLogger); mIconProvider = iconProvider; @@ -137,6 +152,23 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange mMainExecutor.executeDelayed(() -> { mDisplayController.addDisplayWindowListener(this); }, 0); + mShellController.addExternalInterface(KEY_EXTRA_SHELL_DRAG_AND_DROP, + this::createExternalInterface, this); + mShellCommandHandler.addDumpCallback(this::dump, this); + } + + private ExternalInterfaceBinder createExternalInterface() { + return new IDragAndDropImpl(this); + } + + @Override + public Context getContext() { + return mContext; + } + + @Override + public ShellExecutor getRemoteCallExecutor() { + return mMainExecutor; } /** @@ -156,7 +188,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange mListeners.remove(listener); } - private void notifyListeners() { + private void notifyDragStarted() { for (int i = 0; i < mListeners.size(); i++) { mListeners.get(i).onDragStarted(); } @@ -273,7 +305,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange pd.dragLayout.prepare(mDisplayController.getDisplayLayout(displayId), event.getClipData(), loggerSessionId); setDropTargetWindowVisibility(pd, View.VISIBLE); - notifyListeners(); + notifyDragStarted(); break; case ACTION_DRAG_ENTERED: pd.dragLayout.show(); @@ -327,13 +359,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange } private void setDropTargetWindowVisibility(PerDisplay pd, int visibility) { - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, - "Set drop target window visibility: displayId=%d visibility=%d", - pd.displayId, visibility); - pd.rootView.setVisibility(visibility); - if (visibility == View.VISIBLE) { - pd.rootView.requestApplyInsets(); - } + pd.setWindowVisibility(visibility); } private String getMimeTypes(ClipDescription description) { @@ -347,6 +373,18 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange return mimeTypes; } + /** + * Returns if any displays are currently ready to handle a drag/drop. + */ + private boolean isReadyToHandleDrag() { + for (int i = 0; i < mDisplayDropTargets.size(); i++) { + if (mDisplayDropTargets.valueAt(i).mHasDrawn) { + return true; + } + } + return false; + } + // Note: Component callbacks are always called on the main thread of the process @ExternalMainThread @Override @@ -372,12 +410,53 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange // Do nothing } - private static class PerDisplay { + /** + * Dumps information about this controller. + */ + public void dump(@NonNull PrintWriter pw, String prefix) { + pw.println(prefix + TAG); + pw.println(prefix + " listeners=" + mListeners.size()); + } + + /** + * The interface for calls from outside the host process. + */ + @BinderThread + private static class IDragAndDropImpl extends IDragAndDrop.Stub + implements ExternalInterfaceBinder { + private DragAndDropController mController; + + public IDragAndDropImpl(DragAndDropController controller) { + mController = controller; + } + + /** + * Invalidates this instance, preventing future calls from updating the controller. + */ + @Override + public void invalidate() { + mController = null; + } + + @Override + public boolean isReadyToHandleDrag() { + boolean[] result = new boolean[1]; + executeRemoteCallWithTaskPermission(mController, "isReadyToHandleDrag", + controller -> result[0] = controller.isReadyToHandleDrag(), + true /* blocking */ + ); + return result[0]; + } + } + + private static class PerDisplay implements HardwareRenderer.FrameDrawingCallback { final int displayId; final Context context; final WindowManager wm; final FrameLayout rootView; final DragLayout dragLayout; + // Tracks whether the window has fully drawn since it was last made visible + boolean mHasDrawn; boolean isHandlingDrag; // A count of the number of active drags in progress to ensure that we only hide the window @@ -391,5 +470,25 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange rootView = rv; dragLayout = dl; } + + private void setWindowVisibility(int visibility) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, + "Set drop target window visibility: displayId=%d visibility=%d", + displayId, visibility); + rootView.setVisibility(visibility); + if (visibility == View.VISIBLE) { + rootView.requestApplyInsets(); + if (!mHasDrawn && rootView.getViewRootImpl() != null) { + rootView.getViewRootImpl().registerRtFrameCallback(this); + } + } else { + mHasDrawn = false; + } + } + + @Override + public void onFrameDraw(long frame) { + mHasDrawn = true; + } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/IDragAndDrop.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/IDragAndDrop.aidl new file mode 100644 index 000000000000..aeb0c63fa4c5 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/IDragAndDrop.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.draganddrop; + +/** + * Interface that is exposed to remote callers to manipulate drag and drop. + */ +interface IDragAndDrop { + /** + * Returns whether the shell drop target is showing and will handle a drag/drop. + */ + boolean isReadyToHandleDrag() = 1; +} +// Last id = 1
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java index bfa63909cd47..5f54f58557d1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java @@ -42,4 +42,6 @@ public class ShellSharedConstants { public static final String KEY_EXTRA_SHELL_FLOATING_TASKS = "extra_shell_floating_tasks"; // See IDesktopMode.aidl public static final String KEY_EXTRA_SHELL_DESKTOP_MODE = "extra_shell_desktop_mode"; + // See IDragAndDrop.aidl + public static final String KEY_EXTRA_SHELL_DRAG_AND_DROP = "extra_shell_drag_and_drop"; } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java index 523cb6629d9a..54f36f61859d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java @@ -48,6 +48,7 @@ import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; @@ -71,6 +72,8 @@ public class DragAndDropControllerTest extends ShellTestCase { @Mock private ShellController mShellController; @Mock + private ShellCommandHandler mShellCommandHandler; + @Mock private DisplayController mDisplayController; @Mock private UiEventLogger mUiEventLogger; @@ -89,7 +92,8 @@ public class DragAndDropControllerTest extends ShellTestCase { public void setUp() throws RemoteException { MockitoAnnotations.initMocks(this); mController = new DragAndDropController(mContext, mShellInit, mShellController, - mDisplayController, mUiEventLogger, mIconProvider, mMainExecutor); + mShellCommandHandler, mDisplayController, mUiEventLogger, mIconProvider, + mMainExecutor); mController.onInit(); } |