Prompt for confirmation when sfps is active and the power button is pressed.
Fix: 204380676 Test: atest SideFpsEventHandlerTest Test: manual (press power while using biometric prompt) Test: manual (press power while enrolling fingerprint) Change-Id: Ia9efced4034559ba5d416b6bfa24e4424c1e6a73
This commit is contained in:
@@ -49,10 +49,10 @@ public abstract class FingerprintStateListener extends IFingerprintStateListener
|
||||
* Defines behavior in response to state update
|
||||
* @param newState new state of fingerprint sensor
|
||||
*/
|
||||
public void onStateChanged(@FingerprintStateListener.State int newState) {};
|
||||
public void onStateChanged(@FingerprintStateListener.State int newState) {}
|
||||
|
||||
/**
|
||||
* Invoked when enrollment state changes for the specified user
|
||||
*/
|
||||
public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {};
|
||||
public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {}
|
||||
}
|
||||
|
||||
@@ -3417,20 +3417,35 @@
|
||||
|
||||
<!-- [CHAR LIMIT=40] Title of dialog shown to confirm device going to sleep if the power button
|
||||
is pressed during fingerprint enrollment. -->
|
||||
<string name="fp_enrollment_powerbutton_intent_title">Turn off screen?</string>
|
||||
<string name="fp_power_button_enrollment_title">Continue setup?</string>
|
||||
|
||||
<!-- [CHAR LIMIT=NONE] Message of dialog shown to confirm device going to sleep if the power
|
||||
button is pressed during fingerprint enrollment. -->
|
||||
<string name="fp_enrollment_powerbutton_intent_message">While setting up your fingerprint, you
|
||||
pressed the Power button.\n\nThis usually turns off your screen.</string>
|
||||
<string name="fp_power_button_enrollment_message">You pressed the power button — this usually turns off the screen.\n\nTry tapping lightly while setting up your fingerprint.</string>
|
||||
|
||||
<!-- [CHAR LIMIT=20] Positive button of dialog shown to confirm device going to sleep if the
|
||||
power button is pressed during fingerprint enrollment. -->
|
||||
<string name="fp_enrollment_powerbutton_intent_positive_button">Turn off</string>
|
||||
<string name="fp_power_button_enrollment_positive_button">Turn off screen</string>
|
||||
|
||||
<!-- [CHAR LIMIT=20] Negative button of dialog shown to confirm device going to sleep if the
|
||||
power button is pressed during fingerprint enrollment. -->
|
||||
<string name="fp_enrollment_powerbutton_intent_negative_button">Cancel</string>
|
||||
<string name="fp_power_button_enrollment_negative_button">Continue setup</string>
|
||||
|
||||
<!-- [CHAR LIMIT=40] Title of dialog shown to confirm device going to sleep if the power button
|
||||
is pressed during biometric prompt when a side fingerprint sensor is present. -->
|
||||
<string name="fp_power_button_bp_title">Continue verifying your fingerprint?</string>
|
||||
|
||||
<!-- [CHAR LIMIT=NONE] Message of dialog shown to confirm device going to sleep if the power
|
||||
button is pressed during biometric prompt when a side fingerprint sensor is present. -->
|
||||
<string name="fp_power_button_bp_message">You pressed the power button — this usually turns off the screen.\n\nTry tapping lightly to verify your fingerprint.</string>
|
||||
|
||||
<!-- [CHAR LIMIT=20] Positive button of dialog shown to confirm device going to sleep if the
|
||||
power button is pressed during biometric prompt when a side fingerprint sensor is present. -->
|
||||
<string name="fp_power_button_bp_positive_button">Turn off screen</string>
|
||||
|
||||
<!-- [CHAR LIMIT=20] Negative button of dialog shown to confirm device going to sleep if the
|
||||
power button is pressed during biometric prompt when a side fingerprint sensor is present. -->
|
||||
<string name="fp_power_button_bp_negative_button">Continue</string>
|
||||
|
||||
<!-- Notification text to tell the user that a heavy-weight application is running. -->
|
||||
<string name="heavy_weight_notification"><xliff:g id="app">%1$s</xliff:g> running</string>
|
||||
|
||||
@@ -1834,10 +1834,14 @@
|
||||
<java-symbol type="string" name="bugreport_status" />
|
||||
<java-symbol type="string" name="bugreport_title" />
|
||||
<java-symbol type="string" name="faceunlock_multiple_failures" />
|
||||
<java-symbol type="string" name="fp_enrollment_powerbutton_intent_title" />
|
||||
<java-symbol type="string" name="fp_enrollment_powerbutton_intent_message" />
|
||||
<java-symbol type="string" name="fp_enrollment_powerbutton_intent_positive_button" />
|
||||
<java-symbol type="string" name="fp_enrollment_powerbutton_intent_negative_button" />
|
||||
<java-symbol type="string" name="fp_power_button_bp_title" />
|
||||
<java-symbol type="string" name="fp_power_button_bp_message" />
|
||||
<java-symbol type="string" name="fp_power_button_bp_positive_button" />
|
||||
<java-symbol type="string" name="fp_power_button_bp_negative_button" />
|
||||
<java-symbol type="string" name="fp_power_button_enrollment_title" />
|
||||
<java-symbol type="string" name="fp_power_button_enrollment_message" />
|
||||
<java-symbol type="string" name="fp_power_button_enrollment_positive_button" />
|
||||
<java-symbol type="string" name="fp_power_button_enrollment_negative_button" />
|
||||
<java-symbol type="string" name="global_actions" />
|
||||
<java-symbol type="string" name="global_action_power_off" />
|
||||
<java-symbol type="string" name="global_action_power_options" />
|
||||
|
||||
@@ -16,14 +16,19 @@
|
||||
|
||||
package com.android.server.policy;
|
||||
|
||||
import static android.hardware.fingerprint.FingerprintStateListener.STATE_BP_AUTH;
|
||||
import static android.hardware.fingerprint.FingerprintStateListener.STATE_ENROLLING;
|
||||
import static android.hardware.fingerprint.FingerprintStateListener.STATE_IDLE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||
@@ -34,9 +39,11 @@ import android.os.PowerManager;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Defines behavior for handling interactions between power button events and
|
||||
@@ -44,68 +51,115 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* lives on the power button.
|
||||
*/
|
||||
public class SideFpsEventHandler {
|
||||
|
||||
private static final int DEBOUNCE_DELAY_MILLIS = 500;
|
||||
|
||||
@NonNull private final Context mContext;
|
||||
@NonNull private final Handler mHandler;
|
||||
@NonNull private final PowerManager mPowerManager;
|
||||
@NonNull private final AtomicBoolean mIsSideFps;
|
||||
@NonNull private final Supplier<AlertDialog.Builder> mDialogSupplier;
|
||||
@NonNull private final AtomicBoolean mSideFpsEventHandlerReady;
|
||||
|
||||
@Nullable private Dialog mDialog;
|
||||
@NonNull private final DialogInterface.OnDismissListener mDialogDismissListener = (dialog) -> {
|
||||
if (mDialog == dialog) {
|
||||
mDialog = null;
|
||||
}
|
||||
};
|
||||
|
||||
private @FingerprintStateListener.State int mFingerprintState;
|
||||
|
||||
SideFpsEventHandler(Context context, Handler handler, PowerManager powerManager) {
|
||||
this(context, handler, powerManager, () -> new AlertDialog.Builder(context));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
SideFpsEventHandler(Context context, Handler handler, PowerManager powerManager,
|
||||
Supplier<AlertDialog.Builder> dialogSupplier) {
|
||||
mContext = context;
|
||||
mHandler = handler;
|
||||
mPowerManager = powerManager;
|
||||
mDialogSupplier = dialogSupplier;
|
||||
mFingerprintState = STATE_IDLE;
|
||||
mIsSideFps = new AtomicBoolean(false);
|
||||
mSideFpsEventHandlerReady = new AtomicBoolean(false);
|
||||
|
||||
// ensure dialog is dismissed if screen goes off for unrelated reasons
|
||||
context.registerReceiver(new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (mDialog != null) {
|
||||
mDialog.dismiss();
|
||||
mDialog = null;
|
||||
}
|
||||
}
|
||||
}, new IntentFilter(Intent.ACTION_SCREEN_OFF));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from {@link PhoneWindowManager} after power button is pressed. Checks fingerprint
|
||||
* sensor state and if mFingerprintState = STATE_ENROLLING, displays a dialog confirming intent
|
||||
* to turn screen off. If confirmed, the device goes to sleep, and if canceled, the dialog is
|
||||
* dismissed.
|
||||
* Called from {@link PhoneWindowManager} after the power button is pressed and displays a
|
||||
* dialog confirming the user's intent to turn screen off if a fingerprint operation is
|
||||
* active. The device goes to sleep if confirmed otherwise the dialog is dismissed.
|
||||
*
|
||||
* @param eventTime powerPress event time
|
||||
* @return true if powerPress was consumed, false otherwise
|
||||
*/
|
||||
public boolean onSinglePressDetected(long eventTime) {
|
||||
if (!mSideFpsEventHandlerReady.get() || !mIsSideFps.get()
|
||||
|| mFingerprintState != STATE_ENROLLING) {
|
||||
if (!mSideFpsEventHandlerReady.get()) {
|
||||
return false;
|
||||
}
|
||||
mHandler.post(() -> {
|
||||
Dialog confirmScreenOffDialog = new AlertDialog.Builder(mContext)
|
||||
.setTitle(R.string.fp_enrollment_powerbutton_intent_title)
|
||||
.setMessage(R.string.fp_enrollment_powerbutton_intent_message)
|
||||
.setPositiveButton(
|
||||
R.string.fp_enrollment_powerbutton_intent_positive_button,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
mPowerManager.goToSleep(
|
||||
eventTime,
|
||||
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
|
||||
0 /* flags */
|
||||
);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(
|
||||
R.string.fp_enrollment_powerbutton_intent_negative_button,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
})
|
||||
.setCancelable(false)
|
||||
.create();
|
||||
confirmScreenOffDialog.getWindow().setType(
|
||||
WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
|
||||
confirmScreenOffDialog.show();
|
||||
});
|
||||
return true;
|
||||
|
||||
switch (mFingerprintState) {
|
||||
case STATE_ENROLLING:
|
||||
case STATE_BP_AUTH:
|
||||
mHandler.post(() -> {
|
||||
if (mDialog != null) {
|
||||
mDialog.dismiss();
|
||||
}
|
||||
mDialog = showConfirmDialog(mDialogSupplier.get(),
|
||||
mPowerManager, eventTime, mFingerprintState, mDialogDismissListener);
|
||||
});
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Dialog showConfirmDialog(@NonNull AlertDialog.Builder dialogBuilder,
|
||||
@NonNull PowerManager powerManager, long eventTime,
|
||||
@FingerprintStateListener.State int fingerprintState,
|
||||
@NonNull DialogInterface.OnDismissListener dismissListener) {
|
||||
final boolean enrolling = fingerprintState == STATE_ENROLLING;
|
||||
final int title = enrolling ? R.string.fp_power_button_enrollment_title
|
||||
: R.string.fp_power_button_bp_title;
|
||||
final int message = enrolling ? R.string.fp_power_button_enrollment_message
|
||||
: R.string.fp_power_button_bp_message;
|
||||
final int positiveText = enrolling ? R.string.fp_power_button_enrollment_positive_button
|
||||
: R.string.fp_power_button_bp_positive_button;
|
||||
final int negativeText = enrolling ? R.string.fp_power_button_enrollment_negative_button
|
||||
: R.string.fp_power_button_bp_negative_button;
|
||||
|
||||
final Dialog confirmScreenOffDialog = dialogBuilder
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(positiveText,
|
||||
(dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
powerManager.goToSleep(
|
||||
eventTime,
|
||||
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
|
||||
0 /* flags */
|
||||
);
|
||||
})
|
||||
.setNegativeButton(negativeText, (dialog, which) -> dialog.dismiss())
|
||||
.setOnDismissListener(dismissListener)
|
||||
.setCancelable(false)
|
||||
.create();
|
||||
confirmScreenOffDialog.getWindow().setType(
|
||||
WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
|
||||
confirmScreenOffDialog.show();
|
||||
|
||||
return confirmScreenOffDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,26 +170,44 @@ public class SideFpsEventHandler {
|
||||
*/
|
||||
public void onFingerprintSensorReady() {
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
if (!pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) return;
|
||||
FingerprintManager fingerprintManager =
|
||||
if (!pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final FingerprintManager fingerprintManager =
|
||||
mContext.getSystemService(FingerprintManager.class);
|
||||
fingerprintManager.addAuthenticatorsRegisteredCallback(
|
||||
new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
|
||||
@Override
|
||||
public void onAllAuthenticatorsRegistered(
|
||||
List<FingerprintSensorPropertiesInternal> sensors) {
|
||||
mIsSideFps.set(fingerprintManager.isPowerbuttonFps());
|
||||
FingerprintStateListener fingerprintStateListener =
|
||||
new FingerprintStateListener() {
|
||||
@Override
|
||||
public void onStateChanged(
|
||||
@FingerprintStateListener.State int newState) {
|
||||
mFingerprintState = newState;
|
||||
}
|
||||
};
|
||||
fingerprintManager.registerFingerprintStateListener(
|
||||
fingerprintStateListener);
|
||||
mSideFpsEventHandlerReady.set(true);
|
||||
if (fingerprintManager.isPowerbuttonFps()) {
|
||||
fingerprintManager.registerFingerprintStateListener(
|
||||
new FingerprintStateListener() {
|
||||
@Nullable private Runnable mStateRunnable = null;
|
||||
|
||||
@Override
|
||||
public void onStateChanged(
|
||||
@FingerprintStateListener.State int newState) {
|
||||
if (mStateRunnable != null) {
|
||||
mHandler.removeCallbacks(mStateRunnable);
|
||||
mStateRunnable = null;
|
||||
}
|
||||
|
||||
// When the user hits the power button the events can
|
||||
// arrive in any order (success auth & power). Add a
|
||||
// damper when moving to idle in case auth is first
|
||||
if (newState == STATE_IDLE) {
|
||||
mStateRunnable = () -> mFingerprintState = newState;
|
||||
mHandler.postDelayed(mStateRunnable,
|
||||
DEBOUNCE_DELAY_MILLIS);
|
||||
} else {
|
||||
mFingerprintState = newState;
|
||||
}
|
||||
}
|
||||
});
|
||||
mSideFpsEventHandlerReady.set(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.policy;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||
import android.hardware.fingerprint.FingerprintStateListener;
|
||||
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
|
||||
import android.os.Handler;
|
||||
import android.os.PowerManager;
|
||||
import android.os.test.TestLooper;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableContext;
|
||||
import android.view.Window;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.Spy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link SideFpsEventHandler}.
|
||||
* <p/>
|
||||
* Run with <code>atest SideFpsEventHandlerTest</code>.
|
||||
*/
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
public class SideFpsEventHandlerTest {
|
||||
|
||||
private static final List<Integer> sAllStates = List.of(
|
||||
FingerprintStateListener.STATE_IDLE,
|
||||
FingerprintStateListener.STATE_ENROLLING,
|
||||
FingerprintStateListener.STATE_KEYGUARD_AUTH,
|
||||
FingerprintStateListener.STATE_BP_AUTH,
|
||||
FingerprintStateListener.STATE_AUTH_OTHER);
|
||||
|
||||
@Rule
|
||||
public TestableContext mContext =
|
||||
new TestableContext(InstrumentationRegistry.getContext(), null);
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
@Mock
|
||||
private FingerprintManager mFingerprintManager;
|
||||
@Spy
|
||||
private AlertDialog.Builder mDialogBuilder = new AlertDialog.Builder(mContext);
|
||||
@Mock
|
||||
private AlertDialog mAlertDialog;
|
||||
@Mock
|
||||
private Window mWindow;
|
||||
|
||||
private TestLooper mLooper = new TestLooper();
|
||||
private SideFpsEventHandler mEventHandler;
|
||||
private FingerprintStateListener mFingerprintStateListener;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mContext.addMockSystemService(PackageManager.class, mPackageManager);
|
||||
mContext.addMockSystemService(FingerprintManager.class, mFingerprintManager);
|
||||
|
||||
when(mDialogBuilder.create()).thenReturn(mAlertDialog);
|
||||
when(mAlertDialog.getWindow()).thenReturn(mWindow);
|
||||
|
||||
mEventHandler = new SideFpsEventHandler(
|
||||
mContext, new Handler(mLooper.getLooper()),
|
||||
mContext.getSystemService(PowerManager.class), () -> mDialogBuilder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoresWithoutFingerprintFeature() {
|
||||
when(mPackageManager.hasSystemFeature(eq(PackageManager.FEATURE_FINGERPRINT)))
|
||||
.thenReturn(false);
|
||||
|
||||
assertThat(mEventHandler.onSinglePressDetected(60L)).isFalse();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog, never()).show();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoresWithoutSfps() throws Exception {
|
||||
setupWithSensor(false /* hasSfps */, true /* initialized */);
|
||||
|
||||
for (int state : sAllStates) {
|
||||
setFingerprintState(state);
|
||||
assertThat(mEventHandler.onSinglePressDetected(200L)).isFalse();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog, never()).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoresWhileWaitingForSfps() throws Exception {
|
||||
setupWithSensor(true /* hasSfps */, false /* initialized */);
|
||||
|
||||
for (int state : sAllStates) {
|
||||
setFingerprintState(state);
|
||||
assertThat(mEventHandler.onSinglePressDetected(400L)).isFalse();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog, never()).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoresWhenIdleOrUnknown() throws Exception {
|
||||
setupWithSensor(true /* hasSfps */, true /* initialized */);
|
||||
|
||||
setFingerprintState(FingerprintStateListener.STATE_IDLE);
|
||||
assertThat(mEventHandler.onSinglePressDetected(80000L)).isFalse();
|
||||
|
||||
setFingerprintState(FingerprintStateListener.STATE_AUTH_OTHER);
|
||||
assertThat(mEventHandler.onSinglePressDetected(90000L)).isFalse();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog, never()).show();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoresOnKeyguard() throws Exception {
|
||||
setupWithSensor(true /* hasSfps */, true /* initialized */);
|
||||
|
||||
setFingerprintState(FingerprintStateListener.STATE_KEYGUARD_AUTH);
|
||||
assertThat(mEventHandler.onSinglePressDetected(80000L)).isFalse();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog, never()).show();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void promptsWhenBPisActive() throws Exception {
|
||||
setupWithSensor(true /* hasSfps */, true /* initialized */);
|
||||
|
||||
setFingerprintState(FingerprintStateListener.STATE_BP_AUTH);
|
||||
assertThat(mEventHandler.onSinglePressDetected(80000L)).isTrue();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog).show();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void promptsWhenEnrolling() throws Exception {
|
||||
setupWithSensor(true /* hasSfps */, true /* initialized */);
|
||||
|
||||
setFingerprintState(FingerprintStateListener.STATE_ENROLLING);
|
||||
assertThat(mEventHandler.onSinglePressDetected(80000L)).isTrue();
|
||||
|
||||
mLooper.dispatchAll();
|
||||
verify(mAlertDialog).show();
|
||||
}
|
||||
|
||||
private void setFingerprintState(@FingerprintStateListener.State int newState) {
|
||||
if (mFingerprintStateListener != null) {
|
||||
mFingerprintStateListener.onStateChanged(newState);
|
||||
mLooper.dispatchAll();
|
||||
}
|
||||
}
|
||||
|
||||
private void setupWithSensor(boolean hasSfps, boolean initialized) throws Exception {
|
||||
when(mPackageManager.hasSystemFeature(eq(PackageManager.FEATURE_FINGERPRINT)))
|
||||
.thenReturn(true);
|
||||
when(mFingerprintManager.isPowerbuttonFps()).thenReturn(hasSfps);
|
||||
mEventHandler.onFingerprintSensorReady();
|
||||
|
||||
ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> fpCallbackCaptor =
|
||||
ArgumentCaptor.forClass(IFingerprintAuthenticatorsRegisteredCallback.class);
|
||||
verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(fpCallbackCaptor.capture());
|
||||
if (initialized) {
|
||||
fpCallbackCaptor.getValue().onAllAuthenticatorsRegistered(
|
||||
List.of(mock(FingerprintSensorPropertiesInternal.class)));
|
||||
if (hasSfps) {
|
||||
ArgumentCaptor<FingerprintStateListener> captor = ArgumentCaptor.forClass(
|
||||
FingerprintStateListener.class);
|
||||
verify(mFingerprintManager).registerFingerprintStateListener(captor.capture());
|
||||
mFingerprintStateListener = captor.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user