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

Commit fd59573a authored by Winson Chung's avatar Winson Chung
Browse files

Only allow app drags to go to global intercept windows

- Normal app windows shouldn't participate app drags so they should
  be ignored

Bug: 178690347
Test: atest DragDropControllerTests
Change-Id: I086831af1b4d26cb28580df357f2287492e2f0d8
parent 9b14a508
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() {