Add udfps/ and support a11y for the udfps enroll view.

This CL calls methods in UdfpsEnrollUtils.java to announce a11y
message. Besides, scale factor calculation and UdfpsOverlayParams.java
are removed since they are added in settingslib/.

Test: manually tested on device:
      Turn on talkback and turn this flag on via adb command
      adb shell setprop
        sys.fflag.override.settings_show_udfps_enroll_in_settings true
Bug: 186873966, 260617060
Change-Id: I408ac6a36352aa4bfd4ac1374e3922163dbc2199
diff --git a/res/layout/udfps_enroll_view.xml b/res/layout/udfps_enroll_view.xml
index e1c2152..6bf339b 100644
--- a/res/layout/udfps_enroll_view.xml
+++ b/res/layout/udfps_enroll_view.xml
@@ -20,15 +20,6 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <!-- The layout height/width are placeholders, which will be overwritten by
-         FingerprintSensorPropertiesInternal. -->
-    <View
-        android:id="@+id/udfps_enroll_accessibility_view"
-        android:layout_gravity="center"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:contentDescription="@string/accessibility_fingerprint_label"/>
-
     <ImageView
         android:id="@+id/udfps_enroll_animation_fp_progress_view"
         android:layout_width="match_parent"
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index 139a18f..c9c5b37 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -32,6 +32,7 @@
 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;
@@ -40,7 +41,6 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.FingerprintSensorProperties;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
 import android.os.Bundle;
 import android.os.Process;
@@ -48,10 +48,8 @@
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.text.TextUtils;
-import android.util.DisplayUtils;
 import android.util.FeatureFlagUtils;
 import android.util.Log;
-import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.MotionEvent;
 import android.view.OrientationEventListener;
@@ -77,6 +75,8 @@
 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;
@@ -200,6 +200,7 @@
     private boolean mHaveShownSfpsLeftEdgeLottie;
     private boolean mHaveShownSfpsRightEdgeLottie;
     private boolean mShouldShowLottie;
+    private UdfpsUtils mUdfpsUtils;
 
     private OrientationEventListener mOrientationEventListener;
     private int mPreviousRotation = 0;
@@ -254,6 +255,7 @@
 
         mAccessibilityManager = getSystemService(AccessibilityManager.class);
         mIsAccessibilityEnabled = mAccessibilityManager.isEnabled();
+        mUdfpsUtils = new UdfpsUtils();
 
         final boolean isLayoutRtl = (TextUtils.getLayoutDirectionFromLocale(
                 Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL);
@@ -280,7 +282,9 @@
                     layoutContainer.setLayoutParams(lp);
                     if (FeatureFlagUtils.isEnabled(getApplicationContext(),
                             FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS)) {
-                        layout.addView(addUdfpsEnrollView(props.get(0)));
+                        final UdfpsEnrollView udfpsEnrollView = addUdfpsEnrollView(props.get(0));
+                        layout.addView(udfpsEnrollView);
+                        setOnHoverListener(true, layout, udfpsEnrollView);
                     }
                     setContentView(layout, lp);
                     break;
@@ -293,6 +297,7 @@
                             R.layout.udfps_enroll_enrolling, null, false);
                     if (FeatureFlagUtils.isEnabled(getApplicationContext(),
                             FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS)) {
+                        final UdfpsEnrollView udfpsEnrollView = addUdfpsEnrollView(props.get(0));
                         if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
                             // In the portrait mode, set layout_container's height 0, so it's
                             // always shown at the bottom of the screen.
@@ -307,9 +312,11 @@
                             final ViewGroup.LayoutParams containerLp =
                                     portraitLayoutContainer.getLayoutParams();
                             containerLp.height = 0;
-                            portraitLayoutContainer.addView(addUdfpsEnrollView(props.get(0)));
+                            portraitLayoutContainer.addView(udfpsEnrollView);
+                            setOnHoverListener(false, defaultLayout, udfpsEnrollView);
                         } else if (rotation == Surface.ROTATION_270) {
-                            defaultLayout.addView(addUdfpsEnrollView(props.get(0)));
+                            defaultLayout.addView(udfpsEnrollView);
+                            setOnHoverListener(true, defaultLayout, udfpsEnrollView);
                         }
                     }
 
