Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c2a7f5aa authored by Beverly Tai's avatar Beverly Tai Committed by Android (Google) Code Review
Browse files

Merge "Don't play auth haptics if power button pressed"

parents 2ab95f57 84f4c044
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.util.time.SystemClock;

import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -63,6 +64,7 @@ public class WakefulnessLifecycle extends Lifecycle<WakefulnessLifecycle.Observe

    private final Context mContext;
    private final DisplayMetrics mDisplayMetrics;
    private final SystemClock mSystemClock;

    @Nullable
    private final IWallpaperManager mWallpaperManagerService;
@@ -71,6 +73,9 @@ public class WakefulnessLifecycle extends Lifecycle<WakefulnessLifecycle.Observe

    private @PowerManager.WakeReason int mLastWakeReason = PowerManager.WAKE_REASON_UNKNOWN;

    public static final long UNKNOWN_LAST_WAKE_TIME = -1;
    private long mLastWakeTime = UNKNOWN_LAST_WAKE_TIME;

    @Nullable
    private Point mLastWakeOriginLocation = null;

@@ -84,10 +89,12 @@ public class WakefulnessLifecycle extends Lifecycle<WakefulnessLifecycle.Observe
    public WakefulnessLifecycle(
            Context context,
            @Nullable IWallpaperManager wallpaperManagerService,
            SystemClock systemClock,
            DumpManager dumpManager) {
        mContext = context;
        mDisplayMetrics = context.getResources().getDisplayMetrics();
        mWallpaperManagerService = wallpaperManagerService;
        mSystemClock = systemClock;

        dumpManager.registerDumpable(getClass().getSimpleName(), this);
    }
@@ -103,6 +110,14 @@ public class WakefulnessLifecycle extends Lifecycle<WakefulnessLifecycle.Observe
        return mLastWakeReason;
    }

    /**
     * Returns the most recent time (in device uptimeMillis) the display woke up.
     * Returns {@link UNKNOWN_LAST_WAKE_TIME} if there hasn't been a wakeup yet.
     */
    public long getLastWakeTime() {
        return mLastWakeTime;
    }

    /**
     * Returns the most recent reason the device went to sleep up. This is one of
     * PowerManager.GO_TO_SLEEP_REASON_*.
@@ -117,6 +132,7 @@ public class WakefulnessLifecycle extends Lifecycle<WakefulnessLifecycle.Observe
        }
        setWakefulness(WAKEFULNESS_WAKING);
        mLastWakeReason = pmWakeReason;
        mLastWakeTime = mSystemClock.uptimeMillis();
        updateLastWakeOriginLocation();

        if (mWallpaperManagerService != null) {
+34 −8
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.phone;

import static android.app.StatusBarManager.SESSION_KEYGUARD;

import static com.android.systemui.keyguard.WakefulnessLifecycle.UNKNOWN_LAST_WAKE_TIME;

import android.annotation.IntDef;
import android.content.res.Resources;
import android.hardware.biometrics.BiometricFaceConstants;
@@ -27,7 +29,6 @@ import android.hardware.fingerprint.FingerprintManager;
import android.metrics.LogMaker;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.Trace;

import androidx.annotation.Nullable;
@@ -59,6 +60,7 @@ import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.time.SystemClock;

import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -75,6 +77,7 @@ import javax.inject.Inject;
 */
@SysUISingleton
public class BiometricUnlockController extends KeyguardUpdateMonitorCallback implements Dumpable {
    private static final long RECENT_POWER_BUTTON_PRESS_THRESHOLD_MS = 400L;
    private static final long BIOMETRIC_WAKELOCK_TIMEOUT_MS = 15 * 1000;
    private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock:wakelock";
    private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl();
@@ -165,9 +168,11 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
    private final MetricsLogger mMetricsLogger;
    private final AuthController mAuthController;
    private final StatusBarStateController mStatusBarStateController;
    private final WakefulnessLifecycle mWakefulnessLifecycle;
    private final LatencyTracker mLatencyTracker;
    private final VibratorHelper mVibratorHelper;
    private final BiometricUnlockLogger mLogger;
    private final SystemClock mSystemClock;

    private long mLastFpFailureUptimeMillis;
    private int mNumConsecutiveFpFailures;
@@ -272,13 +277,16 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
            SessionTracker sessionTracker,
            LatencyTracker latencyTracker,
            ScreenOffAnimationController screenOffAnimationController,
            VibratorHelper vibrator) {
            VibratorHelper vibrator,
            SystemClock systemClock
    ) {
        mPowerManager = powerManager;
        mUpdateMonitor = keyguardUpdateMonitor;
        mUpdateMonitor.registerCallback(this);
        mMediaManager = notificationMediaManager;
        mLatencyTracker = latencyTracker;
        wakefulnessLifecycle.addObserver(mWakefulnessObserver);
        mWakefulnessLifecycle = wakefulnessLifecycle;
        mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
        screenLifecycle.addObserver(mScreenObserver);

        mNotificationShadeWindowController = notificationShadeWindowController;
@@ -297,6 +305,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
        mScreenOffAnimationController = screenOffAnimationController;
        mVibratorHelper = vibrator;
        mLogger = biometricUnlockLogger;
        mSystemClock = systemClock;

        dumpManager.registerDumpable(getClass().getName(), this);
    }
