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
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user