Loading services/core/java/com/android/server/wm/DragDropController.java +4 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.view.View.DRAG_FLAG_GLOBAL; import static android.view.View.DRAG_FLAG_GLOBAL_SAME_APPLICATION; import static android.view.View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG; import static com.android.input.flags.Flags.enablePointerChoreographer; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG; Loading Loading @@ -373,8 +374,11 @@ class DragDropController { boolean notifyUnhandledDrop(DragEvent dropEvent, String reason) { final boolean isLocalDrag = (mDragState.mFlags & (DRAG_FLAG_GLOBAL_SAME_APPLICATION | DRAG_FLAG_GLOBAL)) == 0; final boolean shouldDelegateUnhandledDrag = (mDragState.mFlags & DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG) != 0; if (!com.android.window.flags.Flags.delegateUnhandledDrags() || mGlobalDragListener == null || !shouldDelegateUnhandledDrag || isLocalDrag) { // Skip if the flag is disabled, there is no unhandled-drag listener, or if this is a // purely local drag Loading services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java +36 −10 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; Loading Loading @@ -541,7 +542,7 @@ public class DragDropControllerTests extends WindowTestsBase { } @Test public void testUnhandledDragListenerNotCalledForNormalDrags() throws RemoteException { public void testUnhandledDragNotCalledForNormalDrags() throws RemoteException { assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags()); final IGlobalDragListener listener = mock(IGlobalDragListener.class); Loading @@ -552,15 +553,16 @@ public class DragDropControllerTests extends WindowTestsBase { } @Test public void testUnhandledDragListenerReceivesUnhandledDropOverWindow() { public void testUnhandledDragReceivesUnhandledDropOverWindow() { assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags()); final IGlobalDragListener listener = mock(IGlobalDragListener.class); doReturn(mock(Binder.class)).when(listener).asBinder(); mTarget.setGlobalDragListener(listener); final int invalidXY = 100_000; startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> { // Notify the unhandled drag listener startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG, ClipData.newPlainText("label", "Test"), () -> { // Trigger an unhandled drop and verify the global drag listener was called mTarget.reportDropWindow(mWindow.mInputChannelToken, invalidXY, invalidXY); mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); mTarget.reportDropResult(mWindow.mClient, false); Loading @@ -575,15 +577,16 @@ public class DragDropControllerTests extends WindowTestsBase { } @Test public void testUnhandledDragListenerReceivesUnhandledDropOverNoValidWindow() { public void testUnhandledDragReceivesUnhandledDropOverNoValidWindow() { assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags()); final IGlobalDragListener listener = mock(IGlobalDragListener.class); doReturn(mock(Binder.class)).when(listener).asBinder(); mTarget.setGlobalDragListener(listener); final int invalidXY = 100_000; startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> { // Notify the unhandled drag listener startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG, ClipData.newPlainText("label", "Test"), () -> { // Trigger an unhandled drop and verify the global drag listener was called mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); mTarget.onUnhandledDropCallback(true); Loading @@ -597,15 +600,38 @@ public class DragDropControllerTests extends WindowTestsBase { } @Test public void testUnhandledDragListenerCallbackTimeout() { public void testUnhandledDragDoesNotReceiveUnhandledDropWithoutDragFlag() { assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags()); final IGlobalDragListener listener = mock(IGlobalDragListener.class); doReturn(mock(Binder.class)).when(listener).asBinder(); mTarget.setGlobalDragListener(listener); final int invalidXY = 100_000; startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> { // Notify the unhandled drag listener startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> { // Trigger an unhandled drop and verify the global drag listener was not called mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); mToken = null; try { verify(listener, never()).onUnhandledDrop(any(), any()); } catch (RemoteException e) { fail("Failed to verify unhandled drop: " + e); } }); } @Test public void testUnhandledDragCallbackTimeout() { assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags()); final IGlobalDragListener listener = mock(IGlobalDragListener.class); doReturn(mock(Binder.class)).when(listener).asBinder(); mTarget.setGlobalDragListener(listener); final int invalidXY = 100_000; startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG, ClipData.newPlainText("label", "Test"), () -> { // Trigger an unhandled drop and verify the global drag listener was called mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); Loading Loading
services/core/java/com/android/server/wm/DragDropController.java +4 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.view.View.DRAG_FLAG_GLOBAL; import static android.view.View.DRAG_FLAG_GLOBAL_SAME_APPLICATION; import static android.view.View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG; import static com.android.input.flags.Flags.enablePointerChoreographer; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG; Loading Loading @@ -373,8 +374,11 @@ class DragDropController { boolean notifyUnhandledDrop(DragEvent dropEvent, String reason) { final boolean isLocalDrag = (mDragState.mFlags & (DRAG_FLAG_GLOBAL_SAME_APPLICATION | DRAG_FLAG_GLOBAL)) == 0; final boolean shouldDelegateUnhandledDrag = (mDragState.mFlags & DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG) != 0; if (!com.android.window.flags.Flags.delegateUnhandledDrags() || mGlobalDragListener == null || !shouldDelegateUnhandledDrag || isLocalDrag) { // Skip if the flag is disabled, there is no unhandled-drag listener, or if this is a // purely local drag Loading
services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java +36 −10 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; Loading Loading @@ -541,7 +542,7 @@ public class DragDropControllerTests extends WindowTestsBase { } @Test public void testUnhandledDragListenerNotCalledForNormalDrags() throws RemoteException { public void testUnhandledDragNotCalledForNormalDrags() throws RemoteException { assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags()); final IGlobalDragListener listener = mock(IGlobalDragListener.class); Loading @@ -552,15 +553,16 @@ public class DragDropControllerTests extends WindowTestsBase { } @Test public void testUnhandledDragListenerReceivesUnhandledDropOverWindow() { public void testUnhandledDragReceivesUnhandledDropOverWindow() { assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags()); final IGlobalDragListener listener = mock(IGlobalDragListener.class); doReturn(mock(Binder.class)).when(listener).asBinder(); mTarget.setGlobalDragListener(listener); final int invalidXY = 100_000; startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> { // Notify the unhandled drag listener startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG, ClipData.newPlainText("label", "Test"), () -> { // Trigger an unhandled drop and verify the global drag listener was called mTarget.reportDropWindow(mWindow.mInputChannelToken, invalidXY, invalidXY); mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); mTarget.reportDropResult(mWindow.mClient, false); Loading @@ -575,15 +577,16 @@ public class DragDropControllerTests extends WindowTestsBase { } @Test public void testUnhandledDragListenerReceivesUnhandledDropOverNoValidWindow() { public void testUnhandledDragReceivesUnhandledDropOverNoValidWindow() { assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags()); final IGlobalDragListener listener = mock(IGlobalDragListener.class); doReturn(mock(Binder.class)).when(listener).asBinder(); mTarget.setGlobalDragListener(listener); final int invalidXY = 100_000; startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> { // Notify the unhandled drag listener startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG, ClipData.newPlainText("label", "Test"), () -> { // Trigger an unhandled drop and verify the global drag listener was called mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); mTarget.onUnhandledDropCallback(true); Loading @@ -597,15 +600,38 @@ public class DragDropControllerTests extends WindowTestsBase { } @Test public void testUnhandledDragListenerCallbackTimeout() { public void testUnhandledDragDoesNotReceiveUnhandledDropWithoutDragFlag() { assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags()); final IGlobalDragListener listener = mock(IGlobalDragListener.class); doReturn(mock(Binder.class)).when(listener).asBinder(); mTarget.setGlobalDragListener(listener); final int invalidXY = 100_000; startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> { // Notify the unhandled drag listener startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> { // Trigger an unhandled drop and verify the global drag listener was not called mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); mToken = null; try { verify(listener, never()).onUnhandledDrop(any(), any()); } catch (RemoteException e) { fail("Failed to verify unhandled drop: " + e); } }); } @Test public void testUnhandledDragCallbackTimeout() { assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags()); final IGlobalDragListener listener = mock(IGlobalDragListener.class); doReturn(mock(Binder.class)).when(listener).asBinder(); mTarget.setGlobalDragListener(listener); final int invalidXY = 100_000; startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG, ClipData.newPlainText("label", "Test"), () -> { // Trigger an unhandled drop and verify the global drag listener was called mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); Loading