Wakeup display on taps before entering true AoD
In this transition state, the device is not technically
pulsing, but it is Dozing. The primary difference
is that the display state is the display is still ON
(not DISPLAY_STATE_DOZE) and the DozeSensor wake gestures
aren't registered yet.
Because isPulsing=false during this transition, instead of checking
isPulsing, check isDozing instead. Only touches when the display
is ON get sent through the NotificationShadeWindowViewController =>
PulsingGestureListener, so the DozeSensors will still handle the
wakeups that aren't fake AoD2 (including both pulsing + transition
period).
This CL:
- updates the PulsingGestureListener to only check
the falsing manager on the ACTION_UP event of the single tap
and double tap gesture. The FalsingManager only works if checked
right after the action occurred. Previously, we'd check double
taps on the double tap's ACTION_DOWN.
- allows the FalsingManager to analyze taps from the NotificationPanel
while Dozing, as to include the taps when the device is
transitioning to AoD. When the device enters the display state DOZE,
taps will no longer be sent to the NotificationPanel.
- removes the vibration when DOZING that goes along with the falsing manager's
feedback when an additional tap is required. if the device is
dozing, its likely the device may be in the pocket so there's no
reason to buzz.
Test: manual
1. Enable AoD
2. Power off display
3. Tap display right after power off
4. Observe: device wakes up to LS
Test: manual
1. Disable AoD
2. Send a delayed (5000ms) high-priority notification
3. Screen off
4. When the notification shows, tap the screen
5. Observe: device wakes up to LS
Test: atest PulsingGestureListenerTest NotificationPanelViewControllerTest
Fixes: 246722709
Bug: 244659326
Bug: 242125976
Change-Id: I1330f2c87482d8bc743a61d652d245fd9b4c69a0
This commit is contained in:
@@ -147,10 +147,10 @@ public interface FalsingManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener that is alerted when a double tap is required to confirm a single tap.
|
||||
* Listener that is alerted when an additional tap is required to confirm a single tap.
|
||||
**/
|
||||
interface FalsingTapListener {
|
||||
void onDoubleTapRequired();
|
||||
void onAdditionalTapRequired();
|
||||
}
|
||||
|
||||
/** Passed to {@link FalsingManager#onProximityEvent}. */
|
||||
|
||||
@@ -291,7 +291,7 @@ public class BrightLineFalsingManager implements FalsingManager {
|
||||
FalsingClassifier.Result.falsed(
|
||||
0, getClass().getSimpleName(), "bad history"));
|
||||
logDebug("False Single Tap: true (bad history)");
|
||||
mFalsingTapListeners.forEach(FalsingTapListener::onDoubleTapRequired);
|
||||
mFalsingTapListeners.forEach(FalsingTapListener::onAdditionalTapRequired);
|
||||
return true;
|
||||
} else {
|
||||
mPriorResults = getPassedResult(0.1);
|
||||
@@ -321,7 +321,7 @@ public class BrightLineFalsingManager implements FalsingManager {
|
||||
mHistoryTracker.falseBelief(),
|
||||
mHistoryTracker.falseConfidence());
|
||||
mPriorResults = Collections.singleton(result);
|
||||
logDebug("False Double Tap: " + result.isFalse());
|
||||
logDebug("False Double Tap: " + result.isFalse() + " reason=" + result.getReason());
|
||||
return result.isFalse();
|
||||
}
|
||||
|
||||
|
||||
@@ -303,9 +303,7 @@ class FalsingCollectorImpl implements FalsingCollector {
|
||||
|
||||
@Override
|
||||
public void onTouchEvent(MotionEvent ev) {
|
||||
if (!mKeyguardStateController.isShowing()
|
||||
|| (mStatusBarStateController.isDozing()
|
||||
&& !mStatusBarStateController.isPulsing())) {
|
||||
if (!mKeyguardStateController.isShowing()) {
|
||||
avoidGesture();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_Q
|
||||
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
|
||||
import static com.android.systemui.statusbar.StatusBarState.SHADE;
|
||||
import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
|
||||
import static com.android.systemui.statusbar.VibratorHelper.TOUCH_VIBRATION_ATTRIBUTES;
|
||||
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
|
||||
import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_FOLD_TO_AOD;
|
||||
import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_CLOSED;
|
||||
@@ -62,6 +63,7 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.PowerManager;
|
||||
import android.os.Process;
|
||||
import android.os.Trace;
|
||||
import android.os.UserManager;
|
||||
import android.os.VibrationEffect;
|
||||
@@ -236,6 +238,9 @@ public final class NotificationPanelViewController extends PanelViewController {
|
||||
private static final boolean SPEW_LOGCAT = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
|
||||
private static final boolean DEBUG_DRAWABLE = false;
|
||||
|
||||
private static final VibrationEffect ADDITIONAL_TAP_REQUIRED_VIBRATION_EFFECT =
|
||||
VibrationEffect.get(VibrationEffect.EFFECT_STRENGTH_MEDIUM, false);
|
||||
|
||||
/**
|
||||
* The parallax amount of the quick settings translation when dragging down the panel
|
||||
*/
|
||||
@@ -682,14 +687,22 @@ public final class NotificationPanelViewController extends PanelViewController {
|
||||
|
||||
private final FalsingTapListener mFalsingTapListener = new FalsingTapListener() {
|
||||
@Override
|
||||
public void onDoubleTapRequired() {
|
||||
public void onAdditionalTapRequired() {
|
||||
if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED) {
|
||||
mTapAgainViewController.show();
|
||||
} else {
|
||||
mKeyguardIndicationController.showTransientIndication(
|
||||
R.string.notification_tap_again);
|
||||
}
|
||||
mVibratorHelper.vibrate(VibrationEffect.EFFECT_STRENGTH_MEDIUM);
|
||||
|
||||
if (!mStatusBarStateController.isDozing()) {
|
||||
mVibratorHelper.vibrate(
|
||||
Process.myUid(),
|
||||
mView.getContext().getPackageName(),
|
||||
ADDITIONAL_TAP_REQUIRED_VIBRATION_EFFECT,
|
||||
"falsing-additional-tap-required",
|
||||
TOUCH_VIBRATION_ATTRIBUTES);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ public class NotificationShadeWindowViewController {
|
||||
private final AmbientState mAmbientState;
|
||||
private final PulsingGestureListener mPulsingGestureListener;
|
||||
|
||||
private GestureDetector mGestureDetector;
|
||||
private GestureDetector mPulsingWakeupGestureHandler;
|
||||
private View mBrightnessMirror;
|
||||
private boolean mTouchActive;
|
||||
private boolean mTouchCancelled;
|
||||
@@ -149,7 +149,8 @@ public class NotificationShadeWindowViewController {
|
||||
/** Inflates the {@link R.layout#status_bar_expanded} layout and sets it up. */
|
||||
public void setupExpandedStatusBar() {
|
||||
mStackScrollLayout = mView.findViewById(R.id.notification_stack_scroller);
|
||||
mGestureDetector = new GestureDetector(mView.getContext(), mPulsingGestureListener);
|
||||
mPulsingWakeupGestureHandler = new GestureDetector(mView.getContext(),
|
||||
mPulsingGestureListener);
|
||||
|
||||
mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() {
|
||||
@Override
|
||||
@@ -196,7 +197,7 @@ public class NotificationShadeWindowViewController {
|
||||
}
|
||||
|
||||
mFalsingCollector.onTouchEvent(ev);
|
||||
mGestureDetector.onTouchEvent(ev);
|
||||
mPulsingWakeupGestureHandler.onTouchEvent(ev);
|
||||
mStatusBarKeyguardViewManager.onTouch(ev);
|
||||
if (mBrightnessMirror != null
|
||||
&& mBrightnessMirror.getVisibility() == View.VISIBLE) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.android.systemui.Dumpable
|
||||
import com.android.systemui.dock.DockManager
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.plugins.FalsingManager
|
||||
import com.android.systemui.plugins.FalsingManager.LOW_PENALTY
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.statusbar.phone.CentralSurfaces
|
||||
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent
|
||||
@@ -36,12 +37,12 @@ import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* If tap and/or double tap to wake is enabled, this gestureListener will wake the display on
|
||||
* tap/double tap when the device is pulsing (AoD 2). Taps are gated by the proximity sensor and
|
||||
* falsing manager.
|
||||
* tap/double tap when the device is pulsing (AoD2) or transitioning to AoD. Taps are gated by the
|
||||
* proximity sensor and falsing manager.
|
||||
*
|
||||
* Touches go through the [NotificationShadeWindowViewController] when the device is pulsing.
|
||||
* Otherwise, if the device is dozing and NOT pulsing, wake-ups are handled by
|
||||
* [com.android.systemui.doze.DozeSensors].
|
||||
* Touches go through the [NotificationShadeWindowViewController] when the device is dozing but the
|
||||
* screen is still ON and not in the true AoD display state. When the device is in the true AoD
|
||||
* display state, wake-ups are handled by [com.android.systemui.doze.DozeSensors].
|
||||
*/
|
||||
@CentralSurfacesComponent.CentralSurfacesScope
|
||||
class PulsingGestureListener @Inject constructor(
|
||||
@@ -75,12 +76,12 @@ class PulsingGestureListener @Inject constructor(
|
||||
dumpManager.registerDumpable(this)
|
||||
}
|
||||
|
||||
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
|
||||
if (statusBarStateController.isPulsing &&
|
||||
override fun onSingleTapUp(e: MotionEvent): Boolean {
|
||||
if (statusBarStateController.isDozing &&
|
||||
singleTapEnabled &&
|
||||
!dockManager.isDocked &&
|
||||
!falsingManager.isProximityNear &&
|
||||
!falsingManager.isFalseTap(FalsingManager.MODERATE_PENALTY)
|
||||
!falsingManager.isFalseTap(LOW_PENALTY)
|
||||
) {
|
||||
centralSurfaces.wakeUpIfDozing(
|
||||
SystemClock.uptimeMillis(),
|
||||
@@ -91,8 +92,15 @@ class PulsingGestureListener @Inject constructor(
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onDoubleTap(e: MotionEvent): Boolean {
|
||||
if (statusBarStateController.isPulsing &&
|
||||
/**
|
||||
* Receives [MotionEvent.ACTION_DOWN], [MotionEvent.ACTION_MOVE], and [MotionEvent.ACTION_UP]
|
||||
* motion events for a double tap.
|
||||
*/
|
||||
override fun onDoubleTapEvent(e: MotionEvent): Boolean {
|
||||
// React to the [MotionEvent.ACTION_UP] event after double tap is detected. Falsing
|
||||
// checks MUST be on the ACTION_UP event.
|
||||
if (e.actionMasked == MotionEvent.ACTION_UP &&
|
||||
statusBarStateController.isDozing &&
|
||||
(doubleTapEnabled || singleTapEnabled) &&
|
||||
!falsingManager.isProximityNear &&
|
||||
!falsingManager.isFalseDoubleTap
|
||||
|
||||
@@ -38,7 +38,7 @@ import javax.inject.Inject;
|
||||
public class VibratorHelper {
|
||||
|
||||
private final Vibrator mVibrator;
|
||||
private static final VibrationAttributes TOUCH_VIBRATION_ATTRIBUTES =
|
||||
public static final VibrationAttributes TOUCH_VIBRATION_ATTRIBUTES =
|
||||
VibrationAttributes.createForUsage(VibrationAttributes.USAGE_TOUCH);
|
||||
private final Executor mExecutor;
|
||||
|
||||
|
||||
@@ -229,7 +229,10 @@ public class FalsingCollectorImplTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAvoidDozingNotPulsing() {
|
||||
public void testGestureWhenDozing() {
|
||||
// We check the FalsingManager for taps during the transition to AoD (dozing=true,
|
||||
// pulsing=false), so the FalsingCollector needs to continue to analyze events that occur
|
||||
// while the device is dozing.
|
||||
MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
|
||||
MotionEvent up = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0);
|
||||
|
||||
@@ -239,13 +242,13 @@ public class FalsingCollectorImplTest extends SysuiTestCase {
|
||||
mFalsingCollector.onTouchEvent(down);
|
||||
verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class));
|
||||
|
||||
// Up event would normally flush the up event, but doesn't.
|
||||
// Up event flushes
|
||||
mFalsingCollector.onTouchEvent(up);
|
||||
verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class));
|
||||
verify(mFalsingDataProvider, times(2)).onMotionEvent(any(MotionEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAvoidDozingButPulsing() {
|
||||
public void testGestureWhenPulsing() {
|
||||
MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
|
||||
MotionEvent up = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0);
|
||||
|
||||
|
||||
@@ -1022,7 +1022,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
|
||||
FalsingManager.FalsingTapListener listener = getFalsingTapListener();
|
||||
mStatusBarStateController.setState(KEYGUARD);
|
||||
|
||||
listener.onDoubleTapRequired();
|
||||
listener.onAdditionalTapRequired();
|
||||
|
||||
verify(mKeyguardIndicationController).showTransientIndication(anyInt());
|
||||
}
|
||||
@@ -1032,7 +1032,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
|
||||
FalsingManager.FalsingTapListener listener = getFalsingTapListener();
|
||||
mStatusBarStateController.setState(SHADE_LOCKED);
|
||||
|
||||
listener.onDoubleTapRequired();
|
||||
listener.onAdditionalTapRequired();
|
||||
|
||||
verify(mTapAgainViewController).show();
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ class PulsingGestureListenerTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun testGestureDetector_singleTapEnabled() {
|
||||
whenever(statusBarStateController.isPulsing).thenReturn(true)
|
||||
whenever(statusBarStateController.isDozing).thenReturn(true)
|
||||
|
||||
// GIVEN tap is enabled, prox not covered
|
||||
whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
|
||||
@@ -100,7 +100,7 @@ class PulsingGestureListenerTest : SysuiTestCase() {
|
||||
whenever(falsingManager.isFalseTap(anyInt())).thenReturn(false)
|
||||
|
||||
// WHEN there's a tap
|
||||
underTest.onSingleTapConfirmed(downEv)
|
||||
underTest.onSingleTapUp(upEv)
|
||||
|
||||
// THEN wake up device if dozing
|
||||
verify(centralSurfaces).wakeUpIfDozing(anyLong(), anyObject(), anyString())
|
||||
@@ -108,7 +108,7 @@ class PulsingGestureListenerTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun testGestureDetector_doubleTapEnabled() {
|
||||
whenever(statusBarStateController.isPulsing).thenReturn(true)
|
||||
whenever(statusBarStateController.isDozing).thenReturn(true)
|
||||
|
||||
// GIVEN double tap is enabled, prox not covered
|
||||
whenever(ambientDisplayConfiguration.doubleTapGestureEnabled(anyInt())).thenReturn(true)
|
||||
@@ -119,15 +119,27 @@ class PulsingGestureListenerTest : SysuiTestCase() {
|
||||
whenever(falsingManager.isFalseDoubleTap).thenReturn(false)
|
||||
|
||||
// WHEN there's a double tap
|
||||
underTest.onDoubleTap(downEv)
|
||||
underTest.onDoubleTapEvent(upEv)
|
||||
|
||||
// THEN wake up device if dozing
|
||||
verify(centralSurfaces).wakeUpIfDozing(anyLong(), anyObject(), anyString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGestureDetector_doubleTapEnabled_onDownEvent_noFalsingCheck() {
|
||||
// GIVEN tap is enabled
|
||||
whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
|
||||
|
||||
// WHEN there's a double tap on DOWN event
|
||||
underTest.onDoubleTapEvent(downEv)
|
||||
|
||||
// THEN don't check the falsing manager, should only be checked on the UP event
|
||||
verify(falsingManager, never()).isFalseDoubleTap()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGestureDetector_singleTapEnabled_falsing() {
|
||||
whenever(statusBarStateController.isPulsing).thenReturn(true)
|
||||
whenever(statusBarStateController.isDozing).thenReturn(true)
|
||||
|
||||
// GIVEN tap is enabled, prox not covered
|
||||
whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
|
||||
@@ -138,29 +150,43 @@ class PulsingGestureListenerTest : SysuiTestCase() {
|
||||
whenever(falsingManager.isFalseTap(anyInt())).thenReturn(true)
|
||||
|
||||
// WHEN there's a tap
|
||||
underTest.onSingleTapConfirmed(downEv)
|
||||
underTest.onSingleTapUp(upEv)
|
||||
|
||||
// THEN the device doesn't wake up
|
||||
verify(centralSurfaces, never()).wakeUpIfDozing(anyLong(), anyObject(), anyString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGestureDetector_notPulsing_noFalsingCheck() {
|
||||
whenever(statusBarStateController.isPulsing).thenReturn(false)
|
||||
fun testSingleTap_notDozing_noFalsingCheck() {
|
||||
whenever(statusBarStateController.isDozing).thenReturn(false)
|
||||
|
||||
// GIVEN tap is enabled, prox not covered
|
||||
// GIVEN tap is enabled
|
||||
whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
|
||||
// WHEN there's a tap
|
||||
underTest.onSingleTapConfirmed(downEv)
|
||||
underTest.onSingleTapUp(upEv)
|
||||
|
||||
// THEN the falsing manager never gets a call (because the device wasn't pulsing
|
||||
// THEN the falsing manager never gets a call (because the device wasn't dozing
|
||||
// during the tap)
|
||||
verify(falsingManager, never()).isFalseTap(anyInt())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDoubleTap_notDozing_noFalsingCheck() {
|
||||
whenever(statusBarStateController.isDozing).thenReturn(false)
|
||||
|
||||
// GIVEN tap is enabled
|
||||
whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
|
||||
// WHEN there's a tap
|
||||
underTest.onDoubleTapEvent(upEv)
|
||||
|
||||
// THEN the falsing manager never gets a call (because the device wasn't dozing
|
||||
// during the tap)
|
||||
verify(falsingManager, never()).isFalseTap(anyInt())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGestureDetector_doubleTapEnabled_falsing() {
|
||||
whenever(statusBarStateController.isPulsing).thenReturn(true)
|
||||
whenever(statusBarStateController.isDozing).thenReturn(true)
|
||||
|
||||
// GIVEN double tap is enabled, prox not covered
|
||||
whenever(ambientDisplayConfiguration.doubleTapGestureEnabled(anyInt())).thenReturn(true)
|
||||
@@ -170,8 +196,8 @@ class PulsingGestureListenerTest : SysuiTestCase() {
|
||||
// GIVEN the falsing manager thinks the tap is a false tap
|
||||
whenever(falsingManager.isFalseDoubleTap).thenReturn(true)
|
||||
|
||||
// WHEN there's a tap
|
||||
underTest.onDoubleTap(downEv)
|
||||
// WHEN there's a double tap ACTION_UP event
|
||||
underTest.onDoubleTapEvent(upEv)
|
||||
|
||||
// THEN the device doesn't wake up
|
||||
verify(centralSurfaces, never()).wakeUpIfDozing(anyLong(), anyObject(), anyString())
|
||||
@@ -179,7 +205,7 @@ class PulsingGestureListenerTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun testGestureDetector_singleTapEnabled_proxCovered() {
|
||||
whenever(statusBarStateController.isPulsing).thenReturn(true)
|
||||
whenever(statusBarStateController.isDozing).thenReturn(true)
|
||||
|
||||
// GIVEN tap is enabled, not a false tap based on classifiers
|
||||
whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
|
||||
@@ -190,7 +216,7 @@ class PulsingGestureListenerTest : SysuiTestCase() {
|
||||
whenever(falsingManager.isProximityNear()).thenReturn(true)
|
||||
|
||||
// WHEN there's a tap
|
||||
underTest.onSingleTapConfirmed(downEv)
|
||||
underTest.onSingleTapUp(upEv)
|
||||
|
||||
// THEN the device doesn't wake up
|
||||
verify(centralSurfaces, never()).wakeUpIfDozing(anyLong(), anyObject(), anyString())
|
||||
@@ -198,7 +224,7 @@ class PulsingGestureListenerTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun testGestureDetector_doubleTapEnabled_proxCovered() {
|
||||
whenever(statusBarStateController.isPulsing).thenReturn(true)
|
||||
whenever(statusBarStateController.isDozing).thenReturn(true)
|
||||
|
||||
// GIVEN double tap is enabled, not a false tap based on classifiers
|
||||
whenever(ambientDisplayConfiguration.doubleTapGestureEnabled(anyInt())).thenReturn(true)
|
||||
@@ -209,7 +235,7 @@ class PulsingGestureListenerTest : SysuiTestCase() {
|
||||
whenever(falsingManager.isProximityNear()).thenReturn(true)
|
||||
|
||||
// WHEN there's a tap
|
||||
underTest.onDoubleTap(downEv)
|
||||
underTest.onDoubleTapEvent(upEv)
|
||||
|
||||
// THEN the device doesn't wake up
|
||||
verify(centralSurfaces, never()).wakeUpIfDozing(anyLong(), anyObject(), anyString())
|
||||
@@ -227,3 +253,4 @@ class PulsingGestureListenerTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
private val downEv = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
|
||||
private val upEv = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0)
|
||||
|
||||
Reference in New Issue
Block a user