If application process handles motion events late, it requests to start
moving task after MotionEvent.ACTION_UP is already fired. In that case,
system will wait for event that is not comming and cannot end drag state.
It's expected that the system finishes moving task when system receives
ACTION_UP by transfering touch focus. In a problem case, ACTION_UP event
is already sent to the application process before transfering touch focus.
If application receives ACTION_UP event after requesting moving task,
notify the system of finishing previous request.
Test: Quickly try to resize freeform windowing app repeatedly.
Test: atest WmTests:TaskPositioningControllerTests
Bug:
129507487
Change-Id: Ifa457ddc55524cae6da455e770472781a7805282
(cherry picked from commit
9a1cd7b5063229da536a1281916ae15ec9246d1a)
*/
boolean startMovingTask(IWindow window, float startX, float startY);
+ void finishMovingTask(IWindow window);
+
void updatePointerIcon(IWindow window);
/**
}
/**
+ * 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)
* startDragAndDrop()}.
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.
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;
}
}
@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<Rect> exclusionRects) {
long ident = Binder.clearCallingIdentity();
try {
private int mCtrlType = CTRL_NONE;
@VisibleForTesting
boolean mDragEnded;
- private IBinder mClientCallback;
+ IBinder mClientCallback;
InputChannel mServerChannel;
InputChannel mClientChannel;
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");
import android.platform.test.annotations.Presubmit;
import android.view.InputChannel;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Before;
* Tests for the {@link TaskPositioningController} class.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:TaskPositioningControllerTests
+ * atest WmTests:TaskPositioningControllerTests
*/
@SmallTest
@Presubmit
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) {