From 2ca3f3232cd5a05055e39f94d83cf96a05305f52 Mon Sep 17 00:00:00 2001 From: Hao Dong Date: Mon, 15 May 2023 19:34:07 +0000 Subject: [PATCH] Fix Fingerprint enrollment UI when display size is largest. 1. Remove land/udfps_enroll_enrolling and use the default land layout instead. Swap header and content when necessary to avoid overlap. 2. Add UdfpsEnrollEnrollingView.java Test: manual test - 1. Set system display and font size largest 2. Launch fingerprint enrollment and check UI. Test: atest FingerprintEnrollEnrollingTest Bug: 269060514 Bug: 283169056 Change-Id: Ifbe6c92c4213979952f2f89a1cd595c9c4bff6ec Merged-In: Ifbe6c92c4213979952f2f89a1cd595c9c4bff6ec --- res/layout-land/udfps_enroll_enrolling.xml | 101 --------- res/layout/udfps_enroll_enrolling.xml | 4 +- .../biometrics/BiometricEnrollBase.java | 17 +- .../FingerprintEnrollEnrolling.java | 197 ++---------------- .../FingerprintEnrollEnrollingTest.java | 22 +- 5 files changed, 42 insertions(+), 299 deletions(-) delete mode 100644 res/layout-land/udfps_enroll_enrolling.xml diff --git a/res/layout-land/udfps_enroll_enrolling.xml b/res/layout-land/udfps_enroll_enrolling.xml deleted file mode 100644 index 743684fb02e..00000000000 --- a/res/layout-land/udfps_enroll_enrolling.xml +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/layout/udfps_enroll_enrolling.xml b/res/layout/udfps_enroll_enrolling.xml index 05556ffe46c..366a87c4740 100644 --- a/res/layout/udfps_enroll_enrolling.xml +++ b/res/layout/udfps_enroll_enrolling.xml @@ -15,7 +15,7 @@ ~ limitations under the License. --> - - + diff --git a/src/com/android/settings/biometrics/BiometricEnrollBase.java b/src/com/android/settings/biometrics/BiometricEnrollBase.java index 2f852f08b9f..6e110799c46 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollBase.java +++ b/src/com/android/settings/biometrics/BiometricEnrollBase.java @@ -133,6 +133,7 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity { protected long mChallenge; protected boolean mFromSettingsSummary; protected FooterBarMixin mFooterBarMixin; + protected boolean mShouldSetFooterBarBackground = true; @Nullable protected ScreenSizeFoldProvider mScreenSizeFoldProvider; @Nullable @@ -191,12 +192,14 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity { super.onPostCreate(savedInstanceState); initViews(); - @SuppressLint("VisibleForTests") - final LinearLayout buttonContainer = mFooterBarMixin != null - ? mFooterBarMixin.getButtonContainer() - : null; - if (buttonContainer != null) { - buttonContainer.setBackgroundColor(getBackgroundColor()); + if (mShouldSetFooterBarBackground) { + @SuppressLint("VisibleForTests") + final LinearLayout buttonContainer = mFooterBarMixin != null + ? mFooterBarMixin.getButtonContainer() + : null; + if (buttonContainer != null) { + buttonContainer.setBackgroundColor(getBackgroundColor()); + } } } @@ -331,7 +334,7 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity { } @ColorInt - private int getBackgroundColor() { + public int getBackgroundColor() { final ColorStateList stateList = Utils.getColorAttr(this, android.R.attr.windowBackground); return stateList != null ? stateList.getDefaultColor() : Color.TRANSPARENT; } diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java index 9bb563b7a6a..dbdb024973a 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java @@ -32,10 +32,8 @@ import android.content.Intent; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; -import android.graphics.Point; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; -import android.graphics.Rect; import android.graphics.drawable.Animatable2; import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; @@ -48,22 +46,16 @@ import android.os.VibrationAttributes; import android.os.VibrationEffect; import android.os.Vibrator; import android.text.TextUtils; -import android.util.FeatureFlagUtils; import android.util.Log; -import android.view.DisplayInfo; import android.view.MotionEvent; import android.view.OrientationEventListener; import android.view.Surface; import android.view.View; -import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; @@ -79,25 +71,20 @@ import com.android.settings.biometrics.BiometricUtils; import com.android.settings.biometrics.BiometricsEnrollEnrolling; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settingslib.display.DisplayDensityUtils; -import com.android.settingslib.udfps.UdfpsOverlayParams; -import com.android.settingslib.udfps.UdfpsUtils; import com.airbnb.lottie.LottieAnimationView; import com.airbnb.lottie.LottieCompositionFactory; import com.airbnb.lottie.LottieProperty; import com.airbnb.lottie.model.KeyPath; -import com.google.android.setupcompat.template.FooterActionButton; import com.google.android.setupcompat.template.FooterBarMixin; import com.google.android.setupcompat.template.FooterButton; import com.google.android.setupcompat.util.WizardManagerHelper; -import com.google.android.setupdesign.GlifLayout; import com.google.android.setupdesign.template.DescriptionMixin; import com.google.android.setupdesign.template.HeaderMixin; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; -import java.util.Locale; /** * Activity which handles the actual enrolling for fingerprint. @@ -176,8 +163,6 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { @VisibleForTesting @Nullable UdfpsEnrollHelper mUdfpsEnrollHelper; - // TODO(b/260617060): Do not hard-code mScaleFactor, referring to AuthController. - private float mScaleFactor = 1.0f; private ObjectAnimator mProgressAnim; private TextView mErrorText; private Interpolator mFastOutSlowInInterpolator; @@ -206,7 +191,7 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { private boolean mHaveShownSfpsLeftEdgeLottie; private boolean mHaveShownSfpsRightEdgeLottie; private boolean mShouldShowLottie; - private UdfpsUtils mUdfpsUtils; + private ObjectAnimator mHelpAnimation; private OrientationEventListener mOrientationEventListener; @@ -251,88 +236,17 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { mAccessibilityManager = getSystemService(AccessibilityManager.class); mIsAccessibilityEnabled = mAccessibilityManager.isEnabled(); - mUdfpsUtils = new UdfpsUtils(); - final boolean isLayoutRtl = (TextUtils.getLayoutDirectionFromLocale( - Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL); listenOrientationEvent(); if (mCanAssumeUdfps) { - int rotation = getApplicationContext().getDisplay().getRotation(); - final GlifLayout layout = (GlifLayout) getLayoutInflater().inflate( - R.layout.udfps_enroll_enrolling, null, false); - final UdfpsEnrollView udfpsEnrollView = layout.findViewById(R.id.udfps_animation_view); - updateUdfpsEnrollView(udfpsEnrollView, props.get(0)); - switch (rotation) { - case Surface.ROTATION_90: - final View sudContent = layout.findViewById(R.id.sud_layout_content); - if (sudContent != null) { - sudContent.setPadding(sudContent.getPaddingLeft(), 0, - sudContent.getPaddingRight(), sudContent.getPaddingBottom()); - } + final UdfpsEnrollEnrollingView layout = + (UdfpsEnrollEnrollingView) getLayoutInflater().inflate( + R.layout.udfps_enroll_enrolling, null, false); + setUdfpsEnrollHelper(); + layout.initView(props.get(0), mUdfpsEnrollHelper, mAccessibilityManager); - final LinearLayout layoutContainer = layout.findViewById( - R.id.layout_container); - final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.MATCH_PARENT); - - lp.setMarginEnd((int) getResources().getDimension( - R.dimen.rotation_90_enroll_margin_end)); - layoutContainer.setPaddingRelative((int) getResources().getDimension( - R.dimen.rotation_90_enroll_padding_start), 0, isLayoutRtl - ? 0 : (int) getResources().getDimension( - R.dimen.rotation_90_enroll_padding_end), 0); - layoutContainer.setLayoutParams(lp); - - setOnHoverListener(true, layout, udfpsEnrollView); - setContentView(layout, lp); - break; - - case Surface.ROTATION_0: - case Surface.ROTATION_180: - // In the portrait mode, layout_container's height is 0, so it's - // always shown at the bottom of the screen. - final FrameLayout portraitLayoutContainer = layout.findViewById( - R.id.layout_container); - - // In the portrait mode, the title and lottie animation view may - // overlap when title needs three lines, so adding some paddings - // between them, and adjusting the fp progress view here accordingly. - final int layoutLottieAnimationPadding = (int) getResources() - .getDimension(R.dimen.udfps_lottie_padding_top); - portraitLayoutContainer.setPadding(0, - layoutLottieAnimationPadding, 0, 0); - final ImageView progressView = udfpsEnrollView.findViewById( - R.id.udfps_enroll_animation_fp_progress_view); - progressView.setPadding(0, -(layoutLottieAnimationPadding), - 0, layoutLottieAnimationPadding); - final ImageView fingerprintView = udfpsEnrollView.findViewById( - R.id.udfps_enroll_animation_fp_view); - fingerprintView.setPadding(0, -layoutLottieAnimationPadding, - 0, layoutLottieAnimationPadding); - - // TODO(b/260970216) Instead of hiding the description text view, we should - // make the header view scrollable if the text is too long. - // If description text view has overlap with udfps progress view, hide it. - View view = layout.getDescriptionTextView(); - layout.getViewTreeObserver().addOnDrawListener(() -> { - if (view.getVisibility() == View.VISIBLE - && hasOverlap(view, udfpsEnrollView)) { - view.setVisibility(View.GONE); - } - }); - - setOnHoverListener(false, layout, udfpsEnrollView); - setContentView(layout); - break; - - case Surface.ROTATION_270: - default: - setOnHoverListener(true, layout, udfpsEnrollView); - setContentView(layout); - break; - } + setContentView(layout); setDescriptionText(R.string.security_settings_udfps_enroll_start_message); } else if (mCanAssumeSfps) { setContentView(R.layout.sfps_enroll_enrolling); @@ -372,22 +286,11 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { .build() ); - if (FeatureFlagUtils.isEnabled(getApplicationContext(), - FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS)) { - // Remove the space view and make the width of footer button container WRAP_CONTENT - // to avoid hiding the udfps view progress bar bottom. - final LinearLayout buttonContainer = mFooterBarMixin.getButtonContainer(); - View spaceView = null; - for (int i = 0; i < buttonContainer.getChildCount(); i++) { - if (!(buttonContainer.getChildAt(i) instanceof FooterActionButton)) { - spaceView = buttonContainer.getChildAt(i); - break; - } - } - if (spaceView != null) { - spaceView.setVisibility(View.GONE); - buttonContainer.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT; - } + // If it's udfps, set the background color only for secondary button if necessary. + if (mCanAssumeUdfps) { + mShouldSetFooterBarBackground = false; + ((UdfpsEnrollEnrollingView) getLayout()).setSecondaryButtonBackground( + getBackgroundColor()); } final LayerDrawable fingerprintDrawable = mProgressBar != null @@ -1237,30 +1140,7 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { } } - private UdfpsEnrollView updateUdfpsEnrollView(UdfpsEnrollView udfpsEnrollView, - FingerprintSensorPropertiesInternal udfpsProps) { - DisplayInfo displayInfo = new DisplayInfo(); - getDisplay().getDisplayInfo(displayInfo); - mScaleFactor = mUdfpsUtils.getScaleFactor(displayInfo); - Rect udfpsBounds = udfpsProps.getLocation().getRect(); - udfpsBounds.scale(mScaleFactor); - - final Rect overlayBounds = new Rect( - 0, /* left */ - displayInfo.getNaturalHeight() / 2, /* top */ - displayInfo.getNaturalWidth(), /* right */ - displayInfo.getNaturalHeight() /* botom */); - - UdfpsOverlayParams params = new UdfpsOverlayParams( - udfpsBounds, - overlayBounds, - displayInfo.getNaturalWidth(), - displayInfo.getNaturalHeight(), - mScaleFactor, - displayInfo.rotation); - - udfpsEnrollView.setOverlayParams(params); - + private void setUdfpsEnrollHelper() { mUdfpsEnrollHelper = (UdfpsEnrollHelper) getSupportFragmentManager().findFragmentByTag( FingerprintEnrollEnrolling.TAG_UDFPS_HELPER); if (mUdfpsEnrollHelper == null) { @@ -1270,57 +1150,6 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { .add(mUdfpsEnrollHelper, FingerprintEnrollEnrolling.TAG_UDFPS_HELPER) .commitAllowingStateLoss(); } - udfpsEnrollView.setEnrollHelper(mUdfpsEnrollHelper); - - return udfpsEnrollView; - } - - private void setOnHoverListener(boolean isLandscape, GlifLayout enrollLayout, - UdfpsEnrollView udfpsEnrollView) { - if (!mIsAccessibilityEnabled) return; - - final Context context = getApplicationContext(); - final View.OnHoverListener onHoverListener = (v, event) -> { - // Map the touch to portrait mode if the device is in - // landscape mode. - final Point scaledTouch = - mUdfpsUtils.getTouchInNativeCoordinates(event.getPointerId(0), - event, udfpsEnrollView.getOverlayParams()); - - if (mUdfpsUtils.isWithinSensorArea(event.getPointerId(0), event, - udfpsEnrollView.getOverlayParams())) { - return false; - } - - final String theStr = mUdfpsUtils.onTouchOutsideOfSensorArea( - mAccessibilityManager.isTouchExplorationEnabled(), context, - scaledTouch.x, scaledTouch.y, udfpsEnrollView.getOverlayParams()); - if (theStr != null) { - v.announceForAccessibility(theStr); - } - return false; - }; - - enrollLayout.findManagedViewById(isLandscape ? R.id.sud_landscape_content_area - : R.id.sud_layout_content).setOnHoverListener(onHoverListener); - } - - - @VisibleForTesting boolean hasOverlap(View view1, View view2) { - int[] firstPosition = new int[2]; - int[] secondPosition = new int[2]; - - view1.getLocationOnScreen(firstPosition); - view2.getLocationOnScreen(secondPosition); - - // Rect constructor parameters: left, top, right, bottom - Rect rectView1 = new Rect(firstPosition[0], firstPosition[1], - firstPosition[0] + view1.getMeasuredWidth(), - firstPosition[1] + view1.getMeasuredHeight()); - Rect rectView2 = new Rect(secondPosition[0], secondPosition[1], - secondPosition[0] + view2.getMeasuredWidth(), - secondPosition[1] + view2.getMeasuredHeight()); - return rectView1.intersect(rectView2); } public static class IconTouchDialog extends InstrumentedDialogFragment { diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java index e5b283ae185..0f12d1e5023 100644 --- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java @@ -56,6 +56,7 @@ import android.os.Vibrator; import android.view.Display; import android.view.Surface; import android.view.View; +import android.view.accessibility.AccessibilityManager; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @@ -314,11 +315,17 @@ public class FingerprintEnrollEnrollingTest { @Test public void fingerprintUdfpsOverlayEnrollment_descriptionViewGoneWithOverlap() { initializeActivityWithoutCreate(TYPE_UDFPS_OPTICAL); - doReturn(true).when(mActivity).hasOverlap(any(), any()); when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0); createActivity(); - final GlifLayout defaultLayout = spy(mActivity.findViewById(R.id.setup_wizard_layout)); + final UdfpsEnrollEnrollingView defaultLayout = spy( + mActivity.findViewById(R.id.setup_wizard_layout)); + doReturn(true).when(defaultLayout).hasOverlap(any(), any()); + + // Somehow spy doesn't work, and we need to call initView manually. + defaultLayout.initView(mFingerprintManager.getSensorPropertiesInternal().get(0), + mActivity.mUdfpsEnrollHelper, + mActivity.getSystemService(AccessibilityManager.class)); final TextView descriptionTextView = defaultLayout.getDescriptionTextView(); defaultLayout.getViewTreeObserver().dispatchOnDraw(); @@ -328,11 +335,17 @@ public class FingerprintEnrollEnrollingTest { @Test public void fingerprintUdfpsOverlayEnrollment_descriptionViewVisibleWithoutOverlap() { initializeActivityWithoutCreate(TYPE_UDFPS_OPTICAL); - doReturn(false).when(mActivity).hasOverlap(any(), any()); when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0); createActivity(); - final GlifLayout defaultLayout = spy(mActivity.findViewById(R.id.setup_wizard_layout)); + final UdfpsEnrollEnrollingView defaultLayout = spy( + mActivity.findViewById(R.id.setup_wizard_layout)); + doReturn(false).when(defaultLayout).hasOverlap(any(), any()); + + // Somehow spy doesn't work, and we need to call initView manually. + defaultLayout.initView(mFingerprintManager.getSensorPropertiesInternal().get(0), + mActivity.mUdfpsEnrollHelper, + mActivity.getSystemService(AccessibilityManager.class)); final TextView descriptionTextView = defaultLayout.getDescriptionTextView(); defaultLayout.getViewTreeObserver().dispatchOnDraw(); @@ -591,7 +604,6 @@ public class FingerprintEnrollEnrollingTest { mContext = spy(RuntimeEnvironment.application); mActivity = spy(FingerprintEnrollEnrolling.class); - when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props); when(mContext.getDisplay()).thenReturn(mMockDisplay); when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);