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

Commit 3add9328 authored by arthurhung's avatar arthurhung
Browse files

Move drag event to InputDispatcher (6/n)

This CL provides a way of notifying the dropping window to
DragState. That helps DragState could dispatch the drop event to the
corresponding client of the target window by checking the pointer in
InputDispacher.

Bug: 158242495
Test: atest CrossAppDragAndDropTests DragDropTest
Test: atest WmTests:DragDropControllerTests
Change-Id: I09e213852ab53ae5ac1d3aa45b119f176ed3145a
parent 235fae7f
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -2605,6 +2605,11 @@ public class InputManagerService extends IInputManager.Stub
        mWindowManagerCallbacks.notifyFocusChanged(oldToken, newToken);
    }

    // Native callback
    private void notifyDropWindow(IBinder token, float x, float y) {
        mWindowManagerCallbacks.notifyDropWindow(token, x, y);
    }

    // Native callback
    private void notifyUntrustedTouch(String packageName) {
        // TODO(b/169067926): Remove toast after gathering feedback on dogfood.
@@ -3035,6 +3040,11 @@ public class InputManagerService extends IInputManager.Stub
         * Called when the focused window has changed.
         */
        void notifyFocusChanged(IBinder oldToken, IBinder newToken);

        /**
         * Called when the drag over window has changed.
         */
        void notifyDropWindow(IBinder token, float x, float y);
    }

    /**
+7 −5
Original line number Diff line number Diff line
@@ -283,11 +283,7 @@ class DragDropController {
                return;
            }

            if (keepHandling) {
                mDragState.notifyMoveLocked(newX, newY);
            } else {
                mDragState.notifyDropLocked(newX, newY);
            }
            mDragState.updateDragSurfaceLocked(keepHandling, newX, newY);
        }
    }

@@ -330,6 +326,12 @@ class DragDropController {
        mDragState = null;
    }

    void reportDropWindow(IBinder token, float x, float y) {
        synchronized (mService.mGlobalLock) {
            mDragState.reportDropWindowLock(token, x, y);
        }
    }

    private class DragHandler extends Handler {
        /**
         * Lock for window manager.
+79 −81
Original line number Diff line number Diff line
@@ -109,7 +109,6 @@ class DragState {
    float mCurrentX, mCurrentY;
    float mThumbOffsetX, mThumbOffsetY;
    InputInterceptor mInputInterceptor;
    WindowState mTargetWindow;
    ArrayList<WindowState> mNotifiedWindows;
    boolean mDragInProgress;
    /**
@@ -217,18 +216,18 @@ class DragState {
                    x = mCurrentX;
                    y = mCurrentY;
                }
                DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
                DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
                        x, y, mThumbOffsetX, mThumbOffsetY, null, null, null, null, null,
                        mDragResult);
                try {
                    ws.mClient.dispatchDragEvent(evt);
                    ws.mClient.dispatchDragEvent(event);
                } catch (RemoteException e) {
                    Slog.w(TAG_WM, "Unable to drag-end window " + ws);
                }
                // if the current window is in the same process,
                // the dispatch has already recycled the event
                if (myPid != ws.mSession.mPid) {
                    evt.recycle();
                    event.recycle();
                }
            }
            mNotifiedWindows.clear();
@@ -270,6 +269,68 @@ class DragState {
        mDragDropController.onDragStateClosedLocked(this);
    }

    /**
     * Notify the drop target and tells it about the data. If the drop event is not sent to the
     * target, invokes {@code endDragLocked} immediately.
     */
    void reportDropWindowLock(IBinder token, float x, float y) {
        if (mAnimator != null) {
            return;
        }

        final WindowState touchedWin = mService.mInputToWindowMap.get(token);
        if (!isWindowNotified(touchedWin)) {
            // "drop" outside a valid window -- no recipient to apply a
            // timeout to, and we can send the drag-ended message immediately.
            mDragResult = false;
            endDragLocked();
            if (DEBUG_DRAG) Slog.d(TAG_WM, "Drop outside a valid window " + touchedWin);
            return;
        }

        if (DEBUG_DRAG) Slog.d(TAG_WM, "sending DROP to " + touchedWin);

        final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid());

        final DragAndDropPermissionsHandler dragAndDropPermissions;
        if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && (mFlags & DRAG_FLAGS_URI_ACCESS) != 0
                && mData != null) {
            dragAndDropPermissions = new DragAndDropPermissionsHandler(mService.mGlobalLock,
                    mData,
                    mUid,
                    touchedWin.getOwningPackage(),
                    mFlags & DRAG_FLAGS_URI_PERMISSIONS,
                    mSourceUserId,
                    targetUserId);
        } else {
            dragAndDropPermissions = null;
        }
        if (mSourceUserId != targetUserId) {
            if (mData != null) {
                mData.fixUris(mSourceUserId);
            }
        }
        final int myPid = Process.myPid();
        final IBinder clientToken = touchedWin.mClient.asBinder();
        final DragEvent event = obtainDragEvent(DragEvent.ACTION_DROP, x, y,
                true /* includeData */, targetInterceptsGlobalDrag(touchedWin),
                dragAndDropPermissions);
        try {
            touchedWin.mClient.dispatchDragEvent(event);

            // 5 second timeout for this window to respond to the drop
            mDragDropController.sendTimeoutMessage(MSG_DRAG_END_TIMEOUT, clientToken);
        } catch (RemoteException e) {
            Slog.w(TAG_WM, "can't send drop notification to win " + touchedWin);
            endDragLocked();
        } finally {
            if (myPid != touchedWin.mSession.mPid) {
                event.recycle();
            }
        }
        mToken = clientToken;
    }

    class InputInterceptor {
        InputChannel mClientChannel;
        DragInputEventReceiver mInputEventReceiver;
@@ -397,9 +458,9 @@ class DragState {
            ClipDescription desc, ClipData data) {
        final boolean interceptsGlobalDrag = targetInterceptsGlobalDrag(newWin);
        if (mDragInProgress && isValidDropTarget(newWin, interceptsGlobalDrag)) {
            DragEvent event = obtainDragEvent(newWin, DragEvent.ACTION_DRAG_STARTED,
                    touchX, touchY, mThumbOffsetX, mThumbOffsetY, null, desc,
                    interceptsGlobalDrag ? data : null, null, null, false);
            DragEvent event = obtainDragEvent(DragEvent.ACTION_DRAG_STARTED, touchX, touchY,
                    interceptsGlobalDrag, false /* includeDragSurface */,
                    null /* dragAndDropPermission */);
            try {
                newWin.mClient.dispatchDragEvent(event);
                // track each window that we've notified that the drag is starting
@@ -501,13 +562,17 @@ class DragState {
        mAnimator = createCancelAnimationLocked();
    }

    void notifyMoveLocked(float x, float y) {
    void updateDragSurfaceLocked(boolean keepHandling, float x, float y) {
        if (mAnimator != null) {
            return;
        }
        mCurrentX = x;
        mCurrentY = y;

        if (!keepHandling) {
            return;
        }

        // Move the surface to the given touch
        if (SHOW_LIGHT_TRANSACTIONS) {
            Slog.i(TAG_WM, ">>> OPEN TRANSACTION notifyMoveLocked");
@@ -517,71 +582,6 @@ class DragState {
                (int) (x - mThumbOffsetX), (int) (y - mThumbOffsetY));
    }

    /**
     * Finds the drop target and tells it about the data. If the drop event is not sent to the
     * target, invokes {@code endDragLocked} immediately.
     */
    void notifyDropLocked(float x, float y) {
        if (mAnimator != null) {
            return;
        }
        mCurrentX = x;
        mCurrentY = y;

        final WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);

        if (!isWindowNotified(touchedWin)) {
            // "drop" outside a valid window -- no recipient to apply a
            // timeout to, and we can send the drag-ended message immediately.
            mDragResult = false;
            endDragLocked();
            return;
        }

        if (DEBUG_DRAG) Slog.d(TAG_WM, "sending DROP to " + touchedWin);

        final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid());

        final DragAndDropPermissionsHandler dragAndDropPermissions;
        if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && (mFlags & DRAG_FLAGS_URI_ACCESS) != 0
                && mData != null) {
            dragAndDropPermissions = new DragAndDropPermissionsHandler(mService.mGlobalLock,
                    mData,
                    mUid,
                    touchedWin.getOwningPackage(),
                    mFlags & DRAG_FLAGS_URI_PERMISSIONS,
                    mSourceUserId,
                    targetUserId);
        } else {
            dragAndDropPermissions = null;
        }
        if (mSourceUserId != targetUserId){
            if (mData != null) {
                mData.fixUris(mSourceUserId);
            }
        }
        final int myPid = Process.myPid();
        final IBinder token = touchedWin.mClient.asBinder();
        final DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
                mThumbOffsetX, mThumbOffsetY, null, null, mData,
                targetInterceptsGlobalDrag(touchedWin) ? mSurfaceControl : null,
                dragAndDropPermissions, false);
        try {
            touchedWin.mClient.dispatchDragEvent(evt);

            // 5 second timeout for this window to respond to the drop
            mDragDropController.sendTimeoutMessage(MSG_DRAG_END_TIMEOUT, token);
        } catch (RemoteException e) {
            Slog.w(TAG_WM, "can't send drop notification to win " + touchedWin);
            endDragLocked();
        } finally {
            if (myPid != touchedWin.mSession.mPid) {
                evt.recycle();
            }
        }
        mToken = token;
    }

    /**
     * Returns true if it has sent DRAG_STARTED broadcast out but has not been sent DRAG_END
     * broadcast.
@@ -590,14 +590,12 @@ class DragState {
        return mDragInProgress;
    }

    private static DragEvent obtainDragEvent(WindowState win, int action, float x, float y,
            float offsetX, float offsetY, Object localState, ClipDescription description,
            ClipData data, SurfaceControl dragSurface,
            IDragAndDropPermissions dragAndDropPermissions, boolean result) {
        final float winX = win.translateToWindowX(x);
        final float winY = win.translateToWindowY(y);
        return DragEvent.obtain(action, winX, winY, offsetX, offsetY, localState, description, data,
                dragSurface, dragAndDropPermissions, result);
    private DragEvent obtainDragEvent(int action, float x, float y, boolean includeData,
            boolean includeDragSurface, IDragAndDropPermissions dragAndDropPermissions) {
        return DragEvent.obtain(action, x, y, mThumbOffsetX, mThumbOffsetY,
                null  /* localState */, mDataDescription,
                includeData ? mData : null, includeDragSurface ? mSurfaceControl : null,
                dragAndDropPermissions, false /* result */);
    }

    private ValueAnimator createReturnAnimationLocked() {
+6 −0
Original line number Diff line number Diff line
@@ -229,6 +229,12 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
                mService::reportFocusChanged, oldToken, newToken));
    }

    @Override
    public void notifyDropWindow(IBinder token, float x, float y) {
        mService.mH.sendMessage(PooledLambda.obtainMessage(
                mService.mDragDropController::reportDropWindow, token, x, y));
    }

    /** Waits until the built-in input devices have been configured. */
    public boolean waitForInputDevicesReady(long timeoutMillis) {
        synchronized (mInputDevicesReadyMonitor) {
+1 −1
Original line number Diff line number Diff line
@@ -44,7 +44,7 @@ public class WindowManagerDebugConfig {
    static final boolean DEBUG_STARTING_WINDOW_VERBOSE = false;
    static final boolean DEBUG_WALLPAPER = false;
    static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
    static final boolean DEBUG_DRAG = false;
    static final boolean DEBUG_DRAG = true;
    static final boolean DEBUG_SCREENSHOT = false;
    static final boolean DEBUG_LAYOUT_REPEATS = false;
    static final boolean DEBUG_WINDOW_TRACE = false;
Loading