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

Commit fece6e21 authored by Joshua Mccloskey's avatar Joshua Mccloskey Committed by Android (Google) Code Review
Browse files

Merge "Created a clickable toast for sidefps enrollment" into tm-qpr-dev

parents 65ca888c 3f802c9c
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
<?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>
 No newline at end of file
+3 −3
Original line number Diff line number Diff line
@@ -3519,9 +3519,9 @@
         (for side fingerprint) -->
    <integer name="config_sidefpsPostAuthDowntime">400</integer>

    <!-- The time (in millis) that a finger tap will wait for a power button
         before dismissing the power dialog during enrollment(for side fingerprint) -->
    <integer name="config_sidefpsEnrollPowerPressWindow">300</integer>
    <!-- The time (in millis) the clickable toast dialog will last until
         automatically dismissing. This is currently used in SideFpsEventHandler -->
    <integer name="config_sideFpsToastTimeout">3000</integer>

    <!-- 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. -->
+5 −9
Original line number Diff line number Diff line
@@ -3568,21 +3568,17 @@
    <!-- [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>

    <!-- [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
    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>

    <!-- [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_power_button_enrollment_positive_button">Turn off screen</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] Negative 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. -->
    <string name="fp_power_button_enrollment_negative_button">Continue setup</string>
    <string name="fp_power_button_enrollment_button_text">Turn off screen</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. -->
+6 −3
Original line number Diff line number Diff line
@@ -1853,8 +1853,7 @@
  <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="fp_power_button_enrollment_button_text" />
  <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" />
@@ -2631,7 +2630,11 @@
  <java-symbol type="integer" name="config_sidefpsBpPowerPressWindow"/>
  <java-symbol type="integer" name="config_sidefpsKeyguardPowerPressWindow"/>
  <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 -->
  <java-symbol type="string" name="face_recalibrate_notification_name" />
+54 −110
Original line number Diff line number Diff line
@@ -23,11 +23,8 @@ import static android.hardware.biometrics.BiometricStateListener.STATE_KEYGUARD_

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;
@@ -35,12 +32,11 @@ import android.hardware.biometrics.BiometricStateListener;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.os.Build;
import android.os.Handler;
import android.os.PowerManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

import com.android.internal.R;
@@ -48,49 +44,48 @@ 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 fingerprint-related
 * 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 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";

    @NonNull private final Context mContext;
    @NonNull private final Handler mHandler;
    @NonNull private final PowerManager mPowerManager;
    @NonNull private final Supplier<AlertDialog.Builder> mDialogSupplier;
    @NonNull private final AtomicBoolean mSideFpsEventHandlerReady;

    @Nullable private Dialog mDialog;
    @NonNull
    private final Context mContext;
    @NonNull
    private final Handler mHandler;
    @NonNull
    private final PowerManager mPowerManager;
    @NonNull
    private final AtomicBoolean mSideFpsEventHandlerReady;
    private final int mDismissDialogTimeout;
    @Nullable
    private SideFpsToast mDialog;
    private final Runnable mTurnOffDialog =
            () -> {
                dismissDialog("mTurnOffDialog");
            };

    @NonNull private final DialogInterface.OnDismissListener mDialogDismissListener;

    private @BiometricStateListener.State int mBiometricState;
    private final int mTapWaitForPowerDuration;
    private FingerprintManager mFingerprintManager;
    private DialogProvider mDialogProvider;
    private long mLastPowerPressTime;

    SideFpsEventHandler(Context context, Handler handler, PowerManager powerManager) {
        this(context, handler, powerManager, () -> new AlertDialog.Builder(context));
    SideFpsEventHandler(
            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
@@ -98,23 +93,13 @@ public class SideFpsEventHandler {
            Context context,
            Handler handler,
            PowerManager powerManager,
            Supplier<AlertDialog.Builder> dialogSupplier) {
            DialogProvider provider) {
        mContext = context;
        mHandler = handler;
        mPowerManager = powerManager;
        mDialogSupplier = dialogSupplier;
        mBiometricState = STATE_IDLE;
        mSideFpsEventHandlerReady = new AtomicBoolean(false);
        mDialogDismissListener =
                (dialog) -> {
                    if (mDialog == dialog) {
                        if (mHandler != null) {
                            mHandler.removeCallbacks(mTurnOffDialog);
                        }
                        mDialog = null;
                    }
                };

        mDialogProvider = provider;
        // ensure dialog is dismissed if screen goes off for unrelated reasons
        context.registerReceiver(
                new BroadcastReceiver() {
@@ -127,7 +112,13 @@ public class SideFpsEventHandler {
                    }
                },
                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");
                                mHandler.removeCallbacks(mTurnOffDialog);
                            }
                        });
                            showDialog(eventTime, "Enroll Power Press");
                            mHandler.postDelayed(mTurnOffDialog, mDismissDialogTimeout);
                        });
                return true;
            case STATE_BP_AUTH:
                return true;
@@ -176,54 +168,11 @@ public class SideFpsEventHandler {
        }
    }

    @NonNull
    private static Dialog showConfirmDialog(
            @NonNull AlertDialog.Builder dialogBuilder,
            @NonNull PowerManager powerManager,
            long eventTime,
            @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(
    private void goToSleep(long eventTime) {
        mPowerManager.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()) {
                            fingerprintManager.registerBiometricStateListener(
                                    new BiometricStateListener() {
                                        @Nullable private Runnable mStateRunnable = null;
                                        @Nullable
                                        private Runnable mStateRunnable = null;

                                        @Override
                                        public void onStateChanged(
@@ -281,13 +231,6 @@ public class SideFpsEventHandler {
                                        public void onBiometricAction(
                                                @BiometricStateListener.Action int action) {
                                            Log.d(TAG, "onBiometricAction " + action);
                                            switch (action) {
                                                case BiometricStateListener.ACTION_SENSOR_TOUCH:
                                                    mHandler.postDelayed(
                                                            mTurnOffDialog,
                                                            mTapWaitForPowerDuration);
                                                    break;
                                            }
                                        }
                                    });
                            mSideFpsEventHandlerReady.set(true);
@@ -309,12 +252,13 @@ public class SideFpsEventHandler {
            Log.d(TAG, "Ignoring show dialog");
            return;
        }
        mDialog =
                showConfirmDialog(
                        mDialogSupplier.get(),
                        mPowerManager,
                        time,
                        mBiometricState,
                        mDialogDismissListener);
        mDialog = mDialogProvider.provideDialog(mContext);
        mLastPowerPressTime = time;
        mDialog.show();
        mDialog.setOnClickListener(this);
    }

    interface DialogProvider {
        SideFpsToast provideDialog(Context context);
    }
}
 No newline at end of file
Loading