Merge "Fix double tap Translucent Letterboxed Activities" into tm-qpr-dev
diff --git a/core/java/com/android/internal/jank/TEST_MAPPING b/core/java/com/android/internal/jank/TEST_MAPPING
new file mode 100644
index 0000000..4e00ff1
--- /dev/null
+++ b/core/java/com/android/internal/jank/TEST_MAPPING
@@ -0,0 +1,22 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksCoreTests",
+      "options": [
+        {
+          "include-filter": "com.android.internal.jank"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ],
+      "file_patterns": [
+        "core/java/com/android/internal/jank/.*",
+        "core/tests/coretests/src/com/android/internal/jank/.*"
+      ]
+    }
+  ]
+}
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 14a6d5e..d3f9e0a 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -16,6 +16,27 @@
 
 import static android.os.Trace.TRACE_TAG_APP;
 
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TURN_ON_SCREEN;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_UDFPS_ILLUMINATE;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_USER_SWITCH;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__UNKNOWN_ACTION;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -30,6 +51,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.EventLogTags;
 import com.android.internal.os.BackgroundThread;
 
@@ -103,14 +125,14 @@
     public static final int ACTION_START_RECENTS_ANIMATION = 8;
 
     /**
-     * Time it takes the sensor to detect rotation.
-     */
-    public static final int ACTION_ROTATE_SCREEN_SENSOR = 9;
-
-    /**
      * Time it takes to for the camera based algorithm to rotate the screen.
      */
-    public static final int ACTION_ROTATE_SCREEN_CAMERA_CHECK = 10;
+    public static final int ACTION_ROTATE_SCREEN_CAMERA_CHECK = 9;
+
+    /**
+     * Time it takes the sensor to detect rotation.
+     */
+    public static final int ACTION_ROTATE_SCREEN_SENSOR = 10;
 
     /**
      * Time it takes to start unlock animation .
@@ -143,9 +165,14 @@
     public static final int ACTION_LOAD_SHARE_SHEET = 16;
 
     /**
+     * Time it takes for showing the selection toolbar.
+     */
+    public static final int ACTION_SHOW_SELECTION_TOOLBAR = 17;
+
+    /**
      * Time it takes to show AOD display after folding the device.
      */
-    public static final int ACTION_FOLD_TO_AOD = 17;
+    public static final int ACTION_FOLD_TO_AOD = 18;
 
     private static final int[] ACTIONS_ALL = {
         ACTION_EXPAND_PANEL,
@@ -157,14 +184,15 @@
         ACTION_ROTATE_SCREEN,
         ACTION_FACE_WAKE_AND_UNLOCK,
         ACTION_START_RECENTS_ANIMATION,
-        ACTION_ROTATE_SCREEN_SENSOR,
         ACTION_ROTATE_SCREEN_CAMERA_CHECK,
+        ACTION_ROTATE_SCREEN_SENSOR,
         ACTION_LOCKSCREEN_UNLOCK,
         ACTION_USER_SWITCH,
         ACTION_SWITCH_DISPLAY_UNFOLD,
         ACTION_UDFPS_ILLUMINATE,
         ACTION_SHOW_BACK_ARROW,
         ACTION_LOAD_SHARE_SHEET,
+        ACTION_SHOW_SELECTION_TOOLBAR,
         ACTION_FOLD_TO_AOD,
     };
 
@@ -179,39 +207,42 @@
         ACTION_ROTATE_SCREEN,
         ACTION_FACE_WAKE_AND_UNLOCK,
         ACTION_START_RECENTS_ANIMATION,
-        ACTION_ROTATE_SCREEN_SENSOR,
         ACTION_ROTATE_SCREEN_CAMERA_CHECK,
+        ACTION_ROTATE_SCREEN_SENSOR,
         ACTION_LOCKSCREEN_UNLOCK,
         ACTION_USER_SWITCH,
         ACTION_SWITCH_DISPLAY_UNFOLD,
         ACTION_UDFPS_ILLUMINATE,
         ACTION_SHOW_BACK_ARROW,
         ACTION_LOAD_SHARE_SHEET,
-        ACTION_FOLD_TO_AOD
+        ACTION_SHOW_SELECTION_TOOLBAR,
+        ACTION_FOLD_TO_AOD,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Action {
     }
 
