diff options
| author | 2021-01-06 00:02:25 +0800 | |
|---|---|---|
| committer | 2021-03-17 11:01:39 +0800 | |
| commit | 3add9328d4aa120cec0579a8174842f430887780 (patch) | |
| tree | 603386bba04470d1931aa2397b93631ca1372020 | |
| parent | 235fae7fdbd5c02fc5a1b52a59a7d28b42ce6cc5 (diff) | |
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
7 files changed, 124 insertions, 88 deletions
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index cbe6e69cbef3..092502709f34 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -2606,6 +2606,11 @@ public class InputManagerService extends IInputManager.Stub } // 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. if (!UNTRUSTED_TOUCHES_TOAST || ArrayUtils.contains( @@ -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); } /** diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java index 1120a074aa8c..d12d07ab7448 100644 --- a/services/core/java/com/android/server/wm/DragDropController.java +++ b/services/core/java/com/android/server/wm/DragDropController.java @@ -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. diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 08d5e800a808..fd4bbd7b36e4 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -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"); @@ -518,71 +583,6 @@ class DragState { } /** - * 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() { diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java index 6e89581bc34a..84616c0bdc8e 100644 --- a/services/core/java/com/android/server/wm/InputManagerCallback.java +++ b/services/core/java/com/android/server/wm/InputManagerCallback.java @@ -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) { diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java index 74337c2b38ed..08404411c02b 100644 --- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java +++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java @@ -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; diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index be06d0395499..3a674c4d7ee5 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -131,6 +131,7 @@ static struct { jmethodID getDeviceAlias; jmethodID getTouchCalibrationForInputDevice; jmethodID getContextForDisplay; + jmethodID notifyDropWindow; } gServiceClassInfo; static struct { @@ -335,6 +336,7 @@ public: bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid, int32_t injectorUid) override; void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) override; void setPointerCapture(bool enabled) override; + void notifyDropWindow(const sp<IBinder>& token, float x, float y) override; /* --- PointerControllerPolicyInterface implementation --- */ @@ -905,6 +907,20 @@ void NativeInputManager::notifyFocusChanged(const sp<IBinder>& oldToken, checkAndClearExceptionFromCallback(env, "notifyFocusChanged"); } +void NativeInputManager::notifyDropWindow(const sp<IBinder>& token, float x, float y) { +#if DEBUG_INPUT_DISPATCHER_POLICY + ALOGD("notifyDropWindow"); +#endif + ATRACE_CALL(); + + JNIEnv* env = jniEnv(); + ScopedLocalFrame localFrame(env); + + jobject tokenObj = javaObjectForIBinder(env, token); + env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyDropWindow, tokenObj, x, y); + checkAndClearExceptionFromCallback(env, "notifyDropWindow"); +} + void NativeInputManager::notifySensorEvent(int32_t deviceId, InputDeviceSensorType sensorType, InputDeviceSensorAccuracy accuracy, nsecs_t timestamp, const std::vector<float>& values) { @@ -2350,6 +2366,8 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gServiceClassInfo.notifyFocusChanged, clazz, "notifyFocusChanged", "(Landroid/os/IBinder;Landroid/os/IBinder;)V"); + GET_METHOD_ID(gServiceClassInfo.notifyDropWindow, clazz, "notifyDropWindow", + "(Landroid/os/IBinder;FF)V"); GET_METHOD_ID(gServiceClassInfo.notifySensorEvent, clazz, "notifySensorEvent", "(IIIJ[F)V"); diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java index 7f9e7da99579..4e2697ab64f8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java @@ -134,6 +134,7 @@ public class DragDropControllerTests extends WindowTestsBase { null, TYPE_BASE_APPLICATION, activity, name, ownerId, false, new TestIWindow()); window.mInputChannel = new InputChannel(); window.mHasSurface = true; + mWm.mInputToWindowMap.put(window.mInputChannelToken, window); return window; } @@ -226,7 +227,7 @@ public class DragDropControllerTests extends WindowTestsBase { // Verify after consuming that the drag surface is relinquished try { mTarget.mDeferDragStateClosed = true; - + mTarget.reportDropWindow(mWindow.mInputChannelToken, 0, 0); // Verify the drop event includes the drag surface mTarget.handleMotionEvent(false, 0, 0); final DragEvent dropEvent = dragEvents.get(dragEvents.size() - 1); @@ -355,6 +356,7 @@ public class DragDropControllerTests extends WindowTestsBase { private void doDragAndDrop(int flags, ClipData data, float dropX, float dropY) { startDrag(flags, data, () -> { + mTarget.reportDropWindow(mWindow.mInputChannelToken, dropX, dropY); mTarget.handleMotionEvent(false, dropX, dropY); mToken = mWindow.mClient.asBinder(); }); |