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

Commit a08f5313 authored by Winson Chung's avatar Winson Chung Committed by Automerger Merge Worker
Browse files

Merge "Only allow app drags to go to global intercept windows" into sc-dev am:...

Merge "Only allow app drags to go to global intercept windows" into sc-dev am: 3bf189f7 am: 29768a1c

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14527702

Change-Id: Iee5057c27613ddf78e2dfc422f8e74ba0b1c7e78
parents c99e72d0 29768a1c
Loading
Loading
Loading
Loading
+28 −5
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.server.wm;

import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;

@@ -441,8 +444,9 @@ class DragState {
            Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")");
        }

        final boolean containsAppExtras = containsApplicationExtras(mDataDescription);
        mService.mRoot.forAllWindows(w -> {
            sendDragStartedLocked(w, touchX, touchY, mDataDescription, mData);
            sendDragStartedLocked(w, touchX, touchY, containsAppExtras);
        }, false /* traverseTopToBottom */);
    }

@@ -455,9 +459,9 @@ class DragState {
     * process, so it's safe for the caller to call recycle() on the event afterwards.
     */
    private void sendDragStartedLocked(WindowState newWin, float touchX, float touchY,
            ClipDescription desc, ClipData data) {
            boolean containsAppExtras) {
        final boolean interceptsGlobalDrag = targetInterceptsGlobalDrag(newWin);
        if (mDragInProgress && isValidDropTarget(newWin, interceptsGlobalDrag)) {
        if (mDragInProgress && isValidDropTarget(newWin, containsAppExtras, interceptsGlobalDrag)) {
            DragEvent event = obtainDragEvent(DragEvent.ACTION_DRAG_STARTED, touchX, touchY,
                    interceptsGlobalDrag, false /* includeDragSurface */,
                    null /* dragAndDropPermission */);
@@ -476,10 +480,28 @@ class DragState {
        }
    }

    private boolean isValidDropTarget(WindowState targetWin, boolean interceptsGlobalDrag) {
    /**
     * Returns true if this is a drag of an application mime type.
     */
    private boolean containsApplicationExtras(ClipDescription desc) {
        if (desc == null) {
            return false;
        }
        return desc.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY)
                || desc.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT)
                || desc.hasMimeType(MIMETYPE_APPLICATION_TASK);
    }

    private boolean isValidDropTarget(WindowState targetWin, boolean containsAppExtras,
            boolean interceptsGlobalDrag) {
        if (targetWin == null) {
            return false;
        }
        if (!interceptsGlobalDrag && containsAppExtras) {
            // App-drags can only go to windows that can intercept global drag, and not to normal
            // app windows
            return false;
        }
        if (!targetWin.isPotentialDragTarget(interceptsGlobalDrag)) {
            return false;
        }
@@ -522,7 +544,8 @@ class DragState {
            if (DEBUG_DRAG) {
                Slog.d(TAG_WM, "need to send DRAG_STARTED to new window " + newWin);
            }
            sendDragStartedLocked(newWin, mCurrentX, mCurrentY, mDataDescription, mData);
            sendDragStartedLocked(newWin, mCurrentX, mCurrentY,
                    containsApplicationExtras(mDataDescription));
        }
    }

+29 −0
Original line number Diff line number Diff line
@@ -238,6 +238,35 @@ public class DragDropControllerTests extends WindowTestsBase {
                });
    }

    @Test
    public void testInterceptGlobalDragDropIgnoresOtherWindows() {
        WindowState globalInterceptWindow = createDropTargetWindow("Global drag test window", 0);
        globalInterceptWindow.mAttrs.privateFlags |= PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;

        // Necessary for now since DragState.sendDragStartedLocked() will recycle drag events
        // immediately after dispatching, which is a problem when using mockito arguments captor
        // because it returns and modifies the same drag event
        TestIWindow iwindow = (TestIWindow) mWindow.mClient;
        final ArrayList<DragEvent> dragEvents = new ArrayList<>();
        iwindow.setDragEventJournal(dragEvents);
        TestIWindow globalInterceptIWindow = (TestIWindow) globalInterceptWindow.mClient;
        final ArrayList<DragEvent> globalInterceptWindowDragEvents = new ArrayList<>();
        globalInterceptIWindow.setDragEventJournal(globalInterceptWindowDragEvents);

        startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ,
                createClipDataForActivity(null, mock(UserHandle.class)), () -> {
                    // Verify the start-drag event is sent for the intercept window but not the
                    // other window
                    assertTrue(dragEvents.isEmpty());
                    assertTrue(globalInterceptWindowDragEvents.get(0).getAction()
                            == ACTION_DRAG_STARTED);

                    mTarget.reportDropWindow(globalInterceptWindow.mInputChannelToken, 0, 0);
                    mTarget.handleMotionEvent(false, 0, 0);
                    mToken = globalInterceptWindow.mClient.asBinder();
                });
    }

    @Test
    public void testValidateAppActivityArguments() {
        final Session session = new Session(mWm, new IWindowSessionCallback.Stub() {