diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index d269323d50a46..caab00c3863e4 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -254,6 +254,8 @@ interface IWindowSession { */ boolean startMovingTask(IWindow window, float startX, float startY); + void finishMovingTask(IWindow window); + void updatePointerIcon(IWindow window); /** diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 921294a78e5eb..85580aad7b4ee 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -25519,6 +25519,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return false; } + /** + * Finish a window move task. + * @hide + */ + public void finishMovingTask() { + if (ViewDebug.DEBUG_POSITIONING) { + Log.d(VIEW_LOG_TAG, "finishMovingTask"); + } + try { + mAttachInfo.mSession.finishMovingTask(mAttachInfo.mWindow); + } catch (RemoteException e) { + Log.e(VIEW_LOG_TAG, "Unable to finish moving", e); + } + } + /** * Handles drag events sent by the system following a call to * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) diff --git a/core/java/com/android/internal/widget/DecorCaptionView.java b/core/java/com/android/internal/widget/DecorCaptionView.java index 19b68e5c467fe..4014c454f6a8b 100644 --- a/core/java/com/android/internal/widget/DecorCaptionView.java +++ b/core/java/com/android/internal/widget/DecorCaptionView.java @@ -188,7 +188,8 @@ public class DecorCaptionView extends ViewGroup implements View.OnTouchListener, final int y = (int) e.getY(); final boolean fromMouse = e.getToolType(e.getActionIndex()) == MotionEvent.TOOL_TYPE_MOUSE; final boolean primaryButton = (e.getButtonState() & MotionEvent.BUTTON_PRIMARY) != 0; - switch (e.getActionMasked()) { + final int actionMasked = e.getActionMasked(); + switch (actionMasked) { case MotionEvent.ACTION_DOWN: if (!mShow) { // When there is no caption we should not react to anything. @@ -220,6 +221,12 @@ public class DecorCaptionView extends ViewGroup implements View.OnTouchListener, break; } // Abort the ongoing dragging. + if (actionMasked == MotionEvent.ACTION_UP) { + // If it receives ACTION_UP event, the dragging is already finished and also + // the system can not end drag on ACTION_UP event. So request to finish + // dragging. + finishMovingTask(); + } mDragging = false; return !mCheckForDragging; } diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 34273f3f23a57..ecb0941b4bd0c 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -315,6 +315,18 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { } } + @Override + public void finishMovingTask(IWindow window) { + if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM, "finishMovingTask"); + + long ident = Binder.clearCallingIdentity(); + try { + mService.mTaskPositioningController.finishTaskPositioning(window); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + @Override public void reportSystemGestureExclusionChanged(IWindow window, List exclusionRects) { long ident = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index efd3e1cbf7706..2fc64eaf8c97f 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -119,7 +119,7 @@ class TaskPositioner implements IBinder.DeathRecipient { private int mCtrlType = CTRL_NONE; @VisibleForTesting boolean mDragEnded; - private IBinder mClientCallback; + IBinder mClientCallback; InputChannel mServerChannel; InputChannel mClientChannel; diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java index 3929a122b6731..2441954012e59 100644 --- a/services/core/java/com/android/server/wm/TaskPositioningController.java +++ b/services/core/java/com/android/server/wm/TaskPositioningController.java @@ -185,6 +185,12 @@ class TaskPositioningController { return true; } + public void finishTaskPositioning(IWindow window) { + if (mTaskPositioner != null && mTaskPositioner.mClientCallback == window.asBinder()) { + finishTaskPositioning(); + } + } + void finishTaskPositioning() { mHandler.post(() -> { if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM, "finishPositioning"); 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 c9263eb805920..714d2f2f94a12 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java @@ -32,6 +32,7 @@ import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; import android.view.InputChannel; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Before; @@ -41,7 +42,7 @@ import org.junit.Test; * Tests for the {@link TaskPositioningController} class. * * Build/Install/Run: - * atest FrameworksServicesTests:TaskPositioningControllerTests + * atest WmTests:TaskPositioningControllerTests */ @SmallTest @Presubmit @@ -87,6 +88,29 @@ public class TaskPositioningControllerTests extends WindowTestsBase { assertNull(mTarget.getDragWindowHandleLocked()); } + @FlakyTest(bugId = 129507487) + @Test + public void testFinishPositioningWhenAppRequested() { + synchronized (mWm.mGlobalLock) { + assertFalse(mTarget.isPositioningLocked()); + assertNull(mTarget.getDragWindowHandleLocked()); + } + + assertTrue(mTarget.startMovingTask(mWindow.mClient, 0, 0)); + + synchronized (mWm.mGlobalLock) { + assertTrue(mTarget.isPositioningLocked()); + assertNotNull(mTarget.getDragWindowHandleLocked()); + } + + mTarget.finishTaskPositioning(mWindow.mClient); + // Wait until the looper processes finishTaskPositioning. + assertTrue(mWm.mH.runWithScissors(() -> { }, TIMEOUT_MS)); + + assertFalse(mTarget.isPositioningLocked()); + assertNull(mTarget.getDragWindowHandleLocked()); + } + @Test public void testHandleTapOutsideTask() { synchronized (mWm.mGlobalLock) {