Merge "Fix pattern rotation header text." into udc-d1-dev
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/applications/specialaccess/notificationaccess/ApprovalPreferenceController.java b/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceController.java
index 0767e65..6bee62c 100644
--- a/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceController.java
+++ b/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceController.java
@@ -81,6 +81,8 @@
         final RestrictedSwitchPreference preference =
                 (RestrictedSwitchPreference) pref;
         final CharSequence label = mPkgInfo.applicationInfo.loadLabel(mPm);
+        final boolean isAllowedCn = mCn.flattenToShortString().length()
+                <= NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH;
         final boolean isEnabled = isServiceEnabled(mCn);
         preference.setChecked(isEnabled);
         preference.setOnPreferenceChangeListener((p, newValue) -> {
@@ -105,7 +107,8 @@
                 return false;
             }
         });
-        preference.updateState(mCn.getPackageName(), mPkgInfo.applicationInfo.uid, isEnabled);
+        preference.updateState(
+                mCn.getPackageName(), mPkgInfo.applicationInfo.uid, isAllowedCn, isEnabled);
     }
 
     public void disable(final ComponentName cn) {
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 9bb563b..dbdb024 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
@@ -1237,30 +1140,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) {
@@ -1270,57 +1150,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/notification/NotificationAccessConfirmationActivity.java b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
index dfe6df2..a6b565a 100644
--- a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
+++ b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
@@ -67,7 +67,9 @@
         mUserId = getIntent().getIntExtra(EXTRA_USER_ID, UserHandle.USER_NULL);
         CharSequence mAppLabel;
 
-        if (mComponentName == null || mComponentName.getPackageName() == null) {
+        if (mComponentName == null || mComponentName.getPackageName() == null
+                || mComponentName.flattenToString().length()
+                > NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH) {
             finish();
             return;
         }
diff --git a/src/com/android/settings/notification/NotificationAccessSettings.java b/src/com/android/settings/notification/NotificationAccessSettings.java
index 369c4f6..e2ef0dd 100644
--- a/src/com/android/settings/notification/NotificationAccessSettings.java
+++ b/src/com/android/settings/notification/NotificationAccessSettings.java
@@ -66,7 +66,6 @@
     private static final String TAG = "NotifAccessSettings";
     static final String ALLOWED_KEY = "allowed";
     static final String NOT_ALLOWED_KEY = "not_allowed";
-    private static final int MAX_CN_LENGTH = 500;
 
     private static final ManagedServiceSettings.Config CONFIG =
             new ManagedServiceSettings.Config.Builder()
@@ -150,7 +149,8 @@
         for (ServiceInfo service : services) {
             final ComponentName cn = new ComponentName(service.packageName, service.name);
             boolean isAllowed = mNm.isNotificationListenerAccessGranted(cn);
-            if (!isAllowed && cn.flattenToString().length() > MAX_CN_LENGTH) {
+            if (!isAllowed && cn.flattenToString().length()
+                    > NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH) {
                 continue;
             }
 
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 e5b283a..0f12d1e 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();
@@ -591,7 +604,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);
 
diff --git a/tests/robotests/src/com/android/settings/notification/NotificationAccessConfirmationActivityTest.java b/tests/robotests/src/com/android/settings/notification/NotificationAccessConfirmationActivityTest.java
new file mode 100644
index 0000000..86631ff
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/NotificationAccessConfirmationActivityTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.notification;
+
+import static com.android.internal.notification.NotificationAccessConfirmationActivityContract.EXTRA_COMPONENT_NAME;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.robolectric.Shadows.shadowOf;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.widget.TextView;
+
+import com.android.settings.R;
+
+import com.google.common.base.Strings;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class NotificationAccessConfirmationActivityTest {
+
+    @Test
+    public void start_showsDialog() {
+        ComponentName cn = new ComponentName("com.example", "com.example.SomeService");
+        installPackage(cn.getPackageName(), "X");
+
+        NotificationAccessConfirmationActivity activity = startActivityWithIntent(cn);
+
+        assertThat(activity.isFinishing()).isFalse();
+        assertThat(getDialogText(activity)).isEqualTo(
+                activity.getString(R.string.notification_listener_security_warning_summary, "X"));
+    }
+
+    @Test
+    public void start_withMissingPackage_finishes() {
+        ComponentName cn = new ComponentName("com.example", "com.example.SomeService");
+
+        NotificationAccessConfirmationActivity activity = startActivityWithIntent(cn);
+
+        assertThat(getDialogText(activity)).isNull();
+        assertThat(activity.isFinishing()).isTrue();
+    }
+
+    @Test
+    public void start_componentNameTooLong_finishes() {
+        ComponentName longCn = new ComponentName("com.example", Strings.repeat("Blah", 150));
+        installPackage(longCn.getPackageName(), "<Unused>");
+
+        NotificationAccessConfirmationActivity activity = startActivityWithIntent(longCn);
+
+        assertThat(getDialogText(activity)).isNull();
+        assertThat(activity.isFinishing()).isTrue();
+    }
+
+    private static NotificationAccessConfirmationActivity startActivityWithIntent(
+            ComponentName cn) {
+        return Robolectric.buildActivity(
+                        NotificationAccessConfirmationActivity.class,
+                        new Intent().putExtra(EXTRA_COMPONENT_NAME, cn))
+                .setup()
+                .get();
+    }
+
+    private static void installPackage(String packageName, String appName) {
+        PackageInfo pi = new PackageInfo();
+        pi.packageName = packageName;
+        pi.applicationInfo = new ApplicationInfo();
+        pi.applicationInfo.packageName = packageName;
+        pi.applicationInfo.name = appName;
+        shadowOf(RuntimeEnvironment.application.getPackageManager()).installPackage(pi);
+    }
+
+    @Nullable
+    private static String getDialogText(Activity activity) {
+        TextView tv = activity.getWindow().findViewById(android.R.id.message);
+        CharSequence text = (tv != null ? tv.getText() : null);
+        return text != null ? text.toString() : null;
+    }
+
+}
diff --git a/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceControllerTest.java
index 249b713..4601a1c 100644
--- a/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceControllerTest.java
@@ -84,6 +84,36 @@
     }
 
     @Test
+    public void updateState_enabled() {
+        when(mAppOpsManager.noteOpNoThrow(anyInt(), anyInt(), anyString())).thenReturn(
+                AppOpsManager.MODE_ALLOWED);
+        when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
+        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(
+                mContext);
+        pref.setAppOps(mAppOpsManager);
+
+        mController.updateState(pref);
+
+        assertThat(pref.isEnabled()).isTrue();
+    }
+
+    @Test
+    public void updateState_invalidCn_disabled() {
+        ComponentName longCn = new ComponentName("com.example.package",
+                com.google.common.base.Strings.repeat("Blah", 150));
+        mController.setCn(longCn);
+        when(mAppOpsManager.noteOpNoThrow(anyInt(), anyInt(), anyString())).thenReturn(
+                AppOpsManager.MODE_ALLOWED);
+        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(
+                mContext);
+        pref.setAppOps(mAppOpsManager);
+
+        mController.updateState(pref);
+
+        assertThat(pref.isEnabled()).isFalse();
+    }
+
+    @Test
     public void updateState_checked() {
         when(mAppOpsManager.noteOpNoThrow(anyInt(), anyInt(), anyString())).thenReturn(
                 AppOpsManager.MODE_ALLOWED);