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:
Beverly
2022-09-15 14:52:47 +00:00
committed by Beverly Tai
parent da9ab025d9
commit dcd012b202
10 changed files with 97 additions and 47 deletions

View File

@@ -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}. */

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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);
}
}
};

View File

@@ -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) {

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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)