@@ -1197,17 +1204,7 @@
 
         DisplayInfo displayInfo = new DisplayInfo();
         getDisplay().getDisplayInfo(displayInfo);
-        final Display.Mode maxDisplayMode =
-                DisplayUtils.getMaximumResolutionDisplayMode(displayInfo.supportedModes);
-        final float scaleFactor = android.util.DisplayUtils.getPhysicalPixelDisplaySizeRatio(
-                maxDisplayMode.getPhysicalWidth(), maxDisplayMode.getPhysicalHeight(),
-                displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight());
-        if (scaleFactor == Float.POSITIVE_INFINITY) {
-            mScaleFactor = 1f;
-        } else {
-            mScaleFactor = scaleFactor;
-        }
-
+        mScaleFactor = mUdfpsUtils.getScaleFactor(displayInfo);
         Rect udfpsBounds = udfpsProps.getLocation().getRect();
         udfpsBounds.scale(mScaleFactor);
 
@@ -1217,16 +1214,13 @@
                 displayInfo.getNaturalWidth(), /* right */
                 displayInfo.getNaturalHeight() /* botom */);
 
-        // TODO(b/260617060): Extract this logic into a 3rd party library for both Settings and
-        //  SysUI to depend on.
         UdfpsOverlayParams params = new UdfpsOverlayParams(
                 udfpsBounds,
                 overlayBounds,
                 displayInfo.getNaturalWidth(),
                 displayInfo.getNaturalHeight(),
                 mScaleFactor,
-                displayInfo.rotation,
-                udfpsProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
+                displayInfo.rotation);
 
         udfpsEnrollView.setOverlayParams(params);
 
@@ -1244,6 +1238,31 @@
         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());
