Merge "Fix Fingerprint enrollment UI when display size is largest." into udc-qpr-dev am: 6cb1f9401d am: 81587b1864
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Settings/+/23418521
Change-Id: I47013f77ec1436048a41afbba34bdb4eeaa6ac6b
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/res/layout-land/udfps_enroll_enrolling.xml b/res/layout-land/udfps_enroll_enrolling.xml
deleted file mode 100644
index 743684f..0000000
--- a/res/layout-land/udfps_enroll_enrolling.xml
+++ /dev/null
@@ -1,101 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.google.android.setupdesign.GlifLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/setup_wizard_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout="@layout/sud_glif_blank_template"
- style="?attr/fingerprint_layout_theme">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:clipToPadding="false"
- android:clipChildren="false">
-
- <!-- Both texts are kept as separate text views so it doesn't jump around in portrait.
- See layouts/fingerprint_enroll_enrolling_base.xml. -->
- <LinearLayout
- android:id="@+id/layout_container"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="match_parent"
- android:layout_marginStart="?attr/sudMarginStart"
- android:layout_marginEnd="@dimen/enroll_margin_end"
- android:layout_marginBottom="@dimen/sud_content_frame_padding_bottom"
- android:paddingStart="@dimen/enroll_padding_start"
- android:paddingEnd="@dimen/enroll_padding_end"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:orientation="vertical">
-
- <ScrollView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:fillViewport="true">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:clipChildren="false"
- android:clipToPadding="false">
-
- <ImageView
- android:id="@+id/sud_layout_icon"
- style="@style/SudGlifIcon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:scaleType="fitStart"
- android:layout_marginStart="0dp"
- android:layout_marginEnd="0dp"
- android:src="@drawable/ic_lock" />
-
- <TextView
- android:id="@+id/suc_layout_title"
- style="@style/SudGlifHeaderTitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="0dp"
- android:layout_marginEnd="0dp" />
-
- <TextView
- style="@style/SudDescription.Glif"
- android:id="@+id/sud_layout_subtitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
-
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1" />
-
- </LinearLayout>
-
- </ScrollView>
-
- </LinearLayout>
-
- </LinearLayout>
-
- <include layout="@layout/udfps_enroll_view" />
-</com.google.android.setupdesign.GlifLayout>
\ No newline at end of file
diff --git a/res/layout/udfps_enroll_enrolling.xml b/res/layout/udfps_enroll_enrolling.xml
index 05556ff..366a87c 100644
--- a/res/layout/udfps_enroll_enrolling.xml
+++ b/res/layout/udfps_enroll_enrolling.xml
@@ -15,7 +15,7 @@
~ limitations under the License.
-->
-<com.google.android.setupdesign.GlifLayout
+<com.android.settings.biometrics.fingerprint.UdfpsEnrollEnrollingView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
@@ -78,4 +78,4 @@
</LinearLayout>
</LinearLayout>
-</com.google.android.setupdesign.GlifLayout>
+</com.android.settings.biometrics.fingerprint.UdfpsEnrollEnrollingView>
diff --git a/src/com/android/settings/biometrics/BiometricEnrollBase.java b/src/com/android/settings/biometrics/BiometricEnrollBase.java
index 2f852f0..6e11079 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollBase.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollBase.java
@@ -133,6 +133,7 @@
protected long mChallenge;
protected boolean mFromSettingsSummary;
protected FooterBarMixin mFooterBarMixin;
+ protected boolean mShouldSetFooterBarBackground = true;
@Nullable
protected ScreenSizeFoldProvider mScreenSizeFoldProvider;
@Nullable
@@ -191,12 +192,14 @@
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 @@
}
@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 f653942..400a92e 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.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.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.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 @@
@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 @@
private boolean mHaveShownSfpsLeftEdgeLottie;
private boolean mHaveShownSfpsRightEdgeLottie;
private boolean mShouldShowLottie;
- private UdfpsUtils mUdfpsUtils;
+
private ObjectAnimator mHelpAnimation;
private OrientationEventListener mOrientationEventListener;
@@ -251,88 +236,17 @@
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 @@
.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
@@ -1230,30 +1133,7 @@
}
}
- 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) {
@@ -1263,57 +1143,6 @@
.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/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollEnrollingView.java b/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollEnrollingView.java
new file mode 100644
index 0000000..9225c64
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollEnrollingView.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2023 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.settings.biometrics.fingerprint;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.DisplayInfo;
+import android.view.Gravity;
+import android.view.Surface;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityManager;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+
+import androidx.annotation.ColorInt;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settingslib.udfps.UdfpsOverlayParams;
+import com.android.settingslib.udfps.UdfpsUtils;
+
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupdesign.GlifLayout;
+import com.google.android.setupdesign.view.BottomScrollView;
+
+import java.util.Locale;
+
+/**
+ * View for udfps enrolling.
+ */
+public class UdfpsEnrollEnrollingView extends GlifLayout {
+ private final UdfpsUtils mUdfpsUtils;
+ private final Context mContext;
+ // We don't need to listen to onConfigurationChanged() for mRotation here because
+ // FingerprintEnrollEnrolling is always recreated once the configuration is changed.
+ private final int mRotation;
+ private final boolean mIsLandscape;
+ private final boolean mShouldUseReverseLandscape;
+ private UdfpsEnrollView mUdfpsEnrollView;
+ private View mHeaderView;
+ private AccessibilityManager mAccessibilityManager;
+
+
+ public UdfpsEnrollEnrollingView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ mRotation = mContext.getDisplay().getRotation();
+ mIsLandscape = mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270;
+ final boolean isLayoutRtl = (TextUtils.getLayoutDirectionFromLocale(Locale.getDefault())
+ == View.LAYOUT_DIRECTION_RTL);
+ mShouldUseReverseLandscape = (mRotation == Surface.ROTATION_90 && isLayoutRtl)
+ || (mRotation == Surface.ROTATION_270 && !isLayoutRtl);
+
+ mUdfpsUtils = new UdfpsUtils();
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mHeaderView = findViewById(R.id.sud_landscape_header_area);
+ mUdfpsEnrollView = findViewById(R.id.udfps_animation_view);
+ }
+
+ void initView(FingerprintSensorPropertiesInternal udfpsProps,
+ UdfpsEnrollHelper udfpsEnrollHelper,
+ AccessibilityManager accessibilityManager) {
+ mAccessibilityManager = accessibilityManager;
+ initUdfpsEnrollView(mUdfpsEnrollView, udfpsProps, udfpsEnrollHelper);
+
+ if (!mIsLandscape) {
+ adjustPortraitPaddings();
+ } else if (mShouldUseReverseLandscape) {
+ swapHeaderAndContent();
+ }
+ setOnHoverListener();
+ }
+
+ void setSecondaryButtonBackground(@ColorInt int color) {
+ // Set the button background only when the button is not under udfps overlay to avoid UI
+ // overlap.
+ if (!mIsLandscape || mShouldUseReverseLandscape) {
+ return;
+ }
+ final Button secondaryButtonView =
+ getMixin(FooterBarMixin.class).getSecondaryButtonView();
+ secondaryButtonView.setBackgroundColor(color);
+ if (mRotation == Surface.ROTATION_90) {
+ secondaryButtonView.setGravity(Gravity.START);
+ } else {
+ secondaryButtonView.setGravity(Gravity.END);
+ }
+ mHeaderView.post(() -> {
+ secondaryButtonView.setLayoutParams(
+ new LinearLayout.LayoutParams(mHeaderView.getMeasuredWidth(),
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ });
+ }
+
+ private void initUdfpsEnrollView(UdfpsEnrollView udfpsEnrollView,
+ FingerprintSensorPropertiesInternal udfpsProps,
+ UdfpsEnrollHelper udfpsEnrollHelper) {
+ DisplayInfo displayInfo = new DisplayInfo();
+ mContext.getDisplay().getDisplayInfo(displayInfo);
+
+ final float scaleFactor = mUdfpsUtils.getScaleFactor(displayInfo);
+ Rect udfpsBounds = udfpsProps.getLocation().getRect();
+ udfpsBounds.scale(scaleFactor);
+
+ 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(),
+ scaleFactor,
+ displayInfo.rotation);
+
+ udfpsEnrollView.setOverlayParams(params);
+ udfpsEnrollView.setEnrollHelper(udfpsEnrollHelper);
+ }
+
+ private void adjustPortraitPaddings() {
+ // In the portrait mode, layout_container's height is 0, so it's
+ // always shown at the bottom of the screen.
+ final FrameLayout portraitLayoutContainer = 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 = mUdfpsEnrollView.findViewById(
+ R.id.udfps_enroll_animation_fp_progress_view);
+ progressView.setPadding(0, -(layoutLottieAnimationPadding),
+ 0, layoutLottieAnimationPadding);
+ final ImageView fingerprintView = mUdfpsEnrollView.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.
+ final View descView = getDescriptionTextView();
+ getViewTreeObserver().addOnDrawListener(() -> {
+ if (descView.getVisibility() == View.VISIBLE
+ && hasOverlap(descView, mUdfpsEnrollView)) {
+ descView.setVisibility(View.GONE);
+ }
+ });
+ }
+
+ private void setOnHoverListener() {
+ if (!mAccessibilityManager.isEnabled()) return;
+
+ 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, mUdfpsEnrollView.getOverlayParams());
+
+ if (mUdfpsUtils.isWithinSensorArea(event.getPointerId(0), event,
+ mUdfpsEnrollView.getOverlayParams())) {
+ return false;
+ }
+
+ final String theStr = mUdfpsUtils.onTouchOutsideOfSensorArea(
+ mAccessibilityManager.isTouchExplorationEnabled(), mContext,
+ scaledTouch.x, scaledTouch.y, mUdfpsEnrollView.getOverlayParams());
+ if (theStr != null) {
+ v.announceForAccessibility(theStr);
+ }
+ return false;
+ };
+
+ findManagedViewById(mIsLandscape ? R.id.sud_landscape_content_area
+ : R.id.sud_layout_content).setOnHoverListener(onHoverListener);
+ }
+
+ private void swapHeaderAndContent() {
+ // Reverse header and body
+ ViewGroup parentView = (ViewGroup) mHeaderView.getParent();
+ parentView.removeView(mHeaderView);
+ parentView.addView(mHeaderView);
+
+ // Hide scroll indicators
+ BottomScrollView headerScrollView = mHeaderView.findViewById(R.id.sud_header_scroll_view);
+ headerScrollView.setScrollIndicators(0);
+ }
+
+ @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);
+ }
+}
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 959c642..8c84128 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.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 @@
@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 @@
@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();
@@ -578,7 +591,6 @@
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);