@@ -420,8 +429,11 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
        Runnable wakeUp = ()-> {
            if (!wasDeviceInteractive || mUpdateMonitor.isDreaming()) {
                mLogger.i("bio wakelock: Authenticated, waking up...");
                mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_BIOMETRIC,
                        "android.policy:BIOMETRIC");
                mPowerManager.wakeUp(
                        mSystemClock.uptimeMillis(),
                        PowerManager.WAKE_REASON_BIOMETRIC,
                        "android.policy:BIOMETRIC"
                );
            }
            Trace.beginSection("release wake-and-unlock");
            releaseBiometricWakeLock();
@@ -652,7 +664,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
            startWakeAndUnlock(MODE_ONLY_WAKE);
        } else if (biometricSourceType == BiometricSourceType.FINGERPRINT
                && mUpdateMonitor.isUdfpsSupported()) {
            long currUptimeMillis = SystemClock.uptimeMillis();
            long currUptimeMillis = mSystemClock.uptimeMillis();
            if (currUptimeMillis - mLastFpFailureUptimeMillis < mConsecutiveFpFailureThreshold) {
                mNumConsecutiveFpFailures += 1;
            } else {
@@ -702,10 +714,24 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp

    // these haptics are for device-entry only
    private void vibrateSuccess(BiometricSourceType type) {
        if (mAuthController.isSfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser())
                && lastWakeupFromPowerButtonWithinHapticThreshold()) {
            mLogger.d("Skip auth success haptic. Power button was recently pressed.");
            return;
        }
        mVibratorHelper.vibrateAuthSuccess(
                getClass().getSimpleName() + ", type =" + type + "device-entry::success");
    }

    private boolean lastWakeupFromPowerButtonWithinHapticThreshold() {
        final boolean lastWakeupFromPowerButton = mWakefulnessLifecycle.getLastWakeReason()
                == PowerManager.WAKE_REASON_POWER_BUTTON;
        return lastWakeupFromPowerButton
                && mWakefulnessLifecycle.getLastWakeTime() != UNKNOWN_LAST_WAKE_TIME
                && mSystemClock.uptimeMillis() - mWakefulnessLifecycle.getLastWakeTime()
                < RECENT_POWER_BUTTON_PRESS_THRESHOLD_MS;
    }

    private void vibrateError(BiometricSourceType type) {
        mVibratorHelper.vibrateAuthError(
                getClass().getSimpleName() + ", type =" + type + "device-entry::error");
@@ -798,7 +824,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
        if (mUpdateMonitor.isUdfpsSupported()) {
            pw.print("   mNumConsecutiveFpFailures="); pw.println(mNumConsecutiveFpFailures);
            pw.print("   time since last failure=");
            pw.println(SystemClock.uptimeMillis() - mLastFpFailureUptimeMillis);
            pw.println(mSystemClock.uptimeMillis() - mLastFpFailureUptimeMillis);
        }
    }

+7 −1
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import androidx.test.filters.SmallTest;

import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.util.time.FakeSystemClock;

import org.junit.Before;
import org.junit.Test;
@@ -51,7 +52,12 @@ public class WakefulnessLifecycleTest extends SysuiTestCase {
    public void setUp() throws Exception {
        mWallpaperManager = mock(IWallpaperManager.class);
        mWakefulness =
                new WakefulnessLifecycle(mContext, mWallpaperManager, mock(DumpManager.class));
                new WakefulnessLifecycle(
                        mContext,
                        mWallpaperManager,
                        new FakeSystemClock(),
                        mock(DumpManager.class)
                );
        mWakefulnessObserver = mock(WakefulnessLifecycle.Observer.class);
        mWakefulness.addObserver(mWakefulnessObserver);
    }
+87 −2
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.systemui.statusbar.phone;

import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
@@ -54,6 +56,7 @@ import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.time.FakeSystemClock;

import org.junit.Before;
import org.junit.Test;
@@ -115,6 +118,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
    private VibratorHelper mVibratorHelper;
    @Mock
    private BiometricUnlockLogger mLogger;
    private final FakeSystemClock mSystemClock = new FakeSystemClock();
    private BiometricUnlockController mBiometricUnlockController;

    @Before
@@ -137,7 +141,9 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
                mMetricsLogger, mDumpManager, mPowerManager, mLogger,
                mNotificationMediaManager, mWakefulnessLifecycle, mScreenLifecycle,
                mAuthController, mStatusBarStateController,
                mSessionTracker, mLatencyTracker, mScreenOffAnimationController, mVibratorHelper);
                mSessionTracker, mLatencyTracker, mScreenOffAnimationController, mVibratorHelper,
                mSystemClock
        );
        mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
        mBiometricUnlockController.addBiometricModeListener(mBiometricModeListener);
        when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(mStrongAuthTracker);
