Merge "Created a clickable toast for sidefps enrollment" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
fece6e2107
43
core/res/res/layout/side_fps_toast.xml
Normal file
43
core/res/res/layout/side_fps_toast.xml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (C) 2022 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minWidth="350dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:theme="?attr/alertDialogTheme">
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/fp_power_button_enrollment_title"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:paddingLeft="20dp"/>
|
||||||
|
<Space
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"/>
|
||||||
|
<Button
|
||||||
|
android:id="@+id/turn_off_screen"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/fp_power_button_enrollment_button_text"
|
||||||
|
android:paddingRight="20dp"
|
||||||
|
style="?android:attr/buttonBarNegativeButtonStyle"
|
||||||
|
android:maxLines="1"/>
|
||||||
|
</LinearLayout>
|
||||||
@@ -3519,9 +3519,9 @@
|
|||||||
(for side fingerprint) -->
|
(for side fingerprint) -->
|
||||||
<integer name="config_sidefpsPostAuthDowntime">400</integer>
|
<integer name="config_sidefpsPostAuthDowntime">400</integer>
|
||||||
|
|
||||||
<!-- The time (in millis) that a finger tap will wait for a power button
|
<!-- The time (in millis) the clickable toast dialog will last until
|
||||||
before dismissing the power dialog during enrollment(for side fingerprint) -->
|
automatically dismissing. This is currently used in SideFpsEventHandler -->
|
||||||
<integer name="config_sidefpsEnrollPowerPressWindow">300</integer>
|
<integer name="config_sideFpsToastTimeout">3000</integer>
|
||||||
|
|
||||||
<!-- This config is used to force VoiceInteractionService to start on certain low ram devices.
|
<!-- This config is used to force VoiceInteractionService to start on certain low ram devices.
|
||||||
It declares the package name of VoiceInteractionService that should be started. -->
|
It declares the package name of VoiceInteractionService that should be started. -->
|
||||||
|
|||||||
@@ -3568,21 +3568,17 @@
|
|||||||
<!-- [CHAR LIMIT=NONE] Message to show in upgrading dialog when the bulk of the upgrade work is done. -->
|
<!-- [CHAR LIMIT=NONE] Message to show in upgrading dialog when the bulk of the upgrade work is done. -->
|
||||||
<string name="android_upgrading_complete">Finishing boot.</string>
|
<string name="android_upgrading_complete">Finishing boot.</string>
|
||||||
|
|
||||||
<!-- [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_power_button_enrollment_title">Continue setup?</string>
|
|
||||||
|
|
||||||
<!-- [CHAR LIMIT=NONE] Message of dialog shown to confirm device going to sleep if the power
|
<!-- [CHAR LIMIT=NONE] Message of dialog shown to confirm device going to sleep if the power
|
||||||
button is pressed during fingerprint enrollment. -->
|
button is pressed during fingerprint enrollment. -->
|
||||||
<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>
|
<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=40] Title of dialog shown to confirm device going to sleep if the power button
|
||||||
|
is pressed during fingerprint enrollment. -->
|
||||||
|
<string name="fp_power_button_enrollment_title">Tap to turn off screen</string>
|
||||||
|
|
||||||
<!-- [CHAR LIMIT=20] Positive button of dialog shown to confirm device going to sleep if the
|
<!-- [CHAR LIMIT=20] Positive button of dialog shown to confirm device going to sleep if the
|
||||||
power button is pressed during fingerprint enrollment. -->
|
power button is pressed during fingerprint enrollment. -->
|
||||||
<string name="fp_power_button_enrollment_positive_button">Turn off screen</string>
|
<string name="fp_power_button_enrollment_button_text">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_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
|
<!-- [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. -->
|
is pressed during biometric prompt when a side fingerprint sensor is present. -->
|
||||||
|
|||||||
@@ -1853,8 +1853,7 @@
|
|||||||
<java-symbol type="string" name="fp_power_button_bp_negative_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_title" />
|
||||||
<java-symbol type="string" name="fp_power_button_enrollment_message" />
|
<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_button_text" />
|
||||||
<java-symbol type="string" name="fp_power_button_enrollment_negative_button" />
|
|
||||||
<java-symbol type="string" name="global_actions" />
|
<java-symbol type="string" name="global_actions" />
|
||||||
<java-symbol type="string" name="global_action_power_off" />
|
<java-symbol type="string" name="global_action_power_off" />
|
||||||
<java-symbol type="string" name="global_action_power_options" />
|
<java-symbol type="string" name="global_action_power_options" />
|
||||||
@@ -2631,7 +2630,11 @@
|
|||||||
<java-symbol type="integer" name="config_sidefpsBpPowerPressWindow"/>
|
<java-symbol type="integer" name="config_sidefpsBpPowerPressWindow"/>
|
||||||
<java-symbol type="integer" name="config_sidefpsKeyguardPowerPressWindow"/>
|
<java-symbol type="integer" name="config_sidefpsKeyguardPowerPressWindow"/>
|
||||||
<java-symbol type="integer" name="config_sidefpsPostAuthDowntime"/>
|
<java-symbol type="integer" name="config_sidefpsPostAuthDowntime"/>
|
||||||
<java-symbol type="integer" name="config_sidefpsEnrollPowerPressWindow"/>
|
<java-symbol type="integer" name="config_sideFpsToastTimeout"/>
|
||||||
|
|
||||||
|
<!-- Clickable toast used during sidefps enrollment -->
|
||||||
|
<java-symbol type="layout" name="side_fps_toast" />
|
||||||
|
<java-symbol type="id" name="turn_off_screen" />
|
||||||
|
|
||||||
<!-- Face authentication messages -->
|
<!-- Face authentication messages -->
|
||||||
<java-symbol type="string" name="face_recalibrate_notification_name" />
|
<java-symbol type="string" name="face_recalibrate_notification_name" />
|
||||||
|
|||||||
@@ -23,11 +23,8 @@ import static android.hardware.biometrics.BiometricStateListener.STATE_KEYGUARD_
|
|||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
@@ -35,12 +32,11 @@ import android.hardware.biometrics.BiometricStateListener;
|
|||||||
import android.hardware.fingerprint.FingerprintManager;
|
import android.hardware.fingerprint.FingerprintManager;
|
||||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||||
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
|
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.UserHandle;
|
|
||||||
import android.provider.Settings;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.Window;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
import com.android.internal.R;
|
import com.android.internal.R;
|
||||||
@@ -48,49 +44,48 @@ import com.android.internal.annotations.VisibleForTesting;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines behavior for handling interactions between power button events and fingerprint-related
|
* Defines behavior for handling interactions between power button events and fingerprint-related
|
||||||
* operations, for devices where the fingerprint sensor (side fps) lives on the power button.
|
* operations, for devices where the fingerprint sensor (side fps) lives on the power button.
|
||||||
*/
|
*/
|
||||||
public class SideFpsEventHandler {
|
public class SideFpsEventHandler implements View.OnClickListener {
|
||||||
|
|
||||||
private static final int DEBOUNCE_DELAY_MILLIS = 500;
|
private static final int DEBOUNCE_DELAY_MILLIS = 500;
|
||||||
|
|
||||||
private int getTapWaitForPowerDuration(Context context) {
|
|
||||||
int tap = context.getResources().getInteger(
|
|
||||||
R.integer.config_sidefpsEnrollPowerPressWindow);
|
|
||||||
if (Build.isDebuggable()) {
|
|
||||||
tap = Settings.Secure.getIntForUser(context.getContentResolver(),
|
|
||||||
Settings.Secure.FINGERPRINT_SIDE_FPS_ENROLL_TAP_WINDOW, tap,
|
|
||||||
UserHandle.USER_CURRENT);
|
|
||||||
}
|
|
||||||
return tap;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String TAG = "SideFpsEventHandler";
|
private static final String TAG = "SideFpsEventHandler";
|
||||||
|
|
||||||
@NonNull private final Context mContext;
|
@NonNull
|
||||||
@NonNull private final Handler mHandler;
|
private final Context mContext;
|
||||||
@NonNull private final PowerManager mPowerManager;
|
@NonNull
|
||||||
@NonNull private final Supplier<AlertDialog.Builder> mDialogSupplier;
|
private final Handler mHandler;
|
||||||
@NonNull private final AtomicBoolean mSideFpsEventHandlerReady;
|
@NonNull
|
||||||
|
private final PowerManager mPowerManager;
|
||||||
@Nullable private Dialog mDialog;
|
@NonNull
|
||||||
|
private final AtomicBoolean mSideFpsEventHandlerReady;
|
||||||
|
private final int mDismissDialogTimeout;
|
||||||
|
@Nullable
|
||||||
|
private SideFpsToast mDialog;
|
||||||
private final Runnable mTurnOffDialog =
|
private final Runnable mTurnOffDialog =
|
||||||
() -> {
|
() -> {
|
||||||
dismissDialog("mTurnOffDialog");
|
dismissDialog("mTurnOffDialog");
|
||||||
};
|
};
|
||||||
|
|
||||||
@NonNull private final DialogInterface.OnDismissListener mDialogDismissListener;
|
|
||||||
|
|
||||||
private @BiometricStateListener.State int mBiometricState;
|
private @BiometricStateListener.State int mBiometricState;
|
||||||
private final int mTapWaitForPowerDuration;
|
|
||||||
private FingerprintManager mFingerprintManager;
|
private FingerprintManager mFingerprintManager;
|
||||||
|
private DialogProvider mDialogProvider;
|
||||||
|
private long mLastPowerPressTime;
|
||||||
|
|
||||||
SideFpsEventHandler(Context context, Handler handler, PowerManager powerManager) {
|
SideFpsEventHandler(
|
||||||
this(context, handler, powerManager, () -> new AlertDialog.Builder(context));
|
Context context,
|
||||||
|
Handler handler,
|
||||||
|
PowerManager powerManager) {
|
||||||
|
this(context, handler, powerManager, (ctx) -> {
|
||||||
|
SideFpsToast dialog = new SideFpsToast(ctx);
|
||||||
|
dialog.getWindow()
|
||||||
|
.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
|
||||||
|
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
return dialog;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -98,23 +93,13 @@ public class SideFpsEventHandler {
|
|||||||
Context context,
|
Context context,
|
||||||
Handler handler,
|
Handler handler,
|
||||||
PowerManager powerManager,
|
PowerManager powerManager,
|
||||||
Supplier<AlertDialog.Builder> dialogSupplier) {
|
DialogProvider provider) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mHandler = handler;
|
mHandler = handler;
|
||||||
mPowerManager = powerManager;
|
mPowerManager = powerManager;
|
||||||
mDialogSupplier = dialogSupplier;
|
|
||||||
mBiometricState = STATE_IDLE;
|
mBiometricState = STATE_IDLE;
|
||||||
mSideFpsEventHandlerReady = new AtomicBoolean(false);
|
mSideFpsEventHandlerReady = new AtomicBoolean(false);
|
||||||
mDialogDismissListener =
|
mDialogProvider = provider;
|
||||||
(dialog) -> {
|
|
||||||
if (mDialog == dialog) {
|
|
||||||
if (mHandler != null) {
|
|
||||||
mHandler.removeCallbacks(mTurnOffDialog);
|
|
||||||
}
|
|
||||||
mDialog = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ensure dialog is dismissed if screen goes off for unrelated reasons
|
// ensure dialog is dismissed if screen goes off for unrelated reasons
|
||||||
context.registerReceiver(
|
context.registerReceiver(
|
||||||
new BroadcastReceiver() {
|
new BroadcastReceiver() {
|
||||||
@@ -127,7 +112,13 @@ public class SideFpsEventHandler {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
new IntentFilter(Intent.ACTION_SCREEN_OFF));
|
new IntentFilter(Intent.ACTION_SCREEN_OFF));
|
||||||
mTapWaitForPowerDuration = getTapWaitForPowerDuration(context);
|
mDismissDialogTimeout = context.getResources().getInteger(
|
||||||
|
R.integer.config_sideFpsToastTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
goToSleep(mLastPowerPressTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -165,8 +156,9 @@ public class SideFpsEventHandler {
|
|||||||
Log.v(TAG, "Detected a tap to turn off dialog, ignoring");
|
Log.v(TAG, "Detected a tap to turn off dialog, ignoring");
|
||||||
mHandler.removeCallbacks(mTurnOffDialog);
|
mHandler.removeCallbacks(mTurnOffDialog);
|
||||||
}
|
}
|
||||||
|
showDialog(eventTime, "Enroll Power Press");
|
||||||
|
mHandler.postDelayed(mTurnOffDialog, mDismissDialogTimeout);
|
||||||
});
|
});
|
||||||
showDialog(eventTime, "Enroll Power Press");
|
|
||||||
return true;
|
return true;
|
||||||
case STATE_BP_AUTH:
|
case STATE_BP_AUTH:
|
||||||
return true;
|
return true;
|
||||||
@@ -176,54 +168,11 @@ public class SideFpsEventHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
private void goToSleep(long eventTime) {
|
||||||
private static Dialog showConfirmDialog(
|
mPowerManager.goToSleep(
|
||||||
@NonNull AlertDialog.Builder dialogBuilder,
|
eventTime,
|
||||||
@NonNull PowerManager powerManager,
|
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
|
||||||
long eventTime,
|
0 /* flags */);
|
||||||
@BiometricStateListener.State int biometricState,
|
|
||||||
@NonNull DialogInterface.OnDismissListener dismissListener) {
|
|
||||||
final boolean enrolling = biometricState == 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -247,7 +196,8 @@ public class SideFpsEventHandler {
|
|||||||
if (fingerprintManager.isPowerbuttonFps()) {
|
if (fingerprintManager.isPowerbuttonFps()) {
|
||||||
fingerprintManager.registerBiometricStateListener(
|
fingerprintManager.registerBiometricStateListener(
|
||||||
new BiometricStateListener() {
|
new BiometricStateListener() {
|
||||||
@Nullable private Runnable mStateRunnable = null;
|
@Nullable
|
||||||
|
private Runnable mStateRunnable = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStateChanged(
|
public void onStateChanged(
|
||||||
@@ -281,13 +231,6 @@ public class SideFpsEventHandler {
|
|||||||
public void onBiometricAction(
|
public void onBiometricAction(
|
||||||
@BiometricStateListener.Action int action) {
|
@BiometricStateListener.Action int action) {
|
||||||
Log.d(TAG, "onBiometricAction " + action);
|
Log.d(TAG, "onBiometricAction " + action);
|
||||||
switch (action) {
|
|
||||||
case BiometricStateListener.ACTION_SENSOR_TOUCH:
|
|
||||||
mHandler.postDelayed(
|
|
||||||
mTurnOffDialog,
|
|
||||||
mTapWaitForPowerDuration);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mSideFpsEventHandlerReady.set(true);
|
mSideFpsEventHandlerReady.set(true);
|
||||||
@@ -309,12 +252,13 @@ public class SideFpsEventHandler {
|
|||||||
Log.d(TAG, "Ignoring show dialog");
|
Log.d(TAG, "Ignoring show dialog");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mDialog =
|
mDialog = mDialogProvider.provideDialog(mContext);
|
||||||
showConfirmDialog(
|
mLastPowerPressTime = time;
|
||||||
mDialogSupplier.get(),
|
mDialog.show();
|
||||||
mPowerManager,
|
mDialog.setOnClickListener(this);
|
||||||
time,
|
|
||||||
mBiometricState,
|
|
||||||
mDialogDismissListener);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
interface DialogProvider {
|
||||||
|
SideFpsToast provideDialog(Context context);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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 android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.Window;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.widget.Button;
|
||||||
|
|
||||||
|
import com.android.internal.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toast for side fps. This is typically shown during enrollment
|
||||||
|
* when a user presses the power button.
|
||||||
|
*
|
||||||
|
* This dialog is used by {@link SideFpsEventHandler}
|
||||||
|
*/
|
||||||
|
public class SideFpsToast extends Dialog {
|
||||||
|
|
||||||
|
SideFpsToast(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.side_fps_toast);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
final Window window = this.getWindow();
|
||||||
|
WindowManager.LayoutParams windowParams = window.getAttributes();
|
||||||
|
windowParams.dimAmount = 0;
|
||||||
|
windowParams.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
|
||||||
|
windowParams.gravity = Gravity.BOTTOM;
|
||||||
|
window.setAttributes(windowParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the onClickListener for the toast dialog.
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
public void setOnClickListener(View.OnClickListener listener) {
|
||||||
|
final Button turnOffScreen = findViewById(R.id.turn_off_screen);
|
||||||
|
if (turnOffScreen != null) {
|
||||||
|
turnOffScreen.setOnClickListener(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,6 @@ import static org.mockito.Mockito.never;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.hardware.biometrics.BiometricStateListener;
|
import android.hardware.biometrics.BiometricStateListener;
|
||||||
import android.hardware.fingerprint.FingerprintManager;
|
import android.hardware.fingerprint.FingerprintManager;
|
||||||
@@ -36,10 +35,13 @@ import android.os.test.TestLooper;
|
|||||||
import android.test.suitebuilder.annotation.SmallTest;
|
import android.test.suitebuilder.annotation.SmallTest;
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
import android.testing.TestableContext;
|
import android.testing.TestableContext;
|
||||||
|
import android.testing.TestableResources;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
|
|
||||||
import androidx.test.InstrumentationRegistry;
|
import androidx.test.InstrumentationRegistry;
|
||||||
|
|
||||||
|
import com.android.internal.R;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -47,7 +49,6 @@ import org.junit.runner.RunWith;
|
|||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.mockito.Spy;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -68,17 +69,22 @@ public class SideFpsEventHandlerTest {
|
|||||||
BiometricStateListener.STATE_BP_AUTH,
|
BiometricStateListener.STATE_BP_AUTH,
|
||||||
BiometricStateListener.STATE_AUTH_OTHER);
|
BiometricStateListener.STATE_AUTH_OTHER);
|
||||||
|
|
||||||
|
private static final Integer AUTO_DISMISS_DIALOG = 500;
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public TestableContext mContext =
|
public TestableContext mContext =
|
||||||
new TestableContext(InstrumentationRegistry.getContext(), null);
|
new TestableContext(InstrumentationRegistry.getContext(), null);
|
||||||
|
|
||||||
@Mock private PackageManager mPackageManager;
|
@Mock
|
||||||
@Mock private FingerprintManager mFingerprintManager;
|
private PackageManager mPackageManager;
|
||||||
@Spy private AlertDialog.Builder mDialogBuilder = new AlertDialog.Builder(mContext);
|
@Mock
|
||||||
@Mock private AlertDialog mAlertDialog;
|
private FingerprintManager mFingerprintManager;
|
||||||
@Mock private Window mWindow;
|
@Mock
|
||||||
|
private SideFpsToast mDialog;
|
||||||
|
@Mock
|
||||||
|
private Window mWindow;
|
||||||
|
|
||||||
private TestLooper mLooper = new TestLooper();
|
private final TestLooper mLooper = new TestLooper();
|
||||||
private SideFpsEventHandler mEventHandler;
|
private SideFpsEventHandler mEventHandler;
|
||||||
private BiometricStateListener mBiometricStateListener;
|
private BiometricStateListener mBiometricStateListener;
|
||||||
|
|
||||||
@@ -88,16 +94,17 @@ public class SideFpsEventHandlerTest {
|
|||||||
|
|
||||||
mContext.addMockSystemService(PackageManager.class, mPackageManager);
|
mContext.addMockSystemService(PackageManager.class, mPackageManager);
|
||||||
mContext.addMockSystemService(FingerprintManager.class, mFingerprintManager);
|
mContext.addMockSystemService(FingerprintManager.class, mFingerprintManager);
|
||||||
|
TestableResources resources = mContext.getOrCreateTestableResources();
|
||||||
|
resources.addOverride(R.integer.config_sideFpsToastTimeout, AUTO_DISMISS_DIALOG);
|
||||||
|
|
||||||
when(mDialogBuilder.create()).thenReturn(mAlertDialog);
|
when(mDialog.getWindow()).thenReturn(mWindow);
|
||||||
when(mAlertDialog.getWindow()).thenReturn(mWindow);
|
|
||||||
|
|
||||||
mEventHandler =
|
mEventHandler =
|
||||||
new SideFpsEventHandler(
|
new SideFpsEventHandler(
|
||||||
mContext,
|
mContext,
|
||||||
new Handler(mLooper.getLooper()),
|
new Handler(mLooper.getLooper()),
|
||||||
mContext.getSystemService(PowerManager.class),
|
mContext.getSystemService(PowerManager.class),
|
||||||
() -> mDialogBuilder);
|
(ctx) -> mDialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -108,7 +115,7 @@ public class SideFpsEventHandlerTest {
|
|||||||
assertThat(mEventHandler.shouldConsumeSinglePress(60L)).isFalse();
|
assertThat(mEventHandler.shouldConsumeSinglePress(60L)).isFalse();
|
||||||
|
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
verify(mAlertDialog, never()).show();
|
verify(mDialog, never()).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -120,7 +127,7 @@ public class SideFpsEventHandlerTest {
|
|||||||
assertThat(mEventHandler.shouldConsumeSinglePress(200L)).isFalse();
|
assertThat(mEventHandler.shouldConsumeSinglePress(200L)).isFalse();
|
||||||
|
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
verify(mAlertDialog, never()).show();
|
verify(mDialog, never()).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +140,7 @@ public class SideFpsEventHandlerTest {
|
|||||||
assertThat(mEventHandler.shouldConsumeSinglePress(400L)).isFalse();
|
assertThat(mEventHandler.shouldConsumeSinglePress(400L)).isFalse();
|
||||||
|
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
verify(mAlertDialog, never()).show();
|
verify(mDialog, never()).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +155,7 @@ public class SideFpsEventHandlerTest {
|
|||||||
assertThat(mEventHandler.shouldConsumeSinglePress(90000L)).isFalse();
|
assertThat(mEventHandler.shouldConsumeSinglePress(90000L)).isFalse();
|
||||||
|
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
verify(mAlertDialog, never()).show();
|
verify(mDialog, never()).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -159,18 +166,18 @@ public class SideFpsEventHandlerTest {
|
|||||||
assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isFalse();
|
assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isFalse();
|
||||||
|
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
verify(mAlertDialog, never()).show();
|
verify(mDialog, never()).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void promptsWhenBPisActive() throws Exception {
|
public void doesNotpromptWhenBPisActive() throws Exception {
|
||||||
setupWithSensor(true /* hasSideFps */, true /* initialized */);
|
setupWithSensor(true /* hasSideFps */, true /* initialized */);
|
||||||
|
|
||||||
setBiometricState(BiometricStateListener.STATE_BP_AUTH);
|
setBiometricState(BiometricStateListener.STATE_BP_AUTH);
|
||||||
assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
|
assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
|
||||||
|
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
verify(mAlertDialog, never()).show();
|
verify(mDialog, never()).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -181,57 +188,40 @@ public class SideFpsEventHandlerTest {
|
|||||||
assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
|
assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
|
||||||
|
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
verify(mAlertDialog).show();
|
verify(mDialog).show();
|
||||||
verify(mAlertDialog, never()).dismiss();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void dismissesDialogOnTouchWhenEnrolling() throws Exception {
|
public void dialogDismissesAfterTime() throws Exception {
|
||||||
setupWithSensor(true /* hasSfps */, true /* initialized */);
|
setupWithSensor(true /* hasSfps */, true /* initialized */);
|
||||||
|
|
||||||
setBiometricState(BiometricStateListener.STATE_ENROLLING);
|
setBiometricState(BiometricStateListener.STATE_ENROLLING);
|
||||||
when(mAlertDialog.isShowing()).thenReturn(true);
|
when(mDialog.isShowing()).thenReturn(true);
|
||||||
assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
|
assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
|
||||||
|
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
verify(mAlertDialog).show();
|
verify(mDialog).show();
|
||||||
|
mLooper.moveTimeForward(AUTO_DISMISS_DIALOG);
|
||||||
mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH);
|
|
||||||
mLooper.moveTimeForward(10000);
|
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
|
verify(mDialog).dismiss();
|
||||||
verify(mAlertDialog).dismiss();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void dismissesDialogFailsWhenPowerPressedAndDialogShowing() throws Exception {
|
public void dialogDoesNotDismissOnSensorTouch() throws Exception {
|
||||||
setupWithSensor(true /* hasSfps */, true /* initialized */);
|
setupWithSensor(true /* hasSfps */, true /* initialized */);
|
||||||
|
|
||||||
setBiometricState(BiometricStateListener.STATE_ENROLLING);
|
setBiometricState(BiometricStateListener.STATE_ENROLLING);
|
||||||
when(mAlertDialog.isShowing()).thenReturn(true);
|
when(mDialog.isShowing()).thenReturn(true);
|
||||||
assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
|
assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
|
||||||
|
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
verify(mAlertDialog).show();
|
verify(mDialog).show();
|
||||||
|
|
||||||
mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH);
|
mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH);
|
||||||
assertThat(mEventHandler.shouldConsumeSinglePress(60L)).isTrue();
|
mLooper.moveTimeForward(AUTO_DISMISS_DIALOG - 1);
|
||||||
|
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
verify(mAlertDialog, never()).dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
verify(mDialog, never()).dismiss();
|
||||||
public void showDialogAfterTap() throws Exception {
|
|
||||||
setupWithSensor(true /* hasSfps */, true /* initialized */);
|
|
||||||
|
|
||||||
setBiometricState(BiometricStateListener.STATE_ENROLLING);
|
|
||||||
when(mAlertDialog.isShowing()).thenReturn(true);
|
|
||||||
mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH);
|
|
||||||
assertThat(mEventHandler.shouldConsumeSinglePress(60L)).isTrue();
|
|
||||||
|
|
||||||
mLooper.dispatchAll();
|
|
||||||
verify(mAlertDialog).show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setBiometricState(@BiometricStateListener.State int newState) {
|
private void setBiometricState(@BiometricStateListener.State int newState) {
|
||||||
|
|||||||
Reference in New Issue
Block a user