+
+            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);
+    }
+
     public static class IconTouchDialog extends InstrumentedDialogFragment {
 
         @Override
diff --git a/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollView.java b/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollView.java
index 3d77f0e..96b49aa 100644
--- a/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollView.java
+++ b/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollView.java
@@ -25,7 +25,6 @@
 import android.util.RotationUtils;
 import android.view.Gravity;
 import android.view.Surface;
-import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -34,11 +33,13 @@
 import androidx.annotation.Nullable;
 
 import com.android.settings.R;
+import com.android.settingslib.udfps.UdfpsOverlayParams;
 
 /**
  * View corresponding with udfps_enroll_view.xml
  */
 public class UdfpsEnrollView extends FrameLayout implements UdfpsEnrollHelper.Listener {
+    private static final String TAG = "UdfpsEnrollView";
     @NonNull
     private final UdfpsEnrollDrawable mFingerprintDrawable;
     @NonNull
@@ -98,12 +99,15 @@
         onFingerDown();
     }
 
-
     @Override
     public void onPointerUp(int sensorId) {
         onFingerUp();
     }
 
+    public UdfpsOverlayParams getOverlayParams() {
+        return mOverlayParams;
+    }
+
     void setOverlayParams(UdfpsOverlayParams params) {
         mOverlayParams = params;
 
@@ -124,7 +128,6 @@
 
     private void onSensorRectUpdated() {
         updateDimensions();
-        updateAccessibilityViewLocation();
 
         // Updates sensor rect in relation to the overlay view
         mSensorRect.set(getPaddingX(), getPaddingY(),
@@ -135,7 +138,7 @@
 
     private void updateDimensions() {
         // Original sensorBounds assume portrait mode.
-        final Rect rotatedBounds = mOverlayParams.getSensorBounds();
+        final Rect rotatedBounds = new Rect(mOverlayParams.getSensorBounds());
         int rotation = mOverlayParams.getRotation();
         if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
             RotationUtils.rotateBounds(
@@ -192,27 +195,14 @@
         setLayoutParams(params);
     }
 
-    private void updateAccessibilityViewLocation() {
-        View fingerprintAccessibilityView = findViewById(R.id.udfps_enroll_accessibility_view);
-        ViewGroup.LayoutParams params = fingerprintAccessibilityView.getLayoutParams();
-        params.width = mOverlayParams.getSensorBounds().width();
-        params.height = mOverlayParams.getSensorBounds().height();
-        fingerprintAccessibilityView.setLayoutParams(params);
-        fingerprintAccessibilityView.requestLayout();
-    }
-
     private void onFingerDown() {
-        if (mOverlayParams.isOptical()) {
-            mFingerprintDrawable.setShouldSkipDraw(true);
-            mFingerprintDrawable.invalidateSelf();
-        }
+        mFingerprintDrawable.setShouldSkipDraw(true);
+        mFingerprintDrawable.invalidateSelf();
     }
 
     private void onFingerUp() {
-        if (mOverlayParams.isOptical()) {
-            mFingerprintDrawable.setShouldSkipDraw(false);
-            mFingerprintDrawable.invalidateSelf();
-        }
+        mFingerprintDrawable.setShouldSkipDraw(false);
+        mFingerprintDrawable.invalidateSelf();
     }
 
     private int getPaddingX() {
diff --git a/src/com/android/settings/biometrics/fingerprint/UdfpsOverlayParams.java b/src/com/android/settings/biometrics/fingerprint/UdfpsOverlayParams.java
deleted file mode 100644
index 9b52ad6..0000000
--- a/src/com/android/settings/biometrics/fingerprint/UdfpsOverlayParams.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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.settings.biometrics.fingerprint;
-
-import android.graphics.Rect;
-
-import androidx.annotation.NonNull;
-
-/**
- * Collection of parameters that define an under-display fingerprint sensor (UDFPS) overlay.
- *
- * [sensorBounds] coordinates of the bounding box around the sensor in natural orientation, in
- * pixels, for the current resolution.
- *
- * [overlayBounds] coordinates of the UI overlay in natural orientation, in pixels, for the current
- * resolution.
- *
- * [naturalDisplayWidth] width of the physical display in natural orientation, in pixels, for the
- * current resolution.
- *
- * [naturalDisplayHeight] height of the physical display in natural orientation, in pixels, for the
- * current resolution.
- *
- * [scaleFactor] ratio of a dimension in the current resolution to the corresponding dimension in
- * the native resolution.
- *
- * [rotation] current rotation of the display.
- */
-public final class UdfpsOverlayParams {
-    @NonNull
-    private final Rect mSensorBounds;
-    @NonNull
-    private final Rect mOverlayBounds;
-    private final int mNaturalDisplayWidth;
-    private final int mNaturalDisplayHeight;
-    private final float mScaleFactor;
-    private final int mRotation;
-    private final boolean mIsOptical;
-
-    public UdfpsOverlayParams(@NonNull Rect sensorBounds, @NonNull Rect overlayBounds,
-            int naturalDisplayWidth, int naturalDisplayHeight, float scaleFactor, int rotation,
-            boolean isOptical) {
-        mSensorBounds = sensorBounds;
-        mOverlayBounds = overlayBounds;
-        mNaturalDisplayWidth = naturalDisplayWidth;
-        mNaturalDisplayHeight = naturalDisplayHeight;
-        mScaleFactor = scaleFactor;
-        mRotation = rotation;
-        mIsOptical = isOptical;
-    }
-
-    @NonNull
-    public Rect getSensorBounds() {
-        return mSensorBounds;
-    }
-
-    @NonNull
-    public Rect getOverlayBounds() {
-        return mOverlayBounds;
-    }
-
-    public int getNaturalDisplayWidth() {
-        return mNaturalDisplayWidth;
-    }
-
-    public int getNaturalDisplayHeight() {
-        return mNaturalDisplayHeight;
-    }
-
-    public float getScaleFactor() {
-        return mScaleFactor;
-    }
-
-    public int getRotation() {
-        return mRotation;
-    }
-
-    public boolean isOptical() {
-        return mIsOptical;
-    }
-}