Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +6 −0 Original line number Original line Diff line number Diff line Loading @@ -156,6 +156,7 @@ import com.android.wm.shell.windowdecor.common.WindowDecorationGestureExclusionT import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost; import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost; import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier; import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier; import com.android.wm.shell.windowdecor.extension.InsetsStateKt; import com.android.wm.shell.windowdecor.extension.InsetsStateKt; import com.android.wm.shell.windowdecor.extension.MotionEventKt; import com.android.wm.shell.windowdecor.extension.TaskInfoKt; import com.android.wm.shell.windowdecor.extension.TaskInfoKt; import com.android.wm.shell.windowdecor.tiling.DesktopTilingDecorViewModel; import com.android.wm.shell.windowdecor.tiling.DesktopTilingDecorViewModel; import com.android.wm.shell.windowdecor.tiling.SnapEventHandler; import com.android.wm.shell.windowdecor.tiling.SnapEventHandler; Loading Loading @@ -1197,6 +1198,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, && id != R.id.maximize_window && id != R.id.minimize_window) { && id != R.id.maximize_window && id != R.id.minimize_window) { return false; return false; } } if (MotionEventKt.isTouchpadGesture(e)) { // Touchpad finger gestures are ignored. return false; } final boolean isAppHandle = !taskInfo.isFreeform(); final boolean isAppHandle = !taskInfo.isFreeform(); final int actionMasked = e.getActionMasked(); final int actionMasked = e.getActionMasked(); final boolean isDown = actionMasked == MotionEvent.ACTION_DOWN; final boolean isDown = actionMasked == MotionEvent.ACTION_DOWN; Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -34,6 +34,8 @@ import android.view.View; import androidx.annotation.Nullable; import androidx.annotation.Nullable; import com.android.wm.shell.windowdecor.extension.MotionEventKt; /** /** * A detector for touch inputs that differentiates between drag and click inputs. It receives a flow * A detector for touch inputs that differentiates between drag and click inputs. It receives a flow * of {@link MotionEvent} and generates a new flow of motion events with slop in consideration to * of {@link MotionEvent} and generates a new flow of motion events with slop in consideration to Loading Loading @@ -90,6 +92,11 @@ public class DragDetector { * {@link #mEventHandler} handles the previous down event if the event shouldn't be passed * {@link #mEventHandler} handles the previous down event if the event shouldn't be passed */ */ public boolean onMotionEvent(View v, MotionEvent ev) { public boolean onMotionEvent(View v, MotionEvent ev) { if (MotionEventKt.isTouchpadGesture(ev)) { // Touchpad finger gestures are ignored. return false; } final boolean isTouchScreen = final boolean isTouchScreen = (ev.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN; (ev.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN; if (!isTouchScreen) { if (!isTouchScreen) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/extension/MotionEvent.kt 0 → 100644 +32 −0 Original line number Original line Diff line number Diff line /* * Copyright 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.windowdecor.extension import android.view.InputDevice import android.view.MotionEvent /** * Checks if the [MotionEvent] is a part of a synthesized touchpad gesture. * * @return true if the [MotionEvent] is a touchpad gesture, false otherwise. */ fun MotionEvent.isTouchpadGesture(): Boolean = source == InputDevice.SOURCE_MOUSE && getToolType(0) == MotionEvent.TOOL_TYPE_FINGER && (classification == MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE || classification == MotionEvent.CLASSIFICATION_PINCH || classification == MotionEvent.CLASSIFICATION_MULTI_FINGER_SWIPE) libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +86 −0 Original line number Original line Diff line number Diff line Loading @@ -45,6 +45,7 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.testing.TestableLooper.RunWithLooper import android.view.Display.DEFAULT_DISPLAY import android.view.Display.DEFAULT_DISPLAY import android.view.ISystemGestureExclusionListener import android.view.ISystemGestureExclusionListener import android.view.InputDevice import android.view.InsetsSource import android.view.InsetsSource import android.view.InsetsState import android.view.InsetsState import android.view.KeyEvent import android.view.KeyEvent Loading @@ -67,6 +68,7 @@ import com.android.wm.shell.desktopmode.DesktopImmersiveController import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason import com.android.wm.shell.desktopmode.DesktopTasksController import com.android.wm.shell.desktopmode.DesktopTasksController import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction Loading Loading @@ -1085,6 +1087,54 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest assertThat(hierarchyOp.container).isEqualTo(decor.mTaskInfo.token.asBinder()) assertThat(hierarchyOp.container).isEqualTo(decor.mTaskInfo.token.asBinder()) } } @Test fun testOnTouchWithClassification_doesNothing() { val onClickListenerCaptor = argumentCaptor<View.OnClickListener>() val onTouchListenerCaptor = argumentCaptor<View.OnTouchListener>() val decor = createOpenTaskDecoration( windowingMode = WINDOWING_MODE_FREEFORM, onCaptionButtonClickListener = onClickListenerCaptor, onCaptionButtonTouchListener = onTouchListenerCaptor, ) val view = mock<View> { on { id } doReturn R.id.desktop_mode_caption } val onTouchListener = onTouchListenerCaptor.firstValue assertFalse( onTouchListener.onTouch( view, createMotionEvent( MotionEvent.ACTION_DOWN, x = 0f, y = 0f, source = InputDevice.SOURCE_MOUSE, classification = MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE ) ) ) verify(mockDesktopTasksController, never()).moveTaskToFront( anyOrNull<RunningTaskInfo>(), anyOrNull(), anyOrNull<UnminimizeReason>(), ) assertFalse( onTouchListener.onTouch( view, createMotionEvent( MotionEvent.ACTION_UP, x = 0f, y = 0f, source = InputDevice.SOURCE_MOUSE, classification = MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE ) ) ) } @Test @Test @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) fun testImmersiveRestoreButtonClick_exitsImmersiveMode() { fun testImmersiveRestoreButtonClick_exitsImmersiveMode() { Loading Loading @@ -1628,6 +1678,42 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest ) ) } } private fun createMotionEvent( action: Int, x: Float = 0f, y: Float = 0f, source: Int = InputDevice.SOURCE_TOUCHSCREEN, classification: Int = MotionEvent.CLASSIFICATION_NONE, ): MotionEvent { val pointerProperties = arrayOf(MotionEvent.PointerProperties().apply { this.id = 0 this.toolType = MotionEvent.TOOL_TYPE_FINGER }) val pointerCoords = arrayOf(MotionEvent.PointerCoords().apply { this.x = x this.y = y }) val ev = MotionEvent.obtain( /* downTime= */ SystemClock.uptimeMillis(), /* eventTime= */ SystemClock.uptimeMillis(), action, /* pointerCount= */ 1, pointerProperties, pointerCoords, /* metaState= */ 0, /* buttonState= */ 0, /* xPrecision= */ 0f, /* yPrecision= */ 0f, /* deviceId= */ 0, /* edgeFlags= */ 0, source, /* displayId= */ 0, /* flags= */ 0, classification, )!! return ev } private companion object { private companion object { const val SECOND_DISPLAY = 2 const val SECOND_DISPLAY = 2 private val BOUNDS_AFTER_FIRST_MOVE = Rect(10, 10, 110, 110) private val BOUNDS_AFTER_FIRST_MOVE = Rect(10, 10, 110, 110) Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt +57 −6 Original line number Original line Diff line number Diff line Loading @@ -18,8 +18,8 @@ package com.android.wm.shell.windowdecor import android.os.SystemClock import android.os.SystemClock import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner import android.view.MotionEvent import android.view.InputDevice import android.view.InputDevice import android.view.MotionEvent import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest import com.android.wm.shell.ShellTestCase import com.android.wm.shell.ShellTestCase import org.junit.After import org.junit.After Loading @@ -29,12 +29,12 @@ import org.junit.Before import org.junit.Test import org.junit.Test import org.junit.runner.RunWith import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mock import org.mockito.MockitoAnnotations import org.mockito.Mockito.`when` import org.mockito.Mockito.any import org.mockito.Mockito.any import org.mockito.Mockito.argThat import org.mockito.Mockito.argThat import org.mockito.Mockito.never import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations import org.mockito.kotlin.times import org.mockito.kotlin.times /** /** Loading Loading @@ -467,16 +467,67 @@ class DragDetectorTest : ShellTestCase() { .handleMotionEvent(any(), argThat { ev -> ev.action == MotionEvent.ACTION_MOVE }) .handleMotionEvent(any(), argThat { ev -> ev.action == MotionEvent.ACTION_MOVE }) } } @Test fun testEventWithMotionClassification_doesNothing() { val dragDetector = createDragDetector() assertFalse( dragDetector.onMotionEvent( createMotionEvent( MotionEvent.ACTION_DOWN, isTouch = false, classification = MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE ) ) ) verify(eventHandler, never()).handleMotionEvent(any(), any()) assertFalse( dragDetector.onMotionEvent( createMotionEvent( MotionEvent.ACTION_UP, isTouch = false, classification = MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE ) ) ) verify(eventHandler, never()).handleMotionEvent(any(), any()) } private fun createMotionEvent( private fun createMotionEvent( action: Int, action: Int, x: Float = X, x: Float = X, y: Float = Y, y: Float = Y, isTouch: Boolean = true, isTouch: Boolean = true, downTime: Long = SystemClock.uptimeMillis(), downTime: Long = SystemClock.uptimeMillis(), eventTime: Long = SystemClock.uptimeMillis() eventTime: Long = SystemClock.uptimeMillis(), classification: Int = MotionEvent.CLASSIFICATION_NONE, ): MotionEvent { ): MotionEvent { val ev = MotionEvent.obtain(downTime, eventTime, action, x, y, 0) val pointerProperties = arrayOf(MotionEvent.PointerProperties().apply { ev.source = if (isTouch) InputDevice.SOURCE_TOUCHSCREEN else InputDevice.SOURCE_MOUSE this.id = 0 this.toolType = MotionEvent.TOOL_TYPE_FINGER }) val pointerCoords = arrayOf(MotionEvent.PointerCoords().apply { this.x = x this.y = y }) val ev = MotionEvent.obtain( downTime, eventTime, action, /* pointerCount= */ 1, pointerProperties, pointerCoords, /* metaState= */ 0, /* buttonState= */ 0, /* xPrecision= */ 0f, /* yPrecision= */ 0f, /* deviceId= */ 0, /* edgeFlags= */ 0, if (isTouch) InputDevice.SOURCE_TOUCHSCREEN else InputDevice.SOURCE_MOUSE, /* displayId= */ 0, /* flags= */ 0, classification, )!! motionEvents.add(ev) motionEvents.add(ev) return ev return ev } } Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +6 −0 Original line number Original line Diff line number Diff line Loading @@ -156,6 +156,7 @@ import com.android.wm.shell.windowdecor.common.WindowDecorationGestureExclusionT import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost; import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost; import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier; import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier; import com.android.wm.shell.windowdecor.extension.InsetsStateKt; import com.android.wm.shell.windowdecor.extension.InsetsStateKt; import com.android.wm.shell.windowdecor.extension.MotionEventKt; import com.android.wm.shell.windowdecor.extension.TaskInfoKt; import com.android.wm.shell.windowdecor.extension.TaskInfoKt; import com.android.wm.shell.windowdecor.tiling.DesktopTilingDecorViewModel; import com.android.wm.shell.windowdecor.tiling.DesktopTilingDecorViewModel; import com.android.wm.shell.windowdecor.tiling.SnapEventHandler; import com.android.wm.shell.windowdecor.tiling.SnapEventHandler; Loading Loading @@ -1197,6 +1198,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, && id != R.id.maximize_window && id != R.id.minimize_window) { && id != R.id.maximize_window && id != R.id.minimize_window) { return false; return false; } } if (MotionEventKt.isTouchpadGesture(e)) { // Touchpad finger gestures are ignored. return false; } final boolean isAppHandle = !taskInfo.isFreeform(); final boolean isAppHandle = !taskInfo.isFreeform(); final int actionMasked = e.getActionMasked(); final int actionMasked = e.getActionMasked(); final boolean isDown = actionMasked == MotionEvent.ACTION_DOWN; final boolean isDown = actionMasked == MotionEvent.ACTION_DOWN; Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -34,6 +34,8 @@ import android.view.View; import androidx.annotation.Nullable; import androidx.annotation.Nullable; import com.android.wm.shell.windowdecor.extension.MotionEventKt; /** /** * A detector for touch inputs that differentiates between drag and click inputs. It receives a flow * A detector for touch inputs that differentiates between drag and click inputs. It receives a flow * of {@link MotionEvent} and generates a new flow of motion events with slop in consideration to * of {@link MotionEvent} and generates a new flow of motion events with slop in consideration to Loading Loading @@ -90,6 +92,11 @@ public class DragDetector { * {@link #mEventHandler} handles the previous down event if the event shouldn't be passed * {@link #mEventHandler} handles the previous down event if the event shouldn't be passed */ */ public boolean onMotionEvent(View v, MotionEvent ev) { public boolean onMotionEvent(View v, MotionEvent ev) { if (MotionEventKt.isTouchpadGesture(ev)) { // Touchpad finger gestures are ignored. return false; } final boolean isTouchScreen = final boolean isTouchScreen = (ev.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN; (ev.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN; if (!isTouchScreen) { if (!isTouchScreen) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/extension/MotionEvent.kt 0 → 100644 +32 −0 Original line number Original line Diff line number Diff line /* * Copyright 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.windowdecor.extension import android.view.InputDevice import android.view.MotionEvent /** * Checks if the [MotionEvent] is a part of a synthesized touchpad gesture. * * @return true if the [MotionEvent] is a touchpad gesture, false otherwise. */ fun MotionEvent.isTouchpadGesture(): Boolean = source == InputDevice.SOURCE_MOUSE && getToolType(0) == MotionEvent.TOOL_TYPE_FINGER && (classification == MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE || classification == MotionEvent.CLASSIFICATION_PINCH || classification == MotionEvent.CLASSIFICATION_MULTI_FINGER_SWIPE)
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +86 −0 Original line number Original line Diff line number Diff line Loading @@ -45,6 +45,7 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.testing.TestableLooper.RunWithLooper import android.view.Display.DEFAULT_DISPLAY import android.view.Display.DEFAULT_DISPLAY import android.view.ISystemGestureExclusionListener import android.view.ISystemGestureExclusionListener import android.view.InputDevice import android.view.InsetsSource import android.view.InsetsSource import android.view.InsetsState import android.view.InsetsState import android.view.KeyEvent import android.view.KeyEvent Loading @@ -67,6 +68,7 @@ import com.android.wm.shell.desktopmode.DesktopImmersiveController import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason import com.android.wm.shell.desktopmode.DesktopTasksController import com.android.wm.shell.desktopmode.DesktopTasksController import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction Loading Loading @@ -1085,6 +1087,54 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest assertThat(hierarchyOp.container).isEqualTo(decor.mTaskInfo.token.asBinder()) assertThat(hierarchyOp.container).isEqualTo(decor.mTaskInfo.token.asBinder()) } } @Test fun testOnTouchWithClassification_doesNothing() { val onClickListenerCaptor = argumentCaptor<View.OnClickListener>() val onTouchListenerCaptor = argumentCaptor<View.OnTouchListener>() val decor = createOpenTaskDecoration( windowingMode = WINDOWING_MODE_FREEFORM, onCaptionButtonClickListener = onClickListenerCaptor, onCaptionButtonTouchListener = onTouchListenerCaptor, ) val view = mock<View> { on { id } doReturn R.id.desktop_mode_caption } val onTouchListener = onTouchListenerCaptor.firstValue assertFalse( onTouchListener.onTouch( view, createMotionEvent( MotionEvent.ACTION_DOWN, x = 0f, y = 0f, source = InputDevice.SOURCE_MOUSE, classification = MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE ) ) ) verify(mockDesktopTasksController, never()).moveTaskToFront( anyOrNull<RunningTaskInfo>(), anyOrNull(), anyOrNull<UnminimizeReason>(), ) assertFalse( onTouchListener.onTouch( view, createMotionEvent( MotionEvent.ACTION_UP, x = 0f, y = 0f, source = InputDevice.SOURCE_MOUSE, classification = MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE ) ) ) } @Test @Test @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) fun testImmersiveRestoreButtonClick_exitsImmersiveMode() { fun testImmersiveRestoreButtonClick_exitsImmersiveMode() { Loading Loading @@ -1628,6 +1678,42 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest ) ) } } private fun createMotionEvent( action: Int, x: Float = 0f, y: Float = 0f, source: Int = InputDevice.SOURCE_TOUCHSCREEN, classification: Int = MotionEvent.CLASSIFICATION_NONE, ): MotionEvent { val pointerProperties = arrayOf(MotionEvent.PointerProperties().apply { this.id = 0 this.toolType = MotionEvent.TOOL_TYPE_FINGER }) val pointerCoords = arrayOf(MotionEvent.PointerCoords().apply { this.x = x this.y = y }) val ev = MotionEvent.obtain( /* downTime= */ SystemClock.uptimeMillis(), /* eventTime= */ SystemClock.uptimeMillis(), action, /* pointerCount= */ 1, pointerProperties, pointerCoords, /* metaState= */ 0, /* buttonState= */ 0, /* xPrecision= */ 0f, /* yPrecision= */ 0f, /* deviceId= */ 0, /* edgeFlags= */ 0, source, /* displayId= */ 0, /* flags= */ 0, classification, )!! return ev } private companion object { private companion object { const val SECOND_DISPLAY = 2 const val SECOND_DISPLAY = 2 private val BOUNDS_AFTER_FIRST_MOVE = Rect(10, 10, 110, 110) private val BOUNDS_AFTER_FIRST_MOVE = Rect(10, 10, 110, 110) Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt +57 −6 Original line number Original line Diff line number Diff line Loading @@ -18,8 +18,8 @@ package com.android.wm.shell.windowdecor import android.os.SystemClock import android.os.SystemClock import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner import android.view.MotionEvent import android.view.InputDevice import android.view.InputDevice import android.view.MotionEvent import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest import com.android.wm.shell.ShellTestCase import com.android.wm.shell.ShellTestCase import org.junit.After import org.junit.After Loading @@ -29,12 +29,12 @@ import org.junit.Before import org.junit.Test import org.junit.Test import org.junit.runner.RunWith import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mock import org.mockito.MockitoAnnotations import org.mockito.Mockito.`when` import org.mockito.Mockito.any import org.mockito.Mockito.any import org.mockito.Mockito.argThat import org.mockito.Mockito.argThat import org.mockito.Mockito.never import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations import org.mockito.kotlin.times import org.mockito.kotlin.times /** /** Loading Loading @@ -467,16 +467,67 @@ class DragDetectorTest : ShellTestCase() { .handleMotionEvent(any(), argThat { ev -> ev.action == MotionEvent.ACTION_MOVE }) .handleMotionEvent(any(), argThat { ev -> ev.action == MotionEvent.ACTION_MOVE }) } } @Test fun testEventWithMotionClassification_doesNothing() { val dragDetector = createDragDetector() assertFalse( dragDetector.onMotionEvent( createMotionEvent( MotionEvent.ACTION_DOWN, isTouch = false, classification = MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE ) ) ) verify(eventHandler, never()).handleMotionEvent(any(), any()) assertFalse( dragDetector.onMotionEvent( createMotionEvent( MotionEvent.ACTION_UP, isTouch = false, classification = MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE ) ) ) verify(eventHandler, never()).handleMotionEvent(any(), any()) } private fun createMotionEvent( private fun createMotionEvent( action: Int, action: Int, x: Float = X, x: Float = X, y: Float = Y, y: Float = Y, isTouch: Boolean = true, isTouch: Boolean = true, downTime: Long = SystemClock.uptimeMillis(), downTime: Long = SystemClock.uptimeMillis(), eventTime: Long = SystemClock.uptimeMillis() eventTime: Long = SystemClock.uptimeMillis(), classification: Int = MotionEvent.CLASSIFICATION_NONE, ): MotionEvent { ): MotionEvent { val ev = MotionEvent.obtain(downTime, eventTime, action, x, y, 0) val pointerProperties = arrayOf(MotionEvent.PointerProperties().apply { ev.source = if (isTouch) InputDevice.SOURCE_TOUCHSCREEN else InputDevice.SOURCE_MOUSE this.id = 0 this.toolType = MotionEvent.TOOL_TYPE_FINGER }) val pointerCoords = arrayOf(MotionEvent.PointerCoords().apply { this.x = x this.y = y }) val ev = MotionEvent.obtain( downTime, eventTime, action, /* pointerCount= */ 1, pointerProperties, pointerCoords, /* metaState= */ 0, /* buttonState= */ 0, /* xPrecision= */ 0f, /* yPrecision= */ 0f, /* deviceId= */ 0, /* edgeFlags= */ 0, if (isTouch) InputDevice.SOURCE_TOUCHSCREEN else InputDevice.SOURCE_MOUSE, /* displayId= */ 0, /* flags= */ 0, classification, )!! motionEvents.add(ev) motionEvents.add(ev) return ev return ev } } Loading