Loading packages/SystemUI/res/layout/auth_biometric_contents.xml +2 −2 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ <FrameLayout android:id="@+id/biometric_icon_frame" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal"> <ImageView Loading Loading @@ -80,7 +80,7 @@ android:layout_height="88dp" style="?android:attr/buttonBarStyle" android:orientation="horizontal" android:paddingTop="16dp"> android:paddingTop="24dp"> <Space android:id="@+id/leftSpacer" android:layout_width="8dp" Loading packages/SystemUI/res/layout/auth_biometric_face_to_udfps_view.xml 0 → 100644 +25 −0 Original line number Diff line number Diff line <!-- ~ 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. --> <com.android.systemui.biometrics.AuthBiometricFaceToUdfpsView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <include layout="@layout/auth_biometric_contents"/> </com.android.systemui.biometrics.AuthBiometricFaceToUdfpsView> No newline at end of file packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToUdfpsView.java 0 → 100644 +147 −0 Original line number Diff line number Diff line /* * 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.systemui.biometrics; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.util.AttributeSet; import android.util.Log; import android.widget.ImageView; import android.widget.TextView; import com.android.systemui.R; /** * Manages the layout of an auth dialog for devices with a face sensor and an under-display * fingerprint sensor (UDFPS). Face authentication is attempted first, followed by fingerprint if * the initial attempt is unsuccessful. */ public class AuthBiometricFaceToUdfpsView extends AuthBiometricFaceView { private static final String TAG = "BiometricPrompt/AuthBiometricFaceToUdfpsView"; protected static class UdfpsIconController extends IconController { protected UdfpsIconController( @NonNull Context context, @NonNull ImageView iconView, @NonNull TextView textView) { super(context, iconView, textView); } @Override protected void updateState(int lastState, int newState) { final boolean lastStateIsErrorIcon = lastState == STATE_ERROR || lastState == STATE_HELP; switch (newState) { case STATE_IDLE: case STATE_AUTHENTICATING_ANIMATING_IN: case STATE_AUTHENTICATING: case STATE_PENDING_CONFIRMATION: case STATE_AUTHENTICATED: if (lastStateIsErrorIcon) { animateOnce(R.drawable.fingerprint_dialog_error_to_fp); } else { showStaticDrawable(R.drawable.fingerprint_dialog_fp_to_error); } mIconView.setContentDescription(mContext.getString( R.string.accessibility_fingerprint_dialog_fingerprint_icon)); break; case STATE_ERROR: case STATE_HELP: if (!lastStateIsErrorIcon) { animateOnce(R.drawable.fingerprint_dialog_fp_to_error); } else { showStaticDrawable(R.drawable.fingerprint_dialog_error_to_fp); } mIconView.setContentDescription(mContext.getString( R.string.biometric_dialog_try_again)); break; default: Log.e(TAG, "Unknown biometric dialog state: " + newState); break; } mState = newState; } } @BiometricAuthenticator.Modality private int mActiveSensorType = TYPE_FACE; @Nullable UdfpsDialogMeasureAdapter mMeasureAdapter; @Nullable private UdfpsIconController mUdfpsIconController; public AuthBiometricFaceToUdfpsView(Context context) { super(context); } public AuthBiometricFaceToUdfpsView(Context context, AttributeSet attrs) { super(context, attrs); } void setFingerprintSensorProps(@NonNull FingerprintSensorPropertiesInternal sensorProps) { if (mMeasureAdapter == null || mMeasureAdapter.getSensorProps() != sensorProps) { mMeasureAdapter = new UdfpsDialogMeasureAdapter(this, sensorProps); } } @Override protected int getDelayAfterAuthenticatedDurationMs() { return mActiveSensorType == TYPE_FINGERPRINT ? 0 : super.getDelayAfterAuthenticatedDurationMs(); } @Override protected boolean supportsManualRetry() { return false; } @Override @NonNull protected IconController getIconController() { if (mActiveSensorType == TYPE_FINGERPRINT) { if (!(mIconController instanceof UdfpsIconController)) { mIconController = new UdfpsIconController(getContext(), mIconView, mIndicatorView); } return mIconController; } return super.getIconController(); } @Override public void updateState(int newState) { if (mState == STATE_HELP || mState == STATE_ERROR) { mActiveSensorType = TYPE_FINGERPRINT; setRequireConfirmation(false); } super.updateState(newState); } @Override @NonNull AuthDialog.LayoutParams onMeasureInternal(int width, int height) { final AuthDialog.LayoutParams layoutParams = super.onMeasureInternal(width, height); return mMeasureAdapter != null ? mMeasureAdapter.onMeasureInternal(width, height, layoutParams) : layoutParams; } } packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java +32 −23 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.biometrics; import android.annotation.NonNull; import android.content.Context; import android.graphics.drawable.Animatable2; import android.graphics.drawable.AnimatedVectorDrawable; Loading @@ -28,7 +29,6 @@ import android.view.View; import android.widget.ImageView; import android.widget.TextView; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; public class AuthBiometricFaceView extends AuthBiometricView { Loading @@ -38,15 +38,15 @@ public class AuthBiometricFaceView extends AuthBiometricView { // Delay before dismissing after being authenticated/confirmed. private static final int HIDE_DELAY_MS = 500; public static class IconController extends Animatable2.AnimationCallback { Context mContext; ImageView mIconView; TextView mTextView; Handler mHandler; boolean mLastPulseLightToDark; // false = dark to light, true = light to dark @BiometricState int mState; protected static class IconController extends Animatable2.AnimationCallback { protected Context mContext; protected ImageView mIconView; protected TextView mTextView; protected Handler mHandler; protected boolean mLastPulseLightToDark; // false = dark to light, true = light to dark protected @BiometricState int mState; IconController(Context context, ImageView iconView, TextView textView) { protected IconController(Context context, ImageView iconView, TextView textView) { mContext = context; mIconView = iconView; mTextView = textView; Loading @@ -54,15 +54,15 @@ public class AuthBiometricFaceView extends AuthBiometricView { showStaticDrawable(R.drawable.face_dialog_pulse_dark_to_light); } void animateOnce(int iconRes) { protected void animateOnce(int iconRes) { animateIcon(iconRes, false); } public void showStaticDrawable(int iconRes) { protected void showStaticDrawable(int iconRes) { mIconView.setImageDrawable(mContext.getDrawable(iconRes)); } void animateIcon(int iconRes, boolean repeat) { protected void animateIcon(int iconRes, boolean repeat) { final AnimatedVectorDrawable icon = (AnimatedVectorDrawable) mContext.getDrawable(iconRes); mIconView.setImageDrawable(icon); Loading @@ -73,12 +73,12 @@ public class AuthBiometricFaceView extends AuthBiometricView { icon.start(); } void startPulsing() { protected void startPulsing() { mLastPulseLightToDark = false; animateIcon(R.drawable.face_dialog_pulse_dark_to_light, true); } void pulseInNextDirection() { protected void pulseInNextDirection() { int iconRes = mLastPulseLightToDark ? R.drawable.face_dialog_pulse_dark_to_light : R.drawable.face_dialog_pulse_light_to_dark; animateIcon(iconRes, true /* repeat */); Loading @@ -93,7 +93,7 @@ public class AuthBiometricFaceView extends AuthBiometricView { } } public void updateState(int lastState, int newState) { protected void updateState(int lastState, int newState) { final boolean lastStateIsErrorIcon = lastState == STATE_ERROR || lastState == STATE_HELP; Loading Loading @@ -138,7 +138,7 @@ public class AuthBiometricFaceView extends AuthBiometricView { } } @VisibleForTesting IconController mIconController; protected IconController mIconController; public AuthBiometricFaceView(Context context) { this(context, null); Loading Loading @@ -174,14 +174,21 @@ public class AuthBiometricFaceView extends AuthBiometricView { } @Override protected void onFinishInflate() { super.onFinishInflate(); protected boolean supportsManualRetry() { return true; } @NonNull protected IconController getIconController() { if (mIconController == null) { mIconController = new IconController(mContext, mIconView, mIndicatorView); } return mIconController; } @Override public void updateState(@BiometricState int newState) { mIconController.updateState(mState, newState); getIconController().updateState(mState, newState); if (newState == STATE_AUTHENTICATING_ANIMATING_IN || (newState == STATE_AUTHENTICATING && getSize() == AuthDialog.SIZE_MEDIUM)) { Loading @@ -195,11 +202,13 @@ public class AuthBiometricFaceView extends AuthBiometricView { @Override public void onAuthenticationFailed(String failureReason) { if (getSize() == AuthDialog.SIZE_MEDIUM) { if (supportsManualRetry()) { mTryAgainButton.setVisibility(View.VISIBLE); mConfirmButton.setVisibility(View.GONE); } } // Do this last since wa want to know if the button is being animated (in the case of // Do this last since we want to know if the button is being animated (in the case of // small -> medium dialog) super.onAuthenticationFailed(failureReason); } Loading packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java +9 −275 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
packages/SystemUI/res/layout/auth_biometric_contents.xml +2 −2 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ <FrameLayout android:id="@+id/biometric_icon_frame" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal"> <ImageView Loading Loading @@ -80,7 +80,7 @@ android:layout_height="88dp" style="?android:attr/buttonBarStyle" android:orientation="horizontal" android:paddingTop="16dp"> android:paddingTop="24dp"> <Space android:id="@+id/leftSpacer" android:layout_width="8dp" Loading
packages/SystemUI/res/layout/auth_biometric_face_to_udfps_view.xml 0 → 100644 +25 −0 Original line number Diff line number Diff line <!-- ~ 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. --> <com.android.systemui.biometrics.AuthBiometricFaceToUdfpsView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <include layout="@layout/auth_biometric_contents"/> </com.android.systemui.biometrics.AuthBiometricFaceToUdfpsView> No newline at end of file
packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToUdfpsView.java 0 → 100644 +147 −0 Original line number Diff line number Diff line /* * 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.systemui.biometrics; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.util.AttributeSet; import android.util.Log; import android.widget.ImageView; import android.widget.TextView; import com.android.systemui.R; /** * Manages the layout of an auth dialog for devices with a face sensor and an under-display * fingerprint sensor (UDFPS). Face authentication is attempted first, followed by fingerprint if * the initial attempt is unsuccessful. */ public class AuthBiometricFaceToUdfpsView extends AuthBiometricFaceView { private static final String TAG = "BiometricPrompt/AuthBiometricFaceToUdfpsView"; protected static class UdfpsIconController extends IconController { protected UdfpsIconController( @NonNull Context context, @NonNull ImageView iconView, @NonNull TextView textView) { super(context, iconView, textView); } @Override protected void updateState(int lastState, int newState) { final boolean lastStateIsErrorIcon = lastState == STATE_ERROR || lastState == STATE_HELP; switch (newState) { case STATE_IDLE: case STATE_AUTHENTICATING_ANIMATING_IN: case STATE_AUTHENTICATING: case STATE_PENDING_CONFIRMATION: case STATE_AUTHENTICATED: if (lastStateIsErrorIcon) { animateOnce(R.drawable.fingerprint_dialog_error_to_fp); } else { showStaticDrawable(R.drawable.fingerprint_dialog_fp_to_error); } mIconView.setContentDescription(mContext.getString( R.string.accessibility_fingerprint_dialog_fingerprint_icon)); break; case STATE_ERROR: case STATE_HELP: if (!lastStateIsErrorIcon) { animateOnce(R.drawable.fingerprint_dialog_fp_to_error); } else { showStaticDrawable(R.drawable.fingerprint_dialog_error_to_fp); } mIconView.setContentDescription(mContext.getString( R.string.biometric_dialog_try_again)); break; default: Log.e(TAG, "Unknown biometric dialog state: " + newState); break; } mState = newState; } } @BiometricAuthenticator.Modality private int mActiveSensorType = TYPE_FACE; @Nullable UdfpsDialogMeasureAdapter mMeasureAdapter; @Nullable private UdfpsIconController mUdfpsIconController; public AuthBiometricFaceToUdfpsView(Context context) { super(context); } public AuthBiometricFaceToUdfpsView(Context context, AttributeSet attrs) { super(context, attrs); } void setFingerprintSensorProps(@NonNull FingerprintSensorPropertiesInternal sensorProps) { if (mMeasureAdapter == null || mMeasureAdapter.getSensorProps() != sensorProps) { mMeasureAdapter = new UdfpsDialogMeasureAdapter(this, sensorProps); } } @Override protected int getDelayAfterAuthenticatedDurationMs() { return mActiveSensorType == TYPE_FINGERPRINT ? 0 : super.getDelayAfterAuthenticatedDurationMs(); } @Override protected boolean supportsManualRetry() { return false; } @Override @NonNull protected IconController getIconController() { if (mActiveSensorType == TYPE_FINGERPRINT) { if (!(mIconController instanceof UdfpsIconController)) { mIconController = new UdfpsIconController(getContext(), mIconView, mIndicatorView); } return mIconController; } return super.getIconController(); } @Override public void updateState(int newState) { if (mState == STATE_HELP || mState == STATE_ERROR) { mActiveSensorType = TYPE_FINGERPRINT; setRequireConfirmation(false); } super.updateState(newState); } @Override @NonNull AuthDialog.LayoutParams onMeasureInternal(int width, int height) { final AuthDialog.LayoutParams layoutParams = super.onMeasureInternal(width, height); return mMeasureAdapter != null ? mMeasureAdapter.onMeasureInternal(width, height, layoutParams) : layoutParams; } }
packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java +32 −23 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.biometrics; import android.annotation.NonNull; import android.content.Context; import android.graphics.drawable.Animatable2; import android.graphics.drawable.AnimatedVectorDrawable; Loading @@ -28,7 +29,6 @@ import android.view.View; import android.widget.ImageView; import android.widget.TextView; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; public class AuthBiometricFaceView extends AuthBiometricView { Loading @@ -38,15 +38,15 @@ public class AuthBiometricFaceView extends AuthBiometricView { // Delay before dismissing after being authenticated/confirmed. private static final int HIDE_DELAY_MS = 500; public static class IconController extends Animatable2.AnimationCallback { Context mContext; ImageView mIconView; TextView mTextView; Handler mHandler; boolean mLastPulseLightToDark; // false = dark to light, true = light to dark @BiometricState int mState; protected static class IconController extends Animatable2.AnimationCallback { protected Context mContext; protected ImageView mIconView; protected TextView mTextView; protected Handler mHandler; protected boolean mLastPulseLightToDark; // false = dark to light, true = light to dark protected @BiometricState int mState; IconController(Context context, ImageView iconView, TextView textView) { protected IconController(Context context, ImageView iconView, TextView textView) { mContext = context; mIconView = iconView; mTextView = textView; Loading @@ -54,15 +54,15 @@ public class AuthBiometricFaceView extends AuthBiometricView { showStaticDrawable(R.drawable.face_dialog_pulse_dark_to_light); } void animateOnce(int iconRes) { protected void animateOnce(int iconRes) { animateIcon(iconRes, false); } public void showStaticDrawable(int iconRes) { protected void showStaticDrawable(int iconRes) { mIconView.setImageDrawable(mContext.getDrawable(iconRes)); } void animateIcon(int iconRes, boolean repeat) { protected void animateIcon(int iconRes, boolean repeat) { final AnimatedVectorDrawable icon = (AnimatedVectorDrawable) mContext.getDrawable(iconRes); mIconView.setImageDrawable(icon); Loading @@ -73,12 +73,12 @@ public class AuthBiometricFaceView extends AuthBiometricView { icon.start(); } void startPulsing() { protected void startPulsing() { mLastPulseLightToDark = false; animateIcon(R.drawable.face_dialog_pulse_dark_to_light, true); } void pulseInNextDirection() { protected void pulseInNextDirection() { int iconRes = mLastPulseLightToDark ? R.drawable.face_dialog_pulse_dark_to_light : R.drawable.face_dialog_pulse_light_to_dark; animateIcon(iconRes, true /* repeat */); Loading @@ -93,7 +93,7 @@ public class AuthBiometricFaceView extends AuthBiometricView { } } public void updateState(int lastState, int newState) { protected void updateState(int lastState, int newState) { final boolean lastStateIsErrorIcon = lastState == STATE_ERROR || lastState == STATE_HELP; Loading Loading @@ -138,7 +138,7 @@ public class AuthBiometricFaceView extends AuthBiometricView { } } @VisibleForTesting IconController mIconController; protected IconController mIconController; public AuthBiometricFaceView(Context context) { this(context, null); Loading Loading @@ -174,14 +174,21 @@ public class AuthBiometricFaceView extends AuthBiometricView { } @Override protected void onFinishInflate() { super.onFinishInflate(); protected boolean supportsManualRetry() { return true; } @NonNull protected IconController getIconController() { if (mIconController == null) { mIconController = new IconController(mContext, mIconView, mIndicatorView); } return mIconController; } @Override public void updateState(@BiometricState int newState) { mIconController.updateState(mState, newState); getIconController().updateState(mState, newState); if (newState == STATE_AUTHENTICATING_ANIMATING_IN || (newState == STATE_AUTHENTICATING && getSize() == AuthDialog.SIZE_MEDIUM)) { Loading @@ -195,11 +202,13 @@ public class AuthBiometricFaceView extends AuthBiometricView { @Override public void onAuthenticationFailed(String failureReason) { if (getSize() == AuthDialog.SIZE_MEDIUM) { if (supportsManualRetry()) { mTryAgainButton.setVisibility(View.VISIBLE); mConfirmButton.setVisibility(View.GONE); } } // Do this last since wa want to know if the button is being animated (in the case of // Do this last since we want to know if the button is being animated (in the case of // small -> medium dialog) super.onAuthenticationFailed(failureReason); } Loading
packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java +9 −275 File changed.Preview size limit exceeded, changes collapsed. Show changes