-    private static final int[] STATSD_ACTION = new int[]{
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TURN_ON_SCREEN,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_USER_SWITCH,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_UDFPS_ILLUMINATE,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD
+    @VisibleForTesting
+    public static final int[] STATSD_ACTION = new int[] {
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_TURN_ON_SCREEN,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_USER_SWITCH,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_UDFPS_ILLUMINATE,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD,
     };
 
     private static LatencyTracker sLatencyTracker;
@@ -269,43 +300,45 @@
     public static String getNameOfAction(int atomsProtoAction) {
         // Defined in AtomsProto.java
         switch (atomsProtoAction) {
-            case 0:
+            case UIACTION_LATENCY_REPORTED__ACTION__UNKNOWN_ACTION:
                 return "UNKNOWN";
-            case 1:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL:
                 return "ACTION_EXPAND_PANEL";
-            case 2:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS:
                 return "ACTION_TOGGLE_RECENTS";
-            case 3:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK:
                 return "ACTION_FINGERPRINT_WAKE_AND_UNLOCK";
-            case 4:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL:
                 return "ACTION_CHECK_CREDENTIAL";
-            case 5:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED:
                 return "ACTION_CHECK_CREDENTIAL_UNLOCKED";
-            case 6:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_TURN_ON_SCREEN:
                 return "ACTION_TURN_ON_SCREEN";
-            case 7:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN:
                 return "ACTION_ROTATE_SCREEN";
-            case 8:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK:
                 return "ACTION_FACE_WAKE_AND_UNLOCK";
-            case 9:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION:
                 return "ACTION_START_RECENTS_ANIMATION";
-            case 10:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK:
                 return "ACTION_ROTATE_SCREEN_CAMERA_CHECK";
-            case 11:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR:
                 return "ACTION_ROTATE_SCREEN_SENSOR";
-            case 12:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK:
                 return "ACTION_LOCKSCREEN_UNLOCK";
-            case 13:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_USER_SWITCH:
                 return "ACTION_USER_SWITCH";
-            case 14:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD:
                 return "ACTION_SWITCH_DISPLAY_UNFOLD";
-            case 15:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_UDFPS_ILLUMINATE:
                 return "ACTION_UDFPS_ILLUMINATE";
-            case 16:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW:
                 return "ACTION_SHOW_BACK_ARROW";
-            case 17:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET:
                 return "ACTION_LOAD_SHARE_SHEET";
-            case 19:
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR:
+                return "ACTION_SHOW_SELECTION_TOOLBAR";
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD:
                 return "ACTION_FOLD_TO_AOD";
             default:
                 throw new IllegalArgumentException("Invalid action");
diff --git a/core/java/com/android/internal/util/TEST_MAPPING b/core/java/com/android/internal/util/TEST_MAPPING
index 5881c51..7970dd8 100644
--- a/core/java/com/android/internal/util/TEST_MAPPING
+++ b/core/java/com/android/internal/util/TEST_MAPPING
@@ -1,7 +1,22 @@
 {
   "presubmit": [
     {
-       "name": "ScreenshotHelperTests"
+      "name": "ScreenshotHelperTests"
+    },
+    {
+      "name": "FrameworksCoreTests",
+      "options": [
+        {
+          "include-filter": "com.android.internal.util.LatencyTrackerTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ],
+      "file_patterns": ["LatencyTracker.java"]
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index f24c666..88aa4de 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2937,13 +2937,14 @@
 
     for (const auto &audioProfile : audioProfiles) {
         jobject jAudioProfile;
-        jStatus = convertAudioProfileFromNative(env, &jAudioProfile, &audioProfile, false);
-        if (jStatus == AUDIO_JAVA_BAD_VALUE) {
+        jint jConvertProfileStatus = convertAudioProfileFromNative(
+                                        env, &jAudioProfile, &audioProfile, false);
+        if (jConvertProfileStatus == AUDIO_JAVA_BAD_VALUE) {
             // skipping Java layer unsupported audio formats
             continue;
         }
-        if (jStatus != AUDIO_JAVA_SUCCESS) {
-            return jStatus;
+        if (jConvertProfileStatus != AUDIO_JAVA_SUCCESS) {
+            return jConvertProfileStatus;
         }
         env->CallBooleanMethod(jAudioProfilesList, gArrayListMethods.add, jAudioProfile);
         env->DeleteLocalRef(jAudioProfile);
diff --git a/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java b/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java
index ddc05e0..7338c3a 100644
--- a/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java
@@ -204,19 +204,6 @@
         assertEquals(100, Color.alpha(bitmap.getPixel(50, 50)));
     }
 
-    @Test
-    public void testSetBounds() throws Exception {
-        mIconDrawable = new AdaptiveIconDrawable(mBackgroundDrawable, mForegroundDrawable);
-        mIconDrawable.setBounds(0, 0, 100, 100);
-
-        assertEquals(new Rect(-25, -25, 125, 125), mBackgroundDrawable.getBounds());
-        assertEquals(new Rect(-25, -25, 125, 125), mForegroundDrawable.getBounds());
-
-        mIconDrawable.setBounds(10, 10, 110, 110);
-        assertEquals(new Rect(-15, -15, 135, 135), mBackgroundDrawable.getBounds());
-        assertEquals(new Rect(-15, -15, 135, 135), mForegroundDrawable.getBounds());
-    }
-
     //
     // Utils
     //
diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
index 1519e48..ecb281b 100644
--- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -262,6 +262,8 @@
                         && f.getType() == int.class)
                 .collect(Collectors.toMap(this::getIntFieldChecked, Field::getName));
 
+        assertThat(enumsMap.size() - 1).isEqualTo(cujs.size());
+
         cujs.forEach(f -> {
             final int cuj = getIntFieldChecked(f);
             final String cujName = f.getName();
@@ -279,7 +281,9 @@
                     .that(expectedEnumName.equals(enumName))
                     .isTrue();
             mExpect
-                    .withMessage(formatSimple("getNameOfCuj(%d) not matches %s", cuj, cujName))
+                    .withMessage(
+                            formatSimple("getNameOfCuj(%d) not matches: %s, expected=%s",
+                                    cuj, cujName, expectedNameOfCuj))
                     .that(cujName.equals(expectedNameOfCuj))
                     .isTrue();
         });
diff --git a/core/tests/coretests/src/com/android/internal/util/LatencyTrackerTest.java b/core/tests/coretests/src/com/android/internal/util/LatencyTrackerTest.java
new file mode 100644
index 0000000..e384e69
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/util/LatencyTrackerTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.internal.util;
+
+import static android.text.TextUtils.formatSimple;
+
+import static com.android.internal.util.LatencyTracker.STATSD_ACTION;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import androidx.test.filters.SmallTest;
+
+import com.google.common.truth.Expect;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@SmallTest
+public class LatencyTrackerTest {
+    private static final String ENUM_NAME_PREFIX = "UIACTION_LATENCY_REPORTED__ACTION__";
+
+    @Rule
+    public final Expect mExpect = Expect.create();
+
+    @Test
+    public void testCujsMapToEnumsCorrectly() {
+        List<Field> actions = Arrays.stream(LatencyTracker.class.getDeclaredFields())
+                .filter(f -> f.getName().startsWith("ACTION_")
+                        && Modifier.isStatic(f.getModifiers())
+                        && f.getType() == int.class)
+                .collect(Collectors.toList());
+
+        Map<Integer, String> enumsMap = Arrays.stream(FrameworkStatsLog.class.getDeclaredFields())
+                .filter(f -> f.getName().startsWith(ENUM_NAME_PREFIX)
+                        && Modifier.isStatic(f.getModifiers())
+                        && f.getType() == int.class)
+                .collect(Collectors.toMap(this::getIntFieldChecked, Field::getName));
+
+        assertThat(enumsMap.size() - 1).isEqualTo(actions.size());
+
+        actions.forEach(f -> {
+            final int action = getIntFieldChecked(f);
+            final String actionName = f.getName();
+            final String expectedEnumName = formatSimple("%s%s", ENUM_NAME_PREFIX, actionName);
+            final int enumKey = STATSD_ACTION[action];
+            final String enumName = enumsMap.get(enumKey);
+            final String expectedActionName = LatencyTracker.getNameOfAction(enumKey);
+            mExpect
+                    .withMessage(formatSimple(
+                            "%s (%d) not matches %s (%d)", actionName, action, enumName, enumKey))
+                    .that(expectedEnumName.equals(enumName))
+                    .isTrue();
+            mExpect
+                    .withMessage(
+                            formatSimple("getNameOfAction(%d) not matches: %s, expected=%s",
+                                    enumKey, actionName, expectedActionName))
+                    .that(actionName.equals(expectedActionName))
+                    .isTrue();
+        });
+    }
+
+    @Test
+    public void testCujTypeEnumCorrectlyDefined() throws Exception {
+        List<Field> cujEnumFields =
+                Arrays.stream(LatencyTracker.class.getDeclaredFields())
+                        .filter(field -> field.getName().startsWith("ACTION_")
+                                && Modifier.isStatic(field.getModifiers())
+                                && field.getType() == int.class)
+                        .collect(Collectors.toList());
+
+        HashSet<Integer> allValues = new HashSet<>();
+        for (Field field : cujEnumFields) {
+            int fieldValue = field.getInt(null);
+            assertWithMessage(
+                    "Field %s must have a mapping to a value in STATSD_ACTION",
+                    field.getName())
+                    .that(fieldValue < STATSD_ACTION.length)
+                    .isTrue();
+            assertWithMessage("All CujType values must be unique. Field %s repeats existing value.",
+                    field.getName())
+                    .that(allValues.add(fieldValue))
+                    .isTrue();
+        }
+    }
+
+    private int getIntFieldChecked(Field field) {
+        try {
+            return field.getInt(null);
+        } catch (IllegalAccessException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+}
diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
index 47de37d..688425a 100644
--- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
+++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
@@ -26,6 +26,8 @@
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
 import android.graphics.BlendMode;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -37,6 +39,8 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.graphics.Shader;
+import android.graphics.Shader.TileMode;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.PathParser;
@@ -102,8 +106,7 @@
     private static final float DEFAULT_VIEW_PORT_SCALE = 1f / (1 + 2 * EXTRA_INSET_PERCENTAGE);
 
     /**
-     * Unused path.
-     * TODO: Remove once the layoutLib is updated
+     * Clip path defined in R.string.config_icon_mask.
      */
     private static Path sMask;
 
@@ -111,10 +114,9 @@
      * Scaled mask based on the view bounds.
      */
     private final Path mMask;
-    private final Path mMaskTransformed;
+    private final Path mMaskScaleOnly;
     private final Matrix mMaskMatrix;
     private final Region mTransparentRegion;
-    private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 
     /**
      * Indices used to access {@link #mLayerState.mChildDrawable} array for foreground and
@@ -129,10 +131,19 @@
      */
     LayerState mLayerState;
 
+    private Shader mLayersShader;
+    private Bitmap mLayersBitmap;
+
     private final Rect mTmpOutRect = new Rect();
     private Rect mHotspotBounds;
     private boolean mMutated;
 
+    private boolean mSuspendChildInvalidation;
+    private boolean mChildRequestedInvalidation;
+    private final Canvas mCanvas;
+    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG |
+        Paint.FILTER_BITMAP_FLAG);
+
     /**
      * Constructor used for xml inflation.
      */
@@ -146,16 +157,19 @@
      */
     AdaptiveIconDrawable(@Nullable LayerState state, @Nullable Resources res) {
         mLayerState = createConstantState(state, res);
-        // config_icon_mask from context bound resource may have been changed using
+        // config_icon_mask from context bound resource may have been chaged using
         // OverlayManager. Read that one first.
         Resources r = ActivityThread.currentActivityThread() == null
                 ? Resources.getSystem()
                 : ActivityThread.currentActivityThread().getApplication().getResources();
-        mMask = PathParser.createPathFromPathData(r.getString(R.string.config_icon_mask));
-        mMaskTransformed = new Path();
+        // TODO: either make sMask update only when config_icon_mask changes OR
+        // get rid of it all-together in layoutlib
+        sMask = PathParser.createPathFromPathData(r.getString(R.string.config_icon_mask));
+        mMask = new Path(sMask);
+        mMaskScaleOnly = new Path(mMask);
         mMaskMatrix = new Matrix();
+        mCanvas = new Canvas();
         mTransparentRegion = new Region();
-        mPaint.setColor(Color.BLACK);
     }
 
     private ChildDrawable createChildDrawable(Drawable drawable) {
@@ -266,7 +280,7 @@
      * @return the mask path object used to clip the drawable
      */
     public Path getIconMask() {
-        return mMaskTransformed;
+        return mMask;
     }
 
     /**
@@ -308,47 +322,92 @@
         if (bounds.isEmpty()) {
             return;
         }
-        // Set the child layer bounds bigger than the view port size
-        // by {@link #DEFAULT_VIEW_PORT_SCALE}
-        float cX = bounds.exactCenterX();
-        float cY = bounds.exactCenterY();
-        float insetWidth = bounds.width() / (DEFAULT_VIEW_PORT_SCALE * 2);
-        float insetHeight = bounds.height() / (DEFAULT_VIEW_PORT_SCALE * 2);
-        final Rect outRect = mTmpOutRect;
-        outRect.set(
-                (int) (cX - insetWidth),
-                (int) (cY - insetHeight),
-                (int) (cX + insetWidth),
-                (int) (cY + insetHeight));
+        updateLayerBounds(bounds);
+    }
+
+    private void updateLayerBounds(Rect bounds) {
+        if (bounds.isEmpty()) {
+            return;
+        }
+        try {
+            suspendChildInvalidation();
+            updateLayerBoundsInternal(bounds);
+            updateMaskBoundsInternal(bounds);
+        } finally {
+            resumeChildInvalidation();
+        }
+    }
+
+    /**
+     * Set the child layer bounds bigger than the view port size by {@link #DEFAULT_VIEW_PORT_SCALE}
+     */
+    private void updateLayerBoundsInternal(Rect bounds) {
+        int cX = bounds.width() / 2;
+        int cY = bounds.height() / 2;
 
         for (int i = 0, count = mLayerState.N_CHILDREN; i < count; i++) {
             final ChildDrawable r = mLayerState.mChildren[i];
-            if (r.mDrawable != null) {
-                r.mDrawable.setBounds(outRect);
+            final Drawable d = r.mDrawable;
+            if (d == null) {
+                continue;
             }
+
+            int insetWidth = (int) (bounds.width() / (DEFAULT_VIEW_PORT_SCALE * 2));
+            int insetHeight = (int) (bounds.height() / (DEFAULT_VIEW_PORT_SCALE * 2));
+            final Rect outRect = mTmpOutRect;
+            outRect.set(cX - insetWidth, cY - insetHeight, cX + insetWidth, cY + insetHeight);
+
+            d.setBounds(outRect);
+        }
+    }
+
+    private void updateMaskBoundsInternal(Rect b) {
+        // reset everything that depends on the view bounds
+        mMaskMatrix.setScale(b.width() / MASK_SIZE, b.height() / MASK_SIZE);
+        sMask.transform(mMaskMatrix, mMaskScaleOnly);
+
+        mMaskMatrix.postTranslate(b.left, b.top);
+        sMask.transform(mMaskMatrix, mMask);
+
+        if (mLayersBitmap == null || mLayersBitmap.getWidth() != b.width()
+                || mLayersBitmap.getHeight() != b.height()) {
+            mLayersBitmap = Bitmap.createBitmap(b.width(), b.height(), Bitmap.Config.ARGB_8888);
         }
 
-        // Update the clipping mask
-        mMaskMatrix.setScale(bounds.width() / MASK_SIZE, bounds.height() / MASK_SIZE);
-        mMaskMatrix.postTranslate(bounds.left, bounds.top);
-        mMask.transform(mMaskMatrix, mMaskTransformed);
-
-        // Clear the transparent region, it is calculated lazily
+        mPaint.setShader(null);
         mTransparentRegion.setEmpty();
+        mLayersShader = null;
     }
 
     @Override
     public void draw(Canvas canvas) {
-        int saveCount = canvas.save();
-        canvas.clipPath(mMaskTransformed);
-        canvas.drawPaint(mPaint);
-        if (mLayerState.mChildren[BACKGROUND_ID].mDrawable != null) {
-            mLayerState.mChildren[BACKGROUND_ID].mDrawable.draw(canvas);
+        if (mLayersBitmap == null) {
+            return;
         }
-        if (mLayerState.mChildren[FOREGROUND_ID].mDrawable != null) {
-            mLayerState.mChildren[FOREGROUND_ID].mDrawable.draw(canvas);
+        if (mLayersShader == null) {
+            mCanvas.setBitmap(mLayersBitmap);
+            mCanvas.drawColor(Color.BLACK);
+            if (mLayerState.mChildren[BACKGROUND_ID].mDrawable != null) {
+                mLayerState.mChildren[BACKGROUND_ID].mDrawable.draw(mCanvas);
+            }
+            if (mLayerState.mChildren[FOREGROUND_ID].mDrawable != null) {
+                mLayerState.mChildren[FOREGROUND_ID].mDrawable.draw(mCanvas);
+            }
+            mLayersShader = new BitmapShader(mLayersBitmap, TileMode.CLAMP, TileMode.CLAMP);
+            mPaint.setShader(mLayersShader);
         }
-        canvas.restoreToCount(saveCount);
+        if (mMaskScaleOnly != null) {
+            Rect bounds = getBounds();
+            canvas.translate(bounds.left, bounds.top);
+            canvas.drawPath(mMaskScaleOnly, mPaint);
+            canvas.translate(-bounds.left, -bounds.top);
+        }
+    }
+
+    @Override
+    public void invalidateSelf() {
+        mLayersShader = null;
+        super.invalidateSelf();
     }
 
     @Override
@@ -541,9 +600,37 @@
         return false;
     }
 
+    /**
+     * Temporarily suspends child invalidation.
+     *
+     * @see #resumeChildInvalidation()
+     */
+    private void suspendChildInvalidation() {
+        mSuspendChildInvalidation = true;
+    }
+
+    /**
+     * Resumes child invalidation after suspension, immediately performing an
+     * invalidation if one was requested by a child during suspension.
+     *
+     * @see #suspendChildInvalidation()
+     */
+    private void resumeChildInvalidation() {
+        mSuspendChildInvalidation = false;
+
+        if (mChildRequestedInvalidation) {
+            mChildRequestedInvalidation = false;
+            invalidateSelf();
+        }
+    }
+
     @Override
     public void invalidateDrawable(@NonNull Drawable who) {
-        invalidateSelf();
+        if (mSuspendChildInvalidation) {
+            mChildRequestedInvalidation = true;
+        } else {
+            invalidateSelf();
+        }
     }
 
     @Override
@@ -627,13 +714,6 @@
     @Override
     public void setAlpha(int alpha) {
         mPaint.setAlpha(alpha);
-        final ChildDrawable[] array = mLayerState.mChildren;
-        for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
-            final Drawable dr = array[i].mDrawable;
-            if (dr != null) {
-                dr.setAlpha(alpha);
-            }
-        }
     }
 
     @Override
@@ -736,6 +816,10 @@
             }
         }
 
+        if (changed) {
+            updateLayerBounds(getBounds());
+        }
+
         return changed;
     }
 
@@ -751,6 +835,10 @@
             }
         }
 
+        if (changed) {
+            updateLayerBounds(getBounds());
+        }
+
         return changed;
     }
 
@@ -891,7 +979,6 @@
         int mDensity;
 
         // The density to use when inflating/looking up the children drawables. A value of 0 means
-
         // use the system's density.
         int mSrcDensityOverride = 0;
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index f170e77..1a52d8c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -324,6 +324,19 @@
         return mPipTransitionController;
     }
 
+    /**
+     * Returns true if the PiP window is currently being animated.
+     */
+    public boolean isAnimating() {
+        // TODO(b/183746978) move this to PipAnimationController, and inject that in PipController
+        PipAnimationController.PipTransitionAnimator animator =
+                mPipAnimationController.getCurrentAnimator();
+        if (animator != null && animator.isRunning()) {
+            return true;
+        }
+        return false;
+    }
+
     public Rect getCurrentOrAnimatingBounds() {
         PipAnimationController.PipTransitionAnimator animator =
                 mPipAnimationController.getCurrentAnimator();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
index 6dd02e4..84071e0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
@@ -54,13 +54,8 @@
                 ? pipBoundsAlgorithm.getEntryDestinationBoundsIgnoringKeepClearAreas()
                 : pipBoundsState.getBounds();
         float snapFraction = pipBoundsAlgorithm.getSnapFraction(startingBounds);
-        int verticalGravity;
+        int verticalGravity = Gravity.BOTTOM;
         int horizontalGravity;
-        if (snapFraction < 1.5f || snapFraction >= 3.5f) {
-            verticalGravity = Gravity.NO_GRAVITY;
-        } else {
-            verticalGravity = Gravity.BOTTOM;
-        }
         if (snapFraction >= 0.5f && snapFraction < 2.5f) {
             horizontalGravity = Gravity.RIGHT;
         } else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 3d879b6..bc8191d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -149,7 +149,42 @@
     private final Rect mTmpInsetBounds = new Rect();
     private final int mEnterAnimationDuration;
 
-    private final Runnable mMovePipInResponseToKeepClearAreasChangeCallback;
+    private final Runnable mMovePipInResponseToKeepClearAreasChangeCallback =
+            this::onKeepClearAreasChangedCallback;
+
+    private void onKeepClearAreasChangedCallback() {
+        if (!mEnablePipKeepClearAlgorithm) {
+            // early bail out if the keep clear areas feature is disabled
+            return;
+        }
+        // if there is another animation ongoing, wait for it to finish and try again
+        if (mPipTaskOrganizer.isAnimating()) {
+            mMainExecutor.removeCallbacks(
+                    mMovePipInResponseToKeepClearAreasChangeCallback);
+            mMainExecutor.executeDelayed(
+                    mMovePipInResponseToKeepClearAreasChangeCallback,
+                    PIP_KEEP_CLEAR_AREAS_DELAY);
+            return;
+        }
+        updatePipPositionForKeepClearAreas();
+    }
+
+    private void updatePipPositionForKeepClearAreas() {
+        if (!mEnablePipKeepClearAlgorithm) {
+            // early bail out if the keep clear areas feature is disabled
+            return;
+        }
+        // only move if already in pip, other transitions account for keep clear areas
+        if (mPipTransitionState.hasEnteredPip()) {
+            Rect destBounds = mPipKeepClearAlgorithm.adjust(mPipBoundsState,
+                    mPipBoundsAlgorithm);
+            // only move if the bounds are actually different
+            if (destBounds != mPipBoundsState.getBounds()) {
+                mPipTaskOrganizer.scheduleAnimateResizePip(destBounds,
+                        mEnterAnimationDuration, null);
+            }
+        }
+    }
 
     private boolean mIsInFixedRotation;
     private PipAnimationListener mPinnedStackAnimationRecentsCallback;
@@ -302,6 +337,9 @@
         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
             mPipBoundsState.setImeVisibility(imeVisible, imeHeight);
             mTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight);
+            if (imeVisible) {
+                updatePipPositionForKeepClearAreas();
+            }
         }
 
         @Override
@@ -414,15 +452,6 @@
 
         mEnterAnimationDuration = mContext.getResources()
                 .getInteger(R.integer.config_pipEnterAnimationDuration);
-        mMovePipInResponseToKeepClearAreasChangeCallback = () -> {
-            // only move if already in pip, other transitions account for keep clear areas
-            if (mPipTransitionState.hasEnteredPip()) {
-                Rect destBounds = mPipKeepClearAlgorithm.adjust(mPipBoundsState,
-                        mPipBoundsAlgorithm);
-                mPipTaskOrganizer.scheduleAnimateResizePip(destBounds,
-                        mEnterAnimationDuration, null);
-            }
-        };
         mPipParamsChangedForwarder = pipParamsChangedForwarder;
         mDisplayInsetsController = displayInsetsController;
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 84d9217..1f3f31e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -34,6 +34,7 @@
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
+import android.os.SystemProperties;
 import android.provider.DeviceConfig;
 import android.util.Size;
 import android.view.DisplayCutout;
@@ -70,6 +71,9 @@
     private static final String TAG = "PipTouchHandler";
     private static final float DEFAULT_STASH_VELOCITY_THRESHOLD = 18000.f;
 
+    private static final boolean ENABLE_PIP_KEEP_CLEAR_ALGORITHM =
+            SystemProperties.getBoolean("persist.wm.debug.enable_pip_keep_clear_algorithm", false);
+
     // Allow PIP to resize to a slightly bigger state upon touch
     private boolean mEnableResize;
     private final Context mContext;
@@ -426,6 +430,9 @@
             if (mTouchState.isUserInteracting()) {
                 // Defer the update of the current movement bounds until after the user finishes
                 // touching the screen
+            } else if (ENABLE_PIP_KEEP_CLEAR_ALGORITHM) {
+                // Ignore moving PiP if keep clear algorithm is enabled, since IME and shelf height
+                // now are accounted for in the keep clear algorithm calculations
             } else {
                 final boolean isExpanded = mMenuState == MENU_STATE_FULL && willResizeMenu();
                 final Rect toMovementBounds = new Rect();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 92f37e0..3ba78ef 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -56,6 +56,7 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserManager;
+import android.util.DisplayUtils;
 import android.util.Log;
 import android.util.RotationUtils;
 import android.util.SparseBooleanArray;
@@ -118,8 +119,6 @@
     private final Provider<UdfpsController> mUdfpsControllerFactory;
     private final Provider<SidefpsController> mSidefpsControllerFactory;
 
-    @NonNull private Point mStableDisplaySize = new Point();
-
     private final Display mDisplay;
     private float mScaleFactor = 1f;
     // sensor locations without any resolution scaling nor rotation adjustments:
@@ -508,10 +507,11 @@
      */
     private void updateSensorLocations() {
         mDisplay.getDisplayInfo(mCachedDisplayInfo);
-
+        final Display.Mode maxDisplayMode =
+                DisplayUtils.getMaximumResolutionDisplayMode(mCachedDisplayInfo.supportedModes);
         final float scaleFactor = android.util.DisplayUtils.getPhysicalPixelDisplaySizeRatio(
-                mStableDisplaySize.x, mStableDisplaySize.y, mCachedDisplayInfo.getNaturalWidth(),
-                mCachedDisplayInfo.getNaturalHeight());
+                maxDisplayMode.getPhysicalWidth(), maxDisplayMode.getPhysicalHeight(),
+                mCachedDisplayInfo.getNaturalWidth(), mCachedDisplayInfo.getNaturalHeight());
         if (scaleFactor == Float.POSITIVE_INFINITY) {
             mScaleFactor = 1f;
         } else {
@@ -768,7 +768,6 @@
                     mFingerprintAuthenticatorsRegisteredCallback);
         }
 
-        mStableDisplaySize = mDisplayManager.getStableDisplaySize();
         mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
         mOrientationListener.enable();
         updateSensorLocations();
@@ -1148,7 +1147,6 @@
     @Override
     public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
         final AuthDialog dialog = mCurrentDialog;
-        pw.println("  stableDisplaySize=" + mStableDisplaySize);
         pw.println("  mCachedDisplayInfo=" + mCachedDisplayInfo);
         pw.println("  mScaleFactor=" + mScaleFactor);
         pw.println("  faceAuthSensorLocationDefault=" + mFaceSensorLocationDefault);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 39291ed..4fee083 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -23,7 +23,6 @@
 import android.graphics.Point
 import android.hardware.biometrics.BiometricFingerprintConstants
 import android.hardware.biometrics.BiometricSourceType
-import android.util.Log
 import androidx.annotation.VisibleForTesting
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
@@ -95,7 +94,6 @@
     public override fun onViewAttached() {
         authController.addCallback(authControllerCallback)
         updateRippleColor()
-        updateSensorLocation()
         updateUdfpsDependentParams()
         udfpsController?.addCallback(udfpsControllerCallback)
         configurationController.addCallback(configurationChangedListener)
@@ -237,7 +235,11 @@
     }
 
     private fun showDwellRipple() {
-        mView.startDwellRipple(statusBarStateController.isDozing)
+        updateSensorLocation()
+        fingerprintSensorLocation?.let {
+            mView.setFingerprintSensorLocation(it, udfpsRadius)
+            mView.startDwellRipple(statusBarStateController.isDozing)
+        }
     }
 
     private val keyguardUpdateMonitorCallback =
@@ -291,13 +293,6 @@
     private val udfpsControllerCallback =
         object : UdfpsController.Callback {
             override fun onFingerDown() {
-                if (fingerprintSensorLocation == null) {
-                    Log.e("AuthRipple", "fingerprintSensorLocation=null onFingerDown. " +
-                            "Skip showing dwell ripple")
-                    return
-                }
-
-                mView.setFingerprintSensorLocation(fingerprintSensorLocation!!, udfpsRadius)
                 showDwellRipple()
             }
 
@@ -310,12 +305,10 @@
         object : AuthController.Callback {
             override fun onAllAuthenticatorsRegistered() {
                 updateUdfpsDependentParams()
-                updateSensorLocation()
             }
 
             override fun onUdfpsLocationChanged() {
                 updateUdfpsDependentParams()
-                updateSensorLocation()
             }
         }
 
@@ -345,13 +338,11 @@
                                 "\n\tudfpsRadius=$udfpsRadius")
                     }
                     "fingerprint" -> {
-                        updateSensorLocation()
                         pw.println("fingerprint ripple sensorLocation=$fingerprintSensorLocation")
                         showUnlockRipple(BiometricSourceType.FINGERPRINT)
                     }
                     "face" -> {
                         // note: only shows when about to proceed to the home screen
-                        updateSensorLocation()
                         pw.println("face ripple sensorLocation=$faceSensorLocation")
                         showUnlockRipple(BiometricSourceType.FACE)
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 57bea67..6e4c858 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -24,6 +24,7 @@
 import android.content.ComponentName;
 import android.content.res.Configuration;
 import android.metrics.LogMaker;
+import android.util.Log;
 import android.view.View;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -61,6 +62,7 @@
  */
 public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewController<T>
         implements Dumpable{
+    private static final String TAG = "QSPanelControllerBase";
     protected final QSTileHost mHost;
     private final QSCustomizerController mQsCustomizerController;
     private final boolean mUsingMediaPlayer;
@@ -90,6 +92,13 @@
                 public void onConfigurationChange(Configuration newConfig) {
                     mShouldUseSplitNotificationShade =
                             LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
+                    // Logging to aid the investigation of b/216244185.
+                    Log.d(TAG,
+                            "onConfigurationChange: "
+                                    + "mShouldUseSplitNotificationShade="
+                                    + mShouldUseSplitNotificationShade + ", "
+                                    + "newConfig.windowConfiguration="
+                                    + newConfig.windowConfiguration);
                     mQSLogger.logOnConfigurationChanged(mLastOrientation, newConfig.orientation,
                             mView.getDumpableTag());
                     onConfigurationChanged();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index 44ef922..37bb0c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -18,6 +18,7 @@
 
 import android.graphics.Point
 import android.hardware.biometrics.BiometricSourceType
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import androidx.test.filters.SmallTest
@@ -76,6 +77,7 @@
     @Mock private lateinit var udfpsController: UdfpsController
     @Mock private lateinit var statusBarStateController: StatusBarStateController
     @Mock private lateinit var lightRevealScrim: LightRevealScrim
+    @Mock private lateinit var fpSensorProp: FingerprintSensorPropertiesInternal
 
     @Before
     fun setUp() {
@@ -86,6 +88,7 @@
                 .startMocking()
 
         `when`(RotationUtils.getRotation(context)).thenReturn(RotationUtils.ROTATION_NONE)
+        `when`(authController.udfpsProps).thenReturn(listOf(fpSensorProp))
         `when`(udfpsControllerProvider.get()).thenReturn(udfpsController)
 
         controller = AuthRippleController(
@@ -132,7 +135,7 @@
             false /* isStrongBiometric */)
 
         // THEN update sensor location and show ripple
-        verify(rippleView).setFingerprintSensorLocation(fpsLocation, -1f)
+        verify(rippleView).setFingerprintSensorLocation(fpsLocation, 0f)
         verify(rippleView).startUnlockedRipple(any())
     }
 
@@ -155,7 +158,7 @@
                 false /* isStrongBiometric */)
 
         // THEN update sensor location and show ripple
-        verify(rippleView).setFingerprintSensorLocation(fpsLocation, -1f)
+        verify(rippleView).setFingerprintSensorLocation(fpsLocation, 0f)
         verify(rippleView).startUnlockedRipple(any())
     }
 
@@ -342,4 +345,23 @@
         captor.value.onUiModeChanged()
         verify(rippleView).setLockScreenColor(ArgumentMatchers.anyInt())
     }
+
+    @Test
+    fun testUdfps_onFingerDown_showDwellRipple() {
+        // GIVEN view is already attached
+        controller.onViewAttached()
+        val captor = ArgumentCaptor.forClass(UdfpsController.Callback::class.java)
+        verify(udfpsController).addCallback(captor.capture())
+
+        // GIVEN fp is updated to Point(5, 5)
+        val fpsLocation = Point(5, 5)
+        `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
+
+        // WHEN finger is down
+        captor.value.onFingerDown()
+
+        // THEN update sensor location and show ripple
+        verify(rippleView).setFingerprintSensorLocation(fpsLocation, 0f)
+        verify(rippleView).startDwellRipple(false)
+    }
 }
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index b56654f..a71f51a 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -4593,9 +4593,8 @@
                 final PackageManager pm = mContext.getPackageManager();
                 final String supplementalPackageName = pm.getSdkSandboxPackageName();
                 if (Objects.equals(packageName, supplementalPackageName)) {
-                    int supplementalAppId = pm.getPackageUid(supplementalPackageName,
-                            PackageManager.PackageInfoFlags.of(0));
-                    uid = UserHandle.getUid(UserHandle.getUserId(uid), supplementalAppId);
+                    uid = pm.getPackageUidAsUser(supplementalPackageName,
+                            PackageManager.PackageInfoFlags.of(0), UserHandle.getUserId(uid));
                 }
             } catch (PackageManager.NameNotFoundException e) {
                 // Shouldn't happen for the supplemental package
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b6f8652..c79fe14 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -190,6 +190,9 @@
     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
     private static final long CALLBACK_ON_MORE_ERROR_CODE_CHANGE = 130595455L;
 
+    // Null IMEI anomaly uuid
+    private static final UUID IMEI_ANOMALY_UUID = UUID.fromString(
+            "83905f14-6455-450c-be29-8206f0427fe9");
     /**
      * The key to use when placing the result of {@link #requestModemActivityInfo(ResultReceiver)}
      * into the ResultReceiver Bundle.
@@ -2132,7 +2135,11 @@
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     @RequiresFeature(PackageManager.FEATURE_TELEPHONY_GSM)
     public String getImei() {
-        return getImei(getSlotIndex());
+        String imei = getImei(getSlotIndex());
+        if (imei == null) {
+            AnomalyReporter.reportAnomaly(IMEI_ANOMALY_UUID, "getImei: IMEI is null.");
+        }
+        return imei;
     }
 
     /**
@@ -2175,7 +2182,10 @@
     @RequiresFeature(PackageManager.FEATURE_TELEPHONY_GSM)
     public String getImei(int slotIndex) {
         ITelephony telephony = getITelephony();
-        if (telephony == null) return null;
+        if (telephony == null) {
+            AnomalyReporter.reportAnomaly(IMEI_ANOMALY_UUID, "getImei: telephony is null");
+            return null;
+        }
 
         try {
             return telephony.getImeiForSlot(slotIndex, getOpPackageName(), getAttributionTag());