@@ -200,7 +206,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {

        verify(mKeyguardViewMediator).onWakeAndUnlocking();
        assertThat(mBiometricUnlockController.getMode())
                .isEqualTo(BiometricUnlockController.MODE_WAKE_AND_UNLOCK);
                .isEqualTo(MODE_WAKE_AND_UNLOCK);
    }

    @Test
@@ -437,4 +443,83 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
        // THEN wakeup the device
        verify(mPowerManager).wakeUp(anyLong(), anyInt(), anyString());
    }

    @Test
    public void onSideFingerprintSuccess_recentPowerButtonPress_noHaptic() {
        // GIVEN side fingerprint enrolled, last wake reason was power button
        when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);
        when(mWakefulnessLifecycle.getLastWakeReason())
                .thenReturn(PowerManager.WAKE_REASON_POWER_BUTTON);

        // GIVEN last wake time just occurred
        when(mWakefulnessLifecycle.getLastWakeTime()).thenReturn(mSystemClock.uptimeMillis());

        // WHEN biometric fingerprint succeeds
        givenFingerprintModeUnlockCollapsing();
        mBiometricUnlockController.startWakeAndUnlock(BiometricSourceType.FINGERPRINT,
                true);

        // THEN DO NOT vibrate the device
        verify(mVibratorHelper, never()).vibrateAuthSuccess(anyString());
    }

    @Test
    public void onSideFingerprintSuccess_oldPowerButtonPress_playHaptic() {
        // GIVEN side fingerprint enrolled, last wake reason was power button
        when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);
        when(mWakefulnessLifecycle.getLastWakeReason())
                .thenReturn(PowerManager.WAKE_REASON_POWER_BUTTON);

        // GIVEN last wake time was 500ms ago
        when(mWakefulnessLifecycle.getLastWakeTime()).thenReturn(mSystemClock.uptimeMillis());
        mSystemClock.advanceTime(500);

        // WHEN biometric fingerprint succeeds
        givenFingerprintModeUnlockCollapsing();
        mBiometricUnlockController.startWakeAndUnlock(BiometricSourceType.FINGERPRINT,
                true);

        // THEN vibrate the device
        verify(mVibratorHelper).vibrateAuthSuccess(anyString());
    }

    @Test
    public void onSideFingerprintSuccess_recentGestureWakeUp_playHaptic() {
        // GIVEN side fingerprint enrolled, wakeup just happened
        when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);
        when(mWakefulnessLifecycle.getLastWakeTime()).thenReturn(mSystemClock.uptimeMillis());

        // GIVEN last wake reason was from a gesture
        when(mWakefulnessLifecycle.getLastWakeReason())
                .thenReturn(PowerManager.WAKE_REASON_GESTURE);

        // WHEN biometric fingerprint succeeds
        givenFingerprintModeUnlockCollapsing();
        mBiometricUnlockController.startWakeAndUnlock(BiometricSourceType.FINGERPRINT,
                true);

        // THEN vibrate the device
        verify(mVibratorHelper).vibrateAuthSuccess(anyString());
    }

    @Test
    public void onSideFingerprintFail_alwaysPlaysHaptic() {
        // GIVEN side fingerprint enrolled, last wake reason was recent power button
        when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);
        when(mWakefulnessLifecycle.getLastWakeReason())
                .thenReturn(PowerManager.WAKE_REASON_POWER_BUTTON);
        when(mWakefulnessLifecycle.getLastWakeTime()).thenReturn(mSystemClock.uptimeMillis());

        // WHEN biometric fingerprint fails
        mBiometricUnlockController.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT);

        // THEN always vibrate the device
        verify(mVibratorHelper).vibrateAuthError(anyString());
    }

    private void givenFingerprintModeUnlockCollapsing() {
        when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
        when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);
        when(mKeyguardStateController.isShowing()).thenReturn(true);
    }
}
+4 −3
Original line number Diff line number Diff line
@@ -178,8 +178,6 @@ import com.android.systemui.volume.VolumeComponent;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.startingsurface.StartingSurface;

import dagger.Lazy;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -192,6 +190,8 @@ import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.util.Optional;

import dagger.Lazy;

@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper(setAsMainLooper = true)
@@ -380,7 +380,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
        }).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());

        mWakefulnessLifecycle =
                new WakefulnessLifecycle(mContext, mIWallpaperManager, mDumpManager);
                new WakefulnessLifecycle(mContext, mIWallpaperManager, mFakeSystemClock,
                        mDumpManager);
        mWakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
        mWakefulnessLifecycle.dispatchFinishedWakingUp();