From c499ad377591bdca3956ae33e7ea10f6aa38b1b4 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Thu, 5 Sep 2019 15:51:14 +0800 Subject: [PATCH 1/4] Revert "Fix drag and drop (1/3)" This reverts commit 59f532efad5562822fc36b44f37046abe1cb9e14. Bug: 137819199 Test: manual Change-Id: If5e8856aad74b6f232fff9d5fd746f56d63288eb --- core/java/android/view/SurfaceControl.java | 19 +------------------ core/jni/android_view_SurfaceControl.cpp | 11 ----------- .../android/server/wm/StubTransaction.java | 5 ----- 3 files changed, 1 insertion(+), 34 deletions(-) diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index d5559aaa71467..6639fbf9551e5 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -187,8 +187,7 @@ public final class SurfaceControl implements Parcelable { private static native void nativeSetInputWindowInfo(long transactionObj, long nativeObject, InputWindowHandle handle); - private static native void nativeTransferTouchFocus(long transactionObj, IBinder fromToken, - IBinder toToken); + private static native boolean nativeGetProtectedContentSupport(); private static native void nativeSetMetadata(long transactionObj, long nativeObject, int key, Parcel data); @@ -2238,22 +2237,6 @@ public final class SurfaceControl implements Parcelable { return this; } - /** - * Transfers touch focus from one window to another. It is possible for multiple windows to - * have touch focus if they support split touch dispatch - * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this - * method only transfers touch focus of the specified window without affecting - * other windows that may also have touch focus at the same time. - * @param fromToken The token of a window that currently has touch focus. - * @param toToken The token of the window that should receive touch focus in - * place of the first. - * @hide - */ - public Transaction transferTouchFocus(IBinder fromToken, IBinder toToken) { - nativeTransferTouchFocus(mNativeObject, fromToken, toToken); - return this; - } - /** * Waits until any changes to input windows have been sent from SurfaceFlinger to * InputFlinger before returning. diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index bf0f10eb50c6b..1ca9383b920f6 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -458,15 +458,6 @@ static void nativeSetInputWindowInfo(JNIEnv* env, jclass clazz, jlong transactio transaction->setInputWindowInfo(ctrl, *handle->getInfo()); } -static void nativeTransferTouchFocus(JNIEnv* env, jclass clazz, jlong transactionObj, - jobject fromTokenObj, jobject toTokenObj) { - auto transaction = reinterpret_cast(transactionObj); - - sp fromToken(ibinderForJavaObject(env, fromTokenObj)); - sp toToken(ibinderForJavaObject(env, toTokenObj)); - transaction->transferTouchFocus(fromToken, toToken); -} - static void nativeSyncInputWindows(JNIEnv* env, jclass clazz, jlong transactionObj) { auto transaction = reinterpret_cast(transactionObj); transaction->syncInputWindows(); @@ -1381,8 +1372,6 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeCaptureLayers }, {"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V", (void*)nativeSetInputWindowInfo }, - {"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;)V", - (void*)nativeTransferTouchFocus }, {"nativeSetMetadata", "(JJILandroid/os/Parcel;)V", (void*)nativeSetMetadata }, {"nativeGetDisplayedContentSamplingAttributes", diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java index 8d2a79b6b5db9..2ad40f2dc5776 100644 --- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java +++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java @@ -96,11 +96,6 @@ public class StubTransaction extends SurfaceControl.Transaction { return this; } - @Override - public SurfaceControl.Transaction transferTouchFocus(IBinder fromToken, IBinder toToken) { - return this; - } - @Override public SurfaceControl.Transaction setGeometry(SurfaceControl sc, Rect sourceCrop, Rect destFrame, @Surface.Rotation int orientation) { From 438fb283e6b2b6c1d42597f1a65eab605800e36d Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Wed, 28 Aug 2019 16:21:29 +0800 Subject: [PATCH 2/4] Revert "Fix drag and drop (2/3)" This reverts commit b5e316c3e43aaeca1a83be46eb4fde0be2e7d7d6. Bug: 137819199 Test: manual Change-Id: I31e60725035d5af06884521499aed9fc07e505c9 --- .../core/java/com/android/server/wm/DragState.java | 6 ++---- .../server/wm/TaskPositioningController.java | 13 +++++++------ .../android/server/wm/WindowManagerInternal.java | 3 +-- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 17daabfe3e797..58e002ce0a28a 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -129,7 +129,6 @@ class DragState { * {@code true} when {@link #closeLocked()} is called. */ private boolean mIsClosing; - IBinder mTransferTouchFromToken; DragState(WindowManagerService service, DragDropController controller, IBinder token, SurfaceControl surface, int flags, IBinder localWin) { @@ -167,10 +166,9 @@ class DragState { mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y); mTransaction.setWindowCrop(mInputSurface, mTmpClipRect); - mTransaction.transferTouchFocus(mTransferTouchFromToken, h.token); - mTransferTouchFromToken = null; - // syncInputWindows here to ensure the input channel isn't removed before the transfer. + // syncInputWindows here to ensure the input window info is sent before the + // transferTouchFocus is called. mTransaction.syncInputWindows(); mTransaction.apply(); } diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java index 2441954012e59..56b3bba2a4311 100644 --- a/services/core/java/com/android/server/wm/TaskPositioningController.java +++ b/services/core/java/com/android/server/wm/TaskPositioningController.java @@ -24,7 +24,6 @@ import android.app.IActivityTaskManager; import android.graphics.Point; import android.graphics.Rect; import android.os.Handler; -import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.util.Slog; @@ -51,7 +50,6 @@ class TaskPositioningController { private @Nullable TaskPositioner mTaskPositioner; private final Rect mTmpClipRect = new Rect(); - private IBinder mTransferTouchFromToken; boolean isPositioningLocked() { return mTaskPositioner != null; @@ -104,8 +102,6 @@ class TaskPositioningController { mTmpClipRect.set(0, 0, p.x, p.y); t.setWindowCrop(mInputSurface, mTmpClipRect); - t.transferTouchFocus(mTransferTouchFromToken, h.token); - mTransferTouchFromToken = null; } boolean startMovingTask(IWindow window, float startX, float startY) { @@ -168,6 +164,7 @@ class TaskPositioningController { mPositioningDisplay = displayContent; mTaskPositioner = TaskPositioner.create(mService); + mTaskPositioner.register(displayContent); // We need to grab the touch focus so that the touch events during the // resizing/scrolling are not sent to the app. 'win' is the main window @@ -178,8 +175,12 @@ class TaskPositioningController { && displayContent.mCurrentFocus.mAppToken == win.mAppToken) { transferFocusFromWin = displayContent.mCurrentFocus; } - mTransferTouchFromToken = transferFocusFromWin.mInputChannel.getToken(); - mTaskPositioner.register(displayContent); + if (!mInputManager.transferTouchFocus( + transferFocusFromWin.mInputChannel, mTaskPositioner.mServerChannel)) { + Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus"); + cleanUpTaskPositioner(); + return false; + } mTaskPositioner.startDrag(win, resize, preserveOrientation, startX, startY); return true; diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index 750926f11180a..b9935e05d7e17 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -160,9 +160,8 @@ public abstract class WindowManagerInternal { default boolean registerInputChannel( DragState state, Display display, InputManagerService service, InputChannel source) { - state.mTransferTouchFromToken = source.getToken(); state.register(display); - return true; + return service.transferTouchFocus(source, state.getInputChannel()); } /** From fd9d94d8e3f31654d70effffa24f7ece52a5112f Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Wed, 28 Aug 2019 16:06:07 +0800 Subject: [PATCH 3/4] Revert "Fix drag and drop (3/3)" This reverts commit 6262f22411091d79e49b39dd8a579ba157236194. Bug: 137819199 Test: manual Change-Id: I10800ff8f76fa68b9a93c935d14c5ade68504917 --- .../server/input/InputManagerService.java | 25 +++++++++++++++++++ ...droid_server_input_InputManagerService.cpp | 23 +++++++++++++++++ .../server/wm/DragDropControllerTests.java | 4 +++ .../wm/TaskPositioningControllerTests.java | 5 ++++ 4 files changed, 57 insertions(+) diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 75b9705e10457..8fbad4c5910bd 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -220,6 +220,8 @@ public class InputManagerService extends IInputManager.Stub private static native void nativeSetFocusedApplication(long ptr, int displayId, InputApplicationHandle application); private static native void nativeSetFocusedDisplay(long ptr, int displayId); + private static native boolean nativeTransferTouchFocus(long ptr, + InputChannel fromChannel, InputChannel toChannel); private static native void nativeSetPointerSpeed(long ptr, int speed); private static native void nativeSetShowTouches(long ptr, boolean enabled); private static native void nativeSetInteractive(long ptr, boolean interactive); @@ -1533,6 +1535,29 @@ public class InputManagerService extends IInputManager.Stub nativeSetSystemUiVisibility(mPtr, visibility); } + /** + * Atomically transfers touch focus from one window to another as identified by + * their input channels. It is possible for multiple windows to have + * touch focus if they support split touch dispatch + * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this + * method only transfers touch focus of the specified window without affecting + * other windows that may also have touch focus at the same time. + * @param fromChannel The channel of a window that currently has touch focus. + * @param toChannel The channel of the window that should receive touch focus in + * place of the first. + * @return True if the transfer was successful. False if the window with the + * specified channel did not actually have touch focus at the time of the request. + */ + public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) { + if (fromChannel == null) { + throw new IllegalArgumentException("fromChannel must not be null."); + } + if (toChannel == null) { + throw new IllegalArgumentException("toChannel must not be null."); + } + return nativeTransferTouchFocus(mPtr, fromChannel, toChannel); + } + @Override // Binder call public void tryPointerSpeed(int speed) { if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED, diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 03f475582a5a9..80bddcdbfa0c4 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -1575,6 +1575,27 @@ static void nativeSetSystemUiVisibility(JNIEnv* /* env */, im->setSystemUiVisibility(visibility); } +static jboolean nativeTransferTouchFocus(JNIEnv* env, + jclass /* clazz */, jlong ptr, jobject fromChannelObj, jobject toChannelObj) { + NativeInputManager* im = reinterpret_cast(ptr); + + sp fromChannel = + android_view_InputChannel_getInputChannel(env, fromChannelObj); + sp toChannel = + android_view_InputChannel_getInputChannel(env, toChannelObj); + + if (fromChannel == nullptr || toChannel == nullptr) { + return JNI_FALSE; + } + + if (im->getInputManager()->getDispatcher()-> + transferTouchFocus(fromChannel->getToken(), toChannel->getToken())) { + return JNI_TRUE; + } else { + return JNI_FALSE; + } +} + static void nativeSetPointerSpeed(JNIEnv* /* env */, jclass /* clazz */, jlong ptr, jint speed) { NativeInputManager* im = reinterpret_cast(ptr); @@ -1775,6 +1796,8 @@ static const JNINativeMethod gInputManagerMethods[] = { (void*) nativeSetInputDispatchMode }, { "nativeSetSystemUiVisibility", "(JI)V", (void*) nativeSetSystemUiVisibility }, + { "nativeTransferTouchFocus", "(JLandroid/view/InputChannel;Landroid/view/InputChannel;)Z", + (void*) nativeTransferTouchFocus }, { "nativeSetPointerSpeed", "(JI)V", (void*) nativeSetPointerSpeed }, { "nativeSetShowTouches", "(JZ)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 0110e94eb1cd1..bb80e5e4ddde6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java @@ -20,9 +20,11 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -124,6 +126,7 @@ public class DragDropControllerTests extends WindowTestsBase { mDisplayContent = spy(mDisplayContent); mWindow = createDropTargetWindow("Drag test window", 0); doReturn(mWindow).when(mDisplayContent).getTouchableWinAtPointLocked(0, 0); + when(mWm.mInputManager.transferTouchFocus(any(), any())).thenReturn(true); synchronized (mWm.mGlobalLock) { mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow); @@ -177,6 +180,7 @@ public class DragDropControllerTests extends WindowTestsBase { .setFormat(PixelFormat.TRANSLUCENT) .build(); + assertTrue(mWm.mInputManager.transferTouchFocus(null, null)); mToken = mTarget.performDrag( new SurfaceSession(), 0, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0, data); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java index 714d2f2f94a12..eb351b63a469a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; @@ -57,6 +58,10 @@ public class TaskPositioningControllerTests extends WindowTestsBase { assertNotNull(mWm.mTaskPositioningController); mTarget = mWm.mTaskPositioningController; + when(mWm.mInputManager.transferTouchFocus( + any(InputChannel.class), + any(InputChannel.class))).thenReturn(true); + mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window"); mWindow.mInputChannel = new InputChannel(); synchronized (mWm.mGlobalLock) { From b62e500e63e60463adb7b35f7543fd8c82273026 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Thu, 29 Aug 2019 12:28:07 +0800 Subject: [PATCH 4/4] Fix drag surface would be stuck (1/2) - If a window is removing, and perform drag-drop at same time, transferTouchFocus would fail because the window can't be found in the inputflinger. - If there is no touch down on the drag window, it should not allow to drag. - If perform drag successful, and a touch up sent out at same time, the transferTouchFocus might fail because there is no touch state for the calling window. This patch would add syncInputTransactions to ensure input windows information has been propagated to native InputManager. So transferTouchFocus can base on current input windows information to check if it should allow the drag-drop. Also use the same transaction to control drag surface to prevent wrong order cause surface can't be dismissed. Bug: 137819199 Test: atest WmTests:TaskPositioningControllerTests Test: atest DragDropTest Change-Id: I382bc1fb04e1f4469df2c512f9e0f2542bbd2390 --- .../core/java/com/android/server/wm/DragDropController.java | 5 ++--- services/core/java/com/android/server/wm/DragState.java | 4 ++-- services/core/java/com/android/server/wm/TaskPositioner.java | 4 +++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java index f8f6334b04dc5..d5f403f856212 100644 --- a/services/core/java/com/android/server/wm/DragDropController.java +++ b/services/core/java/com/android/server/wm/DragDropController.java @@ -113,7 +113,7 @@ class DragDropController { final WindowState callingWin = mService.windowForClientLocked( null, window, false); - if (callingWin == null) { + if (callingWin == null || callingWin.cantReceiveTouchInput()) { Slog.w(TAG_WM, "Bad requesting window " + window); return null; // !!! TODO: throw here? } @@ -167,8 +167,7 @@ class DragDropController { final SurfaceControl surfaceControl = mDragState.mSurfaceControl; if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> OPEN TRANSACTION performDrag"); - final SurfaceControl.Transaction transaction = - callingWin.getPendingTransaction(); + final SurfaceControl.Transaction transaction = mDragState.mTransaction; transaction.setAlpha(surfaceControl, mDragState.mOriginalAlpha); transaction.setPosition( surfaceControl, touchX - thumbCenterX, touchY - thumbCenterY); diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 58e002ce0a28a..3c616945f7629 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -120,7 +120,7 @@ class DragState { // A surface used to catch input events for the drag-and-drop operation. SurfaceControl mInputSurface; - private final SurfaceControl.Transaction mTransaction; + final SurfaceControl.Transaction mTransaction; private final Rect mTmpClipRect = new Rect(); @@ -170,7 +170,7 @@ class DragState { // syncInputWindows here to ensure the input window info is sent before the // transferTouchFocus is called. mTransaction.syncInputWindows(); - mTransaction.apply(); + mTransaction.apply(true); } /** diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index 8b0b6ce8ce32a..7b02009ab1ba3 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -50,6 +50,7 @@ import android.view.InputDevice; import android.view.InputEvent; import android.view.InputWindowHandle; import android.view.MotionEvent; +import android.view.SurfaceControl; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; @@ -307,7 +308,8 @@ class TaskPositioner implements IBinder.DeathRecipient { mDisplayContent.getDisplayRotation().pause(); // Notify InputMonitor to take mDragWindowHandle. - mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/); + mDisplayContent.getInputMonitor().updateInputWindowsImmediately(); + new SurfaceControl.Transaction().syncInputWindows().apply(true); mSideMargin = dipToPixel(SIDE_MARGIN_DIP, mDisplayMetrics); mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics);