Merge "Lint check for new broadcast receiver exported flags."
diff --git a/ProtoLibraries.bp b/ProtoLibraries.bp
index 67acfad..c12f5b4 100644
--- a/ProtoLibraries.bp
+++ b/ProtoLibraries.bp
@@ -35,7 +35,6 @@
         "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
 
     srcs: [
-        ":framework-connectivity-protos",
         ":ipconnectivity-proto-src",
         ":libstats_atom_enum_protos",
         ":libstats_atom_message_protos",
@@ -68,7 +67,6 @@
         "  $(in)",
 
     srcs: [
-        ":framework-connectivity-protos",
         ":ipconnectivity-proto-src",
         ":libstats_atom_enum_protos",
         ":libstats_atom_message_protos",
@@ -84,7 +82,6 @@
 java_library_host {
     name: "platformprotos",
     srcs: [
-        ":framework-connectivity-protos",
         ":ipconnectivity-proto-src",
         ":libstats_atom_enum_protos",
         ":libstats_atom_message_protos",
@@ -124,7 +121,6 @@
     ],
     sdk_version: "9",
     srcs: [
-        ":framework-connectivity-protos",
         ":ipconnectivity-proto-src",
         ":libstats_atom_enum_protos",
         ":libstats_atom_message_protos",
@@ -147,7 +143,6 @@
     },
 
     srcs: [
-        ":framework-connectivity-protos",
         ":ipconnectivity-proto-src",
         ":libstats_atom_enum_protos",
         ":libstats_atom_message_protos",
@@ -185,7 +180,6 @@
     ],
 
     srcs: [
-        ":framework-connectivity-protos",
         ":ipconnectivity-proto-src",
         ":libstats_atom_enum_protos",
         ":libstats_atom_message_protos",
diff --git a/WEAR_OWNERS b/WEAR_OWNERS
new file mode 100644
index 0000000..4f3bc27
--- /dev/null
+++ b/WEAR_OWNERS
@@ -0,0 +1,6 @@
+yzj@google.com
+shreerag@google.com
+yeabkal@google.com
+adsule@google.com
+andriyn@google.com
+yfz@google.com
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index c0a9e67..b6d29aa 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -144,9 +144,9 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.tare.AlarmManagerEconomicPolicy;
 import com.android.server.tare.EconomyManagerInternal;
 import com.android.server.usage.AppStandbyInternal;
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
index 235ce404..12ec9a4 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
@@ -822,37 +822,18 @@
 
     @GuardedBy("mLock")
     void onPackageRemovedLocked(final int userId, @NonNull final String pkgName) {
-        reclaimAssetsLocked(userId, pkgName);
+        mScribe.discardLedgerLocked(userId, pkgName);
+        mCurrentOngoingEvents.delete(userId, pkgName);
         mBalanceThresholdAlarmQueue.removeAlarmForKey(new Package(userId, pkgName));
     }
 
-    /**
-     * Reclaims any ARCs granted to the app, making them available to other apps. Also deletes the
-     * app's ledger and stops any ongoing event tracking.
-     */
     @GuardedBy("mLock")
-    private void reclaimAssetsLocked(final int userId, @NonNull final String pkgName) {
-        final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
-        if (ledger.getCurrentBalance() != 0) {
-            mScribe.adjustRemainingConsumableCakesLocked(-ledger.getCurrentBalance());
-        }
-        mScribe.discardLedgerLocked(userId, pkgName);
-        mCurrentOngoingEvents.delete(userId, pkgName);
-    }
-
-    @GuardedBy("mLock")
-    void onUserRemovedLocked(final int userId, @NonNull final List<String> pkgNames) {
-        reclaimAssetsLocked(userId, pkgNames);
+    void onUserRemovedLocked(final int userId) {
+        mScribe.discardLedgersLocked(userId);
+        mCurrentOngoingEvents.delete(userId);
         mBalanceThresholdAlarmQueue.removeAlarmsForUserId(userId);
     }
 
-    @GuardedBy("mLock")
-    private void reclaimAssetsLocked(final int userId, @NonNull final List<String> pkgNames) {
-        for (int i = 0; i < pkgNames.size(); ++i) {
-            reclaimAssetsLocked(userId, pkgNames.get(i));
-        }
-    }
-
     @VisibleForTesting
     static class TrendCalculator implements Consumer<OngoingEvent> {
         static final long WILL_NOT_CROSS_THRESHOLD = -1;
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
index c10a890..59d4ded 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -578,17 +578,15 @@
     void onUserRemoved(final int userId) {
         synchronized (mLock) {
             mVipOverrides.delete(userId);
-            ArrayList<String> removedPkgs = new ArrayList<>();
             final int uIdx = mPkgCache.indexOfKey(userId);
             if (uIdx >= 0) {
                 for (int p = mPkgCache.numElementsForKeyAt(uIdx) - 1; p >= 0; --p) {
                     final InstalledPackageInfo pkgInfo = mPkgCache.valueAt(uIdx, p);
-                    removedPkgs.add(pkgInfo.packageName);
                     mUidToPackageCache.remove(pkgInfo.uid);
                 }
             }
             mPkgCache.delete(userId);
-            mAgent.onUserRemovedLocked(userId, removedPkgs);
+            mAgent.onUserRemovedLocked(userId);
         }
     }
 
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
index 29478d0..bd4fd72 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
@@ -157,6 +157,12 @@
     }
 
     @GuardedBy("mIrs.getLock()")
+    void discardLedgersLocked(final int userId) {
+        mLedgers.delete(userId);
+        postWrite();
+    }
+
+    @GuardedBy("mIrs.getLock()")
     long getSatiatedConsumptionLimitLocked() {
         return mSatiatedConsumptionLimit;
     }
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index f1c4eb4..67d711c 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -122,7 +122,7 @@
 import com.android.server.AlarmManagerInternal;
 import com.android.server.JobSchedulerBackgroundThread;
 import com.android.server.LocalServices;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.usage.AppIdleHistory.AppUsageHistory;
 
 import libcore.util.EmptyArray;
diff --git a/core/api/current.txt b/core/api/current.txt
index 20d8a26..4d25ad7 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -16896,6 +16896,7 @@
     field public static final int DATASPACE_DEPTH = 4096; // 0x1000
     field public static final int DATASPACE_DISPLAY_P3 = 143261696; // 0x88a0000
     field public static final int DATASPACE_DYNAMIC_DEPTH = 4098; // 0x1002
+    field public static final int DATASPACE_HEIF = 4100; // 0x1004
     field public static final int DATASPACE_JFIF = 146931712; // 0x8c20000
     field public static final int DATASPACE_SCRGB = 411107328; // 0x18810000
     field public static final int DATASPACE_SCRGB_LINEAR = 406913024; // 0x18410000
@@ -53160,7 +53161,9 @@
     method @Nullable public String getFallbackText();
     field public static final int GESTURE_TYPE_DELETE = 4; // 0x4
     field public static final int GESTURE_TYPE_INSERT = 2; // 0x2
+    field public static final int GESTURE_TYPE_JOIN_OR_SPLIT = 16; // 0x10
     field public static final int GESTURE_TYPE_NONE = 0; // 0x0
+    field public static final int GESTURE_TYPE_REMOVE_SPACE = 8; // 0x8
     field public static final int GESTURE_TYPE_SELECT = 1; // 0x1
     field public static final int GRANULARITY_CHARACTER = 2; // 0x2
     field public static final int GRANULARITY_WORD = 1; // 0x1
@@ -53501,6 +53504,35 @@
     method @NonNull public android.view.inputmethod.InsertGesture.Builder setTextToInsert(@NonNull String);
   }
 
+  public final class JoinOrSplitGesture extends android.view.inputmethod.HandwritingGesture implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.graphics.PointF getJoinOrSplitPoint();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.JoinOrSplitGesture> CREATOR;
+  }
+
+  public static final class JoinOrSplitGesture.Builder {
+    ctor public JoinOrSplitGesture.Builder();
+    method @NonNull public android.view.inputmethod.JoinOrSplitGesture build();
+    method @NonNull public android.view.inputmethod.JoinOrSplitGesture.Builder setFallbackText(@Nullable String);
+    method @NonNull public android.view.inputmethod.JoinOrSplitGesture.Builder setJoinOrSplitPoint(@NonNull android.graphics.PointF);
+  }
+
+  public final class RemoveSpaceGesture extends android.view.inputmethod.HandwritingGesture implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.graphics.PointF getEndPoint();
+    method @NonNull public android.graphics.PointF getStartPoint();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.RemoveSpaceGesture> CREATOR;
+  }
+
+  public static final class RemoveSpaceGesture.Builder {
+    ctor public RemoveSpaceGesture.Builder();
+    method @NonNull public android.view.inputmethod.RemoveSpaceGesture build();
+    method @NonNull public android.view.inputmethod.RemoveSpaceGesture.Builder setFallbackText(@Nullable String);
+    method @NonNull public android.view.inputmethod.RemoveSpaceGesture.Builder setPoints(@NonNull android.graphics.PointF, @NonNull android.graphics.PointF);
+  }
+
   public final class SelectGesture extends android.view.inputmethod.HandwritingGesture implements android.os.Parcelable {
     method public int describeContents();
     method public int getGranularity();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 8c53733..deb5aca 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2160,10 +2160,15 @@
     field public static final String NAMESPACE_APP_COMPAT_OVERRIDES = "app_compat_overrides";
     field public static final String NAMESPACE_CONSTRAIN_DISPLAY_APIS = "constrain_display_apis";
     field public static final String NAMESPACE_DEVICE_IDLE = "device_idle";
+    field public static final String NAMESPACE_INPUT_METHOD_MANAGER = "input_method_manager";
     field public static final String NAMESPACE_JOB_SCHEDULER = "jobscheduler";
     field public static final String NAMESPACE_SELECTION_TOOLBAR = "selection_toolbar";
   }
 
+  public interface InputMethodManagerDeviceConfig {
+    field public static final String KEY_HIDE_IME_WHEN_NO_EDITOR_FOCUS = "hide_ime_when_no_editor_focus";
+  }
+
   public final class Settings {
     field public static final int RESET_MODE_PACKAGE_DEFAULTS = 1; // 0x1
   }
diff --git a/core/java/android/hardware/DataSpace.java b/core/java/android/hardware/DataSpace.java
index 01ed132..6c42776 100644
--- a/core/java/android/hardware/DataSpace.java
+++ b/core/java/android/hardware/DataSpace.java
@@ -410,6 +410,22 @@
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(flag = true, value = {
+        DATASPACE_HEIF,
+    })
+    public @interface DataSpaceFileFormat {};
+
+    /**
+     * High Efficiency Image File Format (HEIF).
+     *
+     * <p>This value is valid with {@link android.hardware.HardwareBuffer#BLOB HardwareBuffer.BLOB}
+     * format. The combination is an HEIC image encoded by HEIC or HEVC encoder according to
+     * ISO/IEC 23008-12.</p>
+     */
+    public static final int DATASPACE_HEIF = 4100;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, value = {
         DATASPACE_UNKNOWN,
         DATASPACE_SCRGB_LINEAR,
         DATASPACE_SRGB,
diff --git a/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java b/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
index 84c3623..5ce38e9 100644
--- a/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
+++ b/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
@@ -33,6 +33,8 @@
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputContentInfo;
 import android.view.inputmethod.InsertGesture;
+import android.view.inputmethod.JoinOrSplitGesture;
+import android.view.inputmethod.RemoveSpaceGesture;
 import android.view.inputmethod.SelectGesture;
 import android.view.inputmethod.SurroundingText;
 import android.view.inputmethod.TextAttribute;
@@ -633,16 +635,11 @@
     }
 
     /**
-     * Invokes one of {@link IRemoteInputConnection#performHandwritingSelectGesture(
-     * InputConnectionCommandHeader, SelectGesture, AndroidFuture)},
-     * {@link IRemoteInputConnection#performHandwritingDeleteGesture(InputConnectionCommandHeader,
-     * DeleteGesture, AndroidFuture)},
-     * {@link IRemoteInputConnection#performHandwritingInsertGesture(InputConnectionCommandHeader,
-     * InsertGesture, AndroidFuture)}
-     *
-     * @param {@code gesture} parameter {@link HandwritingGesture}.
-     * @return {@link AndroidFuture<Integer>} that can be used to retrieve the invocation
-     *         result. {@link RemoteException} will be treated as an error.
+     * Invokes one of {@link IRemoteInputConnection#performHandwritingSelectGesture},
+     * {@link IRemoteInputConnection#performHandwritingDeleteGesture},
+     * {@link IRemoteInputConnection#performHandwritingInsertGesture},
+     * {@link IRemoteInputConnection#performHandwritingRemoveSpaceGesture},
+     * {@link IRemoteInputConnection#performHandwritingJoinOrSplitGesture}.
      */
     @AnyThread
     public void performHandwritingGesture(
@@ -664,6 +661,12 @@
             } else if (gesture instanceof DeleteGesture) {
                 mConnection.performHandwritingDeleteGesture(
                         createHeader(), (DeleteGesture) gesture, resultReceiver);
+            } else if (gesture instanceof RemoveSpaceGesture) {
+                mConnection.performHandwritingRemoveSpaceGesture(
+                        createHeader(), (RemoveSpaceGesture) gesture, resultReceiver);
+            } else if (gesture instanceof JoinOrSplitGesture) {
+                mConnection.performHandwritingJoinOrSplitGesture(
+                        createHeader(), (JoinOrSplitGesture) gesture, resultReceiver);
             } else if (consumer != null && executor != null) {
                 executor.execute(()
                         -> consumer.accept(InputConnection.HANDWRITING_GESTURE_RESULT_UNSUPPORTED));
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 87579eb..4e3adfb 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -27,6 +27,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
@@ -396,6 +397,20 @@
     final <T> T getValueAt(int i, @Nullable Class<T> clazz, @Nullable Class<?>... itemTypes) {
         Object object = mMap.valueAt(i);
         if (object instanceof BiFunction<?, ?, ?>) {
+            synchronized (this) {
+                object = unwrapLazyValueFromMapLocked(i, clazz, itemTypes);
+            }
+        }
+        return (clazz != null) ? clazz.cast(object) : (T) object;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Nullable
+    @GuardedBy("this")
+    private Object unwrapLazyValueFromMapLocked(int i, @Nullable Class<?> clazz,
+            @Nullable Class<?>... itemTypes) {
+        Object object = mMap.valueAt(i);
+        if (object instanceof BiFunction<?, ?, ?>) {
             try {
                 object = ((BiFunction<Class<?>, Class<?>[], ?>) object).apply(clazz, itemTypes);
             } catch (BadParcelableException e) {
@@ -409,7 +424,8 @@
             mMap.setValueAt(i, object);
             mLazyValues--;
             if (mOwnsLazyValues) {
-                Preconditions.checkState(mLazyValues >= 0, "Lazy values ref count below 0");
+                Preconditions.checkState(mLazyValues >= 0,
+                        "Lazy values ref count below 0");
                 // No more lazy values in mMap, so we can recycle the parcel early rather than
                 // waiting for the next GC run
                 if (mLazyValues == 0) {
@@ -420,7 +436,7 @@
                 }
             }
         }
-        return (clazz != null) ? clazz.cast(object) : (T) object;
+        return object;
     }
 
     private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean ownsParcel,
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 0ad596b..d71b023 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -961,7 +961,7 @@
          * also be bumped.
          */
         static final String[] USER_ACTIVITY_TYPES = {
-            "other", "button", "touch", "accessibility", "attention"
+            "other", "button", "touch", "accessibility", "attention", "faceDown", "deviceState"
         };
 
         public static final int NUM_USER_ACTIVITY_TYPES = USER_ACTIVITY_TYPES.length;
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 80cf2f8..4f26ad2 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -1262,8 +1262,15 @@
         // Log any exceptions as warnings, don't silently suppress them.
         // If the call was {@link IBinder#FLAG_ONEWAY} then these exceptions
         // disappear into the ether.
-        final boolean tracingEnabled = Trace.isTagEnabled(Trace.TRACE_TAG_AIDL) &&
-                (Binder.isStackTrackingEnabled() || Binder.isTracingEnabled(callingUid));
+        final boolean tagEnabled = Trace.isTagEnabled(Trace.TRACE_TAG_AIDL);
+        final String transactionTraceName;
+        if (tagEnabled) {
+            transactionTraceName = getTransactionTraceName(code);
+        } else {
+            transactionTraceName = null;
+        }
+
+        final boolean tracingEnabled = tagEnabled && transactionTraceName != null;
         try {
             final BinderCallHeavyHitterWatcher heavyHitterWatcher = sHeavyHitterWatcher;
             if (heavyHitterWatcher != null) {
@@ -1271,7 +1278,7 @@
                 heavyHitterWatcher.onTransaction(callingUid, getClass(), code);
             }
             if (tracingEnabled) {
-                Trace.traceBegin(Trace.TRACE_TAG_AIDL, getTransactionTraceName(code));
+                Trace.traceBegin(Trace.TRACE_TAG_AIDL, transactionTraceName);
             }
 
             if ((flags & FLAG_COLLECT_NOTED_APP_OPS) != 0) {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 01b75d1..c0e2864 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -348,6 +348,39 @@
     public static final int USER_ACTIVITY_EVENT_DEVICE_STATE = 6;
 
     /**
+     * @hide
+     */
+    @IntDef(prefix = { "USER_ACTIVITY_EVENT_" }, value = {
+            USER_ACTIVITY_EVENT_OTHER,
+            USER_ACTIVITY_EVENT_BUTTON,
+            USER_ACTIVITY_EVENT_TOUCH,
+            USER_ACTIVITY_EVENT_ACCESSIBILITY,
+            USER_ACTIVITY_EVENT_ATTENTION,
+            USER_ACTIVITY_EVENT_FACE_DOWN,
+            USER_ACTIVITY_EVENT_DEVICE_STATE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface UserActivityEvent{}
+
+    /**
+     *
+     * Convert the user activity event to a string for debugging purposes.
+     * @hide
+     */
+    public static String userActivityEventToString(@UserActivityEvent int userActivityEvent) {
+        switch (userActivityEvent) {
+            case USER_ACTIVITY_EVENT_OTHER: return "other";
+            case USER_ACTIVITY_EVENT_BUTTON: return "button";
+            case USER_ACTIVITY_EVENT_TOUCH: return "touch";
+            case USER_ACTIVITY_EVENT_ACCESSIBILITY: return "accessibility";
+            case USER_ACTIVITY_EVENT_ATTENTION: return "attention";
+            case USER_ACTIVITY_EVENT_FACE_DOWN: return "faceDown";
+            case USER_ACTIVITY_EVENT_DEVICE_STATE: return "deviceState";
+            default: return Integer.toString(userActivityEvent);
+        }
+    }
+
+    /**
      * User activity flag: If already dimmed, extend the dim timeout
      * but do not brighten.  This flag is useful for keeping the screen on
      * a little longer without causing a visible change such as when
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index b7adcb8..d125cbb 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -775,6 +775,14 @@
      */
     public static final String NAMESPACE_WEAR = "wear";
 
+    /**
+     * Namespace for the input method manager platform features.
+     *
+     * @hide
+     */
+    @TestApi
+    public static final String NAMESPACE_INPUT_METHOD_MANAGER = "input_method_manager";
+
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
     private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
diff --git a/core/java/android/provider/InputMethodManagerDeviceConfig.java b/core/java/android/provider/InputMethodManagerDeviceConfig.java
new file mode 100644
index 0000000..906b133
--- /dev/null
+++ b/core/java/android/provider/InputMethodManagerDeviceConfig.java
@@ -0,0 +1,31 @@
+/*
+ * 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 android.provider;
+
+import android.annotation.TestApi;
+
+/**
+ * Interface for accessing keys belonging to {@link DeviceConfig#NAMESPACE_INPUT_METHOD_MANAGER}.
+ * @hide
+ */
+@TestApi
+public interface InputMethodManagerDeviceConfig {
+    /**
+     * Whether the IME should be hidden when the window gained focus without an editor focused.
+     */
+    String KEY_HIDE_IME_WHEN_NO_EDITOR_FOCUS = "hide_ime_when_no_editor_focus";
+}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index bc8822c..be8c140 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -518,7 +518,7 @@
          * {@link #addLocalColorsAreas(List)}
          * {@link #removeLocalColorsAreas(List)}
          * When local colors change, call {@link #notifyLocalColorsChanged(List, List)}
-         * See {@link com.android.systemui.ImageWallpaper} for an example
+         * See {@link com.android.systemui.wallpapers.ImageWallpaper} for an example
          * @hide
          */
         public boolean supportsLocalColorExtraction() {
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index cc68ddd..91febcd 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -765,11 +765,12 @@
                 startNanos = System.nanoTime();
                 final long jitterNanos = startNanos - frameTimeNanos;
                 if (jitterNanos >= frameIntervalNanos) {
-                    long lastFrameOffset = 0;
+                    frameTimeNanos = startNanos;
                     if (frameIntervalNanos == 0) {
                         Log.i(TAG, "Vsync data empty due to timeout");
                     } else {
-                        lastFrameOffset = jitterNanos % frameIntervalNanos;
+                        long lastFrameOffset = jitterNanos % frameIntervalNanos;
+                        frameTimeNanos = frameTimeNanos - lastFrameOffset;
                         final long skippedFrames = jitterNanos / frameIntervalNanos;
                         if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
                             Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
@@ -785,8 +786,7 @@
                                     + " ms in the past.");
                         }
                     }
-                    frameTimeNanos = startNanos - lastFrameOffset;
-                    frameData.updateFrameData(frameTimeNanos);
+                    frameData = getUpdatedFrameData(frameTimeNanos, frameData, jitterNanos);
                 }
 
                 if (frameTimeNanos < mLastFrameTimeNanos) {
@@ -884,7 +884,7 @@
                     }
                     frameTimeNanos = now - lastFrameOffset;
                     mLastFrameTimeNanos = frameTimeNanos;
-                    frameData.updateFrameData(frameTimeNanos);
+                    frameData = getUpdatedFrameData(frameTimeNanos, frameData, jitterNanos);
                 }
             }
         }
@@ -998,9 +998,6 @@
 
     /** Holds data that describes one possible VSync frame event to render at. */
     public static class FrameTimeline {
-        static final FrameTimeline INVALID_FRAME_TIMELINE = new FrameTimeline(
-                FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE);
-
         FrameTimeline(long vsyncId, long expectedPresentTimeNanos, long deadlineNanos) {
             this.mVsyncId = vsyncId;
             this.mExpectedPresentTimeNanos = expectedPresentTimeNanos;
@@ -1019,11 +1016,6 @@
             return mVsyncId;
         }
 
-        /** Reset the vsync ID to invalid. */
-        void resetVsyncId() {
-            mVsyncId = FrameInfo.INVALID_VSYNC_ID;
-        }
-
         /**
          * The time in {@link System#nanoTime()} timebase which this frame is expected to be
          * presented.
@@ -1046,39 +1038,20 @@
      * information including deadline and expected present time.
      */
     public static class FrameData {
-        static final FrameTimeline[] INVALID_FRAME_TIMELINES = new FrameTimeline[0];
-        FrameData() {
-            this.mFrameTimelines = INVALID_FRAME_TIMELINES;
-            this.mPreferredFrameTimeline = FrameTimeline.INVALID_FRAME_TIMELINE;
-        }
-
         FrameData(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) {
-            FrameTimeline[] frameTimelines =
-                    new FrameTimeline[vsyncEventData.frameTimelines.length];
-            for (int i = 0; i <  vsyncEventData.frameTimelines.length; i++) {
-                DisplayEventReceiver.VsyncEventData.FrameTimeline frameTimeline =
-                        vsyncEventData.frameTimelines[i];
-                frameTimelines[i] = new FrameTimeline(frameTimeline.vsyncId,
-                        frameTimeline.expectedPresentTime, frameTimeline.deadline);
-            }
             this.mFrameTimeNanos = frameTimeNanos;
-            this.mFrameTimelines = frameTimelines;
-            this.mPreferredFrameTimeline =
-                    frameTimelines[vsyncEventData.preferredFrameTimelineIndex];
+            this.mFrameTimelines = convertFrameTimelines(vsyncEventData);
+            this.mPreferredFrameTimelineIndex =
+                    vsyncEventData.preferredFrameTimelineIndex;
         }
 
         private long mFrameTimeNanos;
-        private FrameTimeline[] mFrameTimelines;
-        private FrameTimeline mPreferredFrameTimeline;
+        private final FrameTimeline[] mFrameTimelines;
+        private int mPreferredFrameTimelineIndex;
 
-        void updateFrameData(long frameTimeNanos) {
+        void updateFrameData(long frameTimeNanos, int newPreferredFrameTimelineIndex) {
             mFrameTimeNanos = frameTimeNanos;
-            for (FrameTimeline ft : mFrameTimelines) {
-                // The ID is no longer valid because the frame time that was registered with the ID
-                // no longer matches.
-                // TODO(b/205721584): Ask SF for valid vsync information.
-                ft.resetVsyncId();
-            }
+            mPreferredFrameTimelineIndex = newPreferredFrameTimelineIndex;
         }
 
         /** The time in nanoseconds when the frame started being rendered. */
@@ -1096,7 +1069,7 @@
         /** The platform-preferred frame timeline. */
         @NonNull
         public FrameTimeline getPreferredFrameTimeline() {
-            return mPreferredFrameTimeline;
+            return mFrameTimelines[mPreferredFrameTimelineIndex];
         }
 
         private FrameTimeline[] convertFrameTimelines(
@@ -1114,6 +1087,38 @@
     }
 
     /**
+     * Update the frame data when the frame is late.
+     *
+     * @param jitterNanos currentTime - frameTime
+     */
+    private FrameData getUpdatedFrameData(long frameTimeNanos, FrameData frameData,
+            long jitterNanos) {
+        int newPreferredIndex = 0;
+        FrameTimeline[] frameTimelines = frameData.getFrameTimelines();
+        final long minimumDeadline =
+                frameData.getPreferredFrameTimeline().getDeadlineNanos() + jitterNanos;
+        // Look for a non-past deadline timestamp in the existing frame data. Otherwise, binder
+        // query for new frame data. Note that binder is relatively slow, O(ms), so it is
+        // only called when the existing frame data does not hold a valid frame.
+        while (newPreferredIndex < frameTimelines.length - 1
+                && frameTimelines[newPreferredIndex].getDeadlineNanos()
+                < minimumDeadline) {
+            newPreferredIndex++;
+        }
+
+        long newPreferredDeadline =
+                frameData.getFrameTimelines()[newPreferredIndex].getDeadlineNanos();
+        if (newPreferredDeadline < minimumDeadline) {
+            DisplayEventReceiver.VsyncEventData latestVsyncEventData =
+                    mDisplayEventReceiver.getLatestVsyncEventData();
+            return new FrameData(frameTimeNanos, latestVsyncEventData);
+        } else {
+            frameData.updateFrameData(frameTimeNanos, newPreferredIndex);
+            return frameData;
+        }
+    }
+
+    /**
      * Implement this interface to receive a callback to start the next frame. The callback is
      * invoked on the {@link Looper} thread to which the {@link Choreographer} is attached. The
      * callback payload contains information about multiple possible frames, allowing choice of
diff --git a/core/java/android/view/inputmethod/DeleteGesture.java b/core/java/android/view/inputmethod/DeleteGesture.java
index 1395578..9fadabf 100644
--- a/core/java/android/view/inputmethod/DeleteGesture.java
+++ b/core/java/android/view/inputmethod/DeleteGesture.java
@@ -64,7 +64,6 @@
      * Returns the deletion area {@link RectF} in screen coordinates.
      *
      * Getter for deletion area set with {@link DeleteGesture.Builder#setDeletionArea(RectF)}.
-     * {@code null} if area was not set.
      */
     @NonNull
     public RectF getDeletionArea() {
@@ -145,7 +144,8 @@
     /**
      * Used to make this class parcelable.
      */
-    public static final @android.annotation.NonNull Creator<DeleteGesture> CREATOR =
+    @NonNull
+    public static final Creator<DeleteGesture> CREATOR =
             new Creator<DeleteGesture>() {
         @Override
         public DeleteGesture createFromParcel(Parcel source) {
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 36b0334..c3b32c9 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -561,6 +561,10 @@
                 supportedTypes |= HandwritingGesture.GESTURE_TYPE_INSERT;
             } else if (gesture.equals(DeleteGesture.class)) {
                 supportedTypes |= HandwritingGesture.GESTURE_TYPE_DELETE;
+            } else if (gesture.equals(RemoveSpaceGesture.class)) {
+                supportedTypes |= HandwritingGesture.GESTURE_TYPE_REMOVE_SPACE;
+            } else if (gesture.equals(JoinOrSplitGesture.class)) {
+                supportedTypes |= HandwritingGesture.GESTURE_TYPE_JOIN_OR_SPLIT;
             } else {
                 throw new IllegalArgumentException("Unknown gesture type: " + gesture);
             }
@@ -595,6 +599,14 @@
                 == HandwritingGesture.GESTURE_TYPE_DELETE) {
             list.add(DeleteGesture.class);
         }
+        if ((mSupportedHandwritingGestureTypes & HandwritingGesture.GESTURE_TYPE_REMOVE_SPACE)
+                == HandwritingGesture.GESTURE_TYPE_REMOVE_SPACE) {
+            list.add(RemoveSpaceGesture.class);
+        }
+        if ((mSupportedHandwritingGestureTypes & HandwritingGesture.GESTURE_TYPE_JOIN_OR_SPLIT)
+                == HandwritingGesture.GESTURE_TYPE_JOIN_OR_SPLIT) {
+            list.add(JoinOrSplitGesture.class);
+        }
         return list;
     }
 
diff --git a/core/java/android/view/inputmethod/HandwritingGesture.java b/core/java/android/view/inputmethod/HandwritingGesture.java
index a659333..494aaaa 100644
--- a/core/java/android/view/inputmethod/HandwritingGesture.java
+++ b/core/java/android/view/inputmethod/HandwritingGesture.java
@@ -99,15 +99,23 @@
      */
     public static final int GESTURE_TYPE_DELETE = 1 << 2;
 
+    /** Gesture of type {@link RemoveSpaceGesture} to remove whitespace from text. */
+    public static final int GESTURE_TYPE_REMOVE_SPACE = 1 << 3;
+
+    /** Gesture of type {@link JoinOrSplitGesture} to join or split text. */
+    public static final int GESTURE_TYPE_JOIN_OR_SPLIT = 1 << 4;
+
     /**
      * Type of gesture like {@link #GESTURE_TYPE_SELECT}, {@link #GESTURE_TYPE_INSERT},
      * or {@link #GESTURE_TYPE_DELETE}.
      */
     @IntDef(prefix = {"GESTURE_TYPE_"}, value = {
-                GESTURE_TYPE_NONE,
-                GESTURE_TYPE_SELECT,
-                GESTURE_TYPE_INSERT,
-                GESTURE_TYPE_DELETE})
+            GESTURE_TYPE_NONE,
+            GESTURE_TYPE_SELECT,
+            GESTURE_TYPE_INSERT,
+            GESTURE_TYPE_DELETE,
+            GESTURE_TYPE_REMOVE_SPACE,
+            GESTURE_TYPE_JOIN_OR_SPLIT})
     @Retention(RetentionPolicy.SOURCE)
     @interface GestureType{}
 
@@ -121,7 +129,9 @@
     @IntDef(flag = true, prefix = {"GESTURE_TYPE_"}, value = {
             GESTURE_TYPE_SELECT,
             GESTURE_TYPE_INSERT,
-            GESTURE_TYPE_DELETE})
+            GESTURE_TYPE_DELETE,
+            GESTURE_TYPE_REMOVE_SPACE,
+            GESTURE_TYPE_JOIN_OR_SPLIT})
     @Retention(RetentionPolicy.SOURCE)
     public @interface GestureTypeFlags{}
 
diff --git a/core/java/android/view/inputmethod/InsertGesture.java b/core/java/android/view/inputmethod/InsertGesture.java
index cffdf35..8b8359e 100644
--- a/core/java/android/view/inputmethod/InsertGesture.java
+++ b/core/java/android/view/inputmethod/InsertGesture.java
@@ -124,7 +124,8 @@
     /**
      * Used to make this class parcelable.
      */
-    public static final @android.annotation.NonNull Creator<InsertGesture> CREATOR =
+    @NonNull
+    public static final Creator<InsertGesture> CREATOR =
             new Creator<InsertGesture>() {
         @Override
         public InsertGesture createFromParcel(Parcel source) {
diff --git a/core/java/android/view/inputmethod/JoinOrSplitGesture.aidl b/core/java/android/view/inputmethod/JoinOrSplitGesture.aidl
new file mode 100644
index 0000000..e339b55
--- /dev/null
+++ b/core/java/android/view/inputmethod/JoinOrSplitGesture.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.view.inputmethod;
+
+parcelable JoinOrSplitGesture;
diff --git a/core/java/android/view/inputmethod/JoinOrSplitGesture.java b/core/java/android/view/inputmethod/JoinOrSplitGesture.java
new file mode 100644
index 0000000..2fa8063
--- /dev/null
+++ b/core/java/android/view/inputmethod/JoinOrSplitGesture.java
@@ -0,0 +1,145 @@
+/*
+ * 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 android.view.inputmethod;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.PointF;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * A subclass of {@link HandwritingGesture} for deleting or inserting whitespace in text. If the
+ * gesture is drawn over whitespace, then the whitespace will be deleted. Otherwise, a space will be
+ * inserted.
+ */
+public final class JoinOrSplitGesture extends HandwritingGesture implements Parcelable {
+
+    private final PointF mPoint;
+
+    private JoinOrSplitGesture(PointF point, String fallbackText) {
+        mType = GESTURE_TYPE_JOIN_OR_SPLIT;
+        mPoint = point;
+        mFallbackText = fallbackText;
+    }
+
+    private JoinOrSplitGesture(@NonNull Parcel source) {
+        mType = GESTURE_TYPE_JOIN_OR_SPLIT;
+        mPoint = source.readTypedObject(PointF.CREATOR);
+        mFallbackText = source.readString8();
+    }
+
+    /**
+     * Returns the gesture point in screen coordinates set with {@link Builder#setJoinOrSplitPoint}.
+     */
+    @NonNull
+    public PointF getJoinOrSplitPoint() {
+        return mPoint;
+    }
+
+    /** Builder for {@link JoinOrSplitGesture}. This class is not designed to be thread-safe. */
+    public static final class Builder {
+        private PointF mPoint;
+        private String mFallbackText;
+
+        /**
+         * Sets the point to apply the join or split operation in screen coordinates.
+         *
+         * <p>If the text cursor position closest to the point is inside or on the boundary of
+         * whitespace, then the whitespace will be deleted, joining the text on either side of the
+         * whitespace. If there are multiple consecutive whitespace characters, then the entire
+         * whitespace block will be deleted.
+         *
+         * <p>Otherwise, if the text cursor position closest to the point is not touching
+         * whitespace, then a space will be inserted at that position.
+         */
+        @NonNull
+        public Builder setJoinOrSplitPoint(@NonNull PointF point) {
+            mPoint = point;
+            return this;
+        }
+
+        /**
+         * Sets fallback text that will be committed at current cursor position if there is no
+         * applicable text beneath the gesture point.
+         */
+        @NonNull
+        public Builder setFallbackText(@Nullable String fallbackText) {
+            mFallbackText = fallbackText;
+            return this;
+        }
+
+        /**
+         * @return {@link JoinOrSplitGesture} using parameters in this {@link Builder}.
+         * @throws IllegalArgumentException if one or more positional parameters are not specified.
+         */
+        @NonNull
+        public JoinOrSplitGesture build() {
+            if (mPoint == null) {
+                throw new IllegalArgumentException("Point must be set.");
+            }
+            return new JoinOrSplitGesture(mPoint, mFallbackText);
+        }
+    }
+
+    /** Used to make this class parcelable. */
+    @NonNull
+    public static final Parcelable.Creator<JoinOrSplitGesture> CREATOR =
+            new Parcelable.Creator<JoinOrSplitGesture>() {
+                @Override
+                public JoinOrSplitGesture createFromParcel(Parcel source) {
+                    return new JoinOrSplitGesture(source);
+                }
+
+                @Override
+                public JoinOrSplitGesture[] newArray(int size) {
+                    return new JoinOrSplitGesture[size];
+                }
+            };
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mPoint, mFallbackText);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof JoinOrSplitGesture)) return false;
+        JoinOrSplitGesture that = (JoinOrSplitGesture) o;
+        return Objects.equals(mPoint, that.mPoint)
+                && Objects.equals(mFallbackText, that.mFallbackText);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     *
+     * @param dest {@link Parcel} to be written
+     * @param flags flags used for parceling
+     */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeTypedObject(mPoint, flags);
+        dest.writeString8(mFallbackText);
+    }
+}
diff --git a/core/java/android/view/inputmethod/RemoveSpaceGesture.aidl b/core/java/android/view/inputmethod/RemoveSpaceGesture.aidl
new file mode 100644
index 0000000..7aab528
--- /dev/null
+++ b/core/java/android/view/inputmethod/RemoveSpaceGesture.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.view.inputmethod;
+
+parcelable RemoveSpaceGesture;
diff --git a/core/java/android/view/inputmethod/RemoveSpaceGesture.java b/core/java/android/view/inputmethod/RemoveSpaceGesture.java
new file mode 100644
index 0000000..936f259
--- /dev/null
+++ b/core/java/android/view/inputmethod/RemoveSpaceGesture.java
@@ -0,0 +1,152 @@
+/*
+ * 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 android.view.inputmethod;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.graphics.PointF;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/** A subclass of {@link HandwritingGesture} for removing whitespace from text. */
+public final class RemoveSpaceGesture extends HandwritingGesture implements Parcelable {
+
+    private final PointF mStartPoint;
+    private final PointF mEndPoint;
+
+    private RemoveSpaceGesture(PointF startPoint, PointF endPoint, String fallbackText) {
+        mType = GESTURE_TYPE_REMOVE_SPACE;
+        mStartPoint = startPoint;
+        mEndPoint = endPoint;
+        mFallbackText = fallbackText;
+    }
+
+    private RemoveSpaceGesture(@NonNull Parcel source) {
+        mType = GESTURE_TYPE_REMOVE_SPACE;
+        mStartPoint = source.readTypedObject(PointF.CREATOR);
+        mEndPoint = source.readTypedObject(PointF.CREATOR);
+        mFallbackText = source.readString8();
+    }
+
+    /** Returns the start point in screen coordinates set with {@link Builder#setPoints}. */
+    @NonNull
+    public PointF getStartPoint() {
+        return mStartPoint;
+    }
+
+    /** Returns the end point in screen coordinates set with {@link Builder#setPoints}. */
+    @NonNull
+    public PointF getEndPoint() {
+        return mEndPoint;
+    }
+
+    /** Builder for {@link RemoveSpaceGesture}. This class is not designed to be thread-safe. */
+    public static final class Builder {
+        private PointF mStartPoint;
+        private PointF mEndPoint;
+        private String mFallbackText;
+
+        /**
+         * Sets the start and end points in screen coordinates of the line to apply the remove space
+         * operation. All whitespace characters touched by the line joining the points will be
+         * deleted.
+         *
+         * <p>The operation will only be performed on a single line of text. If the start and end
+         * points are on different lines of text, the line will be adjusted to cover only the first
+         * line of text containing one of the points.
+         */
+        @NonNull
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public Builder setPoints(@NonNull PointF startPoint, @NonNull PointF endPoint) {
+            mStartPoint = startPoint;
+            mEndPoint = endPoint;
+            return this;
+        }
+
+        /**
+         * Sets fallback text that will be committed at current cursor position if there is no
+         * whitespace beneath the gesture line.
+         */
+        @NonNull
+        public Builder setFallbackText(@Nullable String fallbackText) {
+            mFallbackText = fallbackText;
+            return this;
+        }
+
+        /**
+         * @return {@link RemoveSpaceGesture} using parameters in this {@link Builder}.
+         * @throws IllegalArgumentException if one or more positional parameters are not specified.
+         */
+        @NonNull
+        public RemoveSpaceGesture build() {
+            if (mStartPoint == null || mEndPoint == null) {
+                throw new IllegalArgumentException("Start and end points must be set.");
+            }
+            return new RemoveSpaceGesture(mStartPoint, mEndPoint, mFallbackText);
+        }
+    }
+
+    /** Used to make this class parcelable. */
+    @NonNull
+    public static final Parcelable.Creator<RemoveSpaceGesture> CREATOR =
+            new Parcelable.Creator<RemoveSpaceGesture>() {
+                @Override
+                public RemoveSpaceGesture createFromParcel(Parcel source) {
+                    return new RemoveSpaceGesture(source);
+                }
+
+                @Override
+                public RemoveSpaceGesture[] newArray(int size) {
+                    return new RemoveSpaceGesture[size];
+                }
+            };
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mStartPoint, mEndPoint, mFallbackText);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof RemoveSpaceGesture)) return false;
+        RemoveSpaceGesture that = (RemoveSpaceGesture) o;
+        return Objects.equals(mStartPoint, that.mStartPoint)
+                && Objects.equals(mEndPoint, that.mEndPoint)
+                && Objects.equals(mFallbackText, that.mFallbackText);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     *
+     * @param dest {@link Parcel} to be written
+     * @param flags flags used for parceling
+     */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeTypedObject(mStartPoint, flags);
+        dest.writeTypedObject(mEndPoint, flags);
+        dest.writeString8(mFallbackText);
+    }
+}
diff --git a/core/java/android/view/inputmethod/SelectGesture.java b/core/java/android/view/inputmethod/SelectGesture.java
index 5b68517..2f02e66 100644
--- a/core/java/android/view/inputmethod/SelectGesture.java
+++ b/core/java/android/view/inputmethod/SelectGesture.java
@@ -63,8 +63,7 @@
     /**
      * Returns the Selection area {@link RectF} in screen coordinates.
      *
-     * Getter for selection area set with {@link Builder#setSelectionArea(RectF)}. {@code null}
-     * if area was not set.
+     * Getter for selection area set with {@link Builder#setSelectionArea(RectF)}.
      */
     @NonNull
     public RectF getSelectionArea() {
@@ -126,7 +125,7 @@
         }
 
         /**
-         * @return {@link SelectGesture} using parameters in this {@link InsertGesture.Builder}.
+         * @return {@link SelectGesture} using parameters in this {@link Builder}.
          * @throws IllegalArgumentException if one or more positional parameters are not specified.
          */
         @NonNull
@@ -144,7 +143,8 @@
     /**
      * Used to make this class parcelable.
      */
-    public static final @android.annotation.NonNull Parcelable.Creator<SelectGesture> CREATOR =
+    @NonNull
+    public static final Parcelable.Creator<SelectGesture> CREATOR =
             new Parcelable.Creator<SelectGesture>() {
         @Override
         public SelectGesture createFromParcel(Parcel source) {
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index be6b08f..075aa6c 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -148,6 +148,9 @@
             startSelectionActionMode(null);
         } else {
             resetTextClassificationHelper();
+            if (mSmartSelectSprite != null && mSmartSelectSprite.isAnimationActive()) {
+                mSmartSelectSprite.cancelAnimation();
+            }
             mTextClassificationAsyncTask = new TextClassificationAsyncTask(
                     mTextView,
                     mTextClassificationHelper.getTimeoutDuration(),
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 8bb8714..5cf7e36 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -2953,12 +2953,14 @@
 
     private void startFinishAnimation() {
         View rootView = findRootView();
-        rootView.startAnimation(new FinishAnimation(this, rootView));
+        if (rootView != null) {
+            rootView.startAnimation(new FinishAnimation(this, rootView));
+        }
     }
 
     private boolean maybeCancelFinishAnimation() {
         View rootView = findRootView();
-        Animation animation = rootView.getAnimation();
+        Animation animation = rootView == null ? null : rootView.getAnimation();
         if (animation instanceof FinishAnimation) {
             boolean hasEnded = animation.hasEnded();
             animation.cancel();
@@ -4086,11 +4088,13 @@
      */
     private static class FinishAnimation extends AlphaAnimation implements
             Animation.AnimationListener {
+        @Nullable
         private Activity mActivity;
+        @Nullable
         private View mRootView;
         private final float mFromAlpha;
 
-        FinishAnimation(Activity activity, View rootView) {
+        FinishAnimation(@NonNull Activity activity, @NonNull View rootView) {
             super(rootView.getAlpha(), 0.0f);
             mActivity = activity;
             mRootView = rootView;
@@ -4114,7 +4118,9 @@
 
         @Override
         public void cancel() {
-            mRootView.setAlpha(mFromAlpha);
+            if (mRootView != null) {
+                mRootView.setAlpha(mFromAlpha);
+            }
             cleanup();
             super.cancel();
         }
@@ -4125,9 +4131,10 @@
 
         @Override
         public void onAnimationEnd(Animation animation) {
-            if (mActivity != null) {
-                mActivity.finish();
-                cleanup();
+            Activity activity = mActivity;
+            cleanup();
+            if (activity != null) {
+                activity.finish();
             }
         }
 
diff --git a/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl b/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl
index 7a219c6..f456e85 100644
--- a/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl
+++ b/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl
@@ -25,6 +25,8 @@
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputContentInfo;
 import android.view.inputmethod.InsertGesture;
+import android.view.inputmethod.JoinOrSplitGesture;
+import android.view.inputmethod.RemoveSpaceGesture;
 import android.view.inputmethod.SelectGesture;
 import android.view.inputmethod.TextAttribute;
 
@@ -99,6 +101,12 @@
     void performHandwritingDeleteGesture(in InputConnectionCommandHeader header,
             in DeleteGesture gesture, in ResultReceiver resultReceiver);
 
+    void performHandwritingRemoveSpaceGesture(in InputConnectionCommandHeader header,
+            in RemoveSpaceGesture gesture, in ResultReceiver resultReceiver);
+
+    void performHandwritingJoinOrSplitGesture(in InputConnectionCommandHeader header,
+            in JoinOrSplitGesture gesture, in ResultReceiver resultReceiver);
+
     void setComposingRegion(in InputConnectionCommandHeader header, int start, int end);
 
     void setComposingRegionWithTextAttribute(in InputConnectionCommandHeader header, int start,
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index 1852c59..bbf0a76 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -20,7 +20,6 @@
 import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
-import android.view.autofill.AutofillManager;
 import android.view.inputmethod.HandwritingGesture;
 
 import java.util.StringJoiner;
@@ -254,6 +253,8 @@
                 return "HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED";
             case SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION:
                 return "HIDE_SOFT_INPUT_IMM_DEPRECATION";
+            case SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR:
+                return "HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR";
             default:
                 return "Unknown=" + reason;
         }
@@ -277,6 +278,12 @@
         if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_DELETE) != 0) {
             joiner.add("DELETE");
         }
+        if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_REMOVE_SPACE) != 0) {
+            joiner.add("REMOVE_SPACE");
+        }
+        if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_JOIN_OR_SPLIT) != 0) {
+            joiner.add("JOIN_OR_SPLIT");
+        }
 
         return joiner.setEmptyValue("(none)").toString();
     }
diff --git a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
index dd173a6..6a7028d 100644
--- a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
@@ -48,6 +48,8 @@
 import android.view.inputmethod.InputContentInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InsertGesture;
+import android.view.inputmethod.JoinOrSplitGesture;
+import android.view.inputmethod.RemoveSpaceGesture;
 import android.view.inputmethod.SelectGesture;
 import android.view.inputmethod.TextAttribute;
 import android.view.inputmethod.TextSnapshot;
@@ -997,6 +999,22 @@
         performHandwritingGestureInternal(header, gesture, resultReceiver);
     }
 
+    @Dispatching(cancellable = true)
+    @Override
+    public void performHandwritingRemoveSpaceGesture(
+            InputConnectionCommandHeader header, RemoveSpaceGesture gesture,
+            ResultReceiver resultReceiver) {
+        performHandwritingGestureInternal(header, gesture, resultReceiver);
+    }
+
+    @Dispatching(cancellable = true)
+    @Override
+    public void performHandwritingJoinOrSplitGesture(
+            InputConnectionCommandHeader header, JoinOrSplitGesture gesture,
+            ResultReceiver resultReceiver) {
+        performHandwritingGestureInternal(header, gesture, resultReceiver);
+    }
+
     private <T extends HandwritingGesture> void performHandwritingGestureInternal(
             InputConnectionCommandHeader header,  T gesture, ResultReceiver resultReceiver) {
         dispatchWithTracing("performHandwritingGesture", () -> {
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index f5b58c0..f1635eb 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -63,7 +63,8 @@
         SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY,
         SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT,
         SoftInputShowHideReason.HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED,
-        SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION})
+        SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION,
+        SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR})
 public @interface SoftInputShowHideReason {
     /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */
     int SHOW_SOFT_INPUT = 0;
@@ -247,4 +248,9 @@
      * {@link InputMethodManager#hideSoftInputFromInputMethod(IBinder, int)}.
      */
     int HIDE_SOFT_INPUT_IMM_DEPRECATION = 31;
+
+    /**
+     * Hide soft input when the window gained focus without an editor from the IME shown window.
+     */
+    int HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR = 32;
 }
diff --git a/core/java/com/android/internal/jank/DisplayResolutionTracker.java b/core/java/com/android/internal/jank/DisplayResolutionTracker.java
new file mode 100644
index 0000000..fd58468
--- /dev/null
+++ b/core/java/com/android/internal/jank/DisplayResolutionTracker.java
@@ -0,0 +1,162 @@
+/*
+ * 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.jank;
+
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__FHD;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__HD;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__QHD;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__SD;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__UNKNOWN_RESOLUTION;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
+import android.os.Handler;
+import android.util.SparseArray;
+import android.view.DisplayInfo;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+* A class that tracks the display resolutions.
+* @hide
+*/
+public class DisplayResolutionTracker {
+    private static final String TAG = DisplayResolutionTracker.class.getSimpleName();
+
+    public static final int RESOLUTION_UNKNOWN =
+            UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__UNKNOWN_RESOLUTION;
+    public static final int RESOLUTION_SD =
+            UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__SD;
+    public static final int RESOLUTION_HD =
+            UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__HD;
+    public static final int RESOLUTION_FHD =
+            UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__FHD;
+    public static final int RESOLUTION_QHD =
+            UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__QHD;
+
+    /** @hide */
+    @IntDef({
+        RESOLUTION_UNKNOWN,
+        RESOLUTION_SD,
+        RESOLUTION_HD,
+        RESOLUTION_FHD,
+        RESOLUTION_QHD,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Resolution {
+    }
+
+    private final DisplayInterface mManager;
+    private final SparseArray<Integer> mResolutions = new SparseArray<>();
+    private final Object mLock = new Object();
+
+    public DisplayResolutionTracker(@Nullable Handler handler) {
+        this(DisplayInterface.getDefault(handler));
+    }
+
+    @VisibleForTesting
+    public DisplayResolutionTracker(DisplayInterface manager) {
+        mManager = manager;
+        mManager.registerDisplayListener(new DisplayManager.DisplayListener() {
+            @Override
+            public void onDisplayAdded(int displayId) {
+                updateDisplay(displayId);
+            }
+
+            @Override
+            public void onDisplayChanged(int displayId) {
+                updateDisplay(displayId);
+            }
+
+            @Override
+            public void onDisplayRemoved(int displayId) {
+                // Not in the event mask below, won't be called.
+            }
+        });
+    }
+
+    private void updateDisplay(int displayId) {
+        DisplayInfo info = mManager.getDisplayInfo(displayId);
+        @Resolution int resolution = getResolution(info);
+
+        synchronized (mLock) {
+            mResolutions.put(displayId, resolution);
+        }
+    }
+
+    /**
+     * Returns the (cached) resolution of the display with the given ID.
+     */
+    @Resolution
+    public int getResolution(int displayId) {
+        return mResolutions.get(displayId, RESOLUTION_UNKNOWN);
+    }
+
+    /**
+     * Returns the resolution of the given {@link DisplayInfo}.
+     */
+    @VisibleForTesting
+    @Resolution
+    public static int getResolution(DisplayInfo info) {
+        int smaller = Math.min(info.logicalWidth, info.logicalHeight);
+        int larger = Math.max(info.logicalWidth, info.logicalHeight);
+        if (smaller < 720 || larger < 1280) {
+            return RESOLUTION_SD;
+        } else if (smaller < 1080 || larger < 1920) {
+            return RESOLUTION_HD;
+        } else if (smaller < 1440 || larger < 2560) {
+            return RESOLUTION_FHD;
+        } else {
+            return RESOLUTION_QHD;
+        }
+    }
+
+    /**
+     * Wrapper around the final {@link DisplayManagerGlobal} class.
+     * @hide
+     */
+    @VisibleForTesting
+    public interface DisplayInterface {
+        /** Reurns an implementation wrapping {@link DisplayManagerGlobal}. */
+        static DisplayInterface getDefault(@Nullable Handler handler) {
+            DisplayManagerGlobal manager = DisplayManagerGlobal.getInstance();
+            return new DisplayInterface() {
+                @Override
+                public void registerDisplayListener(DisplayManager.DisplayListener listener) {
+                    manager.registerDisplayListener(listener, handler,
+                            DisplayManager.EVENT_FLAG_DISPLAY_ADDED
+                                    | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED);
+                }
+
+                @Override
+                public DisplayInfo getDisplayInfo(int displayId) {
+                    return manager.getDisplayInfo(displayId);
+                }
+            };
+        }
+
+        /** {@see DisplayManagerGlobal#registerDisplayListener} */
+        void registerDisplayListener(DisplayManager.DisplayListener listener);
+        /** {@see DisplayManagerGlobal#getDisplayInfo} */
+        DisplayInfo getDisplayInfo(int displayId);
+    }
+}
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 48343803..e4195d2 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -100,6 +100,7 @@
     private final Session mSession;
     private final ViewRootWrapper mViewRoot;
     private final SurfaceControlWrapper mSurfaceControlWrapper;
+    private final int mDisplayId;
     private final ViewRootImpl.SurfaceChangedCallback mSurfaceChangedCallback;
     private final Handler mHandler;
     private final ChoreographerWrapper mChoreographer;
@@ -213,6 +214,7 @@
         mTraceThresholdMissedFrames = traceThresholdMissedFrames;
         mTraceThresholdFrameTimeMillis = traceThresholdFrameTimeMillis;
         mListener = listener;
+        mDisplayId = config.getDisplayId();
 
         if (mSurfaceOnly) {
             mSurfaceControl = config.getSurfaceControl();
@@ -625,6 +627,7 @@
         if (mSession.logToStatsd()) {
             mStatsLog.write(
                     FrameworkStatsLog.UI_INTERACTION_FRAME_INFO_REPORTED,
+                    mDisplayId,
                     mSession.getStatsdInteractionType(),
                     totalFramesCount,
                     missedFramesCount,
@@ -785,9 +788,17 @@
     }
 
     public static class StatsLogWrapper {
-        public void write(int code,
+        private final DisplayResolutionTracker mDisplayResolutionTracker;
+
+        public StatsLogWrapper(DisplayResolutionTracker displayResolutionTracker) {
+            mDisplayResolutionTracker = displayResolutionTracker;
+        }
+
+        /** {@see FrameworkStatsLog#write) */
+        public void write(int code, int displayId,
                 int arg1, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7) {
-            FrameworkStatsLog.write(code, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+            FrameworkStatsLog.write(code, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
+                    mDisplayResolutionTracker.getResolution(displayId));
         }
     }
 
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index fc4e041..b5991b3 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -306,6 +306,7 @@
     @GuardedBy("mLock")
     private final SparseArray<Runnable> mTimeoutActions;
     private final HandlerThread mWorker;
+    private final DisplayResolutionTracker mDisplayResolutionTracker;
     private final Object mLock = new Object();
 
     private volatile boolean mEnabled = DEFAULT_ENABLED;
@@ -408,6 +409,7 @@
         mWorker = worker;
         mWorker.start();
         mSamplingInterval = DEFAULT_SAMPLING_INTERVAL;
+        mDisplayResolutionTracker = new DisplayResolutionTracker(worker.getThreadHandler());
 
         // Post initialization to the background in case we're running on the main
         // thread.
@@ -443,7 +445,8 @@
         final FrameMetricsWrapper frameMetrics = new FrameMetricsWrapper();
 
         return new FrameTracker(this, session, config.getHandler(), threadedRenderer, viewRoot,
-                surfaceControl, choreographer, frameMetrics, new FrameTracker.StatsLogWrapper(),
+                surfaceControl, choreographer, frameMetrics,
+                new FrameTracker.StatsLogWrapper(mDisplayResolutionTracker),
                 mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis,
                 eventsListener, config);
     }
@@ -1098,6 +1101,14 @@
         public Handler getHandler() {
             return mHandler;
         }
+
+        /**
+         * @return the ID of the display this interaction in on.
+         */
+        @VisibleForTesting
+        public int getDisplayId() {
+            return (mSurfaceOnly ? mContext.getDisplay() : mView.getDisplay()).getDisplayId();
+        }
     }
 
     /**
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index b1e7d15..ea5f0b2 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -1001,16 +1001,24 @@
     }
 
     /**
+     * This will enable jdwp by default for all apps. It is OK to cache this property
+     * because we expect to reboot the system whenever this property changes
+     */
+    private static final boolean ENABLE_JDWP = SystemProperties.get(
+                          "persist.debuggable.dalvik.vm.jdwp.enabled").equals("1");
+
+    /**
      * Applies debugger system properties to the zygote arguments.
      *
-     * If "ro.debuggable" is "1", all apps are debuggable. Otherwise,
-     * the debugger state is specified via the "--enable-jdwp" flag
-     * in the spawn request.
+     * For eng builds all apps are debuggable. On userdebug and user builds
+     * if persist.debuggable.dalvik.vm.jdwp.enabled is 1 all apps are
+     * debuggable. Otherwise, the debugger state is specified via the
+     * "--enable-jdwp" flag in the spawn request.
      *
      * @param args non-null; zygote spawner args
      */
     static void applyDebuggerSystemProperty(ZygoteArguments args) {
-        if (RoSystemProperties.DEBUGGABLE) {
+        if (Build.IS_ENG || ENABLE_JDWP) {
             args.mRuntimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
         }
     }
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index cbc3462..550259f 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1277,68 +1277,80 @@
   }
   closedir(dir);
 
-  // Prepare default dirs for user 0 as user 0 always exists.
-  int result = symlink("/data/data", "/data/user/0");
-  if (result != 0) {
-    fail_fn(CREATE_ERROR("Failed to create symlink /data/user/0 %s", strerror(errno)));
-  }
-  PrepareDirIfNotPresent("/data/user_de/0", DEFAULT_DATA_DIR_PERMISSION,
-      AID_ROOT, AID_ROOT, fail_fn);
-
-  for (int i = 0; i < size; i += 3) {
-    std::string const & packageName = merged_data_info_list[i];
-    std::string const & volUuid  = merged_data_info_list[i + 1];
-    std::string const & inode = merged_data_info_list[i + 2];
-
-    std::string::size_type sz;
-    long long ceDataInode = std::stoll(inode, &sz);
-
-    std::string actualCePath, actualDePath;
-    if (volUuid.compare("null") != 0) {
-      // Volume that is stored in /mnt/expand
-      char volPath[PATH_MAX];
-      char volCePath[PATH_MAX];
-      char volDePath[PATH_MAX];
-      char volCeUserPath[PATH_MAX];
-      char volDeUserPath[PATH_MAX];
-
-      snprintf(volPath, PATH_MAX, "/mnt/expand/%s", volUuid.c_str());
-      snprintf(volCePath, PATH_MAX, "%s/user", volPath);
-      snprintf(volDePath, PATH_MAX, "%s/user_de", volPath);
-      snprintf(volCeUserPath, PATH_MAX, "%s/%d", volCePath, userId);
-      snprintf(volDeUserPath, PATH_MAX, "%s/%d", volDePath, userId);
-
-      PrepareDirIfNotPresent(volPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
-      PrepareDirIfNotPresent(volCePath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
-      PrepareDirIfNotPresent(volDePath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
-      PrepareDirIfNotPresent(volCeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
-          fail_fn);
-      PrepareDirIfNotPresent(volDeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
-          fail_fn);
-
-      actualCePath = volCeUserPath;
-      actualDePath = volDeUserPath;
-    } else {
-      // Internal volume that stored in /data
-      char internalCeUserPath[PATH_MAX];
-      char internalDeUserPath[PATH_MAX];
-      snprintf(internalCeUserPath, PATH_MAX, "/data/user/%d", userId);
-      snprintf(internalDeUserPath, PATH_MAX, "/data/user_de/%d", userId);
-      // If it's not user 0, create /data/user/$USER.
-      if (userId == 0) {
-        actualCePath = internalLegacyCePath;
-      } else {
-        PrepareDirIfNotPresent(internalCeUserPath, DEFAULT_DATA_DIR_PERMISSION,
-            AID_ROOT, AID_ROOT, fail_fn);
-        actualCePath = internalCeUserPath;
+  // No bind mounting of app data should occur in the case of a sandbox process since SDK sandboxes
+  // should not be able to read app data. Tmpfs was mounted however since a sandbox should not have
+  // access to app data.
+  appid_t appId = multiuser_get_app_id(uid);
+  bool isSdkSandboxProcess =
+          (appId >= AID_SDK_SANDBOX_PROCESS_START && appId <= AID_SDK_SANDBOX_PROCESS_END);
+  if (!isSdkSandboxProcess) {
+      // Prepare default dirs for user 0 as user 0 always exists.
+      int result = symlink("/data/data", "/data/user/0");
+      if (result != 0) {
+          fail_fn(CREATE_ERROR("Failed to create symlink /data/user/0 %s", strerror(errno)));
       }
-      PrepareDirIfNotPresent(internalDeUserPath, DEFAULT_DATA_DIR_PERMISSION,
-          AID_ROOT, AID_ROOT, fail_fn);
-      actualDePath = internalDeUserPath;
-    }
-    isolateAppDataPerPackage(userId, packageName, volUuid, ceDataInode,
-        actualCePath, actualDePath, fail_fn);
+      PrepareDirIfNotPresent("/data/user_de/0", DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+                             fail_fn);
+
+      for (int i = 0; i < size; i += 3) {
+          std::string const& packageName = merged_data_info_list[i];
+          std::string const& volUuid = merged_data_info_list[i + 1];
+          std::string const& inode = merged_data_info_list[i + 2];
+
+          std::string::size_type sz;
+          long long ceDataInode = std::stoll(inode, &sz);
+
+          std::string actualCePath, actualDePath;
+          if (volUuid.compare("null") != 0) {
+              // Volume that is stored in /mnt/expand
+              char volPath[PATH_MAX];
+              char volCePath[PATH_MAX];
+              char volDePath[PATH_MAX];
+              char volCeUserPath[PATH_MAX];
+              char volDeUserPath[PATH_MAX];
+
+              snprintf(volPath, PATH_MAX, "/mnt/expand/%s", volUuid.c_str());
+              snprintf(volCePath, PATH_MAX, "%s/user", volPath);
+              snprintf(volDePath, PATH_MAX, "%s/user_de", volPath);
+              snprintf(volCeUserPath, PATH_MAX, "%s/%d", volCePath, userId);
+              snprintf(volDeUserPath, PATH_MAX, "%s/%d", volDePath, userId);
+
+              PrepareDirIfNotPresent(volPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+                                     fail_fn);
+              PrepareDirIfNotPresent(volCePath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+                                     fail_fn);
+              PrepareDirIfNotPresent(volDePath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+                                     fail_fn);
+              PrepareDirIfNotPresent(volCeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+                                     fail_fn);
+              PrepareDirIfNotPresent(volDeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+                                     fail_fn);
+
+              actualCePath = volCeUserPath;
+              actualDePath = volDeUserPath;
+          } else {
+              // Internal volume that stored in /data
+              char internalCeUserPath[PATH_MAX];
+              char internalDeUserPath[PATH_MAX];
+              snprintf(internalCeUserPath, PATH_MAX, "/data/user/%d", userId);
+              snprintf(internalDeUserPath, PATH_MAX, "/data/user_de/%d", userId);
+              // If it's not user 0, create /data/user/$USER.
+              if (userId == 0) {
+                  actualCePath = internalLegacyCePath;
+              } else {
+                  PrepareDirIfNotPresent(internalCeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT,
+                                         AID_ROOT, fail_fn);
+                  actualCePath = internalCeUserPath;
+              }
+              PrepareDirIfNotPresent(internalDeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT,
+                                     AID_ROOT, fail_fn);
+              actualDePath = internalDeUserPath;
+          }
+          isolateAppDataPerPackage(userId, packageName, volUuid, ceDataInode, actualCePath,
+                                   actualDePath, fail_fn);
+      }
   }
+
   // We set the label AFTER everything is done, as we are applying
   // the file operations on tmpfs. If we set the label when we mount
   // tmpfs, SELinux will not happy as we are changing system_data_files.
@@ -1379,6 +1391,167 @@
   freecon(dataFileContext);
 }
 
+/**
+ * Without sdk sandbox data isolation, the sandbox could detect if another app is installed on the
+ * system by "touching" other data directories like /data/misc_ce/0/sdksandbox/com.whatsapp, similar
+ * to apps without app data isolation (see {@link #isolateAppData()}).
+ *
+ * To prevent this, tmpfs is mounted onto misc_ce and misc_de directories on all possible volumes in
+ * a separate mount namespace. The sandbox directory path is then created containing the name of the
+ * client app package associated with the sdk sandbox. The contents for this (sdk level storage and
+ * shared sdk storage) are bind mounted from the sandbox data mirror.
+ */
+static void isolateSdkSandboxData(JNIEnv* env, jobjectArray pkg_data_info_list, uid_t uid,
+                                  const char* process_name, jstring managed_nice_name,
+                                  fail_fn_t fail_fn) {
+    const userid_t userId = multiuser_get_user_id(uid);
+
+    int size = (pkg_data_info_list != nullptr) ? env->GetArrayLength(pkg_data_info_list) : 0;
+    // The sandbox should only have information of one associated client app (package, uuid, inode)
+    if (size != 3) {
+        fail_fn(CREATE_ERROR(
+                "Unable to isolate sandbox data, incorrect associated app information"));
+    }
+
+    auto extract_fn = [env, process_name, managed_nice_name,
+                       pkg_data_info_list](int info_list_idx) {
+        jstring jstr = (jstring)(env->GetObjectArrayElement(pkg_data_info_list, info_list_idx));
+        return ExtractJString(env, process_name, managed_nice_name, jstr).value();
+    };
+    std::string packageName = extract_fn(0);
+    std::string volUuid = extract_fn(1);
+
+    char internalCePath[PATH_MAX];
+    char internalDePath[PATH_MAX];
+    char externalPrivateMountPath[PATH_MAX];
+    snprintf(internalCePath, PATH_MAX, "/data/misc_ce");
+    snprintf(internalDePath, PATH_MAX, "/data/misc_de");
+    snprintf(externalPrivateMountPath, PATH_MAX, "/mnt/expand");
+
+    char ceUserPath[PATH_MAX];
+    char deUserPath[PATH_MAX];
+    if (volUuid != "null") {
+        snprintf(ceUserPath, PATH_MAX, "%s/%s/misc_ce/%d", externalPrivateMountPath,
+                 volUuid.c_str(), userId);
+        snprintf(deUserPath, PATH_MAX, "%s/%s/misc_de/%d", externalPrivateMountPath,
+                 volUuid.c_str(), userId);
+    } else {
+        snprintf(ceUserPath, PATH_MAX, "%s/%d", internalCePath, userId);
+        snprintf(deUserPath, PATH_MAX, "%s/%d", internalDePath, userId);
+    }
+
+    char ceSandboxPath[PATH_MAX];
+    char deSandboxPath[PATH_MAX];
+    snprintf(ceSandboxPath, PATH_MAX, "%s/sdksandbox", ceUserPath);
+    snprintf(deSandboxPath, PATH_MAX, "%s/sdksandbox", deUserPath);
+
+    // If the client app using the sandbox has been installed when the device is locked and the
+    // sandbox starts up when the device is locked, sandbox storage might not have been created.
+    // In that case, mount tmpfs for data isolation, but don't bind mount.
+    bool bindMountCeSandboxDataDirs = true;
+    bool bindMountDeSandboxDataDirs = true;
+    if (access(ceSandboxPath, F_OK) != 0) {
+        bindMountCeSandboxDataDirs = false;
+    }
+    if (access(deSandboxPath, F_OK) != 0) {
+        bindMountDeSandboxDataDirs = false;
+    }
+
+    char* context = nullptr;
+    char* userContext = nullptr;
+    char* sandboxContext = nullptr;
+    if (getfilecon(internalDePath, &context) < 0) {
+        fail_fn(CREATE_ERROR("Unable to getfilecon on %s %s", internalDePath, strerror(errno)));
+    }
+    if (bindMountDeSandboxDataDirs) {
+        if (getfilecon(deUserPath, &userContext) < 0) {
+            fail_fn(CREATE_ERROR("Unable to getfilecon on %s %s", deUserPath, strerror(errno)));
+        }
+        if (getfilecon(deSandboxPath, &sandboxContext) < 0) {
+            fail_fn(CREATE_ERROR("Unable to getfilecon on %s %s", deSandboxPath, strerror(errno)));
+        }
+    }
+
+    MountAppDataTmpFs(internalCePath, fail_fn);
+    MountAppDataTmpFs(internalDePath, fail_fn);
+
+    // Mount tmpfs on all external volumes
+    DIR* dir = opendir(externalPrivateMountPath);
+    if (dir == nullptr) {
+        fail_fn(CREATE_ERROR("Failed to opendir %s", externalPrivateMountPath));
+    }
+    struct dirent* ent;
+    while ((ent = readdir(dir))) {
+        if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue;
+        if (ent->d_type != DT_DIR) {
+            fail_fn(CREATE_ERROR("Unexpected type: %d %s", ent->d_type, ent->d_name));
+        }
+        auto volPath = StringPrintf("%s/%s", externalPrivateMountPath, ent->d_name);
+        auto externalCePath = StringPrintf("%s/misc_ce", volPath.c_str());
+        auto externalDePath = StringPrintf("%s/misc_de", volPath.c_str());
+
+        WaitUntilDirReady(externalCePath.c_str(), fail_fn);
+        MountAppDataTmpFs(externalCePath.c_str(), fail_fn);
+        WaitUntilDirReady(externalDePath.c_str(), fail_fn);
+        MountAppDataTmpFs(externalDePath.c_str(), fail_fn);
+    }
+    closedir(dir);
+
+    char mirrorCeSandboxPath[PATH_MAX];
+    char mirrorDeSandboxPath[PATH_MAX];
+    snprintf(mirrorCeSandboxPath, PATH_MAX, "/data_mirror/misc_ce/%s/%d/sdksandbox",
+             volUuid.c_str(), userId);
+    snprintf(mirrorDeSandboxPath, PATH_MAX, "/data_mirror/misc_de/%s/%d/sdksandbox",
+             volUuid.c_str(), userId);
+
+    if (bindMountCeSandboxDataDirs) {
+        PrepareDir(ceUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+        PrepareDir(ceSandboxPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+        // TODO(b/231322885): Use inode numbers to find the correct app path when the device locked.
+        createAndMountAppData(packageName, packageName, mirrorCeSandboxPath, ceSandboxPath, fail_fn,
+                              true /*call_fail_fn*/);
+
+        relabelDir(ceSandboxPath, sandboxContext, fail_fn);
+        relabelDir(ceUserPath, userContext, fail_fn);
+    }
+    if (bindMountDeSandboxDataDirs) {
+        PrepareDir(deUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+        PrepareDir(deSandboxPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+        createAndMountAppData(packageName, packageName, mirrorDeSandboxPath, deSandboxPath, fail_fn,
+                              true /*call_fail_fn*/);
+
+        relabelDir(deSandboxPath, sandboxContext, fail_fn);
+        relabelDir(deUserPath, userContext, fail_fn);
+    }
+
+    // We set the label AFTER everything is done, as we are applying
+    // the file operations on tmpfs. If we set the label when we mount
+    // tmpfs, SELinux will not happy as we are changing system_data_files.
+    relabelDir(internalCePath, context, fail_fn);
+    relabelDir(internalDePath, context, fail_fn);
+
+    // Relabel CE and DE dirs under /mnt/expand
+    dir = opendir(externalPrivateMountPath);
+    if (dir == nullptr) {
+        fail_fn(CREATE_ERROR("Failed to opendir %s", externalPrivateMountPath));
+    }
+    while ((ent = readdir(dir))) {
+        if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue;
+        auto volPath = StringPrintf("%s/%s", externalPrivateMountPath, ent->d_name);
+        auto externalCePath = StringPrintf("%s/misc_ce", volPath.c_str());
+        auto externalDePath = StringPrintf("%s/misc_de", volPath.c_str());
+        relabelDir(externalCePath.c_str(), context, fail_fn);
+        relabelDir(externalDePath.c_str(), context, fail_fn);
+    }
+    closedir(dir);
+
+    if (bindMountDeSandboxDataDirs) {
+        freecon(sandboxContext);
+        freecon(userContext);
+    }
+    freecon(context);
+}
+
 static void insertPackagesToMergedList(JNIEnv* env,
   std::vector<std::string>& merged_data_info_list,
   jobjectArray data_info_list, const char* process_name,
@@ -1444,6 +1617,13 @@
   MountAppDataTmpFs(kCurProfileDirPath, fail_fn);
   MountAppDataTmpFs(kRefProfileDirPath, fail_fn);
 
+  // Sandbox processes do not have JIT profile, so no data needs to be bind mounted. However, it
+  // should still not have access to JIT profile, so tmpfs is mounted.
+  appid_t appId = multiuser_get_app_id(uid);
+  if (appId >= AID_SDK_SANDBOX_PROCESS_START && appId <= AID_SDK_SANDBOX_PROCESS_END) {
+      return;
+  }
+
   // Create profile directory for this user.
   std::string actualCurUserProfile = StringPrintf("%s/%d", kCurProfileDirPath, user_id);
   PrepareDir(actualCurUserProfile, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
@@ -1596,9 +1776,16 @@
     // Make sure app is running in its own mount namespace before isolating its data directories.
     ensureInAppMountNamespace(fail_fn);
 
-    // Sandbox data and jit profile directories by overlaying a tmpfs on those dirs and bind
-    // mount all related packages separately.
+    // Isolate app data, jit profile and sandbox data directories by overlaying a tmpfs on those
+    // dirs and bind mount all related packages separately.
     if (mount_data_dirs) {
+        // Sdk sandbox data isolation does not need to occur for app processes since sepolicy
+        // prevents access to sandbox data anyway.
+        appid_t appId = multiuser_get_app_id(uid);
+        if (appId >= AID_SDK_SANDBOX_PROCESS_START && appId <= AID_SDK_SANDBOX_PROCESS_END) {
+            isolateSdkSandboxData(env, pkg_data_info_list, uid, process_name, managed_nice_name,
+                                  fail_fn);
+        }
         isolateAppData(env, pkg_data_info_list, allowlisted_data_info_list, uid, process_name,
                        managed_nice_name, fail_fn);
         isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 57026d9..4bbfee2 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -61,7 +61,6 @@
 import "frameworks/base/core/proto/android/privacy.proto";
 import "frameworks/base/core/proto/android/section.proto";
 import "frameworks/base/proto/src/ipconnectivity.proto";
-import "packages/modules/Connectivity/framework/proto/netstats.proto";
 import "packages/modules/Permission/service/proto/role_service.proto";
 
 package android.os;
@@ -247,11 +246,7 @@
         (section).args = "fingerprint --proto --incident"
     ];
 
-    optional android.service.NetworkStatsServiceDumpProto netstats = 3001 [
-        (section).type = SECTION_DUMPSYS,
-        (section).args = "netstats --proto",
-        (section).userdebug_and_eng_only = true
-    ];
+    reserved 3001;
 
     optional android.providers.settings.SettingsServiceDumpProto settings = 3002 [
         (section).type = SECTION_DUMPSYS,
diff --git a/core/res/OWNERS b/core/res/OWNERS
index c54638a..d8fc218 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -37,7 +37,7 @@
 per-file res/values/dimens_car.xml = file:/platform/packages/services/Car:/OWNERS
 
 # Wear
-per-file res/*-watch/* = file:/platform/frameworks/opt/wear:/OWNERS
+per-file res/*-watch/* = file:/WEAR_OWNERS
 
 # PowerProfile
 per-file res/xml/power_profile.xml = file:/BATTERY_STATS_OWNERS
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index e5b97f7..9b997bf 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Foon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dokluidsprekers"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Oorfone"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Stelsel"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index c291d9b..698bce4 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ቴሌቪዥን"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ስልክ"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"የትከል ድምፅ ማጉያዎች"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"ኤችዲኤምአይ"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"ኤችዲኤምአይ"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"የጆሮ ማዳመጫዎች"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"ዩ ኤስ ቢ"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"ስርዓት"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 39f6872..82fc943 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1615,7 +1615,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"التلفزيون"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"الهاتف"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"مكبرات صوت للإرساء"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"سماعات رأس"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"النظام"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index d6a4bb0..93957e5 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"টিভি"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ফ\'ন"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ড\'ক স্পীকাৰসমূহ"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"হেডফ\'নবোৰ"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"ইউএছবি"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"ছিষ্টেম"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 370fc6d..c4f3d75 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dok spikerlər"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Qulaqlıq"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistem"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index ef2a68c..bf9c57b 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Zvučnici bazne stanice"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Slušalice"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistem"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 1212c02..1af3c7d 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ТБ"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Тэлефон"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Дынамікі станцыi"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Навушнікі"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Сістэма"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 1007746..4ae1f21 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Телевизор"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Телефон"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Докинг станц.: Високогов."</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Слушалки"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Система"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 96acf7f..2aac0c9 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"টিভি"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ফোন"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ডক স্পিকার"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"হেডফোন"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"সিস্টেম"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index f7a5f38..3c87b0d 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Zvučnici priključne stanice"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Slušalice"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistem"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 4819c9eb..317c004 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Televisor"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telèfon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Altaveus de la base"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Auriculars"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 83c4afb..cbd2df6 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Televize"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Reproduktory doku"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Sluchátka"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Systém"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 672e7c7..083c42c 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Tv"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dockstationens højttalere"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Hovedtelefoner"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 01e3d45..fc8eadaf 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dock-Lautsprecher"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Kopfhörer"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 0e3c0a1..c76b2b0 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Τηλεόραση"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Τηλέφωνο"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Ηχεία βάσης σύνδεσης"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Ακουστικά"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Σύστημα"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 805e014..8591467 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Phone"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dock speakers"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Headphones"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 79d3923..08097a5 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Phone"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dock speakers"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Headphones"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 8054969..bf82587 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Phone"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dock speakers"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Headphones"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 9d1c6a4..110e68f 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Phone"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dock speakers"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Headphones"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index eae7c27a..ddb93a8 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1610,7 +1610,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‎‎‎‎‎‎‎‏‎‏‎‏‏‎‏‏‏‎‏‏‏‎‏‎‎‎‎‏‏‏‎‎‎‏‎‏‎‎‏‏‎‏‎‎‎‎‏‎‎‎‏‏‏‎TV‎‏‎‎‏‎"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‎‏‎‏‏‏‏‎‎‎‎‎‎‏‏‎‏‎‎‏‎Phone‎‏‎‎‏‎"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‎‎‏‏‎‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‏‎‎‎‎‎‎‏‏‎‎‎‏‏‎‎‏‎Dock speakers‎‏‎‎‏‎"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‎‎‎‏‎‎‎‎‏‎‎‎‎‎‎‏‏‎‏‎‎HDMI‎‏‎‎‏‎"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‎‎‎‏‎‎‎‎‏‎‎‎‎‎‎‏‏‎‏‎‎HDMI‎‏‎‎‏‎"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‏‎‏‎‏‏‏‎‎‏‏‎‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‏‏‏‏‎‏‎‎Headphones‎‏‎‎‏‎"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‏‏‎‏‏‏‎‎‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‏‏‎‎‎‏‎‏‎‏‏‎‎‎‏‎‎‎USB‎‏‎‎‏‎"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‏‎‎‏‎‏‎‎‏‏‎System‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index f06903b5..933ccfb 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Dispositivo"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Altavoces del conector"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Auriculares"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 5423512..9795e23 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Teléfono"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Altavoces de la base"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Auriculares"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index bfb6aad..fe7549e 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Teler"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Doki kõlarid"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Kõrvaklapid"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Süsteem"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 4a56b59..7f424eb 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Telebista"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefonoa"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Konektatu bozgorailuak oinarrira"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Entzungailuak"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index ea3b8591..83821a3 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"تلویزیون"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"تلفن"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"بلندگوهای جایگاه"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"هدفون‌ها"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"سیستم"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index ff9e620..8798ffc 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Puhelin"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Telineen kaiuttimet"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Kuulokkeet"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Järjestelmä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 09ef190..87861ae 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Télévision"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Téléphone"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Haut-parleurs de la station d\'accueil"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Oreillettes"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Système"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 487f290..a9dccbc 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Téléviseur"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Téléphone"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Haut-parleurs de la station d\'accueil"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Écouteurs"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Système"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 1113926..ae29e50 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Televisión"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Teléfono"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Conectar altofalantes á base"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Auriculares"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index eec5272..36812e8 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ફોન"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"સ્પીકર્સ ડૉક કરો"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"હેડફોન"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"સિસ્ટમ"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 780616f..2a9a44a 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"टीवी"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"फ़ोन"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"डॉक स्‍पीकर"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"हेडफ़ोन"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"यूएसबी"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"सिस्‍टम"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index fbc47e2..0a2702a 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Televizor"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Zvučnici postolja"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Slušalice"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sustav"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 897904d..01b6f90 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dokkolóegység hangszórója"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Fejhallgató"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Rendszer"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index fc8c3e1..86560be 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Հեռուստացույց"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Հեռախոս"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Դոկ-կայանի բարձրախոսներ"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Ականջակալներ"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Համակարգ"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index af1b0bd..b145e20 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Ponsel"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Pengeras suara dok"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Headphone"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistem"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 69e3127..6f48de2 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Sjónvarp"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Sími"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dokkuhátalarar"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Heyrnartól"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Kerfi"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index bf18581..fb7763a 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefono"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Altoparlanti dock"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Cuffie audio"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 30c6942..7a460a3 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"טלוויזיה"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"טלפון"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"רמקולים של מעגן"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"אוזניות"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"מערכת"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 8733542..cf8521f 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1610,7 +1610,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"テレビ"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"モバイル デバイス"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ホルダーのスピーカー"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ヘッドホン"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"システム"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 2b4262c..ae14cc9 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ტელევიზია"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ტელეფონი"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"სპიკერების მიმაგრება"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ყურსასმენები"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"სისტემა"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 4a37cc5..54edba3 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ТД"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Телефон"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Үндеткіштерді қондыру"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Құлақаспаптар"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Жүйе"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 5738925..0d3d07d 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ទូរទស្សន៍"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ទូរសព្ទ"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ភ្ជាប់​អូប៉ាល័រ"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"កាស"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"ប្រព័ន្ធ"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 61c9415..9925a26 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ಟಿವಿ"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ಫೋನ್"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ಡಾಕ್ ಸ್ಪೀಕರ್‍‌ಗಳು"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ಹೆಡ್‌ಫೋನ್‌ಗಳು"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"ಸಿಸ್ಟಂ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 32fbe92..40c545f 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"휴대전화"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"도크 스피커"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"헤드폰"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"시스템"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index b1673fd..f27b0d6 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Сыналгы"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Телефон"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Аудио док бекет"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Кулакчын"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Тутум"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 3cdebdd..7c9f815 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ໂທລະພາບ"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ໂທລະສັບ"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ບ່ອນຕັ້ງລຳໂພງ"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ຫູຟັງ"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"ລະບົບ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 73ce68a..2954f9c 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefonas"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Doko garsiakalbiai"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Ausinės"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 8429919..853a490 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Tālrunis"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Doka skaļruņi"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Austiņas"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistēma"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 80934d0..9ce43d1 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Телевизор"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Телефон"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Приклучи звучници"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Слушалки"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Систем"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 7437725..c71047d 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ടിവി"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ഫോണ്‍"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ഡോക്ക് സ്‌പീക്കറുകൾ"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ഹെഡ്‌ഫോണുകൾ"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"സിസ്റ്റം"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 1935280..417500d 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Tелевиз"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Утас"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Чанга яригчийг суулгах"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Чихэвч"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Систем"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index ac9f289..f91a18f 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"टीव्ही"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"फोन"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"स्पीकर डॉक करा"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"हेडफोन"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"सिस्टम"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 94be0fc..9b76a16 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Pembesar suara dok"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Fon kepala"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistem"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 0a11698..87916c4 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ဖုန်း"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"အထိုင်ရှိသော စပီကာများ"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"နားကြပ်"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"စနစ်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e439859..e101548 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Google TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dokkhøyttalere"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Hodetelefoner"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index b3647ce..b2bf381 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"टिभी"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"फोन"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"डक स्पिकरहरू"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"हेडफोनहरू"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"प्रणाली"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 92ea1c4..9811e27 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Tv"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefoon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dockluidsprekers"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Hoofdtelefoon"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Systeem"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index e42a7e3..d3cbaec 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ଫୋନ"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ଡକ୍‌ ସ୍ପିକର୍‌"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ହେଡଫୋନ୍‍"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"ସିଷ୍ଟମ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 500f37d..2ffeef4 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ਫ਼ੋਨ ਕਰੋ"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ਡੌਕ ਸਪੀਕਰਸ"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ਹੈੱਡਫ਼ੋਨ"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"ਸਿਸਟਮ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index be71f35..88b54b0 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Telewizor"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Głośniki stacji dokującej"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Słuchawki"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index ad94450..7d5721a 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefone"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Alto-falantes na base"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Fones de ouvido"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 000d3f7..1fe0db7a 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telemóvel"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Altif. estação ancoragem"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Auscultadores"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index ad94450..7d5721a 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefone"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Alto-falantes na base"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Fones de ouvido"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 142b278..27b04d6 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Difuz. dispozit. andocare"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Căști"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistem"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 7b47179..2cceafc 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Телевизор"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Телефон"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Динамики док-станции"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Наушники"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Система"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index f1f8127..06ac0f8 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"රූපවාහිනී"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"දුරකථනය"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"නාදක ඩොක් කරන්න"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ඉස් බණු"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"පද්ධතිය"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index ce3137c..cdc6829 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Televízor"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefón"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Reproduktory doku"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Slúchadlá"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Systém"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 3a56d6d..6da07f8 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Televizor"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Zvočniki stojala"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Slušalke"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistem"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index ab7c68b..587215a 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Televizori"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Altoparlantët e stacionit"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Kufjet"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistemi"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 6220219..2acaf5c 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ТВ"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Телефон"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Звучници базне станице"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Слушалице"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Систем"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 26a496d..a6c162a 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Mobil"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dockningsstationens högtalare"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Hörlurar"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 09083ea..b17f58e 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Runinga"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Simu"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Vipasa sauti vya kituo"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Vipokeasauti"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Mfumo"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index ad49382..6a7973e 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"டிவி"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ஃபோன்"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"மொபைல் வைக்கும் கருவியின் ஸ்பீக்கர்கள்"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ஹெட்ஃபோன்கள்"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"சிஸ்டம்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index fe0efad..8c53b13 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"టీవీ"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ఫోన్"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"డాక్ స్పీకర్‌లు"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"హెడ్‌ఫోన్‌లు"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"సిస్టమ్"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index c60db37..7826774 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ทีวี"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"โทรศัพท์"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ลำโพงแท่นชาร์จ"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"หูฟัง"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"ระบบ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 4f8e7a3e..e9d17a9 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telepono"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Mga speaker ng dock"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Mga Headphone"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index d2c7958..762b731 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Yuva hoparlörleri"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Kulaklıklar"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistem"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 9223d9a..730cfac 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Телевізор"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Телефон"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Динаміки док-станції"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Навушники"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Система"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 5c6c555..6fa0071 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"فون"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ڈاک اسپیکرز"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ہیڈ فونز"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"سسٹم"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 99e2a57..b9a0ae5 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Taglik karnaylar"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Quloq karnaychalari"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Tizim"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 965e520..ad4a3899 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Điện thoại"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Loa đế"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Tai nghe"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Hệ thống"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 02f0ac8..ce5cd53 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"电视"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"手机"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"基座扬声器"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"耳机"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"系统"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 40e313c..96c7b0b 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"電視"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"手機"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"插座喇叭"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"耳機"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"系統"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 147b38b..46d95c7f 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"電視"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"手機"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"座架喇叭"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"耳機"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"系統"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 723e0b2..6e640c6 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"I-TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Ifoni"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Izipikha ze-Dock"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Ama-headphone"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"I-USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Isistimu"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f685415..dfada13 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1733,7 +1733,7 @@
     <item name="default_lock_wallpaper" type="drawable">@null</item>
 
     <!-- Component name of the built in wallpaper used to display bitmap wallpapers. This must not be null. -->
-    <string name="image_wallpaper_component" translatable="false">com.android.systemui/com.android.systemui.ImageWallpaper</string>
+    <string name="image_wallpaper_component" translatable="false">com.android.systemui/com.android.systemui.wallpapers.ImageWallpaper</string>
 
     <!-- True if WallpaperService is enabled -->
     <bool name="config_enableWallpaperService">true</bool>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ef33a22..63eb83e 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1689,7 +1689,7 @@
     <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
     <string name="fingerprint_acquired_partial">Press firmly on the sensor</string>
     <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
-    <string name="fingerprint_acquired_insufficient">Couldn\'t process fingerprint. Please try again.</string>
+    <string name="fingerprint_acquired_insufficient">Can\u2019t recognize fingerprint. Try again.</string>
     <!-- Message shown during fingerprint acquisision when the fingerprint sensor needs cleaning -->
     <string name="fingerprint_acquired_imager_dirty">Clean fingerprint sensor and try again</string>
     <string name="fingerprint_acquired_imager_dirty_alt">Clean sensor and try again</string>
@@ -1725,17 +1725,17 @@
     <!-- Error message shown when the fingerprint hardware has run out of room for storing fingerprints -->
     <string name="fingerprint_error_no_space">Can\u2019t set up fingerprint</string>
     <!-- Error message shown when the fingerprint hardware timer has expired and the user needs to restart the operation. -->
-    <string name="fingerprint_error_timeout">Fingerprint time out reached. Try again.</string>
+    <string name="fingerprint_error_timeout">Fingerprint setup timed out. Try again.</string>
     <!-- Generic error message shown when the fingerprint operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user-->
     <string name="fingerprint_error_canceled">Fingerprint operation canceled.</string>
     <!-- Generic error message shown when the fingerprint authentication operation is canceled due to user input. Generally not shown to the user -->
     <string name="fingerprint_error_user_canceled">Fingerprint operation canceled by user.</string>
     <!-- Generic error message shown when the fingerprint operation fails because too many attempts have been made. -->
-    <string name="fingerprint_error_lockout">Too many attempts. Try again later.</string>
+    <string name="fingerprint_error_lockout">Too many attempts. Use screen lock instead.</string>
     <!-- Generic error message shown when the fingerprint operation fails because strong authentication is required -->
     <string name="fingerprint_error_lockout_permanent">Too many attempts. Use screen lock instead.</string>
     <!-- Generic error message shown when the fingerprint hardware can't recognize the fingerprint -->
-    <string name="fingerprint_error_unable_to_process">Try again.</string>
+    <string name="fingerprint_error_unable_to_process">Can\u2019t process fingerprint. Try again.</string>
     <!-- Generic error message shown when the user has no enrolled fingerprints -->
     <string name="fingerprint_error_no_fingerprints">No fingerprints enrolled.</string>
     <!-- Generic error message shown when the app requests fingerprint authentication on a device without a sensor -->
@@ -4525,8 +4525,8 @@
     <!-- Name of the default audio route when an audio dock is connected. [CHAR LIMIT=50] -->
     <string name="default_audio_route_name_dock_speakers">Dock speakers</string>
 
-    <!-- Name of the default audio route when HDMI is connected. [CHAR LIMIT=50] -->
-    <string name="default_audio_route_name_hdmi">HDMI</string>
+    <!-- Name of the default audio route when an external device is connected. [CHAR LIMIT=50] -->
+    <string name="default_audio_route_name_external_device">External Device</string>
 
     <!-- Name of the default audio route when wired headphones are
          connected. [CHAR LIMIT=50] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9df1515..66bfbb6 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1082,7 +1082,7 @@
   <java-symbol type="string" name="default_audio_route_id" />
   <java-symbol type="string" name="default_audio_route_name" />
   <java-symbol type="string" name="default_audio_route_name_dock_speakers" />
-  <java-symbol type="string" name="default_audio_route_name_hdmi" />
+  <java-symbol type="string" name="default_audio_route_name_external_device" />
   <java-symbol type="string" name="default_audio_route_name_headphones" />
   <java-symbol type="string" name="default_audio_route_name_usb" />
   <java-symbol type="string" name="default_audio_route_category_name" />
diff --git a/core/tests/coretests/src/com/android/internal/jank/DisplayResolutionTrackerTest.java b/core/tests/coretests/src/com/android/internal/jank/DisplayResolutionTrackerTest.java
new file mode 100644
index 0000000..5021022
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/jank/DisplayResolutionTrackerTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 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.jank;
+
+import static com.android.internal.jank.DisplayResolutionTracker.getResolution;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.hardware.display.DisplayManager;
+import android.view.DisplayInfo;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+@SmallTest
+public class DisplayResolutionTrackerTest {
+    private static final DisplayInfo SD = makeDisplayInfo(800, 600);
+    private static final DisplayInfo HD = makeDisplayInfo(720, 1280);
+    private static final DisplayInfo FHD = makeDisplayInfo(2340, 1080);
+    private static final DisplayInfo QHD = makeDisplayInfo(3120, 1440);
+
+    private DisplayResolutionTracker.DisplayInterface mDisplayManager;
+    private ArgumentCaptor<DisplayManager.DisplayListener> mListenerCaptor;
+    private DisplayResolutionTracker mTracker;
+
+    @Before
+    public void setup() throws Exception {
+        mDisplayManager = mock(DisplayResolutionTracker.DisplayInterface.class);
+        mListenerCaptor = ArgumentCaptor.forClass(DisplayManager.DisplayListener.class);
+
+        mTracker = new DisplayResolutionTracker(mDisplayManager);
+
+        verify(mDisplayManager).registerDisplayListener(mListenerCaptor.capture());
+    }
+
+    @Test
+    public void testResolutionMapping() {
+        assertThat(getResolution(SD)).isEqualTo(DisplayResolutionTracker.RESOLUTION_SD);
+        assertThat(getResolution(HD)).isEqualTo(DisplayResolutionTracker.RESOLUTION_HD);
+        assertThat(getResolution(FHD)).isEqualTo(DisplayResolutionTracker.RESOLUTION_FHD);
+        assertThat(getResolution(QHD)).isEqualTo(DisplayResolutionTracker.RESOLUTION_QHD);
+    }
+
+    @Test
+    public void testResolutionUpdatesOnDisplayChanges() throws Exception {
+        assertThat(mTracker.getResolution(42))
+                .isEqualTo(DisplayResolutionTracker.RESOLUTION_UNKNOWN);
+
+        when(mDisplayManager.getDisplayInfo(42)).thenReturn(FHD, QHD);
+
+        mListenerCaptor.getValue().onDisplayAdded(42);
+        assertThat(mTracker.getResolution(42))
+                .isEqualTo(DisplayResolutionTracker.RESOLUTION_FHD);
+        mListenerCaptor.getValue().onDisplayChanged(42);
+        assertThat(mTracker.getResolution(42))
+                .isEqualTo(DisplayResolutionTracker.RESOLUTION_QHD);
+    }
+
+    private static DisplayInfo makeDisplayInfo(int width, int height) {
+        DisplayInfo info = new DisplayInfo();
+        info.logicalWidth = width;
+        info.logicalHeight = height;
+        return info;
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
index e068730..dbbd705 100644
--- a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
@@ -124,6 +124,7 @@
         when(config.isSurfaceOnly()).thenReturn(surfaceOnly);
         when(config.getSurfaceControl()).thenReturn(mSurfaceControl);
         when(config.shouldDeferMonitor()).thenReturn(true);
+        when(config.getDisplayId()).thenReturn(42);
         View view = mRule.getActivity().getWindow().getDecorView();
         Handler spyHandler = spy(new Handler(handler.getLooper()));
         when(config.getView()).thenReturn(surfaceOnly ? null : view);
@@ -168,6 +169,7 @@
         verify(tracker).removeObservers();
         verify(tracker, never()).triggerPerfetto();
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
                 eq(2L) /* totalFrames */,
                 eq(0L) /* missedFrames */,
@@ -204,6 +206,7 @@
         verify(tracker).triggerPerfetto();
 
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
                 eq(2L) /* totalFrames */,
                 eq(1L) /* missedFrames */,
@@ -240,6 +243,7 @@
         verify(tracker, never()).triggerPerfetto();
 
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
                 eq(2L) /* totalFrames */,
                 eq(0L) /* missedFrames */,
@@ -276,6 +280,7 @@
         verify(tracker).triggerPerfetto();
 
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
                 eq(2L) /* totalFrames */,
                 eq(1L) /* missedFrames */,
@@ -315,6 +320,7 @@
         verify(tracker).triggerPerfetto();
 
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
                 eq(2L) /* totalFrames */,
                 eq(1L) /* missedFrames */,
@@ -356,6 +362,7 @@
         verify(tracker).removeObservers();
         verify(tracker, never()).triggerPerfetto();
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
                 eq(2L) /* totalFrames */,
                 eq(0L) /* missedFrames */,
@@ -483,6 +490,7 @@
         verify(tracker).triggerPerfetto();
 
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WALLPAPER_TRANSITION]),
                 eq(2L) /* totalFrames */,
                 eq(1L) /* missedFrames */,
@@ -519,6 +527,7 @@
         verify(tracker, never()).triggerPerfetto();
 
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WALLPAPER_TRANSITION]),
                 eq(2L) /* totalFrames */,
                 eq(0L) /* missedFrames */,
@@ -555,6 +564,7 @@
         verify(tracker, never()).triggerPerfetto();
 
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WALLPAPER_TRANSITION]),
                 eq(2L) /* totalFrames */,
                 eq(0L) /* missedFrames */,
@@ -585,6 +595,7 @@
         verify(mSurfaceControlWrapper).removeJankStatsListener(any());
         verify(tracker).triggerPerfetto();
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WALLPAPER_TRANSITION]),
                 eq(6L) /* totalFrames */,
                 eq(5L) /* missedFrames */,
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..4770fa6 100644
--- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -354,10 +354,11 @@
         when(configuration.isSurfaceOnly()).thenReturn(false);
         when(configuration.getView()).thenReturn(mView);
         when(configuration.getHandler()).thenReturn(mView.getHandler());
+        when(configuration.getDisplayId()).thenReturn(42);
 
         FrameTracker tracker = spy(new FrameTracker(monitor, session, mWorker.getThreadHandler(),
                 threadedRenderer, viewRoot, surfaceControl, choreographer,
-                new FrameMetricsWrapper(), new StatsLogWrapper(),
+                new FrameMetricsWrapper(), new StatsLogWrapper(null),
                 /* traceThresholdMissedFrames= */ 1,
                 /* traceThresholdFrameTimeMillis= */ -1, listener, configuration));
 
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 61fafb5..3d879b6 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
@@ -114,6 +114,9 @@
         UserChangeListener {
     private static final String TAG = "PipController";
 
+    private static final long PIP_KEEP_CLEAR_AREAS_DELAY =
+            SystemProperties.getLong("persist.wm.debug.pip_keep_clear_areas_delay", 200);
+
     private boolean mEnablePipKeepClearAlgorithm =
             SystemProperties.getBoolean("persist.wm.debug.enable_pip_keep_clear_algorithm", false);
 
@@ -146,6 +149,8 @@
     private final Rect mTmpInsetBounds = new Rect();
     private final int mEnterAnimationDuration;
 
+    private final Runnable mMovePipInResponseToKeepClearAreasChangeCallback;
+
     private boolean mIsInFixedRotation;
     private PipAnimationListener mPinnedStackAnimationRecentsCallback;
 
@@ -277,14 +282,12 @@
                     if (mPipBoundsState.getDisplayId() == displayId) {
                         if (mEnablePipKeepClearAlgorithm) {
                             mPipBoundsState.setKeepClearAreas(restricted, unrestricted);
-                            // 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);
-                            }
+
+                            mMainExecutor.removeCallbacks(
+                                    mMovePipInResponseToKeepClearAreasChangeCallback);
+                            mMainExecutor.executeDelayed(
+                                    mMovePipInResponseToKeepClearAreasChangeCallback,
+                                    PIP_KEEP_CLEAR_AREAS_DELAY);
                         }
                     }
                 }
@@ -411,6 +414,15 @@
 
         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/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 9c9841f..8ed16ce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -1887,7 +1887,6 @@
             // properly for the animation itself.
             mSplitLayout.release();
             mSplitLayout.resetDividerPosition();
-            mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT;
             mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
         }
     }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
index 2dccda6f..fac0f73 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
@@ -17,7 +17,6 @@
 package com.android.wm.shell.flicker.bubble
 
 import android.os.SystemClock
-import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
 import androidx.test.uiautomator.By
@@ -90,70 +89,4 @@
             this.isVisible(testApp)
         }
     }
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun entireScreenCovered() =
-        super.entireScreenCovered()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() =
-        super.navBarLayerIsVisibleAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarLayerPositionAtStartAndEnd() =
-        super.navBarLayerPositionAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarWindowIsAlwaysVisible() =
-        super.navBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun statusBarLayerIsVisibleAtStartAndEnd() =
-        super.statusBarLayerIsVisibleAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun statusBarWindowIsAlwaysVisible() =
-        super.statusBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() =
-        super.taskBarLayerIsVisibleAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun taskBarWindowIsAlwaysVisible() =
-        super.taskBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index eebc97b..9684bb3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -17,7 +17,7 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -83,6 +83,7 @@
             }
         }
 
+    @FlakyTest
     @Test
     override fun pipLayerReduces() {
         testSpec.assertLayers {
@@ -96,6 +97,7 @@
     /**
      * Checks that [pipApp] window is animated towards default position in right bottom corner
      */
+    @Presubmit
     @Test
     fun pipLayerMovesTowardsRightBottomCorner() {
         // in gestural nav the swipe makes PiP first go upwards
@@ -111,66 +113,11 @@
         }
     }
 
+    @Presubmit
     @Test
     override fun focusChanges() {
         // in gestural nav the focus goes to different activity on swipe up
         Assume.assumeFalse(testSpec.isGesturalNavigation)
         super.focusChanges()
     }
-
-    @Postsubmit
-    @Test
-    override fun entireScreenCovered() = super.entireScreenCovered()
-
-    @Postsubmit
-    @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
-
-    @Postsubmit
-    @Test
-    override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
-    @Postsubmit
-    @Test
-    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
-
-    @Postsubmit
-    @Test
-    override fun pipAppLayerAlwaysVisible() = super.pipAppLayerAlwaysVisible()
-
-    @Postsubmit
-    @Test
-    override fun pipLayerRemainInsideVisibleBounds() = super.pipLayerRemainInsideVisibleBounds()
-
-    @Postsubmit
-    @Test
-    override fun statusBarLayerIsVisibleAtStartAndEnd() =
-        super.statusBarLayerIsVisibleAtStartAndEnd()
-
-    @Postsubmit
-    @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
-
-    @Postsubmit
-    @Test
-    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
-    @Postsubmit
-    @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
-
-    @Postsubmit
-    @Test
-    override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
-
-    @Postsubmit
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
-    @Postsubmit
-    @Test
-    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
index bac6a0c..59f7ecf 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -17,7 +17,6 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
@@ -81,7 +80,7 @@
             }
         }
 
-    @Postsubmit
+    @Presubmit
     @Test
     override fun pipAppLayerAlwaysVisible() {
         if (!testSpec.isGesturalNavigation) super.pipAppLayerAlwaysVisible() else {
@@ -94,7 +93,7 @@
         }
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     override fun pipLayerReduces() {
         // in gestural nav the pip enters through alpha animation
@@ -102,7 +101,7 @@
         super.pipLayerReduces()
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     override fun focusChanges() {
         // in gestural nav the focus goes to different activity on swipe up
@@ -110,11 +109,6 @@
         super.focusChanges()
     }
 
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun pipAppWindowAlwaysVisible() = super.pipAppWindowAlwaysVisible()
-
     @Presubmit
     @Test
     override fun entireScreenCovered() {
@@ -129,7 +123,7 @@
         super.entireScreenCovered()
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     override fun pipLayerRemainInsideVisibleBounds() {
         if (!testSpec.isGesturalNavigation) super.pipLayerRemainInsideVisibleBounds() else {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index f6bb534..87d800c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -231,11 +231,6 @@
     override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
         super.visibleLayersShownMoreThanOneConsecutiveEntry()
 
-    /** {@inheritDoc}  */
-    @FlakyTest(bugId = 227313015)
-    @Test
-    override fun entireScreenCovered() = super.entireScreenCovered()
-
     companion object {
         /**
          * Creates the test configurations.
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
index 183c06f..0f7d8a9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import com.android.server.wm.flicker.FlickerTestParameter
@@ -90,63 +89,4 @@
                 .isVisible(LAUNCHER)
         }
     }
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun entireScreenCovered() = super.entireScreenCovered()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun statusBarLayerIsVisibleAtStartAndEnd() =
-        super.statusBarLayerIsVisibleAtStartAndEnd()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
index 034f623..75018d1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
@@ -78,7 +78,12 @@
         }
 
     /** {@inheritDoc}  */
-    @FlakyTest(bugId = 206753786)
+    @FlakyTest
+    @Test
+    override fun entireScreenCovered() = super.entireScreenCovered()
+
+    /** {@inheritDoc}  */
+    @Presubmit
     @Test
     override fun statusBarLayerPositionAtStartAndEnd() {
         Assume.assumeFalse(isShellTransitionsEnabled)
@@ -107,11 +112,6 @@
         super.pipLayerExpands()
     }
 
-    /** {@inheritDoc}  */
-    @FlakyTest(bugId = 227313015)
-    @Test
-    override fun entireScreenCovered() = super.entireScreenCovered()
-
     companion object {
         /**
          * Creates the test configurations.
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index 825aca3..4d39ec5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -111,7 +111,7 @@
     /**
      * Checks that the visible region of [pipApp] always expands during the animation
      */
-    @FlakyTest(bugId = 228012337)
+    @Presubmit
     @Test
     fun pipLayerExpands() {
         testSpec.assertLayers {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
index 0b6e7ee..3e08bfb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.RequiresDevice
 import android.view.Surface
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -29,7 +28,6 @@
 import org.junit.Assume
 import org.junit.Before
 import org.junit.FixMethodOrder
-import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
@@ -84,12 +82,6 @@
         current.isLowerOrEqual(previous.region)
     }
 
-    /** {@inheritDoc}  */
-    @FlakyTest(bugId = 206753786)
-    @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
-
     companion object {
         /**
          * Creates the test configurations.
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index df6ba98..27fc2ed 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
@@ -76,12 +75,6 @@
             }
         }
 
-    /** {@inheritDoc}  */
-    @FlakyTest(bugId = 206753786)
-    @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
-
     /**
      * Ensure the pip window remains visible throughout any keyboard interactions
      */
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index fc0f0ee..fd5ff29 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -17,6 +17,7 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -24,7 +25,6 @@
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.annotation.Group4
 import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.entireScreenCovered
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
 import com.android.server.wm.flicker.helpers.setRotation
@@ -83,13 +83,6 @@
         }
 
     /**
-     * Checks that all parts of the screen are covered at the start and end of the transition
-     */
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun entireScreenCovered() = testSpec.entireScreenCovered()
-
-    /**
      * Checks the position of the navigation bar at the start and end of the transition
      */
     @FlakyTest(bugId = 240499181)
@@ -99,7 +92,7 @@
     /**
      * Checks that [fixedApp] layer is within [screenBoundsStart] at the start of the transition
      */
-    @FlakyTest(bugId = 240499181)
+    @Presubmit
     @Test
     fun fixedAppLayer_StartingBounds() {
         testSpec.assertLayersStart {
@@ -110,7 +103,7 @@
     /**
      * Checks that [fixedApp] layer is within [screenBoundsEnd] at the end of the transition
      */
-    @FlakyTest(bugId = 240499181)
+    @Presubmit
     @Test
     fun fixedAppLayer_EndingBounds() {
         testSpec.assertLayersEnd {
@@ -122,7 +115,7 @@
      * Checks that [fixedApp] plus [pipApp] layers are within [screenBoundsEnd] at the start
      * of the transition
      */
-    @FlakyTest(bugId = 240499181)
+    @Presubmit
     @Test
     fun appLayers_StartingBounds() {
         testSpec.assertLayersStart {
@@ -134,7 +127,7 @@
      * Checks that [fixedApp] plus [pipApp] layers are within [screenBoundsEnd] at the end
      * of the transition
      */
-    @FlakyTest(bugId = 240499181)
+    @Presubmit
     @Test
     fun appLayers_EndingBounds() {
         testSpec.assertLayersEnd {
@@ -154,7 +147,7 @@
     /**
      * Checks that [pipApp] layer is within [screenBoundsStart] at the start of the transition
      */
-    @FlakyTest(bugId = 240499181)
+    @Presubmit
     @Test
     fun pipLayerRotates_StartingBounds() {
         pipLayerRotates_StartingBounds_internal()
@@ -163,7 +156,7 @@
     /**
      * Checks that [pipApp] layer is within [screenBoundsEnd] at the end of the transition
      */
-    @FlakyTest(bugId = 240499181)
+    @Presubmit
     @Test
     fun pipLayerRotates_EndingBounds() {
         testSpec.assertLayersEnd {
@@ -175,7 +168,7 @@
      * Ensure that the [pipApp] window does not obscure the [fixedApp] at the start of the
      * transition
      */
-    @FlakyTest(bugId = 240499181)
+    @Presubmit
     @Test
     fun pipIsAboveFixedAppWindow_Start() {
         testSpec.assertWmStart {
@@ -187,7 +180,7 @@
      * Ensure that the [pipApp] window does not obscure the [fixedApp] at the end of the
      * transition
      */
-    @FlakyTest(bugId = 240499181)
+    @Presubmit
     @Test
     fun pipIsAboveFixedAppWindow_End() {
         testSpec.assertWmEnd {
@@ -201,54 +194,6 @@
         super.navBarLayerIsVisibleAtStartAndEnd()
     }
 
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun navBarWindowIsAlwaysVisible() {
-        super.navBarWindowIsAlwaysVisible()
-    }
-
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun statusBarLayerIsVisibleAtStartAndEnd() {
-        super.statusBarLayerIsVisibleAtStartAndEnd()
-    }
-
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun statusBarLayerPositionAtStartAndEnd() {
-        super.statusBarLayerPositionAtStartAndEnd()
-    }
-
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun statusBarWindowIsAlwaysVisible() {
-        super.statusBarWindowIsAlwaysVisible()
-    }
-
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() {
-        super.taskBarLayerIsVisibleAtStartAndEnd()
-    }
-
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun taskBarWindowIsAlwaysVisible() {
-        super.taskBarWindowIsAlwaysVisible()
-    }
-
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-    }
-
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-    }
-
     companion object {
         /**
          * Creates the test configurations.
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest_ShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest_ShellTransit.kt
index 0dd38cd..737f16a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest_ShellTransit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest_ShellTransit.kt
@@ -25,6 +25,7 @@
 import org.junit.Assume
 import org.junit.Before
 import org.junit.FixMethodOrder
+import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
@@ -59,4 +60,10 @@
     override fun before() {
         Assume.assumeTrue(isShellTransitionsEnabled)
     }
+
+    /** {@inheritDoc}  */
+    @FlakyTest
+    @Test
+    override fun navBarLayerPositionAtStartAndEnd() =
+        super.navBarLayerPositionAtStartAndEnd()
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index acada4c..866e4e8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -171,18 +171,6 @@
     /** {@inheritDoc}  */
     @Postsubmit
     @Test
-    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
     override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc}  */
@@ -193,25 +181,8 @@
     /** {@inheritDoc}  */
     @Postsubmit
     @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
     override fun entireScreenCovered() = super.entireScreenCovered()
 
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun navBarWindowIsAlwaysVisible() =
-        super.navBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index fde7afd..ca906d2 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -342,9 +342,14 @@
         // Only include memory for 1 buffer, since actually accounting for the memory used is
         // complex, and 1 buffer is enough for the VM to treat the ImageReader as being of some
         // size.
-        mEstimatedNativeAllocBytes = ImageUtils.getEstimatedNativeAllocBytes(
-            width, height, useLegacyImageFormat ? imageFormat : hardwareBufferFormat,
-            /*buffer count*/ 1);
+        if (hardwareBufferFormat == HardwareBuffer.BLOB) {
+            mEstimatedNativeAllocBytes = ImageUtils.getEstimatedNativeAllocBytes(
+                width, height, imageFormat, /*buffer count*/ 1);
+        } else {
+            mEstimatedNativeAllocBytes = ImageUtils.getEstimatedNativeAllocBytes(
+                width, height, useLegacyImageFormat ? imageFormat : hardwareBufferFormat,
+                /*buffer count*/ 1);
+        }
         VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes);
     }
 
@@ -370,7 +375,6 @@
             MultiResolutionImageReader parent, int hardwareBufferFormat, int dataSpace) {
         mWidth = width;
         mHeight = height;
-        mFormat = ImageFormat.UNKNOWN; // set default image format value as UNKNOWN
         mUsage = usage;
         mMaxImages = maxImages;
         mParent = parent;
@@ -378,6 +382,7 @@
         mDataSpace = dataSpace;
         mUseLegacyImageFormat = false;
         mNumPlanes = ImageUtils.getNumPlanesForHardwareBufferFormat(mHardwareBufferFormat);
+        mFormat = PublicFormatUtils.getPublicFormat(hardwareBufferFormat, dataSpace);
 
         initializeImageReader(width, height, mFormat, maxImages, usage, hardwareBufferFormat,
                 dataSpace, mUseLegacyImageFormat);
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 9f52bf1..259c138 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -29,7 +29,6 @@
 import android.hardware.HardwareBuffer;
 import android.hardware.HardwareBuffer.Usage;
 import android.hardware.SyncFence;
-import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.utils.SurfaceUtils;
 import android.os.Handler;
 import android.os.Looper;
@@ -266,31 +265,11 @@
             // nativeInit internally overrides UNKNOWN format. So does surface format query after
             // nativeInit and before getEstimatedNativeAllocBytes().
             imageFormat = SurfaceUtils.getSurfaceFormat(surface);
-            mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
-            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+            mDataSpace = dataSpace = PublicFormatUtils.getHalDataspace(dataSpace);
+            mHardwareBufferFormat =
+                hardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
         }
 
-        // Several public formats use the same native HAL_PIXEL_FORMAT_BLOB. The native
-        // allocation estimation sequence depends on the public formats values. To avoid
-        // possible errors, convert where necessary.
-        if (imageFormat == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB) {
-            int surfaceDataspace = SurfaceUtils.getSurfaceDataspace(surface);
-            switch (surfaceDataspace) {
-                case StreamConfigurationMap.HAL_DATASPACE_DEPTH:
-                    imageFormat = ImageFormat.DEPTH_POINT_CLOUD;
-                    break;
-                case StreamConfigurationMap.HAL_DATASPACE_DYNAMIC_DEPTH:
-                    imageFormat = ImageFormat.DEPTH_JPEG;
-                    break;
-                case StreamConfigurationMap.HAL_DATASPACE_HEIF:
-                    imageFormat = ImageFormat.HEIC;
-                    break;
-                default:
-                    imageFormat = ImageFormat.JPEG;
-            }
-            mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
-            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
-        }
         // Estimate the native buffer allocation size and register it so it gets accounted for
         // during GC. Note that this doesn't include the buffers required by the buffer queue
         // itself and the buffers requested by the producer.
@@ -301,17 +280,44 @@
         mWidth = width == -1 ? surfSize.getWidth() : width;
         mHeight = height == -1 ? surfSize.getHeight() : height;
 
-        mEstimatedNativeAllocBytes =
-            ImageUtils.getEstimatedNativeAllocBytes(mWidth, mHeight,
-                useLegacyImageFormat ? imageFormat : hardwareBufferFormat, /*buffer count*/ 1);
+        if (hardwareBufferFormat == HardwareBuffer.BLOB) {
+            // TODO(b/246344817): remove mWriterFormat and mDataSpace re-set here after fixing.
+            mWriterFormat = imageFormat = getImageFormatByBLOB(dataSpace);
+            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+
+            mEstimatedNativeAllocBytes = ImageUtils.getEstimatedNativeAllocBytes(mWidth, mHeight,
+                imageFormat, /*buffer count*/ 1);
+        } else {
+            mEstimatedNativeAllocBytes =
+                ImageUtils.getEstimatedNativeAllocBytes(mWidth, mHeight,
+                    useLegacyImageFormat ? imageFormat : hardwareBufferFormat, /*buffer count*/ 1);
+        }
         VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes);
     }
 
+    // Several public formats use the same native HAL_PIXEL_FORMAT_BLOB. The native
+    // allocation estimation sequence depends on the public formats values. To avoid
+    // possible errors, convert where necessary.
+    private int getImageFormatByBLOB(int dataspace) {
+        switch (dataspace) {
+            case DataSpace.DATASPACE_DEPTH:
+                return ImageFormat.DEPTH_POINT_CLOUD;
+            case DataSpace.DATASPACE_DYNAMIC_DEPTH:
+                return ImageFormat.DEPTH_JPEG;
+            case DataSpace.DATASPACE_HEIF:
+                return ImageFormat.HEIC;
+            default:
+                return ImageFormat.JPEG;
+        }
+    }
+
     private ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo,
             int imageFormat, int width, int height) {
         mMaxImages = maxImages;
-        mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
-        mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+        if (!useSurfaceImageFormatInfo) {
+            mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
+            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+        }
 
         initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, true,
                 imageFormat, mHardwareBufferFormat, mDataSpace, width, height, mUsage);
@@ -321,8 +327,10 @@
             int imageFormat, int width, int height, long usage) {
         mMaxImages = maxImages;
         mUsage = usage;
-        mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
-        mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+        if (!useSurfaceImageFormatInfo) {
+            mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
+            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+        }
 
         initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, true,
                 imageFormat, mHardwareBufferFormat, mDataSpace, width, height, usage);
@@ -337,8 +345,6 @@
         // and retrieve corresponding hardwareBufferFormat and dataSpace here.
         if (useSurfaceImageFormatInfo) {
             imageFormat = ImageFormat.UNKNOWN;
-            mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
-            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
         } else {
             imageFormat = PublicFormatUtils.getPublicFormat(hardwareBufferFormat, dataSpace);
             mHardwareBufferFormat = hardwareBufferFormat;
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 53d4efa..da2795f 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -3843,11 +3843,10 @@
     private void invalidateByteBufferLocked(
             @Nullable ByteBuffer[] buffers, int index, boolean input) {
         if (buffers == null) {
-            if (index < 0) {
-                throw new IllegalStateException("index is negative (" + index + ")");
+            if (index >= 0) {
+                BitSet indices = input ? mValidInputIndices : mValidOutputIndices;
+                indices.clear(index);
             }
-            BitSet indices = input ? mValidInputIndices : mValidOutputIndices;
-            indices.clear(index);
         } else if (index >= 0 && index < buffers.length) {
             ByteBuffer buffer = buffers[index];
             if (buffer != null) {
@@ -3859,10 +3858,9 @@
     private void validateInputByteBufferLocked(
             @Nullable ByteBuffer[] buffers, int index) {
         if (buffers == null) {
-            if (index < 0) {
-                throw new IllegalStateException("index is negative (" + index + ")");
+            if (index >= 0) {
+                mValidInputIndices.set(index);
             }
-            mValidInputIndices.set(index);
         } else if (index >= 0 && index < buffers.length) {
             ByteBuffer buffer = buffers[index];
             if (buffer != null) {
@@ -3876,11 +3874,10 @@
             @Nullable ByteBuffer[] buffers, int index, boolean input) {
         synchronized(mBufferLock) {
             if (buffers == null) {
-                if (index < 0) {
-                    throw new IllegalStateException("index is negative (" + index + ")");
+                if (index >= 0) {
+                    BitSet indices = input ? mValidInputIndices : mValidOutputIndices;
+                    indices.set(index);
                 }
-                BitSet indices = input ? mValidInputIndices : mValidOutputIndices;
-                indices.set(index);
             } else if (index >= 0 && index < buffers.length) {
                 ByteBuffer buffer = buffers[index];
                 if (buffer != null) {
@@ -3893,10 +3890,9 @@
     private void validateOutputByteBufferLocked(
             @Nullable ByteBuffer[] buffers, int index, @NonNull BufferInfo info) {
         if (buffers == null) {
-            if (index < 0) {
-                throw new IllegalStateException("index is negative (" + index + ")");
+            if (index >= 0) {
+                mValidOutputIndices.set(index);
             }
-            mValidOutputIndices.set(index);
         } else if (index >= 0 && index < buffers.length) {
             ByteBuffer buffer = buffers[index];
             if (buffer != null) {
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index d7fc205..2e7896e 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -221,7 +221,7 @@
                 } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
                     name = R.string.default_audio_route_name_dock_speakers;
                 } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HDMI) != 0) {
-                    name = R.string.default_audio_route_name_hdmi;
+                    name = R.string.default_audio_route_name_external_device;
                 } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_USB) != 0) {
                     name = R.string.default_audio_route_name_usb;
                 } else {
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt
index 6f675a3..787d096 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt
@@ -52,7 +52,7 @@
             ),
             rootPages = listOf(
                 SettingsPage.create(HomePageProvider.name)
-            ) + ArgumentPageProvider.buildRootPages()
+            )
         )
     }
 
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt
index 7c57e75..d8ef937 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt
@@ -20,9 +20,12 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.theme.SettingsTheme
 import com.android.settingslib.spa.gallery.R
+import com.android.settingslib.spa.gallery.page.ArgumentPageModel
 import com.android.settingslib.spa.gallery.page.ArgumentPageProvider
 import com.android.settingslib.spa.gallery.page.FooterPageProvider
 import com.android.settingslib.spa.gallery.page.IllustrationPageProvider
@@ -35,23 +38,30 @@
 object HomePageProvider : SettingsPageProvider {
     override val name = "Home"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = SettingsPage.create(name)
+        return listOf(
+            PreferenceMainPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+            ArgumentPageProvider.buildInjectEntry("foo")!!.setLink(fromPage = owner).build(),
+            SliderPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+            SpinnerPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+            SettingsPagerPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+            FooterPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+            IllustrationPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+        )
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        HomePage()
-    }
-}
-
-@Composable
-private fun HomePage() {
-    HomeScaffold(title = stringResource(R.string.app_name)) {
-        PreferenceMainPageProvider.EntryItem()
-        ArgumentPageProvider.EntryItem(stringParam = "foo", intParam = 0)
-
-        SliderPageProvider.EntryItem()
-        SpinnerPageProvider.EntryItem()
-        SettingsPagerPageProvider.EntryItem()
-        FooterPageProvider.EntryItem()
-        IllustrationPageProvider.EntryItem()
+        HomeScaffold(title = stringResource(R.string.app_name)) {
+            for (entry in buildEntry(arguments)) {
+                if (entry.name.startsWith(ArgumentPageModel.name)) {
+                    entry.UiLayout(ArgumentPageModel.buildArgument(intParam = 0))
+                } else {
+                    entry.UiLayout()
+                }
+            }
+        }
     }
 }
 
@@ -59,6 +69,6 @@
 @Composable
 private fun HomeScreenPreview() {
     SettingsTheme {
-        HomePage()
+        HomePageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
index 5cce215..e32de7a 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
@@ -43,7 +43,7 @@
                 .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     // Set ui rendering
-                    Preference(ArgumentPageModel.create(arguments).genStringParamPreferenceModel())
+                    Preference(ArgumentPageModel.create(it).genStringParamPreferenceModel())
                 }.build()
         )
 
@@ -53,54 +53,44 @@
                 .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     // Set ui rendering
-                    Preference(ArgumentPageModel.create(arguments).genIntParamPreferenceModel())
+                    Preference(ArgumentPageModel.create(it).genIntParamPreferenceModel())
                 }.build()
         )
 
-        val entryFoo = buildInjectEntry(ArgumentPageModel.buildNextArgument("foo", arguments))
-        val entryBar = buildInjectEntry(ArgumentPageModel.buildNextArgument("bar", arguments))
-        if (entryFoo != null) entryList.add(entryFoo.setLink(fromPage = owner).build())
-        if (entryBar != null) entryList.add(entryBar.setLink(fromPage = owner).build())
+        entryList.add(buildInjectEntry("foo")!!.setLink(fromPage = owner).build())
+        entryList.add(buildInjectEntry("bar")!!.setLink(fromPage = owner).build())
 
         return entryList
     }
 
-    private fun buildInjectEntry(arguments: Bundle?): SettingsEntryBuilder? {
+    fun buildInjectEntry(stringParam: String): SettingsEntryBuilder? {
+        val arguments = ArgumentPageModel.buildArgument(stringParam)
         if (!ArgumentPageModel.isValidArgument(arguments)) return null
 
         return SettingsEntryBuilder.createInject(
-            entryName = ArgumentPageModel.getInjectEntryName(arguments),
+            entryName = "${name}_$stringParam",
             owner = SettingsPage.create(name, parameter, arguments)
         )
             // Set attributes
             .setIsAllowSearch(false)
             .setUiLayoutFn {
                 // Set ui rendering
-                Preference(ArgumentPageModel.create(arguments).genInjectPreferenceModel())
+                Preference(ArgumentPageModel.create(it).genInjectPreferenceModel())
             }
     }
 
-    fun buildRootPages(): List<SettingsPage> {
-        return listOf(
-            SettingsPage.create(name, parameter, ArgumentPageModel.buildArgument("foo")),
-            SettingsPage.create(name, parameter, ArgumentPageModel.buildArgument("bar")),
-        )
-    }
-
     @Composable
     override fun Page(arguments: Bundle?) {
         RegularScaffold(title = ArgumentPageModel.create(arguments).genPageTitle()) {
             for (entry in buildEntry(arguments)) {
-                entry.uiLayout()
+                if (entry.name.startsWith(name)) {
+                    entry.UiLayout(ArgumentPageModel.buildNextArgument(arguments))
+                } else {
+                    entry.UiLayout()
+                }
             }
         }
     }
-
-    @Composable
-    fun EntryItem(stringParam: String, intParam: Int) {
-        buildInjectEntry(ArgumentPageModel.buildArgument(stringParam, intParam))
-            ?.build()?.uiLayout?.let { it() }
-    }
 }
 
 @Preview(showBackground = true)
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt
index e27bf6d..6e86fd7 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt
@@ -44,19 +44,17 @@
             navArgument(INT_PARAM_NAME) { type = NavType.IntType },
         )
 
-        fun buildArgument(stringParam: String, intParam: Int? = null): Bundle {
+        fun buildArgument(stringParam: String? = null, intParam: Int? = null): Bundle {
             val args = Bundle()
-            args.putString(STRING_PARAM_NAME, stringParam)
+            if (stringParam != null) args.putString(STRING_PARAM_NAME, stringParam)
             if (intParam != null) args.putInt(INT_PARAM_NAME, intParam)
             return args
         }
 
-        fun buildNextArgument(newStringParam: String, arguments: Bundle? = null): Bundle {
+        fun buildNextArgument(arguments: Bundle? = null): Bundle {
             val intParam = parameter.getIntArg(INT_PARAM_NAME, arguments)
-            return if (intParam == null)
-                buildArgument(newStringParam)
-            else
-                buildArgument(newStringParam, intParam + 1)
+            val nextIntParam = if (intParam != null) intParam + 1 else null
+            return buildArgument(intParam = nextIntParam)
         }
 
         fun isValidArgument(arguments: Bundle?): Boolean {
@@ -64,10 +62,6 @@
             return (stringParam != null && listOf("foo", "bar").contains(stringParam))
         }
 
-        fun getInjectEntryName(arguments: Bundle?): String {
-            return "${name}_${parameter.getStringArg(STRING_PARAM_NAME, arguments)}"
-        }
-
         @Composable
         fun create(arguments: Bundle?): ArgumentPageModel {
             val pageModel: ArgumentPageModel = viewModel(key = arguments.toString())
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt
index 4a933ac..0fc2a5f 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt
@@ -20,6 +20,9 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.compose.stateOf
@@ -34,30 +37,44 @@
 object FooterPageProvider : SettingsPageProvider {
     override val name = "Footer"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = SettingsPage.create(name)
+        val entryList = mutableListOf<SettingsEntry>()
+        entryList.add(
+            SettingsEntryBuilder.create( "Some Preference", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    Preference(remember {
+                        object : PreferenceModel {
+                            override val title = "Some Preference"
+                            override val summary = stateOf("Some summary")
+                        }
+                    })
+                }.build()
+        )
+
+        return entryList
+    }
+
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        FooterPage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun FooterPage() {
-    RegularScaffold(title = TITLE) {
-        Preference(remember {
-            object : PreferenceModel {
-                override val title = "Some Preference"
-                override val summary = stateOf("Some summary")
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
             }
-        })
-        Footer(footerText = "Footer text always at the end of page.")
+            Footer(footerText = "Footer text always at the end of page.")
+        }
     }
 }
 
@@ -65,6 +82,6 @@
 @Composable
 private fun FooterPagePreview() {
     SettingsTheme {
-        FooterPage()
+        FooterPageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt
index 4f8ea0b..a64d4a5 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt
@@ -17,12 +17,11 @@
 package com.android.settingslib.spa.gallery.page
 
 import android.os.Bundle
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.theme.SettingsTheme
@@ -32,44 +31,64 @@
 import com.android.settingslib.spa.widget.ResourceType
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spa.widget.scaffold.RegularScaffold
+
+private const val TITLE = "Sample Illustration"
 
 object IllustrationPageProvider : SettingsPageProvider {
     override val name = "Illustration"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = SettingsPage.create(name)
+        val entryList = mutableListOf<SettingsEntry>()
+        entryList.add(
+            SettingsEntryBuilder.create( "Lottie Illustration", owner)
+                .setUiLayoutFn {
+                    Preference(object : PreferenceModel {
+                        override val title = "Lottie Illustration"
+                    })
+
+                    Illustration(object : IllustrationModel {
+                        override val resId = R.raw.accessibility_shortcut_type_triple_tap
+                        override val resourceType = ResourceType.LOTTIE
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create( "Image Illustration", owner)
+                .setUiLayoutFn {
+                    Preference(object : PreferenceModel {
+                        override val title = "Image Illustration"
+                    })
+
+                    Illustration(object : IllustrationModel {
+                        override val resId = R.drawable.accessibility_captioning_banner
+                        override val resourceType = ResourceType.IMAGE
+                    })
+                }.build()
+        )
+
+        return entryList
+    }
+
+     fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        IllustrationPage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = "Sample Illustration"
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun IllustrationPage() {
-    Column(Modifier.verticalScroll(rememberScrollState())) {
-        Preference(object : PreferenceModel {
-            override val title = "Lottie Illustration"
-        })
-
-        Illustration(object : IllustrationModel {
-            override val resId = R.raw.accessibility_shortcut_type_triple_tap
-            override val resourceType = ResourceType.LOTTIE
-        })
-
-        Preference(object : PreferenceModel {
-            override val title = "Image Illustration"
-        })
-
-        Illustration(object : IllustrationModel {
-            override val resId = R.drawable.accessibility_captioning_banner
-            override val resourceType = ResourceType.IMAGE
-        })
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
+        }
     }
 }
 
@@ -77,6 +96,6 @@
 @Composable
 private fun IllustrationPagePreview() {
     SettingsTheme {
-        IllustrationPage()
+        IllustrationPageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
index 9d80818..e09ebda 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
@@ -19,6 +19,8 @@
 import android.os.Bundle
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.theme.SettingsTheme
@@ -33,25 +35,23 @@
 object SettingsPagerPageProvider : SettingsPageProvider {
     override val name = "SettingsPager"
 
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        SettingsPagerPage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun SettingsPagerPage() {
-    SettingsScaffold(title = TITLE) {
-        SettingsPager(listOf("Personal", "Work")) {
-            PlaceholderTitle("Page $it")
+        SettingsScaffold(title = TITLE) {
+            SettingsPager(listOf("Personal", "Work")) {
+                PlaceholderTitle("Page $it")
+            }
         }
     }
 }
@@ -60,6 +60,6 @@
 @Composable
 private fun SettingsPagerPagePreview() {
     SettingsTheme {
-        SettingsPagerPage()
+        SettingsPagerPageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt
index 130cbd9..0f95bf6 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt
@@ -27,6 +27,9 @@
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.theme.SettingsTheme
@@ -41,59 +44,88 @@
 object SliderPageProvider : SettingsPageProvider {
     override val name = "Slider"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = SettingsPage.create(name)
+        val entryList = mutableListOf<SettingsEntry>()
+        entryList.add(
+            SettingsEntryBuilder.create("Simple Slider", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SettingsSlider(object : SettingsSliderModel {
+                        override val title = "Simple Slider"
+                        override val initValue = 40
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create("Slider with icon", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SettingsSlider(object : SettingsSliderModel {
+                        override val title = "Slider with icon"
+                        override val initValue = 30
+                        override val onValueChangeFinished = {
+                            println("onValueChangeFinished")
+                        }
+                        override val icon = Icons.Outlined.AccessAlarm
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create("Slider with changeable icon", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    val initValue = 0
+                    var icon by remember { mutableStateOf(Icons.Outlined.MusicOff) }
+                    var sliderPosition by remember { mutableStateOf(initValue) }
+                    SettingsSlider(object : SettingsSliderModel {
+                        override val title = "Slider with changeable icon"
+                        override val initValue = initValue
+                        override val onValueChange = { it: Int ->
+                            sliderPosition = it
+                            icon = if (it > 0) Icons.Outlined.MusicNote else Icons.Outlined.MusicOff
+                        }
+                        override val onValueChangeFinished = {
+                            println("onValueChangeFinished: the value is $sliderPosition")
+                        }
+                        override val icon = icon
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create("Slider with steps", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SettingsSlider(object : SettingsSliderModel {
+                        override val title = "Slider with steps"
+                        override val initValue = 2
+                        override val valueRange = 1..5
+                        override val showSteps = true
+                    })
+                }.build()
+        )
+
+        return entryList
+    }
+
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        SliderPage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun SliderPage() {
-    RegularScaffold(title = TITLE) {
-        SettingsSlider(object : SettingsSliderModel {
-            override val title = "Slider"
-            override val initValue = 40
-        })
-
-        SettingsSlider(object : SettingsSliderModel {
-            override val title = "Slider with icon"
-            override val initValue = 30
-            override val onValueChangeFinished = {
-                println("onValueChangeFinished")
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
             }
-            override val icon = Icons.Outlined.AccessAlarm
-        })
-
-        val initValue = 0
-        var icon by remember { mutableStateOf(Icons.Outlined.MusicOff) }
-        var sliderPosition by remember { mutableStateOf(initValue) }
-        SettingsSlider(object : SettingsSliderModel {
-            override val title = "Slider with changeable icon"
-            override val initValue = initValue
-            override val onValueChange = { it: Int ->
-                sliderPosition = it
-                icon = if (it > 0) Icons.Outlined.MusicNote else Icons.Outlined.MusicOff
-            }
-            override val onValueChangeFinished = {
-                println("onValueChangeFinished: the value is $sliderPosition")
-            }
-            override val icon = icon
-        })
-
-        SettingsSlider(object : SettingsSliderModel {
-            override val title = "Slider with steps"
-            override val initValue = 2
-            override val valueRange = 1..5
-            override val showSteps = true
-        })
+        }
     }
 }
 
@@ -101,6 +133,6 @@
 @Composable
 private fun SliderPagePreview() {
     SettingsTheme {
-        SliderPage()
+        SliderPageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt
index 53d7648..a8e4938 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt
@@ -22,6 +22,9 @@
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.compose.stateOf
@@ -37,25 +40,45 @@
 object MainSwitchPreferencePageProvider : SettingsPageProvider {
     override val name = "MainSwitchPreference"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = SettingsPage.create(name)
+        val entryList = mutableListOf<SettingsEntry>()
+        entryList.add(
+            SettingsEntryBuilder.create( "MainSwitchPreference", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleMainSwitchPreference()
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create( "MainSwitchPreference not changeable", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleNotChangeableMainSwitchPreference()
+                }.build()
+        )
+
+        return entryList
+    }
+
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        MainSwitchPreferencePage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun MainSwitchPreferencePage() {
-    RegularScaffold(title = TITLE) {
-        SampleMainSwitchPreference()
-        SampleNotChangeableMainSwitchPreference()
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
+        }
     }
 }
 
@@ -88,6 +111,6 @@
 @Composable
 private fun MainSwitchPreferencePagePreview() {
     SettingsTheme {
-        MainSwitchPreferencePage()
+        MainSwitchPreferencePageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt
index 0a8dae3..0f99c57 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt
@@ -18,6 +18,9 @@
 
 import android.os.Bundle
 import androidx.compose.runtime.Composable
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.widget.preference.Preference
@@ -29,26 +32,36 @@
 object PreferenceMainPageProvider : SettingsPageProvider {
     override val name = "PreferenceMain"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        return listOf(
+            PreferencePageProvider.buildInjectEntry()
+                .setLink(fromPage = SettingsPage.create(name)).build(),
+            SwitchPreferencePageProvider.buildInjectEntry()
+                .setLink(fromPage = SettingsPage.create(name)).build(),
+            MainSwitchPreferencePageProvider.buildInjectEntry()
+                .setLink(fromPage = SettingsPage.create(name)).build(),
+            TwoTargetSwitchPreferencePageProvider.buildInjectEntry()
+                .setLink(fromPage = SettingsPage.create(name)).build(),
+        )
+    }
+
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        PreferenceMain()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun PreferenceMain() {
-    RegularScaffold(title = TITLE) {
-        PreferencePageProvider.EntryItem()
-        SwitchPreferencePageProvider.EntryItem()
-        MainSwitchPreferencePageProvider.EntryItem()
-        TwoTargetSwitchPreferencePageProvider.EntryItem()
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
+        }
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
index 36c619f..cbd028d 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
@@ -29,6 +29,9 @@
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.compose.toState
@@ -44,68 +47,107 @@
 object PreferencePageProvider : SettingsPageProvider {
     override val name = "Preference"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = SettingsPage.create(name)
+        val entryList = mutableListOf<SettingsEntry>()
+        entryList.add(
+            SettingsEntryBuilder.create("Preference", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    Preference(object : PreferenceModel {
+                        override val title = "Preference"
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create("Preference with summary", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    Preference(object : PreferenceModel {
+                        override val title = "Preference"
+                        override val summary = "With summary".toState()
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create("Preference with async summary", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    Preference(object : PreferenceModel {
+                        override val title = "Preference"
+                        override val summary = produceState(initialValue = " ") {
+                            delay(1000L)
+                            value = "Async summary"
+                        }
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create("Click me", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    var count by rememberSaveable { mutableStateOf(0) }
+                    Preference(object : PreferenceModel {
+                        override val title = "Click me"
+                        override val summary = derivedStateOf { count.toString() }
+                        override val onClick: (() -> Unit) = { count++ }
+                        override val icon = @Composable {
+                            SettingsIcon(imageVector = Icons.Outlined.TouchApp)
+                        }
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create("Ticker", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    var ticks by rememberSaveable { mutableStateOf(0) }
+                    LaunchedEffect(ticks) {
+                        delay(1000L)
+                        ticks++
+                    }
+                    Preference(object : PreferenceModel {
+                        override val title = "Ticker"
+                        override val summary = derivedStateOf { ticks.toString() }
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create("Disabled", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    Preference(object : PreferenceModel {
+                        override val title = "Disabled"
+                        override val summary = "Disabled".toState()
+                        override val enabled = false.toState()
+                        override val icon = @Composable {
+                            SettingsIcon(imageVector = Icons.Outlined.DisabledByDefault)
+                        }
+                    })
+                }.build()
+        )
+
+        return entryList
+    }
+
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        PreferencePage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun PreferencePage() {
-    RegularScaffold(title = TITLE) {
-        Preference(object : PreferenceModel {
-            override val title = "Preference"
-        })
-
-        Preference(object : PreferenceModel {
-            override val title = "Preference"
-            override val summary = "With summary".toState()
-        })
-
-        Preference(object : PreferenceModel {
-            override val title = "Preference"
-            override val summary = produceState(initialValue = " ") {
-                delay(1000L)
-                value = "Async summary"
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
             }
-        })
-
-        var count by rememberSaveable { mutableStateOf(0) }
-        Preference(object : PreferenceModel {
-            override val title = "Click me"
-            override val summary = derivedStateOf { count.toString() }
-            override val onClick: (() -> Unit) = { count++ }
-            override val icon = @Composable {
-                SettingsIcon(imageVector = Icons.Outlined.TouchApp)
-            }
-        })
-
-        var ticks by rememberSaveable { mutableStateOf(0) }
-        LaunchedEffect(ticks) {
-            delay(1000L)
-            ticks++
         }
-        Preference(object : PreferenceModel {
-            override val title = "Ticker"
-            override val summary = derivedStateOf { ticks.toString() }
-        })
-
-        Preference(object : PreferenceModel {
-            override val title = "Disabled"
-            override val summary = "Disabled".toState()
-            override val enabled = false.toState()
-            override val icon = @Composable {
-              SettingsIcon(imageVector = Icons.Outlined.DisabledByDefault)
-            }
-        })
     }
 }
 
@@ -113,6 +155,6 @@
 @Composable
 private fun PreferencePagePreview() {
     SettingsTheme {
-        PreferencePage()
+        PreferencePageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
index 8be6a89..46b44ca 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
@@ -23,6 +23,9 @@
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.compose.stateOf
@@ -39,27 +42,59 @@
 object SwitchPreferencePageProvider : SettingsPageProvider {
     override val name = "SwitchPreference"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = SettingsPage.create(name)
+        val entryList = mutableListOf<SettingsEntry>()
+        entryList.add(
+            SettingsEntryBuilder.create( "SwitchPreference", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleSwitchPreference()
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create( "SwitchPreference with summary", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleSwitchPreferenceWithSummary()
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create( "SwitchPreference with async summary", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleSwitchPreferenceWithAsyncSummary()
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create( "SwitchPreference not changeable", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleNotChangeableSwitchPreference()
+                }.build()
+        )
+
+        return entryList
+    }
+
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        SwitchPreferencePage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun SwitchPreferencePage() {
-    RegularScaffold(title = TITLE) {
-        SampleSwitchPreference()
-        SampleSwitchPreferenceWithSummary()
-        SampleSwitchPreferenceWithAsyncSummary()
-        SampleNotChangeableSwitchPreference()
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
+        }
     }
 }
 
@@ -123,6 +158,6 @@
 @Composable
 private fun SwitchPreferencePagePreview() {
     SettingsTheme {
-        SwitchPreferencePage()
+        SwitchPreferencePageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt
index 894692b..b991f59 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt
@@ -23,6 +23,9 @@
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.compose.stateOf
@@ -39,27 +42,59 @@
 object TwoTargetSwitchPreferencePageProvider : SettingsPageProvider {
     override val name = "TwoTargetSwitchPreference"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = SettingsPage.create(name)
+        val entryList = mutableListOf<SettingsEntry>()
+        entryList.add(
+            SettingsEntryBuilder.create( "TwoTargetSwitchPreference", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleTwoTargetSwitchPreference()
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create( "TwoTargetSwitchPreference with summary", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleTwoTargetSwitchPreferenceWithSummary()
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create( "TwoTargetSwitchPreference with async summary", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleTwoTargetSwitchPreferenceWithAsyncSummary()
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create( "TwoTargetSwitchPreference not changeable", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleNotChangeableTwoTargetSwitchPreference()
+                }.build()
+        )
+
+        return entryList
+    }
+
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        TwoTargetSwitchPreferencePage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun TwoTargetSwitchPreferencePage() {
-    RegularScaffold(title = TITLE) {
-        SampleTwoTargetSwitchPreference()
-        SampleTwoTargetSwitchPreferenceWithSummary()
-        SampleTwoTargetSwitchPreferenceWithAsyncSummary()
-        SampleNotChangeableTwoTargetSwitchPreference()
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
+        }
     }
 }
 
@@ -123,6 +158,6 @@
 @Composable
 private fun TwoTargetSwitchPreferencePagePreview() {
     SettingsTheme {
-        TwoTargetSwitchPreferencePage()
+        TwoTargetSwitchPreferencePageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt
index 7efa85b..03b72d3 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt
@@ -23,6 +23,8 @@
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.theme.SettingsTheme
@@ -36,33 +38,33 @@
 object SpinnerPageProvider : SettingsPageProvider {
     override val name = "Spinner"
 
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        SpinnerPage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun SpinnerPage() {
-    RegularScaffold(title = TITLE) {
-        val selectedIndex = rememberSaveable { mutableStateOf(0) }
-        Spinner(
-            options = (1..3).map { "Option $it" },
-            selectedIndex = selectedIndex.value,
-            setIndex = { selectedIndex.value = it },
-        )
-        Preference(object : PreferenceModel {
-            override val title = "Selected index"
-            override val summary = remember { derivedStateOf { selectedIndex.value.toString() } }
-        })
+        RegularScaffold(title = TITLE) {
+            val selectedIndex = rememberSaveable { mutableStateOf(0) }
+            Spinner(
+                options = (1..3).map { "Option $it" },
+                selectedIndex = selectedIndex.value,
+                setIndex = { selectedIndex.value = it },
+            )
+            Preference(object : PreferenceModel {
+                override val title = "Selected index"
+                override val summary = remember {
+                    derivedStateOf { selectedIndex.value.toString() }
+                }
+            })
+        }
     }
 }
 
@@ -70,6 +72,6 @@
 @Composable
 private fun SpinnerPagePreview() {
     SettingsTheme {
-        SpinnerPage()
+        SpinnerPageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/spa/Android.bp b/packages/SettingsLib/Spa/spa/Android.bp
index a4928e6..6871f21 100644
--- a/packages/SettingsLib/Spa/spa/Android.bp
+++ b/packages/SettingsLib/Spa/spa/Android.bp
@@ -27,6 +27,7 @@
         "androidx.compose.material3_material3",
         "androidx.compose.material_material-icons-extended",
         "androidx.compose.runtime_runtime",
+        "androidx.compose.runtime_runtime-livedata",
         "androidx.compose.ui_ui-tooling-preview",
         "androidx.navigation_navigation-compose",
         "com.google.android.material_material",
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/DebugActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/DebugActivity.kt
index 095e683..bd5aaa7 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/DebugActivity.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/DebugActivity.kt
@@ -60,6 +60,17 @@
         setTheme(R.style.Theme_SpaLib_DayNight)
         super.onCreate(savedInstanceState)
 
+        val packageName = browseActivityClass.packageName
+        val className = browseActivityClass.toString().removePrefix("class $packageName")
+        for (pageWithEntry in entryRepository.getAllPageWithEntry()) {
+            if (pageWithEntry.page.hasRuntimeParam()) continue
+            val route = pageWithEntry.page.buildRoute()
+            Log.d(
+                "DEBUG ACTIVITY",
+                "adb shell am start -n $packageName/$className -e $KEY_DESTINATION $route"
+            )
+        }
+
         setContent {
             SettingsTheme {
                 MainContent()
@@ -136,6 +147,7 @@
             Text(text = "Entry size: ${pageWithEntry.entries.size}")
             Preference(model = object : PreferenceModel {
                 override val title = "open page"
+                override val enabled = (!pageWithEntry.page.hasRuntimeParam()).toState()
                 override val onClick = openPage(pageWithEntry.page)
             })
             EntryList(pageWithEntry.entries)
@@ -149,6 +161,7 @@
         RegularScaffold(title = "Entry ${entry.displayName}") {
             Preference(model = object : PreferenceModel {
                 override val title = "open entry"
+                override val enabled = (!entry.hasRuntimeParam()).toState()
                 override val onClick = openEntry(entry)
             })
             Text(text = entry.formatAll())
@@ -168,7 +181,8 @@
     }
 
     @Composable
-    private fun openPage(page: SettingsPage): () -> Unit {
+    private fun openPage(page: SettingsPage): (() -> Unit)? {
+        if (page.hasRuntimeParam()) return null
         val route = page.buildRoute()
         val context = LocalContext.current
         val intent = Intent(context, browseActivityClass).apply {
@@ -181,7 +195,8 @@
     }
 
     @Composable
-    private fun openEntry(entry: SettingsEntry): () -> Unit {
+    private fun openEntry(entry: SettingsEntry): (() -> Unit)? {
+        if (entry.hasRuntimeParam()) return null
         val route = entry.buildRoute()
         val context = LocalContext.current
         val intent = Intent(context, browseActivityClass).apply {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
index 86e75f3d..b0a1cbe 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
@@ -19,9 +19,9 @@
 import android.os.Bundle
 import androidx.compose.runtime.Composable
 import androidx.navigation.NamedNavArgument
+import androidx.navigation.NavType
 import com.android.settingslib.spa.framework.BrowseActivity
 import com.android.settingslib.spa.framework.util.navLink
-import com.android.settingslib.spa.framework.util.normalize
 
 const val INJECT_ENTRY_NAME = "INJECT"
 const val ROOT_ENTRY_NAME = "ROOT"
@@ -85,6 +85,10 @@
                 "?${BrowseActivity.HIGHLIGHT_ENTRY_PARAM_NAME}=$highlightEntryName"
         return name + parameter.navLink(arguments) + highlightParam
     }
+
+    fun hasRuntimeParam(): Boolean {
+        return parameter.hasRuntimeParam(arguments)
+    }
 }
 
 /**
@@ -139,7 +143,7 @@
      * injected entry. In the long term, we may deprecate the @Composable Page() API in SPP, and
      * use each entries' UI rendering function in the page instead.
      */
-    val uiLayout: (@Composable () -> Unit) = {},
+    val uiLayoutImpl: (@Composable (arguments: Bundle?) -> Unit) = {},
 ) {
     fun formatAll(): String {
         val content = listOf<String>(
@@ -150,10 +154,25 @@
         return content.joinToString("\n")
     }
 
+    private fun getDisplayPage(): SettingsPage {
+        // Display the entry on its from-page, or on its owner page if the from-page is unset.
+        return fromPage ?: owner
+    }
+
     fun buildRoute(): String {
-        // Open entry in its fromPage.
-        val page = fromPage ?: owner
-        return page.buildRoute(name)
+        return getDisplayPage().buildRoute(name)
+    }
+
+    fun hasRuntimeParam(): Boolean {
+        return getDisplayPage().hasRuntimeParam()
+    }
+
+    @Composable
+    fun UiLayout(runtimeArguments: Bundle? = null) {
+        val arguments = Bundle()
+        if (owner.arguments != null) arguments.putAll(owner.arguments)
+        if (runtimeArguments != null) arguments.putAll(runtimeArguments)
+        uiLayoutImpl(arguments)
     }
 }
 
@@ -196,7 +215,7 @@
     private var isAllowSearch: Boolean? = null
 
     private var searchDataFn: () -> SearchData? = { null }
-    private var uiLayoutFn: (@Composable () -> Unit) = {}
+    private var uiLayoutFn: (@Composable (arguments: Bundle?) -> Unit) = {}
 
     fun build(): SettingsEntry {
         return SettingsEntry(
@@ -214,7 +233,7 @@
 
             // functions
             searchData = searchDataFn,
-            uiLayout = uiLayoutFn,
+            uiLayoutImpl = uiLayoutFn,
         )
     }
 
@@ -237,7 +256,7 @@
         return this
     }
 
-    fun setUiLayoutFn(fn: @Composable () -> Unit): SettingsEntryBuilder {
+    fun setUiLayoutFn(fn: @Composable (arguments: Bundle?) -> Unit): SettingsEntryBuilder {
         this.uiLayoutFn = fn
         return this
     }
@@ -272,3 +291,33 @@
 private fun String.toUniqueId(): Int {
     return this.hashCode()
 }
+
+private fun List<NamedNavArgument>.normalize(arguments: Bundle? = null): Bundle? {
+    if (this.isEmpty()) return null
+    val normArgs = Bundle()
+    for (navArg in this) {
+        when (navArg.argument.type) {
+            NavType.StringType -> {
+                val value = arguments?.getString(navArg.name)
+                if (value != null)
+                    normArgs.putString(navArg.name, value)
+                else
+                    normArgs.putString("unset_" + navArg.name, null)
+            }
+            NavType.IntType -> {
+                if (arguments != null && arguments.containsKey(navArg.name))
+                    normArgs.putInt(navArg.name, arguments.getInt(navArg.name))
+                else
+                    normArgs.putString("unset_" + navArg.name, null)
+            }
+        }
+    }
+    return normArgs
+}
+
+private fun List<NamedNavArgument>.hasRuntimeParam(arguments: Bundle? = null): Boolean {
+    for (navArg in this) {
+        if (arguments == null || !arguments.containsKey(navArg.name)) return true
+    }
+    return false
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Parameter.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Parameter.kt
index 4e768eb..aaf8107 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Parameter.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Parameter.kt
@@ -40,29 +40,6 @@
     return argsArray.joinToString("") { arg -> "/$arg" }
 }
 
-fun List<NamedNavArgument>.normalize(arguments: Bundle? = null): Bundle? {
-    if (this.isEmpty()) return null
-    val normArgs = Bundle()
-    for (navArg in this) {
-        when (navArg.argument.type) {
-            NavType.StringType -> {
-                val value = arguments?.getString(navArg.name)
-                if (value != null)
-                    normArgs.putString(navArg.name, value)
-                else
-                    normArgs.putString("unset_" + navArg.name, null)
-            }
-            NavType.IntType -> {
-                if (arguments != null && arguments.containsKey(navArg.name))
-                    normArgs.putInt(navArg.name, arguments.getInt(navArg.name))
-                else
-                    normArgs.putString("unset_" + navArg.name, null)
-            }
-        }
-    }
-    return normArgs
-}
-
 fun List<NamedNavArgument>.getStringArg(name: String, arguments: Bundle? = null): String? {
     if (this.containsStringArg(name) && arguments != null) {
         return arguments.getString(name)
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
index 8876f66..93ba4f7 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
@@ -24,6 +24,7 @@
 import android.content.pm.ApplicationInfo
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.Transformations
 
 class AppOpsController(
     context: Context,
@@ -32,21 +33,23 @@
 ) {
     private val appOpsManager = checkNotNull(context.getSystemService(AppOpsManager::class.java))
 
+    val mode: LiveData<Int>
+        get() = _mode
     val isAllowed: LiveData<Boolean>
-        get() = _isAllowed
+        get() = Transformations.map(_mode) { it == MODE_ALLOWED }
 
     fun setAllowed(allowed: Boolean) {
         val mode = if (allowed) MODE_ALLOWED else MODE_ERRORED
         appOpsManager.setMode(op, app.uid, app.packageName, mode)
-        _isAllowed.postValue(allowed)
+        _mode.postValue(mode)
     }
 
     @Mode
     fun getMode(): Int = appOpsManager.checkOpNoThrow(op, app.uid, app.packageName)
 
-    private val _isAllowed = object : MutableLiveData<Boolean>() {
+    private val _mode = object : MutableLiveData<Int>() {
         override fun onActive() {
-            postValue(getMode() == MODE_ALLOWED)
+            postValue(getMode())
         }
 
         override fun onInactive() {
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt
index e521edd..ba8af54 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt
@@ -16,31 +16,52 @@
 
 package com.android.settingslib.spaprivileged.model.app
 
+import android.app.AppGlobals
 import android.content.pm.ApplicationInfo
 import android.content.pm.PackageInfo
+import android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED
 import android.content.pm.PackageManager
 import android.util.Log
+import com.android.settingslib.spa.framework.util.asyncFilter
 
 private const val TAG = "PackageManagers"
 
 object PackageManagers {
-    fun getPackageInfoAsUser(packageName: String, userId: Int): PackageInfo =
-        PackageManager.getPackageInfoAsUserCached(packageName, 0, userId)
+    private val iPackageManager by lazy { AppGlobals.getPackageManager() }
+
+    fun getPackageInfoAsUser(packageName: String, userId: Int): PackageInfo? =
+        getPackageInfoAsUser(packageName, 0, userId)
 
     fun getApplicationInfoAsUser(packageName: String, userId: Int): ApplicationInfo =
         PackageManager.getApplicationInfoAsUserCached(packageName, 0, userId)
 
-    fun hasRequestPermission(app: ApplicationInfo, permission: String): Boolean {
-        val packageInfo = try {
-            PackageManager.getPackageInfoAsUserCached(
-                app.packageName, PackageManager.GET_PERMISSIONS.toLong(), app.userId
-            )
-        } catch (e: PackageManager.NameNotFoundException) {
-            Log.w(TAG, "getPackageInfoAsUserCached() failed", e)
-            return false
-        }
+    fun ApplicationInfo.hasRequestPermission(permission: String): Boolean {
+        val packageInfo = getPackageInfoAsUser(packageName, PackageManager.GET_PERMISSIONS, userId)
         return packageInfo?.requestedPermissions?.let {
             permission in it
         } ?: false
     }
+
+    fun ApplicationInfo.hasGrantPermission(permission: String): Boolean {
+        val packageInfo = getPackageInfoAsUser(packageName, PackageManager.GET_PERMISSIONS, userId)
+            ?: return false
+        val index = packageInfo.requestedPermissions.indexOf(permission)
+        return index >= 0 &&
+            packageInfo.requestedPermissionsFlags[index].hasFlag(REQUESTED_PERMISSION_GRANTED)
+    }
+
+    suspend fun getAppOpPermissionPackages(userId: Int, permission: String): Set<String> =
+        iPackageManager.getAppOpPermissionPackages(permission, userId).asIterable().asyncFilter {
+            iPackageManager.isPackageAvailable(it, userId)
+        }.toSet()
+
+    private fun getPackageInfoAsUser(packageName: String, flags: Int, userId: Int): PackageInfo? =
+        try {
+            PackageManager.getPackageInfoAsUserCached(packageName, flags.toLong(), userId)
+        } catch (e: PackageManager.NameNotFoundException) {
+            Log.w(TAG, "getPackageInfoAsUserCached() failed", e)
+            null
+        }
+
+    private fun Int.hasFlag(flag: Int) = (this and flag) > 0
 }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
index 99deb70..f51d2db 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
@@ -49,7 +49,8 @@
             ),
         horizontalAlignment = Alignment.CenterHorizontally,
     ) {
-        val packageInfo = remember { PackageManagers.getPackageInfoAsUser(packageName, userId) }
+        val packageInfo =
+            remember { PackageManagers.getPackageInfoAsUser(packageName, userId) } ?: return
         Box(modifier = Modifier.padding(SettingsDimension.itemPaddingAround)) {
             AppIcon(app = packageInfo.applicationInfo, size = SettingsDimension.appIconInfoSize)
         }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
new file mode 100644
index 0000000..c6f41d3
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
@@ -0,0 +1,101 @@
+/*
+ * 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.settingslib.spaprivileged.template.app
+
+import android.app.AppOpsManager.MODE_ALLOWED
+import android.app.AppOpsManager.MODE_DEFAULT
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.remember
+import com.android.settingslib.spaprivileged.model.app.AppOpsController
+import com.android.settingslib.spaprivileged.model.app.AppRecord
+import com.android.settingslib.spaprivileged.model.app.PackageManagers
+import com.android.settingslib.spaprivileged.model.app.PackageManagers.hasGrantPermission
+import com.android.settingslib.spaprivileged.model.app.PackageManagers.hasRequestPermission
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+
+data class AppOpPermissionRecord(
+    override val app: ApplicationInfo,
+    val hasRequestPermission: Boolean,
+    var appOpsController: AppOpsController,
+) : AppRecord
+
+abstract class AppOpPermissionListModel(private val context: Context) :
+    TogglePermissionAppListModel<AppOpPermissionRecord> {
+
+    abstract val appOp: Int
+    abstract val permission: String
+
+    private val notChangeablePackages =
+        setOf("android", "com.android.systemui", context.packageName)
+
+    override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
+        userIdFlow.map { userId ->
+            PackageManagers.getAppOpPermissionPackages(userId, permission)
+        }.combine(appListFlow) { packageNames, appList ->
+            appList.map { app ->
+                AppOpPermissionRecord(
+                    app = app,
+                    hasRequestPermission = app.packageName in packageNames,
+                    appOpsController = AppOpsController(context = context, app = app, op = appOp),
+                )
+            }
+        }
+
+    override fun transformItem(app: ApplicationInfo) = AppOpPermissionRecord(
+        app = app,
+        hasRequestPermission = app.hasRequestPermission(permission),
+        appOpsController = AppOpsController(context = context, app = app, op = appOp),
+    )
+
+    override fun filter(userIdFlow: Flow<Int>, recordListFlow: Flow<List<AppOpPermissionRecord>>) =
+        recordListFlow.map { recordList ->
+            recordList.filter { it.hasRequestPermission }
+        }
+
+    /**
+     * Defining the default behavior as permissible as long as the package requested this permission
+     * (This means pre-M gets approval during install time; M apps gets approval during runtime).
+     */
+    @Composable
+    override fun isAllowed(record: AppOpPermissionRecord): State<Boolean?> {
+        val mode = record.appOpsController.mode.observeAsState()
+        return remember {
+            derivedStateOf {
+                when (mode.value) {
+                    null -> null
+                    MODE_ALLOWED -> true
+                    MODE_DEFAULT -> record.app.hasGrantPermission(permission)
+                    else -> false
+                }
+            }
+        }
+    }
+
+    override fun isChangeable(record: AppOpPermissionRecord) =
+        record.hasRequestPermission && record.app.packageName !in notChangeablePackages
+
+    override fun setAllowed(record: AppOpPermissionRecord, newAllowed: Boolean) {
+        record.appOpsController.setAllowed(newAllowed)
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index a5f3df9..7927c5d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -81,8 +81,10 @@
     private int mDeviceMode;
     private long mHiSyncId;
     private int mGroupId;
+
     // Need this since there is no method for getting RSSI
     short mRssi;
+
     // mProfiles and mRemovedProfiles does not do swap() between main and sub device. It is
     // because current sub device is only for HearingAid and its profile is the same.
     private final Collection<LocalBluetoothProfile> mProfiles = new CopyOnWriteArrayList<>();
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
index 818f5ca..cf4e1ee 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
@@ -46,16 +46,43 @@
         if (isValidHiSyncId(hiSyncId)) {
             // Once hiSyncId is valid, assign hiSyncId
             newDevice.setHiSyncId(hiSyncId);
+            final int side = getDeviceSide(newDevice.getDevice());
+            final int mode = getDeviceMode(newDevice.getDevice());
+            newDevice.setDeviceSide(side);
+            newDevice.setDeviceMode(mode);
         }
     }
 
     private long getHiSyncId(BluetoothDevice device) {
-        LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
-        HearingAidProfile profileProxy = profileManager.getHearingAidProfile();
-        if (profileProxy != null) {
-            return profileProxy.getHiSyncId(device);
+        final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
+        final HearingAidProfile profileProxy = profileManager.getHearingAidProfile();
+        if (profileProxy == null) {
+            return BluetoothHearingAid.HI_SYNC_ID_INVALID;
         }
-        return BluetoothHearingAid.HI_SYNC_ID_INVALID;
+
+        return profileProxy.getHiSyncId(device);
+    }
+
+    private int getDeviceSide(BluetoothDevice device) {
+        final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
+        final HearingAidProfile profileProxy = profileManager.getHearingAidProfile();
+        if (profileProxy == null) {
+            Log.w(TAG, "HearingAidProfile is not supported and not ready to fetch device side");
+            return HearingAidProfile.DeviceSide.SIDE_INVALID;
+        }
+
+        return profileProxy.getDeviceSide(device);
+    }
+
+    private int getDeviceMode(BluetoothDevice device) {
+        final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
+        final HearingAidProfile profileProxy = profileManager.getHearingAidProfile();
+        if (profileProxy == null) {
+            Log.w(TAG, "HearingAidProfile is not supported and not ready to fetch device mode");
+            return HearingAidProfile.DeviceMode.MODE_INVALID;
+        }
+
+        return profileProxy.getDeviceMode(device);
     }
 
     boolean setSubDeviceIfNeeded(CachedBluetoothDevice newDevice) {
@@ -98,6 +125,10 @@
                 if (isValidHiSyncId(newHiSyncId)) {
                     cachedDevice.setHiSyncId(newHiSyncId);
                     newSyncIdSet.add(newHiSyncId);
+                    final int side = getDeviceSide(cachedDevice.getDevice());
+                    final int mode = getDeviceMode(cachedDevice.getDevice());
+                    cachedDevice.setDeviceSide(side);
+                    cachedDevice.setDeviceMode(mode);
                 }
             }
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java
new file mode 100644
index 0000000..feb5e0b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java
@@ -0,0 +1,73 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.util.HashMap;
+
+/** Utils class to report hearing aid metrics to statsd */
+public final class HearingAidStatsLogUtils {
+
+    private static final String TAG = "HearingAidStatsLogUtils";
+    private static final HashMap<String, Integer> sDeviceAddressToBondEntryMap = new HashMap<>();
+
+    /**
+     * Sets the mapping from hearing aid device to the bond entry where this device starts it's
+     * bonding(connecting) process.
+     *
+     * @param bondEntry The entry page id where the bonding process starts
+     * @param device The bonding(connecting) hearing aid device
+     */
+    public static void setBondEntryForDevice(int bondEntry, CachedBluetoothDevice device) {
+        sDeviceAddressToBondEntryMap.put(device.getAddress(), bondEntry);
+    }
+
+    /**
+     * Logs hearing aid device information to westworld, including device mode, device side, and
+     * entry page id where the binding(connecting) process starts.
+     *
+     * Only logs the info once after hearing aid is bonded(connected). Clears the map entry of this
+     * device when logging is completed.
+     *
+     * @param device The bonded(connected) hearing aid device
+     */
+    public static void logHearingAidInfo(CachedBluetoothDevice device) {
+        final String deviceAddress = device.getAddress();
+        if (sDeviceAddressToBondEntryMap.containsKey(deviceAddress)) {
+            final int bondEntry = sDeviceAddressToBondEntryMap.getOrDefault(deviceAddress, -1);
+            final int deviceMode = device.getDeviceMode();
+            final int deviceSide = device.getDeviceSide();
+            FrameworkStatsLog.write(FrameworkStatsLog.HEARING_AID_INFO_REPORTED, deviceMode,
+                    deviceSide, bondEntry);
+
+            sDeviceAddressToBondEntryMap.remove(deviceAddress);
+        } else {
+            Log.w(TAG, "The device address was not found. Hearing aid device info is not logged.");
+        }
+    }
+
+    @VisibleForTesting
+    static HashMap<String, Integer> getDeviceAddressToBondEntryMap() {
+        return sDeviceAddressToBondEntryMap;
+    }
+
+    private HearingAidStatsLogUtils() {}
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 4714ff9..8a9f9dd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -352,6 +352,8 @@
                         cachedDevice.setHiSyncId(newHiSyncId);
                     }
                 }
+
+                HearingAidStatsLogUtils.logHearingAidInfo(cachedDevice);
             }
 
             if (getCsipSetCoordinatorProfile() != null
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
index adfa39e..4ce88ee 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
@@ -21,6 +21,8 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
@@ -46,6 +48,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.List;
 import java.util.concurrent.ExecutionException;
 
 class AvatarPhotoController {
@@ -57,9 +60,9 @@
 
         void startActivityForResult(Intent intent, int resultCode);
 
-        int getPhotoSize();
+        boolean startSystemActivityForResult(Intent intent, int resultCode);
 
-        boolean canCropPhoto();
+        int getPhotoSize();
     }
 
     interface ContextInjector {
@@ -82,6 +85,7 @@
     private static final long DELAY_BEFORE_CROP_MILLIS = 150;
 
     private static final String IMAGES_DIR = "multi_user";
+    private static final String PRE_CROP_PICTURE_FILE_NAME = "PreCropEditUserPhoto.jpg";
     private static final String CROP_PICTURE_FILE_NAME = "CropEditUserPhoto.jpg";
     private static final String TAKE_PICTURE_FILE_NAME = "TakeEditUserPhoto.jpg";
 
@@ -91,6 +95,7 @@
     private final ContextInjector mContextInjector;
 
     private final File mImagesDir;
+    private final Uri mPreCropPictureUri;
     private final Uri mCropPictureUri;
     private final Uri mTakePictureUri;
 
@@ -100,6 +105,8 @@
 
         mImagesDir = new File(mContextInjector.getCacheDir(), IMAGES_DIR);
         mImagesDir.mkdir();
+        mPreCropPictureUri = mContextInjector
+                .createTempImageUri(mImagesDir, PRE_CROP_PICTURE_FILE_NAME, !waiting);
         mCropPictureUri =
                 mContextInjector.createTempImageUri(mImagesDir, CROP_PICTURE_FILE_NAME, !waiting);
         mTakePictureUri =
@@ -131,7 +138,7 @@
                 return true;
             case REQUEST_CODE_TAKE_PHOTO:
                 if (mTakePictureUri.equals(pictureUri)) {
-                    cropPhoto();
+                    cropPhoto(pictureUri);
                 } else {
                     copyAndCropPhoto(pictureUri, false);
                 }
@@ -160,7 +167,7 @@
             ThreadUtils.postOnBackgroundThread(() -> {
                 final ContentResolver cr = mContextInjector.getContentResolver();
                 try (InputStream in = cr.openInputStream(pictureUri);
-                     OutputStream out = cr.openOutputStream(mTakePictureUri)) {
+                        OutputStream out = cr.openOutputStream(mPreCropPictureUri)) {
                     Streams.copy(in, out);
                 } catch (IOException e) {
                     Log.w(TAG, "Failed to copy photo", e);
@@ -168,7 +175,7 @@
                 }
                 Runnable cropRunnable = () -> {
                     if (!mAvatarUi.isFinishing()) {
-                        cropPhoto();
+                        cropPhoto(mPreCropPictureUri);
                     }
                 };
                 if (delayBeforeCrop) {
@@ -183,22 +190,21 @@
         }
     }
 
-    private void cropPhoto() {
-        if (mAvatarUi.canCropPhoto()) {
-            // TODO: Use a public intent, when there is one.
-            Intent intent = new Intent("com.android.camera.action.CROP");
-            intent.setDataAndType(mTakePictureUri, "image/*");
-            appendOutputExtra(intent, mCropPictureUri);
-            appendCropExtras(intent);
-            try {
-                StrictMode.disableDeathOnFileUriExposure();
-                mAvatarUi.startActivityForResult(intent, REQUEST_CODE_CROP_PHOTO);
-            } finally {
-                StrictMode.enableDeathOnFileUriExposure();
+    private void cropPhoto(final Uri pictureUri) {
+        // TODO: Use a public intent, when there is one.
+        Intent intent = new Intent("com.android.camera.action.CROP");
+        intent.setDataAndType(pictureUri, "image/*");
+        appendOutputExtra(intent, mCropPictureUri);
+        appendCropExtras(intent);
+        try {
+            StrictMode.disableDeathOnFileUriExposure();
+            if (mAvatarUi.startSystemActivityForResult(intent, REQUEST_CODE_CROP_PHOTO)) {
+                return;
             }
-        } else {
-            onPhotoNotCropped(mTakePictureUri);
+        } finally {
+            StrictMode.enableDeathOnFileUriExposure();
         }
+        onPhotoNotCropped(pictureUri);
     }
 
     private void appendOutputExtra(Intent intent, Uri pictureUri) {
@@ -320,14 +326,22 @@
         }
 
         @Override
-        public int getPhotoSize() {
-            return mActivity.getResources()
-                    .getDimensionPixelSize(com.android.internal.R.dimen.user_icon_size);
+        public boolean startSystemActivityForResult(Intent intent, int code) {
+            List<ResolveInfo> resolveInfos = mActivity.getPackageManager()
+                    .queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
+            if (resolveInfos.isEmpty()) {
+                Log.w(TAG, "No system package activity could be found for code " + code);
+                return false;
+            }
+            intent.setPackage(resolveInfos.get(0).activityInfo.packageName);
+            mActivity.startActivityForResult(intent, code);
+            return true;
         }
 
         @Override
-        public boolean canCropPhoto() {
-            return PhotoCapabilityUtils.canCropPhoto(mActivity);
+        public int getPhotoSize() {
+            return mActivity.getResources()
+                    .getDimensionPixelSize(com.android.internal.R.dimen.user_icon_size);
         }
     }
 
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java
index 3dc2fab..d988111 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java
@@ -34,6 +34,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.net.Uri;
 import android.provider.MediaStore;
 
@@ -51,6 +52,7 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 
 @RunWith(AndroidJUnit4.class)
@@ -73,6 +75,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         when(mMockAvatarUi.getPhotoSize()).thenReturn(PHOTO_SIZE);
+        when(mMockAvatarUi.startSystemActivityForResult(any(), anyInt())).thenReturn(true);
 
         mImagesDir = new File(
                 InstrumentationRegistry.getTargetContext().getCacheDir(), "multi_user");
@@ -110,9 +113,7 @@
     }
 
     @Test
-    public void takePhotoIsFollowedByCropWhenSupported() throws IOException {
-        when(mMockAvatarUi.canCropPhoto()).thenReturn(true);
-
+    public void takePhotoIsFollowedByCrop() throws IOException {
         new File(mImagesDir, "file.txt").createNewFile();
 
         Intent intent = new Intent();
@@ -121,14 +122,12 @@
         mController.onActivityResult(
                 REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_OK, intent);
 
-        verifyStartActivityForResult(
+        verifyStartSystemActivityForResult(
                 "com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
     }
 
     @Test
     public void takePhotoIsNotFollowedByCropWhenResultCodeNotOk() throws IOException {
-        when(mMockAvatarUi.canCropPhoto()).thenReturn(true);
-
         new File(mImagesDir, "file.txt").createNewFile();
 
         Intent intent = new Intent();
@@ -138,12 +137,11 @@
                 REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_CANCELED, intent);
 
         verify(mMockAvatarUi, never()).startActivityForResult(any(), anyInt());
+        verify(mMockAvatarUi, never()).startSystemActivityForResult(any(), anyInt());
     }
 
     @Test
     public void takePhotoIsFollowedByCropWhenTakePhotoUriReturned() throws IOException {
-        when(mMockAvatarUi.canCropPhoto()).thenReturn(true);
-
         new File(mImagesDir, "TakeEditUserPhoto.jpg").createNewFile();
 
         Intent intent = new Intent();
@@ -151,14 +149,12 @@
         mController.onActivityResult(
                 REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_OK, intent);
 
-        verifyStartActivityForResult(
+        verifyStartSystemActivityForResult(
                 "com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
     }
 
     @Test
     public void choosePhotoIsFollowedByCrop() throws IOException {
-        when(mMockAvatarUi.canCropPhoto()).thenReturn(true);
-
         new File(mImagesDir, "file.txt").createNewFile();
 
         Intent intent = new Intent();
@@ -167,14 +163,12 @@
         mController.onActivityResult(
                 REQUEST_CODE_CHOOSE_PHOTO, Activity.RESULT_OK, intent);
 
-        verifyStartActivityForResult(
+        verifyStartSystemActivityForResult(
                 "com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
     }
 
     @Test
     public void choosePhotoIsNotFollowedByCropWhenResultCodeNotOk() throws IOException {
-        when(mMockAvatarUi.canCropPhoto()).thenReturn(true);
-
         new File(mImagesDir, "file.txt").createNewFile();
 
         Intent intent = new Intent();
@@ -184,12 +178,11 @@
                 REQUEST_CODE_CHOOSE_PHOTO, Activity.RESULT_CANCELED, intent);
 
         verify(mMockAvatarUi, never()).startActivityForResult(any(), anyInt());
+        verify(mMockAvatarUi, never()).startSystemActivityForResult(any(), anyInt());
     }
 
     @Test
     public void choosePhotoIsFollowedByCropWhenTakePhotoUriReturned() throws IOException {
-        when(mMockAvatarUi.canCropPhoto()).thenReturn(true);
-
         new File(mImagesDir, "TakeEditUserPhoto.jpg").createNewFile();
 
         Intent intent = new Intent();
@@ -197,28 +190,11 @@
         mController.onActivityResult(
                 REQUEST_CODE_CHOOSE_PHOTO, Activity.RESULT_OK, intent);
 
-        verifyStartActivityForResult(
+        verifyStartSystemActivityForResult(
                 "com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
     }
 
     @Test
-    public void choosePhotoIsNotFollowedByCropIntentWhenCropNotSupported() throws IOException {
-        when(mMockAvatarUi.canCropPhoto()).thenReturn(false);
-
-        File file = new File(mImagesDir, "file.txt");
-        saveBitmapToFile(file);
-
-        Intent intent = new Intent();
-        intent.setData(Uri.parse(
-                "content://com.android.settingslib.test/my_cache/multi_user/file.txt"));
-        mController.onActivityResult(
-                REQUEST_CODE_CHOOSE_PHOTO, Activity.RESULT_OK, intent);
-
-        verify(mMockAvatarUi, never()).startActivityForResult(any(), anyInt());
-        verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS)).returnUriResult(mCropPhotoUri);
-    }
-
-    @Test
     public void cropPhotoResultIsReturnedIfResultOkAndContent() {
         Intent intent = new Intent();
         intent.setData(mCropPhotoUri);
@@ -242,11 +218,58 @@
         verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS).times(0)).returnUriResult(mCropPhotoUri);
     }
 
-    private void verifyStartActivityForResult(String action, int resultCode) {
+    @Test
+    public void cropDoesNotUseTakePhotoUri() throws IOException {
+        new File(mImagesDir, "file.txt").createNewFile();
+
+        Intent intent = new Intent();
+        intent.setData(Uri.parse(
+                "content://com.android.settingslib.test/my_cache/multi_user/file.txt"));
+        mController.onActivityResult(
+                REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_OK, intent);
+
+        Intent startIntent = verifyStartSystemActivityForResult(
+                "com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
+        assertThat(startIntent.getData()).isNotEqualTo(mTakePhotoUri);
+    }
+
+    @Test
+    public void internalCropUsedIfNoSystemCropperFound() throws IOException {
+        when(mMockAvatarUi.startSystemActivityForResult(any(), anyInt())).thenReturn(false);
+
+        File file = new File(mImagesDir, "file.txt");
+        saveBitmapToFile(file);
+
+        Intent intent = new Intent();
+        intent.setData(Uri.parse(
+                "content://com.android.settingslib.test/my_cache/multi_user/file.txt"));
+        mController.onActivityResult(
+                REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_OK, intent);
+
+        verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS)).returnUriResult(mCropPhotoUri);
+
+        InputStream imageStream = mContext.getContentResolver().openInputStream(mCropPhotoUri);
+        Bitmap bitmap = BitmapFactory.decodeStream(imageStream);
+        assertThat(bitmap.getWidth()).isEqualTo(PHOTO_SIZE);
+        assertThat(bitmap.getHeight()).isEqualTo(PHOTO_SIZE);
+    }
+
+    private Intent verifyStartActivityForResult(String action, int resultCode) {
         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
         verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS))
                 .startActivityForResult(captor.capture(), eq(resultCode));
-        assertThat(captor.getValue().getAction()).isEqualTo(action);
+        Intent intent = captor.getValue();
+        assertThat(intent.getAction()).isEqualTo(action);
+        return intent;
+    }
+
+    private Intent verifyStartSystemActivityForResult(String action, int resultCode) {
+        ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+        verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS))
+                .startSystemActivityForResult(captor.capture(), eq(resultCode));
+        Intent intent = captor.getValue();
+        assertThat(intent.getAction()).isEqualTo(action);
+        return intent;
     }
 
     private void saveBitmapToFile(File file) throws IOException {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
index d80a591..611b0a4 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
@@ -102,16 +102,25 @@
     }
 
     /**
-     * Test initHearingAidDeviceIfNeeded, a valid HiSyncId will be assigned
+     * Test initHearingAidDeviceIfNeeded, set HearingAid's information, including HiSyncId,
+     * deviceSide, deviceMode.
      */
     @Test
-    public void initHearingAidDeviceIfNeeded_validHiSyncId_verifyHiSyncId() {
+    public void initHearingAidDeviceIfNeeded_validHiSyncId_setHearingAidInfos() {
         when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(HISYNCID1);
+        when(mHearingAidProfile.getDeviceMode(mDevice1)).thenReturn(
+                HearingAidProfile.DeviceMode.MODE_BINAURAL);
+        when(mHearingAidProfile.getDeviceSide(mDevice1)).thenReturn(
+                HearingAidProfile.DeviceSide.SIDE_RIGHT);
 
         assertThat(mCachedDevice1.getHiSyncId()).isNotEqualTo(HISYNCID1);
         mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(mCachedDevice1);
 
         assertThat(mCachedDevice1.getHiSyncId()).isEqualTo(HISYNCID1);
+        assertThat(mCachedDevice1.getDeviceMode()).isEqualTo(
+                HearingAidProfile.DeviceMode.MODE_BINAURAL);
+        assertThat(mCachedDevice1.getDeviceSide()).isEqualTo(
+                HearingAidProfile.DeviceSide.SIDE_RIGHT);
     }
 
     /**
@@ -251,6 +260,29 @@
     }
 
     /**
+     * Test updateHearingAidsDevices, set HearingAid's information, including HiSyncId, deviceSide,
+     * deviceMode.
+     */
+    @Test
+    public void updateHearingAidsDevices_validHiSyncId_setHearingAidInfos() {
+        when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(HISYNCID1);
+        when(mHearingAidProfile.getDeviceMode(mDevice1)).thenReturn(
+                HearingAidProfile.DeviceMode.MODE_BINAURAL);
+        when(mHearingAidProfile.getDeviceSide(mDevice1)).thenReturn(
+                HearingAidProfile.DeviceSide.SIDE_RIGHT);
+        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+
+        mHearingAidDeviceManager.updateHearingAidsDevices();
+
+        assertThat(mCachedDevice1.getHiSyncId()).isEqualTo(HISYNCID1);
+        assertThat(mCachedDevice1.getDeviceMode()).isEqualTo(
+                HearingAidProfile.DeviceMode.MODE_BINAURAL);
+        assertThat(mCachedDevice1.getDeviceSide()).isEqualTo(
+                HearingAidProfile.DeviceSide.SIDE_RIGHT);
+        verify(mHearingAidDeviceManager).onHiSyncIdChanged(HISYNCID1);
+    }
+
+    /**
      * Test onProfileConnectionStateChangedIfProcessed.
      * When first hearing aid device is connected, to process it same as other generic devices.
      * No need to process it.
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java
new file mode 100644
index 0000000..0cf5b89
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.HashMap;
+
+@RunWith(RobolectricTestRunner.class)
+public class HearingAidStatsLogUtilsTest {
+
+    private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
+
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+
+    @Mock
+    private CachedBluetoothDevice mCachedBluetoothDevice;
+
+    @Test
+    public void setBondEntryForDevice_addsEntryToDeviceAddressToBondEntryMap() {
+        when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
+
+        HearingAidStatsLogUtils.setBondEntryForDevice(
+                FrameworkStatsLog.HEARING_AID_INFO_REPORTED__BOND_ENTRY__BLUETOOTH,
+                mCachedBluetoothDevice);
+
+        final HashMap<String, Integer> map =
+                HearingAidStatsLogUtils.getDeviceAddressToBondEntryMap();
+        assertThat(map.containsKey(TEST_DEVICE_ADDRESS)).isTrue();
+        assertThat(map.get(TEST_DEVICE_ADDRESS)).isEqualTo(
+                FrameworkStatsLog.HEARING_AID_INFO_REPORTED__BOND_ENTRY__BLUETOOTH);
+    }
+
+    @Test
+    public void logHearingAidInfo_removesEntryFromDeviceAddressToBondEntryMap() {
+        when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
+
+        HearingAidStatsLogUtils.setBondEntryForDevice(
+                FrameworkStatsLog.HEARING_AID_INFO_REPORTED__BOND_ENTRY__BLUETOOTH,
+                mCachedBluetoothDevice);
+        HearingAidStatsLogUtils.logHearingAidInfo(mCachedBluetoothDevice);
+
+        final HashMap<String, Integer> map =
+                HearingAidStatsLogUtils.getDeviceAddressToBondEntryMap();
+        assertThat(map.containsKey(TEST_DEVICE_ADDRESS)).isFalse();
+    }
+}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 7649de6..2737ecf 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -414,7 +414,7 @@
             </intent-filter>
         </receiver>
 
-        <service android:name=".ImageWallpaper"
+        <service android:name=".wallpapers.ImageWallpaper"
                 android:singleUser="true"
                 android:permission="android.permission.BIND_WALLPAPER"
                 android:exported="true" />
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index 57193e7..436145e 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -16,6 +16,8 @@
 
 import android.view.View;
 
+import androidx.annotation.FloatRange;
+
 import com.android.systemui.plugins.FragmentBase;
 import com.android.systemui.plugins.annotations.DependsOn;
 import com.android.systemui.plugins.annotations.ProvidesInterface;
@@ -107,10 +109,24 @@
     void setInSplitShade(boolean shouldTranslate);
 
     /**
-     * Set the amount of pixels we have currently dragged down if we're transitioning to the full
-     * shade. 0.0f means we're not transitioning yet.
+     * Sets the progress of the transition to full shade on the lockscreen.
+     *
+     * @param isTransitioningToFullShade
+     *        whether the transition to full shade is in progress. This might be {@code true}, even
+     *        though {@code qsTransitionFraction} is still 0.
+     *        The reason for that is that on some device configurations, the QS transition has a
+     *        start delay compared to the overall transition.
+     *
+     * @param qsTransitionFraction
+     *        the fraction of the QS transition progress, from 0 to 1.
+     *
+     * @param qsSquishinessFraction
+     *        the fraction of the QS "squish" transition progress, from 0 to 1.
      */
-    default void setTransitionToFullShadeAmount(float pxAmount, float progress) {}
+    default void setTransitionToFullShadeProgress(
+            boolean isTransitioningToFullShade,
+            @FloatRange(from = 0.0, to = 1.0) float qsTransitionFraction,
+            @FloatRange(from = 0.0, to = 1.0) float qsSquishinessFraction) {}
 
     /**
      * A rounded corner clipping that makes QS feel as if it were behind everything.
@@ -140,6 +156,12 @@
     default void setOverScrollAmount(int overScrollAmount) {}
 
     /**
+     * Sets whether the notification panel is using the full width of the screen. Typically true on
+     * small screens and false on large screens.
+     */
+    void setIsNotificationPanelFullWidth(boolean isFullWidth);
+
+    /**
      * Callback for when QSPanel container is scrolled
      */
     @ProvidesInterface(version = ScrollListener.VERSION)
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index d638c9d..f4d4824 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -49,54 +49,29 @@
 
     <dimen name="status_view_margin_horizontal">8dp</dimen>
 
-    <!-- Distance that the full shade transition takes in order to complete by tapping on a button
-         like "expand". -->
+    <!-- Lockscreen shade transition values -->
     <dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen>
-
-    <!-- Distance that the full shade transition takes in order to complete.  -->
     <dimen name="lockscreen_shade_full_transition_distance">200dp</dimen>
-
-    <!-- Distance that the full shade transition takes in order for media to fully transition to
-         the shade -->
-    <dimen name="lockscreen_shade_media_transition_distance">200dp</dimen>
-
-    <!-- Distance that the full shade transition takes in order for scrim to fully transition to
-         the shade (in alpha) -->
+    <!-- Media transition distance = qs delay + qs distance   -->
+    <dimen name="lockscreen_shade_media_transition_distance">129.28dp</dimen>
     <dimen name="lockscreen_shade_scrim_transition_distance">80dp</dimen>
-
     <!-- The notifications scrim transition should start when the other scrims' transition is at
          95%. -->
     <dimen name="lockscreen_shade_notifications_scrim_transition_delay">76dp</dimen>
-
     <!-- The notifications scrim transition duration is 66.6% of the duration of the other scrims'
-         transition. -->
+        transition. -->
     <dimen name="lockscreen_shade_notifications_scrim_transition_distance">53.28dp</dimen>
-
-    <!-- Distance that the full shade transition takes in order for the keyguard content on
-         NotificationPanelViewController to fully fade (e.g. Clock & Smartspace) -->
     <dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">80dp</dimen>
-
-    <!-- Distance that the full shade transition takes in order for the notification shell to fully
-         expand. -->
     <dimen name="lockscreen_shade_notif_shelf_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
-
-    <!-- Distance that the full shade transition takes in order for the Quick Settings to fully
-         fade and expand. -->
-    <dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
-
-    <!-- Distance that the full shade transition takes in order for depth of the wallpaper to fully
-         change.
-         On split-shade, there should be no depth effect, so setting the value to 0. -->
+    <dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_notifications_scrim_transition_distance</dimen>
+    <dimen name="lockscreen_shade_qs_transition_delay">@dimen/lockscreen_shade_notifications_scrim_transition_delay</dimen>
+    <dimen name="lockscreen_shade_qs_squish_transition_distance">@dimen/lockscreen_shade_qs_transition_distance</dimen>
+    <!-- On split-shade, the QS squish transition should start from half height.  -->
+    <item name="lockscreen_shade_qs_squish_start_fraction" type="dimen" format="float" >0.5</item>
+    <!-- On split-shade, there should be no depth effect, so setting the value to 0.  -->
     <dimen name="lockscreen_shade_depth_controller_transition_distance">0dp</dimen>
-
-    <!-- Distance that the full shade transition takes in order for the UDFPS Keyguard View to fully
-         fade. -->
     <dimen name="lockscreen_shade_udfps_keyguard_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
-
-    <!-- Used for StatusBar to know that a transition is in progress. At the moment it only checks
-         whether the progress is > 0, therefore this value is not very important. -->
     <dimen name="lockscreen_shade_status_bar_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
-
     <dimen name="lockscreen_shade_keyguard_transition_distance">@dimen/lockscreen_shade_media_transition_distance</dimen>
 
     <!-- Roughly the same distance as media on LS to media on QS. We will translate by this value
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 008299b..a587e5a 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -73,4 +73,24 @@
     <dimen name="large_dialog_width">472dp</dimen>
 
     <dimen name="large_screen_shade_header_height">42dp</dimen>
+
+    <!-- Lockscreen shade transition values -->
+    <dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen>
+    <dimen name="lockscreen_shade_full_transition_distance">80dp</dimen>
+    <dimen name="lockscreen_shade_media_transition_distance">120dp</dimen>
+    <dimen name="lockscreen_shade_scrim_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+    <dimen name="lockscreen_shade_notifications_scrim_transition_delay">@dimen/lockscreen_shade_scrim_transition_distance</dimen>
+    <dimen name="lockscreen_shade_notifications_scrim_transition_distance">@dimen/lockscreen_shade_scrim_transition_distance</dimen>
+    <dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+    <dimen name="lockscreen_shade_notif_shelf_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+    <dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+    <dimen name="lockscreen_shade_qs_transition_delay">@dimen/lockscreen_shade_scrim_transition_distance</dimen>
+    <dimen name="lockscreen_shade_qs_squish_transition_distance">@dimen/lockscreen_shade_qs_transition_distance</dimen>
+    <!-- On large screen portrait, the QS squish transition should start from half height.  -->
+    <item name="lockscreen_shade_qs_squish_start_fraction" type="dimen" format="float" >0.5</item>
+    <dimen name="lockscreen_shade_depth_controller_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+    <dimen name="lockscreen_shade_udfps_keyguard_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+    <dimen name="lockscreen_shade_status_bar_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+    <dimen name="lockscreen_shade_keyguard_transition_distance">@dimen/lockscreen_shade_media_transition_distance</dimen>
+
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 19a6aba..9cb4cc4 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1223,6 +1223,17 @@
          fade and expand. -->
     <dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
 
+    <!-- Distance delay for the QS transition to start during the lockscreen shade expansion. -->
+    <dimen name="lockscreen_shade_qs_transition_delay">0dp</dimen>
+
+    <!-- Distance that it takes to complete the QS "squish" transition during the lockscreen shade
+         expansion. -->
+    <dimen name="lockscreen_shade_qs_squish_transition_distance">@dimen/lockscreen_shade_qs_transition_distance</dimen>
+
+    <!-- The fraction at which the QS "squish" transition should start during the lockscreen shade
+         expansion. 0 is fully collapsed, 1 is fully expanded. -->
+    <item type="dimen" format="float" name="lockscreen_shade_qs_squish_start_fraction">0</item>
+
     <!-- Distance that the full shade transition takes in order for depth of the wallpaper to fully
          change.  -->
     <dimen name="lockscreen_shade_depth_controller_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
index e1cbdcd..92eeace 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
@@ -18,7 +18,6 @@
 
 import android.app.Service;
 
-import com.android.systemui.ImageWallpaper;
 import com.android.systemui.SystemUIService;
 import com.android.systemui.doze.DozeService;
 import com.android.systemui.dreams.DreamOverlayService;
@@ -26,6 +25,7 @@
 import com.android.systemui.keyguard.KeyguardService;
 import com.android.systemui.screenrecord.RecordingService;
 import com.android.systemui.statusbar.phone.NotificationListenerWithPlugins;
+import com.android.systemui.wallpapers.ImageWallpaper;
 
 import dagger.Binds;
 import dagger.Module;
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 4c6aa7b..cc77ed1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -458,6 +458,7 @@
         val existingPlayer = MediaPlayerData.getMediaPlayer(key)
         val curVisibleMediaKey = MediaPlayerData.playerKeys()
                 .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
+        val isCurVisibleMediaPlaying = MediaPlayerData.getMediaData(curVisibleMediaKey)?.isPlaying
         if (existingPlayer == null) {
             val newPlayer = mediaControlPanelFactory.get()
             newPlayer.attachPlayer(MediaViewHolder.create(
@@ -472,13 +473,23 @@
                 key, data, newPlayer, systemClock, isSsReactivated, debugLogger
             )
             updatePlayerToState(newPlayer, noAnimation = true)
-            reorderAllPlayers(curVisibleMediaKey)
+            if (data.active) {
+                reorderAllPlayers(curVisibleMediaKey)
+            } else {
+                needsReordering = true
+            }
         } else {
             existingPlayer.bindPlayer(data, key)
             MediaPlayerData.addMediaPlayer(
                 key, data, existingPlayer, systemClock, isSsReactivated, debugLogger
             )
-            if (isReorderingAllowed || shouldScrollToActivePlayer) {
+            // Check the playing status of both current visible and new media players
+            // To make sure we scroll to the active playing media card.
+            if (isReorderingAllowed ||
+                    shouldScrollToActivePlayer &&
+                    data.isPlaying == true &&
+                    isCurVisibleMediaPlaying == false
+            ) {
                 reorderAllPlayers(curVisibleMediaKey)
             } else {
                 needsReordering = true
@@ -1035,6 +1046,15 @@
         }
     }
 
+    fun getMediaData(mediaSortKey: MediaSortKey?): MediaData? {
+        mediaData.forEach { (key, value) ->
+            if (value == mediaSortKey) {
+                return mediaData[key]?.data
+            }
+        }
+        return null
+    }
+
     fun getMediaPlayer(key: String): MediaControlPanel? {
         return mediaData.get(key)?.let { mediaPlayers.get(it) }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index b31e472..072c32f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -34,6 +34,7 @@
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 
+import androidx.annotation.FloatRange;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.lifecycle.Lifecycle;
@@ -166,6 +167,13 @@
     // visible;
     private boolean mQsVisible;
 
+    /**
+     * Whether the notification panel uses the full width of the screen.
+     *
+     * Usually {@code true} on small screens, and {@code false} on large screens.
+     */
+    private boolean mIsNotificationPanelFullWidth;
+
     @Inject
     public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
             QSTileHost qsTileHost,
@@ -571,15 +579,17 @@
     }
 
     @Override
-    public void setTransitionToFullShadeAmount(float pxAmount, float progress) {
-        boolean isTransitioningToFullShade = pxAmount > 0;
+    public void setTransitionToFullShadeProgress(
+            boolean isTransitioningToFullShade,
+            @FloatRange(from = 0.0, to = 1.0) float qsTransitionFraction,
+            @FloatRange(from = 0.0, to = 1.0) float qsSquishinessFraction) {
         if (isTransitioningToFullShade != mTransitioningToFullShade) {
             mTransitioningToFullShade = isTransitioningToFullShade;
             updateShowCollapsedOnKeyguard();
         }
-        mFullShadeProgress = progress;
+        mFullShadeProgress = qsTransitionFraction;
         setQsExpansion(mLastQSExpansion, mLastPanelFraction, mLastHeaderTranslation,
-                isTransitioningToFullShade ? progress : mSquishinessFraction);
+                isTransitioningToFullShade ? qsSquishinessFraction : mSquishinessFraction);
     }
 
     @Override
@@ -598,12 +608,16 @@
     }
 
     @Override
+    public void setIsNotificationPanelFullWidth(boolean isFullWidth) {
+        mIsNotificationPanelFullWidth = isFullWidth;
+    }
+
+    @Override
     public void setQsExpansion(float expansion, float panelExpansionFraction,
             float proposedTranslation, float squishinessFraction) {
         float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation;
-        float alphaProgress = mTransitioningToFullShade || mState == StatusBarState.KEYGUARD
-                ? mFullShadeProgress : panelExpansionFraction;
-        setAlphaAnimationProgress(mInSplitShade ? alphaProgress : 1);
+        float alphaProgress = calculateAlphaProgress(panelExpansionFraction);
+        setAlphaAnimationProgress(alphaProgress);
         mContainer.setExpansion(expansion);
         final float translationScaleY = (mInSplitShade
                 ? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1);
@@ -684,10 +698,43 @@
         } else if (progress > 0 && view.getVisibility() != View.VISIBLE) {
             view.setVisibility((View.VISIBLE));
         }
-        float alpha = mQSPanelController.isBouncerInTransit()
-                ? BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(progress)
-                : ShadeInterpolation.getContentAlpha(progress);
-        view.setAlpha(alpha);
+        view.setAlpha(interpolateAlphaAnimationProgress(progress));
+    }
+
+    private float calculateAlphaProgress(float panelExpansionFraction) {
+        if (mIsNotificationPanelFullWidth) {
+            // Small screens. QS alpha is not animated.
+            return 1;
+        }
+        if (mInSplitShade) {
+            // Large screens in landscape.
+            if (mTransitioningToFullShade || isKeyguardState()) {
+                // Always use "mFullShadeProgress" on keyguard, because
+                // "panelExpansionFractions" is always 1 on keyguard split shade.
+                return mFullShadeProgress;
+            } else {
+                return panelExpansionFraction;
+            }
+        }
+        // Large screens in portrait.
+        if (mTransitioningToFullShade) {
+            // Only use this value during the standard lock screen shade expansion. During the
+            // "quick" expansion from top, this value is 0.
+            return mFullShadeProgress;
+        } else {
+            return panelExpansionFraction;
+        }
+    }
+
+    private float interpolateAlphaAnimationProgress(float progress) {
+        if (mQSPanelController.isBouncerInTransit()) {
+            return BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(progress);
+        }
+        if (isKeyguardState()) {
+            // Alpha progress should be linear on lockscreen shade expansion.
+            return progress;
+        }
+        return ShadeInterpolation.getContentAlpha(progress);
     }
 
     private void updateQsBounds() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index c3b265f..156b123 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -1320,6 +1320,9 @@
         mIsFullWidth = isFullWidth;
         mScrimController.setClipsQsScrim(isFullWidth);
         mNotificationStackScrollLayoutController.setIsFullWidth(isFullWidth);
+        if (mQs != null) {
+            mQs.setIsNotificationPanelFullWidth(isFullWidth);
+        }
     }
 
     private void startQsSizeChangeAnimation(int oldHeight, final int newHeight) {
@@ -2428,8 +2431,8 @@
         final float squishiness;
         if ((mQsExpandImmediate || mQsExpanded) && !mSplitShadeEnabled) {
             squishiness = 1;
-        } else if (mLockscreenShadeTransitionController.getQSDragProgress() > 0) {
-            squishiness = mLockscreenShadeTransitionController.getQSDragProgress();
+        } else if (mTransitioningToFullShadeProgress > 0.0f) {
+            squishiness = mLockscreenShadeTransitionController.getQsSquishTransitionFraction();
         } else {
             squishiness = mNotificationStackScrollLayoutController
                     .getNotificationSquishinessFraction();
@@ -3716,6 +3719,7 @@
             mQs.setHeaderClickable(isQsExpansionEnabled());
             mQs.setOverscrolling(mStackScrollerOverscrolling);
             mQs.setInSplitShade(mSplitShadeEnabled);
+            mQs.setIsNotificationPanelFullWidth(mIsFullWidth);
 
             // recompute internal state when qspanel height changes
             mQs.getView().addOnLayoutChangeListener(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt
new file mode 100644
index 0000000..62c225b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt
@@ -0,0 +1,159 @@
+/*
+ * 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.systemui.statusbar
+
+import android.content.Context
+import android.util.IndentingPrintWriter
+import android.util.MathUtils
+import androidx.annotation.FloatRange
+import androidx.annotation.Px
+import com.android.systemui.R
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.qs.QS
+import com.android.systemui.statusbar.policy.ConfigurationController
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlin.math.max
+
+/** Responsible for the QS components during the lockscreen shade transition. */
+class LockscreenShadeQsTransitionController
+@AssistedInject
+constructor(
+    context: Context,
+    configurationController: ConfigurationController,
+    dumpManager: DumpManager,
+    @Assisted private val qsProvider: () -> QS,
+) : AbstractLockscreenShadeTransitionController(context, configurationController, dumpManager) {
+
+    private val qs: QS
+        get() = qsProvider()
+
+    /**
+     * The progress fraction of the QS transition during lockscreen shade expansion.
+     *
+     * Note that this value might be 0 for some time when the expansion is already in progress,
+     * since there is a transition start delay for QS on some device configurations. For this
+     * reason, don't use this value to check whether the shade expansion is in progress.
+     */
+    @FloatRange(from = 0.0, to = 1.0)
+    var qsTransitionFraction = 0f
+        private set
+
+    /**
+     * The fraction of the QS "squish" transition progress during lockscreen shade expansion.
+     *
+     * Note that in some device configurations (large screens) this value can start at a value
+     * greater than 0. For this reason don't use this value to check whether the QS transition has
+     * started or not.
+     */
+    @FloatRange(from = 0.0, to = 1.0)
+    var qsSquishTransitionFraction = 0f
+        private set
+
+    /**
+     * The drag down amount, in pixels __for the QS transition__, also taking into account the
+     * [qsTransitionStartDelay].
+     *
+     * Since it takes into account the start delay, it is __not__ the same as the raw drag down
+     * amount from the shade expansion.
+     */
+    @Px private var qsDragDownAmount = 0f
+
+    /**
+     * Distance it takes for the QS transition to complete during the lockscreen shade expansion.
+     */
+    @Px private var qsTransitionDistance = 0
+
+    /** Distance delay for the QS transition to start during the lockscreen shade expansion. */
+    @Px private var qsTransitionStartDelay = 0
+
+    /**
+     * Distance that it takes to complete the QS "squish" transition during the lockscreen shade
+     * expansion.
+     */
+    @Px private var qsSquishTransitionDistance = 0
+
+    /**
+     * Whether the transition to full shade is in progress. Might be `true` even though
+     * [qsTransitionFraction] is still 0, due to [qsTransitionStartDelay].
+     */
+    private var isTransitioningToFullShade = false
+
+    /**
+     * The fraction at which the QS "squish" transition should start during the lockscreen shade
+     * expansion.
+     *
+     * 0 is fully collapsed, 1 is fully expanded.
+     */
+    @FloatRange(from = 0.0, to = 1.0) private var qsSquishStartFraction = 0f
+
+    override fun updateResources() {
+        qsTransitionDistance =
+            context.resources.getDimensionPixelSize(R.dimen.lockscreen_shade_qs_transition_distance)
+        qsTransitionStartDelay =
+            context.resources.getDimensionPixelSize(R.dimen.lockscreen_shade_qs_transition_delay)
+        qsSquishTransitionDistance =
+            context.resources.getDimensionPixelSize(
+                R.dimen.lockscreen_shade_qs_squish_transition_distance
+            )
+        qsSquishStartFraction =
+            context.resources.getFloat(R.dimen.lockscreen_shade_qs_squish_start_fraction)
+
+        qsSquishTransitionFraction = max(qsSquishTransitionFraction, qsSquishStartFraction)
+    }
+
+    override fun onDragDownAmountChanged(dragDownAmount: Float) {
+        qsDragDownAmount = dragDownAmount - qsTransitionStartDelay
+        qsTransitionFraction = MathUtils.saturate(qsDragDownAmount / qsTransitionDistance)
+        qsSquishTransitionFraction =
+            MathUtils.lerp(
+                /* start= */ qsSquishStartFraction,
+                /* stop= */ 1f,
+                /* amount= */ MathUtils.saturate(qsDragDownAmount / qsSquishTransitionDistance)
+            )
+        isTransitioningToFullShade = dragDownAmount > 0.0f
+        qs.setTransitionToFullShadeProgress(
+            isTransitioningToFullShade,
+            qsTransitionFraction,
+            qsSquishTransitionFraction
+        )
+    }
+
+    override fun dump(pw: IndentingPrintWriter) {
+        pw.println(
+            """
+            Resources:
+              qsTransitionDistance: $qsTransitionDistance
+              qsTransitionStartDelay: $qsTransitionStartDelay
+              qsSquishTransitionDistance: $qsSquishTransitionDistance
+              qsSquishStartFraction: $qsSquishStartFraction
+            State:
+              dragDownAmount: $dragDownAmount
+              qsDragDownAmount: $qsDragDownAmount
+              qsDragFraction: $qsTransitionFraction
+              qsSquishFraction: $qsSquishTransitionFraction
+              isTransitioningToFullShade: $isTransitioningToFullShade
+        """.trimIndent()
+        )
+    }
+
+    @AssistedFactory
+    fun interface Factory {
+        fun create(qsProvider: () -> QS): LockscreenShadeQsTransitionController
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index d3343df..8006931 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -11,6 +11,7 @@
 import android.view.MotionEvent
 import android.view.View
 import android.view.ViewConfiguration
+import androidx.annotation.FloatRange
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.Dumpable
 import com.android.systemui.ExpandHelper
@@ -68,7 +69,8 @@
     wakefulnessLifecycle: WakefulnessLifecycle,
     configurationController: ConfigurationController,
     falsingManager: FalsingManager,
-    dumpManager: DumpManager
+    dumpManager: DumpManager,
+    qsTransitionControllerFactory: LockscreenShadeQsTransitionController.Factory,
 ) : Dumpable {
     private var pulseHeight: Float = 0f
     @get:VisibleForTesting
@@ -120,12 +122,6 @@
     private var notificationShelfTransitionDistance = 0
 
     /**
-     * Distance that the full shade transition takes in order for the Quick Settings to fully fade
-     * and expand.
-     */
-    private var qsTransitionDistance = 0
-
-    /**
      * Distance that the full shade transition takes in order for depth of the wallpaper to fully
      * change.
      */
@@ -188,6 +184,18 @@
         keyguardTransitionControllerFactory.create(notificationPanelController)
     }
 
+    private val qsTransitionController = qsTransitionControllerFactory.create { qS }
+
+    /** See [LockscreenShadeQsTransitionController.qsTransitionFraction].*/
+    @get:FloatRange(from = 0.0, to = 1.0)
+    val qSDragProgress: Float
+        get() = qsTransitionController.qsTransitionFraction
+
+    /** See [LockscreenShadeQsTransitionController.qsSquishTransitionFraction].*/
+    @get:FloatRange(from = 0.0, to = 1.0)
+    val qsSquishTransitionFraction: Float
+        get() = qsTransitionController.qsSquishTransitionFraction
+
     /**
      * [LockScreenShadeOverScroller] property that delegates to either
      * [SingleShadeLockScreenOverScroller] or [SplitShadeLockScreenOverScroller].
@@ -242,8 +250,6 @@
             R.dimen.lockscreen_shade_transition_by_tap_distance)
         notificationShelfTransitionDistance = context.resources.getDimensionPixelSize(
                 R.dimen.lockscreen_shade_notif_shelf_transition_distance)
-        qsTransitionDistance = context.resources.getDimensionPixelSize(
-                R.dimen.lockscreen_shade_qs_transition_distance)
         depthControllerTransitionDistance = context.resources.getDimensionPixelSize(
                 R.dimen.lockscreen_shade_depth_controller_transition_distance)
         udfpsTransitionDistance = context.resources.getDimensionPixelSize(
@@ -411,8 +417,7 @@
                         MathUtils.saturate(dragDownAmount / notificationShelfTransitionDistance)
                     nsslController.setTransitionToFullShadeAmount(fractionToShade)
 
-                    qSDragProgress = MathUtils.saturate(dragDownAmount / qsTransitionDistance)
-                    qS.setTransitionToFullShadeAmount(field, qSDragProgress)
+                    qsTransitionController.dragDownAmount = value
 
                     notificationPanelController.setTransitionToFullShadeAmount(field,
                             false /* animate */, 0 /* delay */)
@@ -426,12 +431,6 @@
             }
         }
 
-    /**
-     * The drag progress of the quick settings drag down amount
-     */
-    var qSDragProgress = 0f
-        private set
-
     private fun transitionToShadeAmountCommon(dragDownAmount: Float) {
         if (depthControllerTransitionDistance == 0) { // split shade
             depthController.transitionToFullShadeProgress = 0f
@@ -704,7 +703,6 @@
             it.println("pulseHeight: $pulseHeight")
             it.println("useSplitShade: $useSplitShade")
             it.println("dragDownAmount: $dragDownAmount")
-            it.println("qSDragProgress: $qSDragProgress")
             it.println("isDragDownAnywhereEnabled: $isDragDownAnywhereEnabled")
             it.println("isFalsingCheckNeeded: $isFalsingCheckNeeded")
             it.println("isWakingToShadeLocked: $isWakingToShadeLocked")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index cb0a148..4d1c361 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -259,11 +259,17 @@
     private boolean mKeyguardOccluded;
 
     @Inject
-    public ScrimController(LightBarController lightBarController, DozeParameters dozeParameters,
-            AlarmManager alarmManager, KeyguardStateController keyguardStateController,
-            DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
-            KeyguardUpdateMonitor keyguardUpdateMonitor, DockManager dockManager,
-            ConfigurationController configurationController, @Main Executor mainExecutor,
+    public ScrimController(
+            LightBarController lightBarController,
+            DozeParameters dozeParameters,
+            AlarmManager alarmManager,
+            KeyguardStateController keyguardStateController,
+            DelayedWakeLock.Builder delayedWakeLockBuilder,
+            Handler handler,
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            DockManager dockManager,
+            ConfigurationController configurationController,
+            @Main Executor mainExecutor,
             ScreenOffAnimationController screenOffAnimationController,
             KeyguardUnlockAnimationController keyguardUnlockAnimationController,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
@@ -826,20 +832,15 @@
                 mBehindTint = Color.BLACK;
             } else {
                 mBehindAlpha = behindAlpha;
-                if (mState == ScrimState.SHADE_LOCKED) {
+                if (mState == ScrimState.KEYGUARD && mTransitionToFullShadeProgress > 0.0f) {
+                    mNotificationsAlpha = MathUtils
+                            .saturate(mTransitionToLockScreenFullShadeNotificationsProgress);
+                } else if (mState == ScrimState.SHADE_LOCKED) {
                     // going from KEYGUARD to SHADE_LOCKED state
                     mNotificationsAlpha = getInterpolatedFraction();
                 } else {
                     mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion);
                 }
-                if (mState == ScrimState.KEYGUARD
-                        && mTransitionToLockScreenFullShadeNotificationsProgress > 0.0f) {
-                    // Interpolate the notification alpha when transitioning!
-                    mNotificationsAlpha = MathUtils.lerp(
-                            mNotificationsAlpha,
-                            getInterpolatedFraction(),
-                            mTransitionToLockScreenFullShadeNotificationsProgress);
-                }
                 mNotificationsTint = mState.getNotifTint();
                 mBehindTint = behindTint;
             }
@@ -1430,6 +1431,8 @@
         pw.print(mNotificationsAlpha);
         pw.print(" tint=0x");
         pw.println(Integer.toHexString(mNotificationsScrim.getTint()));
+        pw.print(" expansionProgress=");
+        pw.println(mTransitionToLockScreenFullShadeNotificationsProgress);
 
         pw.print("  mTracking=");
         pw.println(mTracking);
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index 8ff90f7..2878ad9 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui;
+package com.android.systemui.wallpapers;
 
 import android.app.WallpaperColors;
 import android.graphics.Bitmap;
@@ -37,8 +37,8 @@
 import androidx.annotation.NonNull;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.glwallpaper.EglHelper;
-import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
+import com.android.systemui.wallpapers.gl.EglHelper;
+import com.android.systemui.wallpapers.gl.ImageWallpaperRenderer;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/OWNERS b/packages/SystemUI/src/com/android/systemui/wallpapers/OWNERS
new file mode 100644
index 0000000..731c798
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+cinek@google.com
+dupin@google.com
+pomini@google.com
+santie@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/EglHelper.java
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/gl/EglHelper.java
index 11e215d..f9ddce8 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/EglHelper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
 
 import static android.opengl.EGL14.EGL_ALPHA_SIZE;
 import static android.opengl.EGL14.EGL_BLUE_SIZE;
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/GLWallpaperRenderer.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/gl/GLWallpaperRenderer.java
index 6152490..692ced0 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/GLWallpaperRenderer.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
 
 import android.util.Size;
 
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLProgram.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLProgram.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLProgram.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLProgram.java
index d03b00b..d34eca4 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLProgram.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLProgram.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
 
 import static android.opengl.GLES20.GL_FRAGMENT_SHADER;
 import static android.opengl.GLES20.GL_VERTEX_SHADER;
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLWallpaper.java
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLWallpaper.java
index 1a53c28..f1659b9 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLWallpaper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
 
 import static android.opengl.GLES20.GL_FLOAT;
 import static android.opengl.GLES20.GL_LINEAR;
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageWallpaperRenderer.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageWallpaperRenderer.java
index 7c0b93b..e393786 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageWallpaperRenderer.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
 
 import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
 import static android.opengl.GLES20.glClear;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
index 1bc1972..5a50a9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.animation.TransitionLayout
 import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.time.FakeSystemClock
 import javax.inject.Provider
@@ -38,6 +39,8 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
 import org.mockito.Mock
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
@@ -71,6 +74,10 @@
     @Mock lateinit var player: TransitionLayout
     @Mock lateinit var recommendationViewHolder: RecommendationViewHolder
     @Mock lateinit var recommendations: TransitionLayout
+    @Mock lateinit var mediaPlayer: MediaControlPanel
+    @Mock lateinit var mediaViewController: MediaViewController
+    @Mock lateinit var smartspaceMediaData: SmartspaceMediaData
+    @Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
 
     private val clock = FakeSystemClock()
     private lateinit var mediaCarouselController: MediaCarouselController
@@ -94,7 +101,10 @@
             logger,
             debugLogger
         )
-
+        verify(mediaDataManager).addListener(capture(listener))
+        whenever(mediaControlPanelFactory.get()).thenReturn(mediaPlayer)
+        whenever(mediaPlayer.mediaViewController).thenReturn(mediaViewController)
+        whenever(mediaDataManager.smartspaceMediaData).thenReturn(smartspaceMediaData)
         MediaPlayerData.clear()
     }
 
@@ -305,4 +315,63 @@
         verifyNoMoreInteractions(mediaViewHolder)
         verify(recommendationViewHolder.recommendations).bottom = 75
     }
+
+    fun testMediaLoaded_ScrollToActivePlayer() {
+        listener.value.onMediaDataLoaded("playing local",
+                null,
+                DATA.copy(active = true, isPlaying = true,
+                        playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false)
+        )
+        listener.value.onMediaDataLoaded("paused local",
+                null,
+                DATA.copy(active = true, isPlaying = false,
+                        playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false))
+        // adding a media recommendation card.
+        MediaPlayerData.addMediaRecommendation(SMARTSPACE_KEY, EMPTY_SMARTSPACE_MEDIA_DATA, panel,
+                false, clock)
+        mediaCarouselController.shouldScrollToActivePlayer = true
+        // switching between media players.
+        listener.value.onMediaDataLoaded("playing local",
+        "playing local",
+                DATA.copy(active = true, isPlaying = false,
+                        playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = true)
+        )
+        listener.value.onMediaDataLoaded("paused local",
+                "paused local",
+                DATA.copy(active = true, isPlaying = true,
+                        playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false))
+
+        assertEquals(
+                MediaPlayerData.getMediaPlayerIndex("paused local"),
+                mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
+        )
+    }
+
+    @Test
+    fun testMediaLoadedFromRecommendationCard_ScrollToActivePlayer() {
+        MediaPlayerData.addMediaRecommendation(SMARTSPACE_KEY, EMPTY_SMARTSPACE_MEDIA_DATA, panel,
+                false, clock)
+        listener.value.onMediaDataLoaded("playing local",
+                null,
+                DATA.copy(active = true, isPlaying = true,
+                        playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false)
+        )
+
+        var playerIndex = MediaPlayerData.getMediaPlayerIndex("playing local")
+        assertEquals(
+                playerIndex,
+                mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
+        )
+        assertEquals( playerIndex, 0)
+
+        // Replaying the same media player one more time.
+        // And check that the card stays in its position.
+        listener.value.onMediaDataLoaded("playing local",
+                null,
+                DATA.copy(active = true, isPlaying = true,
+                        playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false)
+        )
+        playerIndex = MediaPlayerData.getMediaPlayerIndex("playing local")
+        assertEquals(playerIndex, 0)
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index f08ad24..5d5918d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -94,6 +94,7 @@
     @Mock private QSPanel.QSTileLayout mQQsTileLayout;
     @Mock private QSAnimator mQSAnimator;
     @Mock private StatusBarStateController mStatusBarStateController;
+    @Mock private QSSquishinessController mSquishinessController;
     private View mQsFragmentView;
 
     public QSFragmentTest() {
@@ -139,13 +140,15 @@
     }
 
     @Test
-    public void transitionToFullShade_inSplitShade_setsAlphaBasedOnProgress() {
+    public void transitionToFullShade_setsAlphaUsingShadeInterpolator() {
         QSFragment fragment = resumeAndGetFragment();
-        enableSplitShade();
-        int transitionPxAmount = 123;
+        setStatusBarState(StatusBarState.SHADE);
+        boolean isTransitioningToFullShade = true;
         float transitionProgress = 0.5f;
+        float squishinessFraction = 0.5f;
 
-        fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+        fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+                squishinessFraction);
 
         assertThat(mQsFragmentView.getAlpha())
                 .isEqualTo(ShadeInterpolation.getContentAlpha(transitionProgress));
@@ -153,31 +156,32 @@
 
     @Test
     public void
-            transitionToFullShade_inSplitShade_onKeyguard_bouncerNotActive_usesShadeInterpolator() {
+            transitionToFullShade_onKeyguard_noBouncer_setsAlphaUsingLinearInterpolator() {
         QSFragment fragment = resumeAndGetFragment();
-        enableSplitShade();
         setStatusBarState(StatusBarState.KEYGUARD);
         when(mQSPanelController.isBouncerInTransit()).thenReturn(false);
-        int transitionPxAmount = 123;
+        boolean isTransitioningToFullShade = true;
         float transitionProgress = 0.5f;
+        float squishinessFraction = 0.5f;
 
-        fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+        fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+                squishinessFraction);
 
-        assertThat(mQsFragmentView.getAlpha())
-                .isEqualTo(ShadeInterpolation.getContentAlpha(transitionProgress));
+        assertThat(mQsFragmentView.getAlpha()).isEqualTo(transitionProgress);
     }
 
     @Test
     public void
-            transitionToFullShade_inSplitShade_onKeyguard_bouncerActive_usesBouncerInterpolator() {
+            transitionToFullShade_onKeyguard_bouncerActive_setsAlphaUsingBouncerInterpolator() {
         QSFragment fragment = resumeAndGetFragment();
-        enableSplitShade();
         setStatusBarState(StatusBarState.KEYGUARD);
         when(mQSPanelController.isBouncerInTransit()).thenReturn(true);
-        int transitionPxAmount = 123;
+        boolean isTransitioningToFullShade = true;
         float transitionProgress = 0.5f;
+        float squishinessFraction = 0.5f;
 
-        fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+        fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+                squishinessFraction);
 
         assertThat(mQsFragmentView.getAlpha())
                 .isEqualTo(
@@ -186,28 +190,44 @@
     }
 
     @Test
-    public void transitionToFullShade_notInSplitShade_alwaysSetsAlphaTo1() {
+    public void transitionToFullShade_inFullWidth_alwaysSetsAlphaTo1() {
         QSFragment fragment = resumeAndGetFragment();
-        disableSplitShade();
+        fragment.setIsNotificationPanelFullWidth(true);
 
-        int transitionPxAmount = 12;
+        boolean isTransitioningToFullShade = true;
         float transitionProgress = 0.1f;
-        fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+        float squishinessFraction = 0.5f;
+        fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+                squishinessFraction);
         assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
 
-        transitionPxAmount = 123;
         transitionProgress = 0.5f;
-        fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+        fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+                squishinessFraction);
         assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
         assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
 
-        transitionPxAmount = 234;
         transitionProgress = 0.7f;
-        fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+        fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+                squishinessFraction);
         assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
     }
 
     @Test
+    public void transitionToFullShade_setsSquishinessOnController() {
+        QSFragment fragment = resumeAndGetFragment();
+        boolean isTransitioningToFullShade = true;
+        float transitionProgress = 0.123f;
+        float squishinessFraction = 0.456f;
+
+        fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+                squishinessFraction);
+
+        verify(mQsFragmentComponent.getQSSquishinessController())
+                .setSquishiness(squishinessFraction);
+    }
+
+    @Test
     public void setQsExpansion_inSplitShade_setsFooterActionsExpansion_basedOnPanelExpFraction() {
         // Random test values without any meaning. They just have to be different from each other.
         float expansion = 0.123f;
@@ -453,6 +473,7 @@
         when(mQsFragmentComponent.getQSFooterActionController())
                 .thenReturn(mQSFooterActionController);
         when(mQsFragmentComponent.getQSAnimator()).thenReturn(mQSAnimator);
+        when(mQsFragmentComponent.getQSSquishinessController()).thenReturn(mSquishinessController);
     }
 
     private QSFragment getFragment() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 3224a6f..f1c54ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -42,7 +42,6 @@
 import static org.mockito.Mockito.when;
 
 import android.annotation.IdRes;
-import android.app.ActivityManager;
 import android.content.ContentResolver;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -57,6 +56,7 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.ViewPropertyAnimator;
 import android.view.ViewStub;
@@ -107,6 +107,7 @@
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
+import com.android.systemui.qs.QSFragment;
 import com.android.systemui.screenrecord.RecordingController;
 import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.statusbar.CommandQueue;
@@ -160,8 +161,6 @@
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView;
 import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.unfold.SysUIUnfoldComponent;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.settings.SecureSettings;
 import com.android.systemui.util.time.FakeSystemClock;
 import com.android.systemui.util.time.SystemClock;
 import com.android.systemui.wallet.controller.QuickAccessWalletController;
@@ -185,225 +184,134 @@
 public class NotificationPanelViewControllerTest extends SysuiTestCase {
 
     private static final int NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE = 50;
+    private static final int PANEL_WIDTH = 500; // Random value just for the test.
 
-    @Mock
-    private CentralSurfaces mCentralSurfaces;
-    @Mock
-    private NotificationStackScrollLayout mNotificationStackScrollLayout;
-    @Mock
-    private KeyguardBottomAreaView mKeyguardBottomArea;
-    @Mock
-    private KeyguardBottomAreaViewController mKeyguardBottomAreaViewController;
-    @Mock
-    private KeyguardBottomAreaView mQsFrame;
-    private KeyguardStatusView mKeyguardStatusView;
-    @Mock
-    private NotificationIconAreaController mNotificationAreaController;
-    @Mock
-    private HeadsUpManagerPhone mHeadsUpManager;
-    @Mock
-    private NotificationShelfController mNotificationShelfController;
-    @Mock
-    private KeyguardStatusBarView mKeyguardStatusBar;
-    @Mock
-    private KeyguardUserSwitcherView mUserSwitcherView;
-    @Mock
-    private ViewStub mUserSwitcherStubView;
-    @Mock
-    private HeadsUpTouchHelper.Callback mHeadsUpCallback;
-    @Mock
-    private KeyguardUpdateMonitor mUpdateMonitor;
-    @Mock
-    private KeyguardBypassController mKeyguardBypassController;
-    @Mock
-    private DozeParameters mDozeParameters;
-    @Mock
-    private ScreenOffAnimationController mScreenOffAnimationController;
-    @Mock
-    private NotificationPanelView mView;
-    @Mock
-    private LayoutInflater mLayoutInflater;
-    @Mock
-    private FeatureFlags mFeatureFlags;
-    @Mock
-    private DynamicPrivacyController mDynamicPrivacyController;
-    @Mock
-    private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
-    @Mock
-    private KeyguardStateController mKeyguardStateController;
-    @Mock
-    private DozeLog mDozeLog;
-    @Mock
-    private ShadeLogger mShadeLog;
-    @Mock
-    private CommandQueue mCommandQueue;
-    @Mock
-    private VibratorHelper mVibratorHelper;
-    @Mock
-    private LatencyTracker mLatencyTracker;
-    @Mock
-    private PowerManager mPowerManager;
-    @Mock
-    private AccessibilityManager mAccessibilityManager;
-    @Mock
-    private MetricsLogger mMetricsLogger;
-    @Mock
-    private ActivityManager mActivityManager;
-    @Mock
-    private Resources mResources;
-    @Mock
-    private Configuration mConfiguration;
-    private DisplayMetrics mDisplayMetrics = new DisplayMetrics();
-    @Mock
-    private KeyguardClockSwitch mKeyguardClockSwitch;
-    private NotificationPanelViewController.TouchHandler mTouchHandler;
-    private ConfigurationController mConfigurationController;
-    @Mock
-    private MediaHierarchyManager mMediaHiearchyManager;
-    @Mock
-    private ConversationNotificationManager mConversationNotificationManager;
-    @Mock
-    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
-    @Mock
-    private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
-    @Mock
-    private KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory;
-    @Mock
-    private KeyguardQsUserSwitchComponent mKeyguardQsUserSwitchComponent;
-    @Mock
-    private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
-    @Mock
-    private KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
-    @Mock
-    private KeyguardUserSwitcherComponent mKeyguardUserSwitcherComponent;
-    @Mock
-    private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
-    @Mock
-    private KeyguardStatusViewComponent mKeyguardStatusViewComponent;
-    @Mock
-    private KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
-    @Mock
-    private KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent;
-    @Mock
-    private KeyguardClockSwitchController mKeyguardClockSwitchController;
-    @Mock
-    private KeyguardStatusViewController mKeyguardStatusViewController;
-    @Mock
-    private KeyguardStatusBarViewController mKeyguardStatusBarViewController;
-    @Mock
-    private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
-    @Mock
-    private NotificationShadeDepthController mNotificationShadeDepthController;
-    @Mock
-    private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
-    @Mock
-    private AuthController mAuthController;
-    @Mock
-    private ScrimController mScrimController;
-    @Mock
-    private MediaDataManager mMediaDataManager;
-    @Mock
-    private AmbientState mAmbientState;
-    @Mock
-    private UserManager mUserManager;
-    @Mock
-    private UiEventLogger mUiEventLogger;
-    @Mock
-    private LockIconViewController mLockIconViewController;
-    @Mock
-    private KeyguardMediaController mKeyguardMediaController;
-    @Mock
-    private PrivacyDotViewController mPrivacyDotViewController;
-    @Mock
-    private NavigationModeController mNavigationModeController;
-    @Mock
-    private SecureSettings mSecureSettings;
-    @Mock
-    private LargeScreenShadeHeaderController mLargeScreenShadeHeaderController;
-    @Mock
-    private ContentResolver mContentResolver;
-    @Mock
-    private TapAgainViewController mTapAgainViewController;
-    @Mock
-    private KeyguardIndicationController mKeyguardIndicationController;
-    @Mock
-    private FragmentService mFragmentService;
-    @Mock
-    private FragmentHostManager mFragmentHostManager;
-    @Mock
-    private QuickAccessWalletController mQuickAccessWalletController;
-    @Mock
-    private QRCodeScannerController mQrCodeScannerController;
-    @Mock
-    private NotificationRemoteInputManager mNotificationRemoteInputManager;
-    @Mock
-    private RecordingController mRecordingController;
-    @Mock
-    private ControlsComponent mControlsComponent;
-    @Mock
-    private LockscreenGestureLogger mLockscreenGestureLogger;
-    @Mock
-    private DumpManager mDumpManager;
-    @Mock
-    private InteractionJankMonitor mInteractionJankMonitor;
-    @Mock
-    private NotificationsQSContainerController mNotificationsQSContainerController;
-    @Mock
-    private QsFrameTranslateController mQsFrameTranslateController;
-    @Mock
-    private StatusBarWindowStateController mStatusBarWindowStateController;
-    @Mock
-    private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
-    @Mock
-    private NotificationShadeWindowController mNotificationShadeWindowController;
-    @Mock
-    private SysUiState mSysUiState;
-    @Mock
-    private NotificationListContainer mNotificationListContainer;
-    @Mock
-    private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
-    @Mock
-    private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
-    @Mock
-    private ShadeTransitionController mShadeTransitionController;
-    @Mock
-    private QS mQs;
-    @Mock
-    private View mQsHeader;
-    @Mock
-    private ViewParent mViewParent;
-    @Mock
-    private ViewTreeObserver mViewTreeObserver;
+    @Mock private CentralSurfaces mCentralSurfaces;
+    @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout;
+    @Mock private KeyguardBottomAreaView mKeyguardBottomArea;
+    @Mock private KeyguardBottomAreaViewController mKeyguardBottomAreaViewController;
+    @Mock private KeyguardBottomAreaView mQsFrame;
+    @Mock private NotificationIconAreaController mNotificationAreaController;
+    @Mock private HeadsUpManagerPhone mHeadsUpManager;
+    @Mock private NotificationShelfController mNotificationShelfController;
+    @Mock private KeyguardStatusBarView mKeyguardStatusBar;
+    @Mock private KeyguardUserSwitcherView mUserSwitcherView;
+    @Mock private ViewStub mUserSwitcherStubView;
+    @Mock private HeadsUpTouchHelper.Callback mHeadsUpCallback;
+    @Mock private KeyguardUpdateMonitor mUpdateMonitor;
+    @Mock private KeyguardBypassController mKeyguardBypassController;
+    @Mock private DozeParameters mDozeParameters;
+    @Mock private ScreenOffAnimationController mScreenOffAnimationController;
+    @Mock private NotificationPanelView mView;
+    @Mock private LayoutInflater mLayoutInflater;
+    @Mock private FeatureFlags mFeatureFlags;
+    @Mock private DynamicPrivacyController mDynamicPrivacyController;
+    @Mock private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+    @Mock private KeyguardStateController mKeyguardStateController;
+    @Mock private DozeLog mDozeLog;
+    @Mock private ShadeLogger mShadeLog;
+    @Mock private CommandQueue mCommandQueue;
+    @Mock private VibratorHelper mVibratorHelper;
+    @Mock private LatencyTracker mLatencyTracker;
+    @Mock private PowerManager mPowerManager;
+    @Mock private AccessibilityManager mAccessibilityManager;
+    @Mock private MetricsLogger mMetricsLogger;
+    @Mock private Resources mResources;
+    @Mock private Configuration mConfiguration;
+    @Mock private KeyguardClockSwitch mKeyguardClockSwitch;
+    @Mock private MediaHierarchyManager mMediaHiearchyManager;
+    @Mock private ConversationNotificationManager mConversationNotificationManager;
+    @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    @Mock private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
+    @Mock private KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory;
+    @Mock private KeyguardQsUserSwitchComponent mKeyguardQsUserSwitchComponent;
+    @Mock private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
+    @Mock private KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
+    @Mock private KeyguardUserSwitcherComponent mKeyguardUserSwitcherComponent;
+    @Mock private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
+    @Mock private KeyguardStatusViewComponent mKeyguardStatusViewComponent;
+    @Mock private KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
+    @Mock private KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent;
+    @Mock private KeyguardClockSwitchController mKeyguardClockSwitchController;
+    @Mock private KeyguardStatusViewController mKeyguardStatusViewController;
+    @Mock private KeyguardStatusBarViewController mKeyguardStatusBarViewController;
+    @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
+    @Mock private NotificationShadeDepthController mNotificationShadeDepthController;
+    @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+    @Mock private AuthController mAuthController;
+    @Mock private ScrimController mScrimController;
+    @Mock private MediaDataManager mMediaDataManager;
+    @Mock private AmbientState mAmbientState;
+    @Mock private UserManager mUserManager;
+    @Mock private UiEventLogger mUiEventLogger;
+    @Mock private LockIconViewController mLockIconViewController;
+    @Mock private KeyguardMediaController mKeyguardMediaController;
+    @Mock private PrivacyDotViewController mPrivacyDotViewController;
+    @Mock private NavigationModeController mNavigationModeController;
+    @Mock private LargeScreenShadeHeaderController mLargeScreenShadeHeaderController;
+    @Mock private ContentResolver mContentResolver;
+    @Mock private TapAgainViewController mTapAgainViewController;
+    @Mock private KeyguardIndicationController mKeyguardIndicationController;
+    @Mock private FragmentService mFragmentService;
+    @Mock private FragmentHostManager mFragmentHostManager;
+    @Mock private QuickAccessWalletController mQuickAccessWalletController;
+    @Mock private QRCodeScannerController mQrCodeScannerController;
+    @Mock private NotificationRemoteInputManager mNotificationRemoteInputManager;
+    @Mock private RecordingController mRecordingController;
+    @Mock private ControlsComponent mControlsComponent;
+    @Mock private LockscreenGestureLogger mLockscreenGestureLogger;
+    @Mock private DumpManager mDumpManager;
+    @Mock private InteractionJankMonitor mInteractionJankMonitor;
+    @Mock private NotificationsQSContainerController mNotificationsQSContainerController;
+    @Mock private QsFrameTranslateController mQsFrameTranslateController;
+    @Mock private StatusBarWindowStateController mStatusBarWindowStateController;
+    @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+    @Mock private NotificationShadeWindowController mNotificationShadeWindowController;
+    @Mock private SysUiState mSysUiState;
+    @Mock private NotificationListContainer mNotificationListContainer;
+    @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
+    @Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+    @Mock private ShadeTransitionController mShadeTransitionController;
+    @Mock private QS mQs;
+    @Mock private QSFragment mQSFragment;
+    @Mock private ViewGroup mQsHeader;
+    @Mock private ViewParent mViewParent;
+    @Mock private ViewTreeObserver mViewTreeObserver;
     @Mock private KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
     @Mock private KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
-    private NotificationPanelViewController.PanelEventsEmitter mPanelEventsEmitter;
-    private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
+
+    private NotificationPanelViewController.TouchHandler mTouchHandler;
+    private ConfigurationController mConfigurationController;
     private SysuiStatusBarStateController mStatusBarStateController;
     private NotificationPanelViewController mNotificationPanelViewController;
     private View.AccessibilityDelegate mAccessibiltyDelegate;
     private NotificationsQuickSettingsContainer mNotificationContainerParent;
     private List<View.OnAttachStateChangeListener> mOnAttachStateChangeListeners;
-    private FalsingManagerFake mFalsingManager = new FalsingManagerFake();
-    private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
     private Handler mMainHandler;
+    private View.OnLayoutChangeListener mLayoutChangeListener;
+
+    private final FalsingManagerFake mFalsingManager = new FalsingManagerFake();
+    private final Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
+    private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
     private final PanelExpansionStateManager mPanelExpansionStateManager =
             new PanelExpansionStateManager();
-    private SystemClock mSystemClock;
+    private FragmentHostManager.FragmentListener mFragmentListener;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        mSystemClock = new FakeSystemClock();
+        SystemClock systemClock = new FakeSystemClock();
         mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager,
                 mInteractionJankMonitor);
 
-        mKeyguardStatusView = new KeyguardStatusView(mContext);
-        mKeyguardStatusView.setId(R.id.keyguard_status_view);
+        KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext);
+        keyguardStatusView.setId(R.id.keyguard_status_view);
         DejankUtils.setImmediate(true);
 
         when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
         when(mHeadsUpCallback.getContext()).thenReturn(mContext);
         when(mView.getResources()).thenReturn(mResources);
+        when(mView.getWidth()).thenReturn(PANEL_WIDTH);
         when(mResources.getConfiguration()).thenReturn(mConfiguration);
         mConfiguration.orientation = ORIENTATION_PORTRAIT;
         when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
@@ -431,7 +339,7 @@
         when(mView.findViewById(R.id.keyguard_status_view))
                 .thenReturn(mock(KeyguardStatusView.class));
         mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
-        mNotificationContainerParent.addView(mKeyguardStatusView);
+        mNotificationContainerParent.addView(keyguardStatusView);
         mNotificationContainerParent.onFinishInflate();
         when(mView.findViewById(R.id.notification_container_parent))
                 .thenReturn(mNotificationContainerParent);
@@ -447,7 +355,12 @@
         when(mKeyguardUserSwitcherComponent.getKeyguardUserSwitcherController())
                 .thenReturn(mKeyguardUserSwitcherController);
         when(mScreenOffAnimationController.shouldAnimateClockChange()).thenReturn(true);
-
+        when(mQs.getView()).thenReturn(mView);
+        when(mQSFragment.getView()).thenReturn(mView);
+        doAnswer(invocation -> {
+            mFragmentListener = invocation.getArgument(1);
+            return null;
+        }).when(mFragmentHostManager).addTagListener(eq(QS.TAG), any());
         doAnswer((Answer<Void>) invocation -> {
             mTouchHandler = invocation.getArgument(0);
             return null;
@@ -484,7 +397,7 @@
         when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
                 .thenReturn(mKeyguardStatusBarViewController);
         when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean()))
-                .thenReturn(mKeyguardStatusView);
+                .thenReturn(keyguardStatusView);
         when(mLayoutInflater.inflate(eq(R.layout.keyguard_user_switcher), any(), anyBoolean()))
                 .thenReturn(mUserSwitcherView);
         when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean()))
@@ -499,13 +412,18 @@
             ((Runnable) invocation.getArgument(0)).run();
             return null;
         }).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any());
+        doAnswer(invocation -> {
+            mLayoutChangeListener = invocation.getArgument(0);
+            return null;
+        }).when(mView).addOnLayoutChangeListener(any());
 
         when(mView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
         when(mView.getParent()).thenReturn(mViewParent);
         when(mQs.getHeader()).thenReturn(mQsHeader);
 
         mMainHandler = new Handler(Looper.getMainLooper());
-        mPanelEventsEmitter = new NotificationPanelViewController.PanelEventsEmitter();
+        NotificationPanelViewController.PanelEventsEmitter panelEventsEmitter =
+                new NotificationPanelViewController.PanelEventsEmitter();
 
         mNotificationPanelViewController = new NotificationPanelViewController(
                 mView,
@@ -560,11 +478,11 @@
                 () -> mKeyguardBottomAreaViewController,
                 mKeyguardUnlockAnimationController,
                 mNotificationListContainer,
-                mPanelEventsEmitter,
+                panelEventsEmitter,
                 mNotificationStackSizeCalculator,
                 mUnlockedScreenOffAnimationController,
                 mShadeTransitionController,
-                mSystemClock,
+                systemClock,
                 mock(CameraGestureHelper.class),
                 mKeyguardBottomAreaViewModel,
                 mKeyguardBottomAreaInteractor);
@@ -1481,6 +1399,96 @@
         assertThat(maxPanelHeight).isNotEqualTo(splitShadeFullTransitionDistance);
     }
 
+    @Test
+    public void onLayoutChange_fullWidth_updatesQSWithFullWithTrue() {
+        mNotificationPanelViewController.mQs = mQs;
+
+        setIsFullWidth(true);
+
+        verify(mQs).setIsNotificationPanelFullWidth(true);
+    }
+
+    @Test
+    public void onLayoutChange_notFullWidth_updatesQSWithFullWithFalse() {
+        mNotificationPanelViewController.mQs = mQs;
+
+        setIsFullWidth(false);
+
+        verify(mQs).setIsNotificationPanelFullWidth(false);
+    }
+
+    @Test
+    public void onLayoutChange_qsNotSet_doesNotCrash() {
+        mNotificationPanelViewController.mQs = null;
+
+        triggerLayoutChange();
+    }
+
+    @Test
+    public void onQsFragmentAttached_fullWidth_setsFullWidthTrueOnQS() {
+        setIsFullWidth(true);
+        givenViewAttached();
+        mFragmentListener.onFragmentViewCreated(QS.TAG, mQSFragment);
+
+        verify(mQSFragment).setIsNotificationPanelFullWidth(true);
+    }
+
+    @Test
+    public void onQsFragmentAttached_notFullWidth_setsFullWidthFalseOnQS() {
+        setIsFullWidth(false);
+        givenViewAttached();
+        mFragmentListener.onFragmentViewCreated(QS.TAG, mQSFragment);
+
+        verify(mQSFragment).setIsNotificationPanelFullWidth(false);
+    }
+
+    @Test
+    public void setQsExpansion_lockscreenShadeTransitionInProgress_usesLockscreenSquishiness() {
+        float squishinessFraction = 0.456f;
+        mNotificationPanelViewController.mQs = mQs;
+        when(mLockscreenShadeTransitionController.getQsSquishTransitionFraction())
+                .thenReturn(squishinessFraction);
+        when(mNotificationStackScrollLayoutController.getNotificationSquishinessFraction())
+                .thenReturn(0.987f);
+        // Call setTransitionToFullShadeAmount to get into the full shade transition in progress
+        // state.
+        mNotificationPanelViewController.setTransitionToFullShadeAmount(
+                /* pxAmount= */ 234,
+                /* animate= */ false,
+                /* delay= */ 0
+        );
+
+        mNotificationPanelViewController.setQsExpansion(/* height= */ 123);
+
+        // First for setTransitionToFullShadeAmount and then setQsExpansion
+        verify(mQs, times(2)).setQsExpansion(
+                /* expansion= */ anyFloat(),
+                /* panelExpansionFraction= */ anyFloat(),
+                /* proposedTranslation= */ anyFloat(),
+                eq(squishinessFraction)
+        );
+    }
+
+    @Test
+    public void setQsExpansion_lockscreenShadeTransitionNotInProgress_usesStandardSquishiness() {
+        float lsSquishinessFraction = 0.456f;
+        float nsslSquishinessFraction = 0.987f;
+        mNotificationPanelViewController.mQs = mQs;
+        when(mLockscreenShadeTransitionController.getQsSquishTransitionFraction())
+                .thenReturn(lsSquishinessFraction);
+        when(mNotificationStackScrollLayoutController.getNotificationSquishinessFraction())
+                .thenReturn(nsslSquishinessFraction);
+
+        mNotificationPanelViewController.setQsExpansion(/* height= */ 123);
+
+        verify(mQs).setQsExpansion(
+                /* expansion= */ anyFloat(),
+                /* panelExpansionFraction= */ anyFloat(),
+                /* proposedTranslation= */ anyFloat(),
+                eq(nsslSquishinessFraction)
+        );
+    }
+
     private static MotionEvent createMotionEvent(int x, int y, int action) {
         return MotionEvent.obtain(
                 /* downTime= */ 0, /* eventTime= */ 0, action, x, y, /* metaState= */ 0);
@@ -1504,12 +1512,6 @@
         }
     }
 
-    private void givenViewDetached() {
-        for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
-            listener.onViewDetachedFromWindow(mView);
-        }
-    }
-
     private ConstraintSet.Layout getConstraintSetLayout(@IdRes int id) {
         ConstraintSet constraintSet = new ConstraintSet();
         constraintSet.clone(mNotificationContainerParent);
@@ -1566,4 +1568,24 @@
         assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd).isEqualTo(
                 R.id.qs_edge_guideline);
     }
+
+    private void setIsFullWidth(boolean fullWidth) {
+        float nsslWidth = fullWidth ? PANEL_WIDTH : PANEL_WIDTH / 2f;
+        when(mNotificationStackScrollLayoutController.getWidth()).thenReturn(nsslWidth);
+        triggerLayoutChange();
+    }
+
+    private void triggerLayoutChange() {
+        mLayoutChangeListener.onLayoutChange(
+                mView,
+                /* left= */ 0,
+                /* top= */ 0,
+                /* right= */ 0,
+                /* bottom= */ 0,
+                /* oldLeft= */ 0,
+                /* oldTop= */ 0,
+                /* oldRight= */ 0,
+                /* oldBottom= */ 0
+        );
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
new file mode 100644
index 0000000..7041262
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
@@ -0,0 +1,255 @@
+/*
+ * 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.systemui.statusbar
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.qs.QS
+import com.android.systemui.statusbar.policy.FakeConfigurationController
+import com.google.common.truth.Expect
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class LockscreenShadeQsTransitionControllerTest : SysuiTestCase() {
+
+    private val configurationController = FakeConfigurationController()
+
+    @get:Rule val expect: Expect = Expect.create()
+
+    @Mock private lateinit var dumpManager: DumpManager
+    @Mock private lateinit var qS: QS
+
+    private lateinit var controller: LockscreenShadeQsTransitionController
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        setTransitionDistance(TRANSITION_DISTANCE)
+        setTransitionDelay(TRANSITION_DELAY)
+        setSquishTransitionDistance(SQUISH_TRANSITION_DISTANCE)
+        setSquishStartFraction(SQUISH_START_FRACTION)
+
+        controller =
+            LockscreenShadeQsTransitionController(
+                context,
+                configurationController,
+                dumpManager,
+                qsProvider = { qS }
+            )
+    }
+
+    @Test
+    fun qsTransitionFraction_byDefault_returns0() {
+        assertThat(controller.qsTransitionFraction).isZero()
+    }
+
+    @Test
+    fun qsTransitionFraction_noStartDelay_returnsBasedOnTransitionDistance() {
+        setTransitionDelay(0)
+        setTransitionDistance(100)
+
+        controller.dragDownAmount = 25f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0.25f)
+
+        controller.dragDownAmount = 50f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0.5f)
+
+        controller.dragDownAmount = 75f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0.75f)
+
+        controller.dragDownAmount = 100f
+        expect.that(controller.qsTransitionFraction).isEqualTo(1f)
+    }
+
+    @Test
+    fun qsTransitionFraction_noStartDelay_returnsValuesBetween0and1() {
+        setTransitionDelay(0)
+        setTransitionDistance(100)
+
+        controller.dragDownAmount = -500f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0f)
+
+        controller.dragDownAmount = 500f
+        expect.that(controller.qsTransitionFraction).isEqualTo(1f)
+    }
+
+    @Test
+    fun qsTransitionFraction_withStartDelay_returnsBasedOnTransitionDistanceAndDelay() {
+        setTransitionDelay(10)
+        setTransitionDistance(100)
+
+        controller.dragDownAmount = 0f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0f)
+
+        controller.dragDownAmount = 10f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0f)
+
+        controller.dragDownAmount = 25f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0.15f)
+
+        controller.dragDownAmount = 100f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0.9f)
+
+        controller.dragDownAmount = 110f
+        expect.that(controller.qsTransitionFraction).isEqualTo(1f)
+    }
+
+    @Test
+    fun qsTransitionFraction_withStartDelay_returnsValuesBetween0and1() {
+        setTransitionDelay(10)
+        setTransitionDistance(100)
+
+        controller.dragDownAmount = -500f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0f)
+
+        controller.dragDownAmount = 500f
+        expect.that(controller.qsTransitionFraction).isEqualTo(1f)
+    }
+
+    @Test
+    fun qsSquishTransitionFraction_byDefault_returnsValueSetFromResource() {
+        assertThat(controller.qsSquishTransitionFraction).isEqualTo(SQUISH_START_FRACTION)
+    }
+
+    @Test
+    fun qsSquishTransitionFraction_noStartDelay_startFraction0_returnsBasedOnTransitionDistance() {
+        setTransitionDelay(0)
+        setSquishStartFraction(0f)
+        setSquishTransitionDistance(1000)
+
+        controller.dragDownAmount = 250f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.25f)
+
+        controller.dragDownAmount = 500f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.5f)
+
+        controller.dragDownAmount = 750f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.75f)
+
+        controller.dragDownAmount = 1000f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(1f)
+    }
+
+    @Test
+    fun qsSquishTransitionFraction_startDelay_startFraction0_basedOnTransitionDistanceAndDelay() {
+        setTransitionDelay(100)
+        setSquishStartFraction(0f)
+        setSquishTransitionDistance(1000)
+
+        controller.dragDownAmount = 250f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.15f)
+
+        controller.dragDownAmount = 500f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.4f)
+
+        controller.dragDownAmount = 750f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.65f)
+
+        controller.dragDownAmount = 1000f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.9f)
+
+        controller.dragDownAmount = 1100f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(1f)
+    }
+
+    @Test
+    fun qsSquishTransitionFraction_noStartDelay_startFractionSet_returnsBasedOnStartAndDistance() {
+        setTransitionDelay(0)
+        setSquishStartFraction(0.5f)
+        setSquishTransitionDistance(1000)
+
+        controller.dragDownAmount = 0f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.5f)
+
+        controller.dragDownAmount = 500f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.75f)
+
+        controller.dragDownAmount = 1000f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(1f)
+    }
+
+    @Test
+    fun qsSquishTransitionFraction_startDelay_startFractionSet_basedOnStartAndDistanceAndDelay() {
+        setTransitionDelay(10)
+        setSquishStartFraction(0.5f)
+        setSquishTransitionDistance(100)
+
+        controller.dragDownAmount = 0f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.5f)
+
+        controller.dragDownAmount = 50f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.7f)
+
+        controller.dragDownAmount = 100f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.95f)
+
+        controller.dragDownAmount = 110f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(1f)
+    }
+
+    @Test
+    fun onDragDownAmountChanged_setsValuesOnQS() {
+        val rawDragAmount = 200f
+
+        controller.dragDownAmount = rawDragAmount
+
+        verify(qS)
+            .setTransitionToFullShadeProgress(
+                /* isTransitioningToFullShade= */ true,
+                /* transitionFraction= */ controller.qsTransitionFraction,
+                /* squishinessFraction= */ controller.qsSquishTransitionFraction
+            )
+    }
+
+    private fun setTransitionDistance(value: Int) {
+        overrideResource(R.dimen.lockscreen_shade_qs_transition_distance, value)
+        configurationController.notifyConfigurationChanged()
+    }
+
+    private fun setTransitionDelay(value: Int) {
+        overrideResource(R.dimen.lockscreen_shade_qs_transition_delay, value)
+        configurationController.notifyConfigurationChanged()
+    }
+
+    private fun setSquishTransitionDistance(value: Int) {
+        overrideResource(R.dimen.lockscreen_shade_qs_squish_transition_distance, value)
+        configurationController.notifyConfigurationChanged()
+    }
+
+    private fun setSquishStartFraction(value: Float) {
+        overrideResource(R.dimen.lockscreen_shade_qs_squish_start_fraction, value)
+        configurationController.notifyConfigurationChanged()
+    }
+
+    companion object {
+        private const val TRANSITION_DELAY = 123
+        private const val TRANSITION_DISTANCE = 321
+        private const val SQUISH_START_FRACTION = 0.123f
+        private const val SQUISH_TRANSITION_DISTANCE = 456
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index fe1cd97..8643e86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -1,9 +1,9 @@
 package com.android.systemui.statusbar
 
-import android.test.suitebuilder.annotation.SmallTest
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
 import com.android.systemui.ExpandHelper
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
@@ -78,6 +78,7 @@
     @Mock lateinit var qS: QS
     @Mock lateinit var singleShadeOverScroller: SingleShadeLockScreenOverScroller
     @Mock lateinit var splitShadeOverScroller: SplitShadeLockScreenOverScroller
+    @Mock lateinit var qsTransitionController: LockscreenShadeQsTransitionController
     @JvmField @Rule val mockito = MockitoJUnit.rule()
 
     private val configurationController = FakeConfigurationController()
@@ -120,7 +121,9 @@
                         context,
                         configurationController,
                         dumpManager)
-                })
+                },
+                qsTransitionControllerFactory = { qsTransitionController },
+            )
         whenever(nsslController.view).thenReturn(stackscroller)
         whenever(nsslController.expandHelperCallback).thenReturn(expandHelperCallback)
         transitionController.notificationPanelController = notificationPanelController
@@ -249,7 +252,7 @@
         verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
         verify(notificationPanelController, never()).setTransitionToFullShadeAmount(anyFloat(),
                 anyBoolean(), anyLong())
-        verify(qS, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
+        verify(qsTransitionController, never()).dragDownAmount = anyFloat()
     }
 
     @Test
@@ -260,7 +263,7 @@
         verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
         verify(notificationPanelController).setTransitionToFullShadeAmount(anyFloat(),
                 anyBoolean(), anyLong())
-        verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
+        verify(qsTransitionController).dragDownAmount = 10f
         verify(depthController).transitionToFullShadeProgress = anyFloat()
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 7cd275d..4d1a52c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -59,16 +59,19 @@
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.scrim.ScrimView;
-import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.FakeConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
 import com.android.systemui.util.wakelock.DelayedWakeLock;
 import com.android.systemui.utils.os.FakeHandler;
 
+import com.google.common.truth.Expect;
+
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -86,6 +89,11 @@
 @SmallTest
 public class ScrimControllerTest extends SysuiTestCase {
 
+    @Rule public Expect mExpect = Expect.create();
+
+    private final FakeConfigurationController mConfigurationController =
+            new FakeConfigurationController();
+
     private ScrimController mScrimController;
     private ScrimView mScrimBehind;
     private ScrimView mNotificationsScrim;
@@ -96,32 +104,19 @@
     private int mScrimVisibility;
     private boolean mAlwaysOnEnabled;
     private TestableLooper mLooper;
-    @Mock
-    private AlarmManager mAlarmManager;
-    @Mock
-    private DozeParameters mDozeParameters;
-    @Mock
-    LightBarController mLightBarController;
-    @Mock
-    DelayedWakeLock.Builder mDelayedWakeLockBuilder;
-    @Mock
-    private DelayedWakeLock mWakeLock;
-    @Mock
-    KeyguardStateController mKeyguardStateController;
-    @Mock
-    KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-    @Mock
-    private DockManager mDockManager;
-    @Mock
-    private ConfigurationController mConfigurationController;
-    @Mock
-    private ScreenOffAnimationController mScreenOffAnimationController;
-    @Mock
-    private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+    @Mock private AlarmManager mAlarmManager;
+    @Mock private DozeParameters mDozeParameters;
+    @Mock private LightBarController mLightBarController;
+    @Mock private DelayedWakeLock.Builder mDelayedWakeLockBuilder;
+    @Mock private DelayedWakeLock mWakeLock;
+    @Mock private KeyguardStateController mKeyguardStateController;
+    @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @Mock private DockManager mDockManager;
+    @Mock private ScreenOffAnimationController mScreenOffAnimationController;
+    @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     // TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
     //   event-dispatch-on-registration pattern caused some of these unit tests to fail.)
-    @Mock
-    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
 
     private static class AnimatorListener implements Animator.AnimatorListener {
         private int mNumStarts;
@@ -1450,6 +1445,41 @@
     }
 
     @Test
+    public void notificationAlpha_qsNotClipped_alphaMatchesNotificationExpansionProgress() {
+        mScrimController.setClipsQsScrim(false);
+        mScrimController.transitionTo(ScrimState.KEYGUARD);
+        // RawPanelExpansion and QsExpansion are usually used for the notification alpha
+        // calculation.
+        // Here we set them to non-zero values explicitly to make sure that in not clipped mode,
+        // they are not being used even when set.
+        mScrimController.setRawPanelExpansionFraction(0.5f);
+        mScrimController.setQsPosition(/* expansionFraction= */ 0.5f, /* qsPanelBottomY= */ 500);
+        finishAnimationsImmediately();
+
+        float progress = 0.5f;
+
+        float notificationExpansionProgress = 0f;
+        mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
+        mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
+
+        notificationExpansionProgress = 0.25f;
+        mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
+        mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
+
+        notificationExpansionProgress = 0.5f;
+        mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
+        mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
+
+        notificationExpansionProgress = 0.75f;
+        mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
+        mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
+
+        notificationExpansionProgress = 1f;
+        mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
+        mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
+    }
+
+    @Test
     public void setNotificationsOverScrollAmount_setsTranslationYOnNotificationsScrim() {
         int overScrollAmount = 10;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
index e1ddaad..e47acd8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui;
+package com.android.systemui.wallpapers;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
@@ -40,7 +40,8 @@
 import android.view.DisplayInfo;
 import android.view.SurfaceHolder;
 
-import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.wallpapers.gl.ImageWallpaperRenderer;
 
 import org.junit.Before;
 import org.junit.Ignore;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/EglHelperTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/EglHelperTest.java
index a3221b5..a42bade 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/EglHelperTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/ImageWallpaperRendererTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/ImageWallpaperRendererTest.java
index 510b907..89b2222 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/ImageWallpaperRendererTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index bd1ecb2..7ca6254 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -48,8 +48,7 @@
 import com.android.server.pm.PackageList;
 import com.android.server.pm.PackageSetting;
 import com.android.server.pm.dex.DynamicCodeLogger;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.pkg.AndroidPackageApi;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.SharedUserApi;
 import com.android.server.pm.pkg.component.ParsedMainComponent;
@@ -644,7 +643,7 @@
      * Returns the {@link SystemApi} variant of a package for use with mainline.
      */
     @Nullable
-    public abstract AndroidPackageApi getAndroidPackage(@NonNull String packageName);
+    public abstract AndroidPackage getAndroidPackage(@NonNull String packageName);
 
     @Nullable
     public abstract PackageStateInternal getPackageStateInternal(@NonNull String packageName);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 26899f1..6e52d21 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -407,8 +407,8 @@
 import com.android.server.pm.Computer;
 import com.android.server.pm.Installer;
 import com.android.server.pm.UserManagerInternal;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.SELinuxUtil;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 import com.android.server.pm.snapshot.PackageDataSnapshot;
@@ -16145,8 +16145,7 @@
     @Override
     public boolean startUserInBackgroundOnSecondaryDisplay(int userId, int displayId) {
         // Permission check done inside UserController.
-        return mUserController.startUserOnSecondaryDisplay(userId, displayId,
-                /* unlockListener= */ null);
+        return mUserController.startUserOnSecondaryDisplay(userId, displayId);
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index a36c298..86c9770 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -81,7 +81,7 @@
 import com.android.server.LocalServices;
 import com.android.server.RescueParty;
 import com.android.server.pm.UserManagerInternal;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index affb084..992d416 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -133,7 +133,7 @@
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityManagerService.ProcessChangeItem;
 import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.wm.ActivityServiceConnectionsHolder;
 import com.android.server.wm.WindowManagerService;
@@ -2200,16 +2200,25 @@
             Map<String, Pair<String, Long>> allowlistedAppDataInfoMap;
             boolean bindMountAppStorageDirs = false;
             boolean bindMountAppsData = mAppDataIsolationEnabled
-                    && (UserHandle.isApp(app.uid) || UserHandle.isIsolated(app.uid))
+                    && (UserHandle.isApp(app.uid) || UserHandle.isIsolated(app.uid)
+                        || app.isSdkSandbox)
                     && mPlatformCompat.isChangeEnabled(APP_DATA_DIRECTORY_ISOLATION, app.info);
 
             // Get all packages belongs to the same shared uid. sharedPackages is empty array
             // if it doesn't have shared uid.
             final PackageManagerInternal pmInt = mService.getPackageManagerInternal();
-            final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage(
-                    app.info.packageName, app.userId);
-            final String[] targetPackagesList = sharedPackages.length == 0
-                    ? new String[]{app.info.packageName} : sharedPackages;
+
+            // In the case of sdk sandbox, the pkgDataInfoMap of only the client app associated with
+            // the sandbox is required to handle app visibility restrictions for the sandbox.
+            final String[] targetPackagesList;
+            if (app.isSdkSandbox) {
+                targetPackagesList = new String[]{app.sdkSandboxClientAppPackage};
+            } else {
+                final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage(
+                        app.info.packageName, app.userId);
+                targetPackagesList = sharedPackages.length == 0
+                        ? new String[]{app.info.packageName} : sharedPackages;
+            }
 
             final boolean hasAppStorage = hasAppStorage(pmInt, app.info.packageName);
 
@@ -2235,7 +2244,7 @@
                 bindMountAppsData = false;
             }
 
-            if (!hasAppStorage) {
+            if (!hasAppStorage && !app.isSdkSandbox) {
                 bindMountAppsData = false;
                 pkgDataInfoMap = null;
                 allowlistedAppDataInfoMap = null;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 043da55..1954f76 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1375,8 +1375,9 @@
         }
         final int profilesToStartSize = profilesToStart.size();
         int i = 0;
-        // TODO(b/239982558): pass displayId
         for (; i < profilesToStartSize && i < (getMaxRunningUsers() - 1); ++i) {
+            // NOTE: this method is setting the profiles of the current user - which is always
+            // assigned to the default display - so there's no need to pass PARENT_DISPLAY
             startUser(profilesToStart.get(i).id, /* foreground= */ false);
         }
         if (i < profilesToStartSize) {
@@ -1419,8 +1420,10 @@
             return false;
         }
 
-        // TODO(b/239982558): pass proper displayId
-        return startUserNoChecks(userId, Display.DEFAULT_DISPLAY, /* foreground= */ false,
+        int displayId = mInjector.isUsersOnSecondaryDisplaysEnabled()
+                ? UserManagerInternal.PARENT_DISPLAY
+                : Display.DEFAULT_DISPLAY;
+        return startUserNoChecks(userId, displayId, /* foreground= */ false,
                 /* unlockListener= */ null);
     }
 
@@ -1472,8 +1475,7 @@
 
     // TODO(b/239982558): add javadoc (need to wait until the intents / SystemService callbacks are
     // defined
-    boolean startUserOnSecondaryDisplay(@UserIdInt int userId, int displayId,
-            @Nullable IProgressListener unlockListener) {
+    boolean startUserOnSecondaryDisplay(@UserIdInt int userId, int displayId) {
         checkCallingHasOneOfThosePermissions("startUserOnSecondaryDisplay",
                 MANAGE_USERS, CREATE_USERS);
 
@@ -1482,7 +1484,8 @@
                 "Cannot use DEFAULT_DISPLAY");
 
         try {
-            return startUserNoChecks(userId, displayId, /* foreground= */ false, unlockListener);
+            return startUserNoChecks(userId, displayId, /* foreground= */ false,
+                    /* unlockListener= */ null);
         } catch (RuntimeException e) {
             Slogf.w(TAG, "startUserOnSecondaryDisplay(%d, %d) failed: %s", userId, displayId, e);
             return false;
@@ -1514,8 +1517,6 @@
             Preconditions.checkArgument(!foreground, "Cannot start user %d in foreground AND "
                     + "on secondary display (%d)", userId, displayId);
         }
-        mInjector.getUserManagerInternal().assignUserToDisplay(userId, displayId);
-
         // TODO(b/239982558): log display id (or use a new event)
         EventLog.writeEvent(EventLogTags.UC_START_USER_INTERNAL, userId);
 
@@ -1571,6 +1572,8 @@
                 return false;
             }
 
+            mInjector.getUserManagerInternal().assignUserToDisplay(userId, displayId);
+
             // TODO(b/239982558): might need something similar for bg users on secondary display
             if (foreground && isUserSwitchUiEnabled()) {
                 t.traceBegin("startFreezingScreen");
@@ -3484,5 +3487,9 @@
                 }
             }, reason);
         }
+
+        boolean isUsersOnSecondaryDisplaysEnabled() {
+            return UserManager.isUsersOnSecondaryDisplaysEnabled();
+        }
     }
 }
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index 71a5511..4741849 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -35,18 +35,20 @@
 public final class UserState {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "UserState" : TAG_AM;
 
+    // user doesn't exist.
+    public static final int STATE_NONE = -1;
     // User is first coming up.
-    public final static int STATE_BOOTING = 0;
+    public static final int STATE_BOOTING = 0;
     // User is in the locked state.
-    public final static int STATE_RUNNING_LOCKED = 1;
+    public static final int STATE_RUNNING_LOCKED = 1;
     // User is in the unlocking state.
-    public final static int STATE_RUNNING_UNLOCKING = 2;
+    public static final int STATE_RUNNING_UNLOCKING = 2;
     // User is in the running state.
-    public final static int STATE_RUNNING_UNLOCKED = 3;
+    public static final int STATE_RUNNING_UNLOCKED = 3;
     // User is in the initial process of being stopped.
-    public final static int STATE_STOPPING = 4;
+    public static final int STATE_STOPPING = 4;
     // User is in the final phase of stopping, sending Intent.ACTION_SHUTDOWN.
-    public final static int STATE_SHUTDOWN = 5;
+    public static final int STATE_SHUTDOWN = 5;
 
     public final UserHandle mHandle;
     public final ArrayList<IStopUserCallback> mStopCallbacks = new ArrayList<>();
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 7bdcfdb..62ae9b8 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -177,7 +177,7 @@
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.SystemServiceManager;
 import com.android.server.pm.PackageList;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.component.ParsedAttribution;
 import com.android.server.policy.AppOpsPolicy;
 
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 9cb1f1d..431be88 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1198,7 +1198,7 @@
                 mContext.unbindService(mConnection);
                 cleanupVpnStateLocked();
             } else if (mVpnRunner != null) {
-                stopVpnRunnerAndNotifyAppLocked(mPackage);
+                stopVpnRunnerAndNotifyAppLocked();
             }
 
             try {
@@ -4061,7 +4061,7 @@
     }
 
     @GuardedBy("this")
-    private void stopVpnRunnerAndNotifyAppLocked(@NonNull String packageName) {
+    private void stopVpnRunnerAndNotifyAppLocked() {
         // Build intent first because the sessionKey will be reset after performing
         // VpnRunner.exit(). Also, cache mOwnerUID even if ownerUID will not be changed in
         // VpnRunner.exit() to prevent design being changed in the future.
@@ -4069,17 +4069,17 @@
         //  ConnectivityServiceTest.
         final int ownerUid = mOwnerUID;
         Intent intent = null;
-        if (SdkLevel.isAtLeastT() && isVpnApp(packageName)) {
+        if (SdkLevel.isAtLeastT() && isVpnApp(mPackage)) {
             intent = buildVpnManagerEventIntent(
                     VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER,
-                    -1 /* errorClass */, -1 /* errorCode*/, packageName,
+                    -1 /* errorClass */, -1 /* errorCode*/, mPackage,
                     getSessionKeyLocked(), makeVpnProfileStateLocked(),
                     null /* underlyingNetwork */, null /* nc */, null /* lp */);
         }
         // cleanupVpnStateLocked() is called from mVpnRunner.exit()
         mVpnRunner.exit();
-        if (intent != null && isVpnApp(packageName)) {
-            notifyVpnManagerVpnStopped(packageName, ownerUid, intent);
+        if (intent != null && isVpnApp(mPackage)) {
+            notifyVpnManagerVpnStopped(mPackage, ownerUid, intent);
         }
     }
 
@@ -4099,7 +4099,7 @@
         // To stop the VPN profile, the caller must be the current prepared package and must be
         // running an Ikev2VpnProfile.
         if (isCurrentIkev2VpnLocked(packageName)) {
-            stopVpnRunnerAndNotifyAppLocked(packageName);
+            stopVpnRunnerAndNotifyAppLocked();
         }
     }
 
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodDeviceConfigs.java b/services/core/java/com/android/server/inputmethod/InputMethodDeviceConfigs.java
new file mode 100644
index 0000000..9d5393f
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/InputMethodDeviceConfigs.java
@@ -0,0 +1,59 @@
+/*
+ * 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.server.inputmethod;
+
+import static android.provider.InputMethodManagerDeviceConfig.KEY_HIDE_IME_WHEN_NO_EDITOR_FOCUS;
+
+import android.app.ActivityThread;
+import android.provider.DeviceConfig;
+
+/**
+ * Class for the device-level configuration related to the input method manager
+ * platform features in {@link DeviceConfig}.
+ */
+public final class InputMethodDeviceConfigs {
+    private boolean mHideImeWhenNoEditorFocus;
+    private final DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener;
+
+    public InputMethodDeviceConfigs() {
+        mDeviceConfigChangedListener = properties -> {
+            if (!DeviceConfig.NAMESPACE_INPUT_METHOD_MANAGER.equals(properties.getNamespace())) {
+                return;
+            }
+            for (String name : properties.getKeyset()) {
+                if (KEY_HIDE_IME_WHEN_NO_EDITOR_FOCUS.equals(name)) {
+                    mHideImeWhenNoEditorFocus = properties.getBoolean(name,
+                            true /* defaultValue */);
+                }
+            }
+        };
+        mHideImeWhenNoEditorFocus = DeviceConfig.getBoolean(
+                DeviceConfig.NAMESPACE_INPUT_METHOD_MANAGER,
+                KEY_HIDE_IME_WHEN_NO_EDITOR_FOCUS, true);
+        DeviceConfig.addOnPropertiesChangedListener(
+                DeviceConfig.NAMESPACE_INPUT_METHOD_MANAGER,
+                ActivityThread.currentApplication().getMainExecutor(),
+                mDeviceConfigChangedListener);
+    }
+
+    /**
+     * Whether the IME should be hidden when the window gained focus without an editor focused.
+     */
+    public boolean shouldHideImeWhenNoEditorFocus() {
+        return mHideImeWhenNoEditorFocus;
+    }
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 7bd835c..729de41 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -303,6 +303,7 @@
     final PackageManagerInternal mPackageManagerInternal;
     final InputManagerInternal mInputManagerInternal;
     final ImePlatformCompatUtils mImePlatformCompatUtils;
+    final InputMethodDeviceConfigs mInputMethodDeviceConfigs;
     private final DisplayManagerInternal mDisplayManagerInternal;
     final boolean mHasFeature;
     private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
@@ -1732,6 +1733,7 @@
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
         mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
         mImePlatformCompatUtils = new ImePlatformCompatUtils();
+        mInputMethodDeviceConfigs = new InputMethodDeviceConfigs();
         mImeDisplayValidator = mWindowManagerInternal::getDisplayImePolicy;
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
         mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
@@ -3889,6 +3891,18 @@
                                 SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR);
                     }
                 }
+                if (!isTextEditor && mInputShown && startInputByWinGainedFocus
+                        && mInputMethodDeviceConfigs.shouldHideImeWhenNoEditorFocus()) {
+                    // Hide the soft-keyboard when the system do nothing for softInputModeState
+                    // of the window being gained focus without an editor. This behavior benefits
+                    // to resolve some unexpected IME visible cases while that window with following
+                    // configurations being switched from an IME shown window:
+                    // 1) SOFT_INPUT_STATE_UNCHANGED state without an editor
+                    // 2) SOFT_INPUT_STATE_VISIBLE state without an editor
+                    // 3) SOFT_INPUT_STATE_ALWAYS_VISIBLE state without an editor
+                    hideCurrentInputLocked(mCurFocusedWindow, 0, null,
+                            SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR);
+                }
                 res = startInputUncheckedLocked(cs, inputContext,
                         remoteAccessibilityInputConnection, editorInfo, startInputFlags,
                         startInputReason, unverifiedTargetSdkVersion,
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index d91bf8c..9466a6f5 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -287,7 +287,7 @@
                 name = com.android.internal.R.string.default_audio_route_name_dock_speakers;
             } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HDMI) != 0) {
                 type = TYPE_HDMI;
-                name = com.android.internal.R.string.default_audio_route_name_hdmi;
+                name = com.android.internal.R.string.default_audio_route_name_external_device;
             } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_USB) != 0) {
                 type = TYPE_USB_DEVICE;
                 name = com.android.internal.R.string.default_audio_route_name_usb;
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index f3cb7fb..b611b5d 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -31,7 +31,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.IOException;
 import java.lang.annotation.Retention;
diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
index c4b6485..c35d8631 100644
--- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java
+++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
@@ -28,7 +28,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.IOException;
 import java.util.List;
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 7159673..ba71438 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -84,7 +84,7 @@
 import com.android.server.SystemService;
 import com.android.server.pm.KnownPackages;
 import com.android.server.pm.UserManagerService;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import libcore.util.EmptyArray;
 
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index dade7aa..ae305ca 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -47,7 +47,7 @@
 
 import com.android.internal.content.om.OverlayConfig;
 import com.android.internal.util.CollectionUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/om/OverlayReferenceMapper.java b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
index 539fecf..fdceabe 100644
--- a/services/core/java/com/android/server/om/OverlayReferenceMapper.java
+++ b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
@@ -28,7 +28,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.CollectionUtils;
 import com.android.server.SystemConfig;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.Collection;
 import java.util.Collections;
diff --git a/services/core/java/com/android/server/om/PackageManagerHelper.java b/services/core/java/com/android/server/om/PackageManagerHelper.java
index 750f5c3..cbdabdd 100644
--- a/services/core/java/com/android/server/om/PackageManagerHelper.java
+++ b/services/core/java/com/android/server/om/PackageManagerHelper.java
@@ -19,19 +19,14 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.om.OverlayableInfo;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.os.RemoteException;
 import android.util.ArrayMap;
-import android.util.Slog;
 
 import com.android.server.pm.PackageManagerServiceUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 /**
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 01ddc48..71593e1 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -49,7 +49,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.modules.utils.build.UnboundedSdkLevel;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.component.ParsedApexSystemService;
 import com.android.server.utils.TimingsTraceAndSlog;
 
diff --git a/services/core/java/com/android/server/pm/ApexPackageInfo.java b/services/core/java/com/android/server/pm/ApexPackageInfo.java
index 73cb0ad..4dd9c49 100644
--- a/services/core/java/com/android/server/pm/ApexPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ApexPackageInfo.java
@@ -31,9 +31,9 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 
diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java
index c2f2b0a..a286160 100644
--- a/services/core/java/com/android/server/pm/ApkChecksums.java
+++ b/services/core/java/com/android/server/pm/ApkChecksums.java
@@ -64,7 +64,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.security.VerityUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index da8992a..0f5d8fd 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -45,8 +45,8 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.pm.dex.ArtManagerService;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.SELinuxUtil;
 
diff --git a/services/core/java/com/android/server/pm/AppsFilterBase.java b/services/core/java/com/android/server/pm/AppsFilterBase.java
index 5b3eff9..14140b5 100644
--- a/services/core/java/com/android/server/pm/AppsFilterBase.java
+++ b/services/core/java/com/android/server/pm/AppsFilterBase.java
@@ -40,7 +40,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.function.QuadFunction;
 import com.android.server.om.OverlayReferenceMapper;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.snapshot.PackageDataSnapshot;
 import com.android.server.utils.SnapshotCache;
diff --git a/services/core/java/com/android/server/pm/AppsFilterImpl.java b/services/core/java/com/android/server/pm/AppsFilterImpl.java
index 5e0b47a..79d72a3 100644
--- a/services/core/java/com/android/server/pm/AppsFilterImpl.java
+++ b/services/core/java/com/android/server/pm/AppsFilterImpl.java
@@ -51,8 +51,8 @@
 import com.android.server.FgThread;
 import com.android.server.compat.CompatChange;
 import com.android.server.om.OverlayReferenceMapper;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.component.ParsedInstrumentation;
 import com.android.server.pm.pkg.component.ParsedPermission;
diff --git a/services/core/java/com/android/server/pm/AppsFilterSnapshot.java b/services/core/java/com/android/server/pm/AppsFilterSnapshot.java
index de037f3..dd84e06 100644
--- a/services/core/java/com/android/server/pm/AppsFilterSnapshot.java
+++ b/services/core/java/com/android/server/pm/AppsFilterSnapshot.java
@@ -23,7 +23,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.util.function.QuadFunction;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.snapshot.PackageDataSnapshot;
 
diff --git a/services/core/java/com/android/server/pm/AppsFilterUtils.java b/services/core/java/com/android/server/pm/AppsFilterUtils.java
index 3a105c0..7daa0b9 100644
--- a/services/core/java/com/android/server/pm/AppsFilterUtils.java
+++ b/services/core/java/com/android/server/pm/AppsFilterUtils.java
@@ -23,7 +23,7 @@
 import android.content.IntentFilter;
 
 import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.component.ParsedComponent;
 import com.android.server.pm.pkg.component.ParsedIntentInfo;
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index ab99860..5916196 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -48,7 +48,7 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageState;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.SharedUserApi;
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index d442fb2..3211ca1 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -129,9 +129,9 @@
 import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.dex.PackageDexUsage;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.pm.pkg.PackageUserStateInternal;
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 7193587..9f6aa63 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -60,8 +60,8 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageUserState;
 import com.android.server.wm.ActivityTaskManagerInternal;
@@ -572,7 +572,7 @@
         if (deleteCodeAndResources && (outInfo != null)) {
             outInfo.mArgs = new InstallArgs(
                     ps.getPathString(), getAppDexInstructionSets(
-                            ps.getPrimaryCpuAbi(), ps.getSecondaryCpuAbi()), mPm);
+                            ps.getPrimaryCpuAbi(), ps.getSecondaryCpuAbi()));
             if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.mArgs);
         }
     }
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index d501386..2b8a196 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -58,8 +58,8 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.dex.DexoptOptions;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 import dalvik.system.DexFile;
diff --git a/services/core/java/com/android/server/pm/DomainVerificationConnection.java b/services/core/java/com/android/server/pm/DomainVerificationConnection.java
index 4134671..624d005 100644
--- a/services/core/java/com/android/server/pm/DomainVerificationConnection.java
+++ b/services/core/java/com/android/server/pm/DomainVerificationConnection.java
@@ -26,7 +26,7 @@
 import android.os.UserHandle;
 
 import com.android.server.DeviceIdleInternal;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.verify.domain.DomainVerificationService;
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV2;
diff --git a/services/core/java/com/android/server/pm/FeatureConfig.java b/services/core/java/com/android/server/pm/FeatureConfig.java
index 6e356de..1a57743 100644
--- a/services/core/java/com/android/server/pm/FeatureConfig.java
+++ b/services/core/java/com/android/server/pm/FeatureConfig.java
@@ -19,7 +19,7 @@
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 @VisibleForTesting(visibility = PRIVATE)
diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
index 52e3fd9..797d4c3 100644
--- a/services/core/java/com/android/server/pm/InitAppsHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -52,7 +52,7 @@
 import com.android.server.EventLogTags;
 import com.android.server.pm.parsing.PackageCacher;
 import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 import com.android.server.utils.WatchedArrayMap;
 
@@ -227,7 +227,7 @@
             }
         }
         final OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
-                consumer -> mPm.forEachPackage(mPm.snapshotComputer(),
+                consumer -> mPm.forEachPackageInternal(mPm.snapshotComputer(),
                         pkg -> consumer.accept(pkg, pkg.isSystem(),
                                 apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
 
diff --git a/services/core/java/com/android/server/pm/InstallArgs.java b/services/core/java/com/android/server/pm/InstallArgs.java
index 616bb8f..65c2378 100644
--- a/services/core/java/com/android/server/pm/InstallArgs.java
+++ b/services/core/java/com/android/server/pm/InstallArgs.java
@@ -65,9 +65,6 @@
     // if we move dex files under the common app path.
     @Nullable String[] mInstructionSets;
 
-    @NonNull final PackageManagerService mPm;
-    @NonNull final RemovePackageHelper mRemovePackageHelper;
-
     InstallArgs(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer,
             int installFlags, InstallSource installSource, String volumeUuid,
             UserHandle user, String[] instructionSets,
@@ -76,7 +73,7 @@
             int autoRevokePermissionsMode,
             String traceMethod, int traceCookie, SigningDetails signingDetails,
             int installReason, int installScenario, boolean forceQueryableOverride,
-            int dataLoaderType, int packageSource, PackageManagerService pm) {
+            int dataLoaderType, int packageSource) {
         mOriginInfo = originInfo;
         mMoveInfo = moveInfo;
         mInstallFlags = installFlags;
@@ -97,8 +94,6 @@
         mForceQueryableOverride = forceQueryableOverride;
         mDataLoaderType = dataLoaderType;
         mPackageSource = packageSource;
-        mPm = pm;
-        mRemovePackageHelper = new RemovePackageHelper(mPm);
     }
 
     /** New install */
@@ -110,19 +105,19 @@
                 params.mAutoRevokePermissionsMode,
                 params.mTraceMethod, params.mTraceCookie, params.mSigningDetails,
                 params.mInstallReason, params.mInstallScenario, params.mForceQueryableOverride,
-                params.mDataLoaderType, params.mPackageSource, params.mPm);
+                params.mDataLoaderType, params.mPackageSource);
     }
 
     /**
      * Create args that describe an existing installed package. Typically used
      * when cleaning up old installs, or used as a move source.
      */
-    InstallArgs(String codePath, String[] instructionSets, PackageManagerService pm) {
+    InstallArgs(String codePath, String[] instructionSets) {
         this(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY,
                 null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0,
                 SigningDetails.UNKNOWN, PackageManager.INSTALL_REASON_UNKNOWN,
                 PackageManager.INSTALL_SCENARIO_DEFAULT, false, DataLoaderType.NONE,
-                PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED, pm);
+                PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED);
         mCodeFile = (codePath != null) ? new File(codePath) : null;
     }
 
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 8024d41..d201710 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -162,11 +162,11 @@
 import com.android.server.pm.dex.ViewCompiler;
 import com.android.server.pm.parsing.PackageCacher;
 import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.pm.permission.Permission;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.component.ComponentMutateUtils;
 import com.android.server.pm.pkg.component.ParsedInstrumentation;
@@ -1937,7 +1937,7 @@
                                         AndroidPackageUtils.getPrimaryCpuAbi(oldPackage,
                                                 deletedPkgSetting),
                                         AndroidPackageUtils.getSecondaryCpuAbi(oldPackage,
-                                                deletedPkgSetting)), mPm);
+                                                deletedPkgSetting)));
                     } else {
                         res.mRemovedInfo.mArgs = null;
                     }
@@ -3311,7 +3311,8 @@
             if (disabledPs == null) {
                 logCriticalInfo(Log.WARN, "System package " + packageName
                         + " no longer exists; its data will be wiped");
-                mRemovePackageHelper.removePackageData(ps, userIds, null, 0, false);
+                mInjector.getHandler().post(
+                        () -> mRemovePackageHelper.removePackageData(ps, userIds, null, 0, false));
             } else {
                 // we still have a disabled system package, but, it still might have
                 // been removed. check the code path still exists and check there's
@@ -3937,7 +3938,7 @@
 
             final InstallArgs args = new InstallArgs(
                     pkgSetting.getPathString(), getAppDexInstructionSets(
-                    pkgSetting.getPrimaryCpuAbi(), pkgSetting.getSecondaryCpuAbi()), mPm);
+                    pkgSetting.getPrimaryCpuAbi(), pkgSetting.getSecondaryCpuAbi()));
             mRemovePackageHelper.cleanUpResources(args);
             synchronized (mPm.mLock) {
                 mPm.mSettings.enableSystemPackageLPw(pkgSetting.getPackageName());
@@ -4022,8 +4023,7 @@
                                 + parsedPackage.getPath());
                 InstallArgs args = new InstallArgs(
                         pkgSetting.getPathString(), getAppDexInstructionSets(
-                        pkgSetting.getPrimaryCpuAbi(), pkgSetting.getSecondaryCpuAbi()),
-                        mPm);
+                        pkgSetting.getPrimaryCpuAbi(), pkgSetting.getSecondaryCpuAbi()));
                 mRemovePackageHelper.cleanUpResources(args);
             } else {
                 // The application on /system is older than the application on /data. Hide
diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java
index 0630ccd..a7f1727 100644
--- a/services/core/java/com/android/server/pm/InstallingSession.java
+++ b/services/core/java/com/android/server/pm/InstallingSession.java
@@ -51,7 +51,7 @@
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.util.Preconditions;
 import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import libcore.io.IoUtils;
 
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 39a2839..71bd2d7 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -56,9 +56,9 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.pm.pkg.PackageUserStateInternal;
diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java
index 2d42107..f1cfc5b 100644
--- a/services/core/java/com/android/server/pm/InstructionSets.java
+++ b/services/core/java/com/android/server/pm/InstructionSets.java
@@ -21,9 +21,6 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-
 import dalvik.system.VMRuntime;
 
 import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 5c29833..7774b6a 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -30,7 +30,7 @@
 import android.util.TypedXmlPullParser;
 import android.util.TypedXmlSerializer;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.SharedUserApi;
 import com.android.server.utils.WatchedArrayMap;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 59bd427..c38b822 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -96,7 +96,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
 import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/pm/MovePackageHelper.java b/services/core/java/com/android/server/pm/MovePackageHelper.java
index df02223..b27373e 100644
--- a/services/core/java/com/android/server/pm/MovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/MovePackageHelper.java
@@ -55,8 +55,8 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.FrameworkStatsLog;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUtils;
 
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index e4dcf1a..5507b44 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -38,8 +38,8 @@
 import com.android.server.LocalServices;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.dex.DexoptOptions;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 import java.io.File;
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
index 1dbab90..9bea599 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelper.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -22,9 +22,9 @@
 import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 import java.io.File;
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index 73d81ba..75f5f93 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -40,8 +40,8 @@
 
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 import dalvik.system.VMRuntime;
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 4b6543b..3fb4066 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -77,8 +77,8 @@
 import com.android.server.pm.dex.DexoptOptions;
 import com.android.server.pm.dex.DexoptUtils;
 import com.android.server.pm.dex.PackageDexUsage;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 import dalvik.system.DexFile;
diff --git a/services/core/java/com/android/server/pm/PackageInstalledInfo.java b/services/core/java/com/android/server/pm/PackageInstalledInfo.java
index 1c25dbb..247abf3 100644
--- a/services/core/java/com/android/server/pm/PackageInstalledInfo.java
+++ b/services/core/java/com/android/server/pm/PackageInstalledInfo.java
@@ -22,7 +22,7 @@
 import android.util.ExceptionUtils;
 import android.util.Slog;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.ArrayList;
 
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index df02fe1..e9f26e9 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -152,7 +152,7 @@
 import com.android.server.LocalServices;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.dex.DexManager;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
index 330e3313..34d6d29 100644
--- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -49,9 +49,8 @@
 
 import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.dex.DynamicCodeLogger;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
-import com.android.server.pm.pkg.AndroidPackageApi;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.pm.pkg.SharedUserApi;
@@ -155,7 +154,7 @@
     @Nullable
     @Override
     @Deprecated
-    public final AndroidPackageApi getAndroidPackage(@NonNull String packageName) {
+    public final AndroidPackage getAndroidPackage(@NonNull String packageName) {
         return snapshot().getPackage(packageName);
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 752ebf3..259202f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -203,13 +203,14 @@
 import com.android.server.pm.dex.ViewCompiler;
 import com.android.server.pm.parsing.PackageInfoUtils;
 import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.pm.permission.LegacyPermissionManagerInternal;
 import com.android.server.pm.permission.LegacyPermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageUserState;
 import com.android.server.pm.pkg.PackageUserStateInternal;
@@ -6716,6 +6717,19 @@
         }
     }
 
+    void forEachPackageInternal(@NonNull Computer snapshot,
+            @NonNull Consumer<AndroidPackageInternal> consumer) {
+        final ArrayMap<String, ? extends PackageStateInternal> packageStates =
+                snapshot.getPackageStates();
+        int size = packageStates.size();
+        for (int index = 0; index < size; index++) {
+            PackageStateInternal packageState = packageStates.valueAt(index);
+            if (packageState.getPkg() != null) {
+                consumer.accept(packageState.getPkg());
+            }
+        }
+    }
+
     private void forEachPackageState(
             @NonNull ArrayMap<String, ? extends PackageStateInternal> packageStates,
             @NonNull Consumer<PackageStateInternal> consumer) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index ec1b29e..4391fdd 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -34,8 +34,8 @@
 import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.dex.ViewCompiler;
 import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.LegacyPermissionManagerInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.File;
 import java.util.List;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index f466655..77334e5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -93,7 +93,7 @@
 import com.android.server.Watchdog;
 import com.android.server.compat.PlatformCompat;
 import com.android.server.pm.dex.PackageDexUsage;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.component.ParsedMainComponent;
 import com.android.server.pm.resolution.ComponentResolverApi;
diff --git a/services/core/java/com/android/server/pm/PackageProperty.java b/services/core/java/com/android/server/pm/PackageProperty.java
index 2055537..241f143 100644
--- a/services/core/java/com/android/server/pm/PackageProperty.java
+++ b/services/core/java/com/android/server/pm/PackageProperty.java
@@ -27,12 +27,12 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.Property;
 import android.content.pm.PackageManager.PropertyLocation;
-import com.android.server.pm.pkg.component.ParsedComponent;
 import android.os.Binder;
 import android.os.UserHandle;
 import android.util.ArrayMap;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.component.ParsedComponent;
 
 import java.util.ArrayList;
 import java.util.Iterator;
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index f84db1f..4764a5c 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -41,10 +41,11 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.DataClass;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.pm.permission.LegacyPermissionDataProvider;
 import com.android.server.pm.permission.LegacyPermissionState;
-import com.android.server.pm.pkg.AndroidPackageApi;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageState;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUnserialized;
@@ -126,7 +127,7 @@
      * @see PackageState#getAndroidPackage()
      */
     @Nullable
-    private AndroidPackage pkg;
+    private AndroidPackageInternal pkg;
 
     /** @see AndroidPackage#getPath() */
     @NonNull
@@ -418,8 +419,9 @@
         return hasChanges;
     }
 
+    // TODO: Remove, only commit package when it's actually finalized
     public PackageSetting setPkg(AndroidPackage pkg) {
-        this.pkg = pkg;
+        this.pkg = (AndroidPackageInternal) pkg;
         onChanged();
         return this;
     }
@@ -1165,7 +1167,7 @@
 
     @Nullable
     @Override
-    public AndroidPackageApi getAndroidPackage() {
+    public AndroidPackage getAndroidPackage() {
         return getPkg();
     }
 
@@ -1366,7 +1368,7 @@
      * @see PackageState#getAndroidPackage()
      */
     @DataClass.Generated.Member
-    public @Nullable AndroidPackage getPkg() {
+    public @Nullable AndroidPackageInternal getPkg() {
         return pkg;
     }
 
@@ -1473,10 +1475,10 @@
     }
 
     @DataClass.Generated(
-            time = 1644270960923L,
+            time = 1659546705292L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/services/core/java/com/android/server/pm/PackageSetting.java",
-            inputSignatures = "private  int mSharedUserAppId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate  int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackage pkg\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate  float mLoadingProgress\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate  long mLastModifiedTime\nprivate  long lastUpdateTime\nprivate  long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate  boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate  int categoryOverride\nprivate  boolean updateAvailable\nprivate  boolean forceQueryableOverride\nprivate final @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate  com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic  com.android.server.pm.PackageSetting snapshot()\npublic  void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic  com.android.server.pm.PackageSetting setAppId(int)\npublic  com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic  com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic  com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic  com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic  com.android.server.pm.PackageSetting setInstallerPackageName(java.lang.String)\npublic  com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n  com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic  com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic  com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic  com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic  com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic  com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic  boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPkg(com.android.server.pm.parsing.pkg.AndroidPackage)\npublic  com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic  com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic  com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic  void setSharedUserAppId(int)\npublic @java.lang.Override int getSharedUserAppId()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override java.lang.String toString()\nprotected  void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  void updateFrom(com.android.server.pm.PackageSetting)\n  com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic  com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic  boolean isPrivileged()\npublic  boolean isOem()\npublic  boolean isVendor()\npublic  boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic  boolean isSystemExt()\npublic  boolean isOdm()\npublic  boolean isSystem()\npublic  android.content.pm.SigningDetails getSigningDetails()\npublic  com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic  void copyPackageSetting(com.android.server.pm.PackageSetting)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic  com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n  void setEnabled(int,int,java.lang.String)\n  int getEnabled(int)\n  void setInstalled(boolean,int)\n  boolean getInstalled(int)\n  int getInstallReason(int)\n  void setInstallReason(int,int)\n  int getUninstallReason(int)\n  void setUninstallReason(int,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n  boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n  boolean isAnyInstalled(int[])\n  int[] queryInstalledUsers(int[],boolean)\n  long getCeDataInode(int)\n  void setCeDataInode(long,int)\n  boolean getStopped(int)\n  void setStopped(boolean,int)\n  boolean getNotLaunched(int)\n  void setNotLaunched(boolean,int)\n  boolean getHidden(int)\n  void setHidden(boolean,int)\n  int getDistractionFlags(int)\n  void setDistractionFlags(int,int)\npublic  boolean getInstantApp(int)\n  void setInstantApp(boolean,int)\n  boolean getVirtualPreload(int)\n  void setVirtualPreload(boolean,int)\n  void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long)\n  void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n  android.util.ArraySet<java.lang.String> getEnabledComponents(int)\n  android.util.ArraySet<java.lang.String> getDisabledComponents(int)\n  void setEnabledComponents(android.util.ArraySet<java.lang.String>,int)\n  void setDisabledComponents(android.util.ArraySet<java.lang.String>,int)\n  void setEnabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n  void setDisabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n  com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n  void addDisabledComponent(java.lang.String,int)\n  void addEnabledComponent(java.lang.String,int)\n  boolean enableComponentLPw(java.lang.String,int)\n  boolean disableComponentLPw(java.lang.String,int)\n  boolean restoreComponentLPw(java.lang.String,int)\n  int getCurrentEnabledStateLPr(java.lang.String,int)\n  void removeUser(int)\npublic  int[] getNotInstalledUserIds()\n  void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected  void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n  com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic  void resetOverrideComponentLabelIcon(int)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic  boolean isLoading()\npublic  com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackageApi getAndroidPackage()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<android.content.pm.SharedLibraryInfo> getUsesLibraryInfos()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic  com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic  com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic  com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic  com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic  com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
+            inputSignatures = "private  int mSharedUserAppId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate  int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackageInternal pkg\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate  float mLoadingProgress\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate  long mLastModifiedTime\nprivate  long lastUpdateTime\nprivate  long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate  boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate  int categoryOverride\nprivate  boolean updateAvailable\nprivate  boolean forceQueryableOverride\nprivate final @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate  com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic  com.android.server.pm.PackageSetting snapshot()\npublic  void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic  com.android.server.pm.PackageSetting setAppId(int)\npublic  com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic  com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic  com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic  com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic  com.android.server.pm.PackageSetting setInstallerPackageName(java.lang.String)\npublic  com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n  com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic  com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic  com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic  com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic  com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic  com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic  boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPkg(com.android.server.pm.parsing.pkg.AndroidPackageInternal)\npublic  com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic  com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic  com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic  void setSharedUserAppId(int)\npublic @java.lang.Override int getSharedUserAppId()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override java.lang.String toString()\nprotected  void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  void updateFrom(com.android.server.pm.PackageSetting)\n  com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic  com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic  boolean isPrivileged()\npublic  boolean isOem()\npublic  boolean isVendor()\npublic  boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic  boolean isSystemExt()\npublic  boolean isOdm()\npublic  boolean isSystem()\npublic  android.content.pm.SigningDetails getSigningDetails()\npublic  com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic  void copyPackageSetting(com.android.server.pm.PackageSetting,boolean)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic  com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n  void setEnabled(int,int,java.lang.String)\n  int getEnabled(int)\n  void setInstalled(boolean,int)\n  boolean getInstalled(int)\n  int getInstallReason(int)\n  void setInstallReason(int,int)\n  int getUninstallReason(int)\n  void setUninstallReason(int,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n  boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n  boolean isAnyInstalled(int[])\n  int[] queryInstalledUsers(int[],boolean)\n  long getCeDataInode(int)\n  void setCeDataInode(long,int)\n  boolean getStopped(int)\n  void setStopped(boolean,int)\n  boolean getNotLaunched(int)\n  void setNotLaunched(boolean,int)\n  boolean getHidden(int)\n  void setHidden(boolean,int)\n  int getDistractionFlags(int)\n  void setDistractionFlags(int,int)\npublic  boolean getInstantApp(int)\n  void setInstantApp(boolean,int)\n  boolean getVirtualPreload(int)\n  void setVirtualPreload(boolean,int)\n  void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long)\n  void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n  com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponents(int)\n  com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponents(int)\n  void setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setEnabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setDisabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n  void addDisabledComponent(java.lang.String,int)\n  void addEnabledComponent(java.lang.String,int)\n  boolean enableComponentLPw(java.lang.String,int)\n  boolean disableComponentLPw(java.lang.String,int)\n  boolean restoreComponentLPw(java.lang.String,int)\n  int getCurrentEnabledStateLPr(java.lang.String,int)\n  void removeUser(int)\npublic  int[] getNotInstalledUserIds()\n  void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected  void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n  com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic  void resetOverrideComponentLabelIcon(int)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic  boolean isLoading()\npublic  com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackage getAndroidPackage()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<android.content.pm.SharedLibraryInfo> getUsesLibraryInfos()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isApkInUpdatedApex()\npublic  com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic  com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic  com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic  com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic  com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/PrepareResult.java b/services/core/java/com/android/server/pm/PrepareResult.java
index 4e08e16..e074f44a 100644
--- a/services/core/java/com/android/server/pm/PrepareResult.java
+++ b/services/core/java/com/android/server/pm/PrepareResult.java
@@ -18,8 +18,8 @@
 
 import android.annotation.Nullable;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 /**
  * The set of data needed to successfully install the prepared package. This includes data that
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index d6a133e..0f7c652 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -30,8 +30,8 @@
 import android.util.ArrayMap;
 import android.util.Log;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 import com.android.server.utils.WatchedLongSparseArray;
 
diff --git a/services/core/java/com/android/server/pm/ReconcileRequest.java b/services/core/java/com/android/server/pm/ReconcileRequest.java
index 9e4e986..84b292f 100644
--- a/services/core/java/com/android/server/pm/ReconcileRequest.java
+++ b/services/core/java/com/android/server/pm/ReconcileRequest.java
@@ -16,7 +16,7 @@
 
 package com.android.server.pm;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.Collections;
 import java.util.Map;
diff --git a/services/core/java/com/android/server/pm/ReconciledPackage.java b/services/core/java/com/android/server/pm/ReconciledPackage.java
index 1bfe357..3bb5a1b 100644
--- a/services/core/java/com/android/server/pm/ReconciledPackage.java
+++ b/services/core/java/com/android/server/pm/ReconciledPackage.java
@@ -22,7 +22,7 @@
 import android.content.pm.SigningDetails;
 import android.util.ArrayMap;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index f083b67..a025965 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -46,9 +46,9 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.pm.parsing.PackageCacher;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.component.ParsedInstrumentation;
 
diff --git a/services/core/java/com/android/server/pm/ResolveIntentHelper.java b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
index 24ed621..c2fd637 100644
--- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java
+++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
@@ -53,7 +53,7 @@
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.resolution.ComponentResolverApi;
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index c0e191f..f7e04d4 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -27,8 +27,8 @@
 import android.util.Xml;
 
 import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.SharedUserApi;
 
 import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 86affdd..9bd8e12 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -76,9 +76,9 @@
 import com.android.server.SystemConfig;
 import com.android.server.pm.parsing.PackageInfoUtils;
 import com.android.server.pm.parsing.library.PackageBackwardCompatibility;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.pm.pkg.component.ComponentMutateUtils;
 import com.android.server.pm.pkg.component.ParsedActivity;
diff --git a/services/core/java/com/android/server/pm/ScanRequest.java b/services/core/java/com/android/server/pm/ScanRequest.java
index 98d11bd..e66a72f 100644
--- a/services/core/java/com/android/server/pm/ScanRequest.java
+++ b/services/core/java/com/android/server/pm/ScanRequest.java
@@ -21,8 +21,8 @@
 import android.os.UserHandle;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 
 /** A package to be scanned */
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 10e9b54..9037f04 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -102,12 +102,12 @@
 import com.android.server.backup.PreferredActivityBackupHelper;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.permission.LegacyPermissionDataProvider;
 import com.android.server.pm.permission.LegacyPermissionSettings;
 import com.android.server.pm.permission.LegacyPermissionState;
 import com.android.server.pm.permission.LegacyPermissionState.PermissionState;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageUserState;
 import com.android.server.pm.pkg.PackageUserStateInternal;
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
index 7432b84..5905741 100644
--- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
+++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
@@ -47,9 +47,9 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.server.SystemConfig;
 import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.utils.Snappable;
 import com.android.server.utils.SnapshotCache;
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 58be878..fb2ba32 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -26,8 +26,8 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.LegacyPermissionState;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.SharedUserApi;
 import com.android.server.pm.pkg.component.ComponentMutateUtils;
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 43dde5c..1da442b 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -53,8 +53,8 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.rollback.RollbackManagerInternal;
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index 41c6c0f..477e260 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -48,7 +48,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.policy.AttributeCache;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index 6847b70..df7e375 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -42,7 +42,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageUserStateInternal;
 import com.android.server.pm.pkg.SuspendParams;
@@ -157,9 +157,11 @@
                 }
             }
 
-            // If size one, the package will be unsuspended from this call
-            boolean packageUnsuspended =
-                    !suspended && CollectionUtils.size(suspendParamsMap) <= 1;
+            // If only the callingPackage is suspending this package,
+            // it will be unsuspended when this change is committed
+            boolean packageUnsuspended = !suspended
+                    && CollectionUtils.size(suspendParamsMap) == 1
+                    && suspendParamsMap.containsKey(callingPackage);
             if (suspended || packageUnsuspended) {
                 changedPackagesList.add(packageName);
                 changedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index b9a1195..4f5fd02 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -46,6 +46,15 @@
     public @interface OwnerType {
     }
 
+    // TODO(b/245963156): move to Display.java (and @hide) if we decide to support profiles on MUMD
+    /**
+     * Used only when starting a profile (on systems that
+     * {@link android.os.UserManager#isUsersOnSecondaryDisplaysSupported() support users running on
+     * secondary displays}), to indicate the profile should be started in the same display as its
+     * parent user.
+     */
+    public static final int PARENT_DISPLAY = -2;
+
     public interface UserRestrictionsListener {
         /**
          * Called when a user restriction changes.
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 6749ceb..07ec80b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1862,22 +1862,48 @@
     }
 
     // TODO(b/239982558): try to merge with isUserVisibleUnchecked() (once both are unit tested)
+    /**
+     * See {@link UserManagerInternal#isUserVisible(int, int)}.
+     */
     boolean isUserVisibleOnDisplay(@UserIdInt int userId, int displayId) {
-        // TODO(b/244644281): temporary workaround to let WM use this API without breaking current
-        // behavior (otherwise current user / profiles wouldn't be able to launch activities on
-        // other non-passenger displays, like cluster, display, or virtual displays)
-        if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
-            return true;
+        if (displayId == Display.INVALID_DISPLAY) {
+            return false;
         }
-
-        if (displayId == Display.DEFAULT_DISPLAY) {
+        if (!mUsersOnSecondaryDisplaysEnabled) {
             return isCurrentUserOrRunningProfileOfCurrentUser(userId);
         }
 
-        // Device doesn't support multiple users on multiple displays, so only users checked above
-        // can be visible
-        if (!mUsersOnSecondaryDisplaysEnabled) {
-            return false;
+        // TODO(b/244644281): temporary workaround to let WM use this API without breaking current
+        // behavior - return true for current user / profile for any display (other than those
+        // explicitly assigned to another users), otherwise they wouldn't be able to launch
+        // activities on other non-passenger displays, like cluster, display, or virtual displays).
+        // In the long-term, it should rely just on mUsersOnSecondaryDisplays, which
+        // would be updated by DisplayManagerService when displays are created / initialized.
+        if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
+            synchronized (mUsersOnSecondaryDisplays) {
+                boolean assignedToUser = false;
+                boolean assignedToAnotherUser = false;
+                for (int i = 0; i < mUsersOnSecondaryDisplays.size(); i++) {
+                    if (mUsersOnSecondaryDisplays.valueAt(i) == displayId) {
+                        if (mUsersOnSecondaryDisplays.keyAt(i) == userId) {
+                            assignedToUser = true;
+                            break;
+                        } else {
+                            assignedToAnotherUser = true;
+                            // Cannot break because it could be assigned to a profile of the user
+                            // (and we better not assume that the iteration will check for the
+                            // parent user before its profiles)
+                        }
+                    }
+                }
+                if (DBG_MUMD) {
+                    Slogf.d(LOG_TAG, "isUserVisibleOnDisplay(%d, %d): assignedToUser=%b, "
+                            + "assignedToAnotherUser=%b, mUsersOnSecondaryDisplays=%s",
+                            userId, displayId, assignedToUser, assignedToAnotherUser,
+                            mUsersOnSecondaryDisplays);
+                }
+                return assignedToUser || !assignedToAnotherUser;
+            }
         }
 
         synchronized (mUsersOnSecondaryDisplays) {
@@ -6578,9 +6604,14 @@
 
         @Override
         public boolean isUserRunning(@UserIdInt int userId) {
+            int state;
             synchronized (mUserStates) {
-                return mUserStates.get(userId, -1) >= 0;
+                state =  mUserStates.get(userId, UserState.STATE_NONE);
             }
+
+            return state != UserState.STATE_NONE
+                    && state != UserState.STATE_STOPPING
+                    && state != UserState.STATE_SHUTDOWN;
         }
 
         @Override
@@ -6794,53 +6825,44 @@
 
             int currentUserId = getCurrentUserId();
             Preconditions.checkArgument(userId != currentUserId,
-                    "Cannot assign current user to other displays");
-
-            boolean isProfile = isProfileUnchecked(userId);
-
-            Preconditions.checkArgument(userId != currentUserId,
-                    "Cannot assign current user to other displays");
-
-            Preconditions.checkArgument(
-                    !isProfile || getProfileParentIdUnchecked(userId) != currentUserId,
-                    "Cannot assign profile user %d to display %d when its parent is the current "
-                    + "user (%d)", userId, displayId, currentUserId);
+                    "Cannot assign current user (%d) to other displays", currentUserId);
 
             synchronized (mUsersOnSecondaryDisplays) {
-                if (DBG_MUMD) {
-                    Slogf.d(LOG_TAG, "Adding %d->%d to mUsersOnSecondaryDisplays",
-                            userId, displayId);
-                }
-
-                if (isProfile) {
+                if (isProfileUnchecked(userId)) {
                     // Profile can only start in the same display as parent
+                    Preconditions.checkArgument(displayId == UserManagerInternal.PARENT_DISPLAY,
+                            "Profile user can only be started in the same display as parent");
                     int parentUserId = getProfileParentId(userId);
                     int parentDisplayId = mUsersOnSecondaryDisplays.get(parentUserId);
-                    if (displayId != parentDisplayId) {
-                        throw new IllegalStateException("Cannot assign profile " + userId + " to "
-                                + "display " + displayId + " as its parent (user " + parentUserId
-                                + ") is assigned to display " + parentDisplayId);
+                    if (DBG_MUMD) {
+                        Slogf.d(LOG_TAG, "Adding profile user %d -> display %d", userId,
+                                parentDisplayId);
                     }
-                } else {
-                    // Check if display is available
-                    for (int i = 0; i < mUsersOnSecondaryDisplays.size(); i++) {
-                        // Make sure display is not used by other users...
-                        // TODO(b/240736142); currently, if a user was started in a display, it
-                        // would need to be stopped first, so "switching" a user on secondary
-                        // diplay requires 2 non-atomic operations (stop and start). Once this logic
-                        // is refactored, it should be atomic.
-                        if (mUsersOnSecondaryDisplays.valueAt(i) == displayId) {
-                            throw new IllegalStateException("Cannot assign " + userId + " to "
-                                    + "display " + displayId + " as it's already assigned to "
-                                    + "user " + mUsersOnSecondaryDisplays.keyAt(i));
-                        }
-                        // TODO(b/239982558) also check that user is not already assigned to other
-                        // display (including 0). That would be harder to tested under CTS though
-                        // (for example, would need to add a new AM method to start user in bg on
-                        // main display), so it's better to test on unit tests
-                    }
+                    mUsersOnSecondaryDisplays.put(userId, parentDisplayId);
+                    return;
                 }
 
+                // Check if display is available
+                for (int i = 0; i < mUsersOnSecondaryDisplays.size(); i++) {
+                    // Make sure display is not used by other users...
+                    // TODO(b/240736142); currently, if a user was started in a display, it
+                    // would need to be stopped first, so "switching" a user on secondary
+                    // diplay requires 2 non-atomic operations (stop and start). Once this logic
+                    // is refactored, it should be atomic.
+                    if (mUsersOnSecondaryDisplays.valueAt(i) == displayId) {
+                        throw new IllegalStateException("Cannot assign " + userId + " to "
+                                + "display " + displayId + " as it's already assigned to "
+                                + "user " + mUsersOnSecondaryDisplays.keyAt(i));
+                    }
+                    // TODO(b/239982558) also check that user is not already assigned to other
+                    // display (including 0). That would be harder to tested under CTS though
+                    // (for example, would need to add a new AM method to start user in bg on
+                    // main display), so it's better to test on unit tests
+                }
+
+                if (DBG_MUMD) {
+                    Slogf.d(LOG_TAG, "Adding full user %d -> display %d", userId, displayId);
+                }
                 mUsersOnSecondaryDisplays.put(userId, displayId);
             }
         }
diff --git a/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java b/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java
index 8f13f7a..6e86123 100644
--- a/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java
+++ b/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java
@@ -35,7 +35,6 @@
 import android.os.UserManager;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
-import android.view.Display;
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
@@ -374,21 +373,16 @@
     })
     private int runIsUserVisible() {
         PrintWriter pw = getOutPrintWriter();
-        int displayId = Display.INVALID_DISPLAY;
+        Integer displayId = null;
         String opt;
         while ((opt = getNextOption()) != null) {
-            boolean invalidOption = false;
             switch (opt) {
                 case "--display":
                     displayId = Integer.parseInt(getNextArgRequired());
-                    invalidOption = displayId == Display.INVALID_DISPLAY;
                     break;
                 default:
-                    invalidOption = true;
-            }
-            if (invalidOption) {
-                pw.println("Invalid option: " + opt);
-                return -1;
+                    pw.println("Invalid option: " + opt);
+                    return -1;
             }
         }
         int userId = UserHandle.parseUserArg(getNextArgRequired());
@@ -404,7 +398,7 @@
         }
 
         boolean isVisible;
-        if (displayId != Display.INVALID_DISPLAY) {
+        if (displayId != null) {
             isVisible = mService.isUserVisibleOnDisplay(userId, displayId);
         } else {
             isVisible = getUserManagerForUser(userId).isUserVisible();
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index b57d4d5..2d876ed 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -35,7 +35,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 import java.lang.annotation.Retention;
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index cca3b35..6bc323e 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -54,7 +54,7 @@
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.PackageManagerServiceCompilerMapping;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import dalvik.system.DexFile;
 import dalvik.system.VMRuntime;
diff --git a/services/core/java/com/android/server/pm/dex/ArtUtils.java b/services/core/java/com/android/server/pm/dex/ArtUtils.java
index 068a064..77aefc5c 100644
--- a/services/core/java/com/android/server/pm/dex/ArtUtils.java
+++ b/services/core/java/com/android/server/pm/dex/ArtUtils.java
@@ -21,8 +21,8 @@
 import android.annotation.NonNull;
 
 import com.android.server.pm.PackageDexOptimizer;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 import java.io.File;
diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
index beea86d..5ba209d 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
@@ -23,7 +23,7 @@
 
 import com.android.internal.os.ClassLoaderFactory;
 import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.File;
 import java.util.List;
diff --git a/services/core/java/com/android/server/pm/dex/ViewCompiler.java b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
index ee66a5586..9ce648f 100644
--- a/services/core/java/com/android/server/pm/dex/ViewCompiler.java
+++ b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
@@ -23,7 +23,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.pm.Installer;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.File;
 
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 5be81d5..1084145 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -54,9 +54,9 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUnserialized;
 import com.android.server.pm.pkg.PackageUserState;
diff --git a/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java b/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java
index c67d0d2..7031dc3 100644
--- a/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java
+++ b/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java
@@ -28,9 +28,9 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.compat.IPlatformCompat;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 /**
  * Updates a package to ensure that if it targets <= Q that the android.test.base library is
diff --git a/services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java b/services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
index 7de457e..96fead2 100644
--- a/services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
+++ b/services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
@@ -20,8 +20,8 @@
 import android.os.Build;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 /**
  * Updates a package to ensure that if it targets < P that the org.apache.http.legacy library is
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageInternal.java
similarity index 86%
rename from services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
rename to services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageInternal.java
index b314fe2..8d43fe7 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageInternal.java
@@ -17,7 +17,7 @@
 package com.android.server.pm.parsing.pkg;
 
 import com.android.internal.content.om.OverlayConfig;
-import com.android.server.pm.pkg.AndroidPackageApi;
+import com.android.server.pm.pkg.AndroidPackage;
 
 /**
  * The last state of a package during parsing/install before it is available in {@link
@@ -29,6 +29,7 @@
  *
  * @hide
  */
-public interface AndroidPackage extends AndroidPackageApi, OverlayConfig.PackageProvider.Package {
+public interface AndroidPackageInternal extends AndroidPackage,
+        OverlayConfig.PackageProvider.Package {
 
 }
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index 76bae37..f6585f6 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -33,7 +33,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.server.SystemConfig;
 import com.android.server.pm.PackageManagerException;
-import com.android.server.pm.pkg.AndroidPackageApi;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.component.ParsedActivity;
 import com.android.server.pm.pkg.component.ParsedInstrumentation;
@@ -340,7 +340,7 @@
         info.versionCodeMajor = ((ParsingPackageHidden) pkg).getVersionCodeMajor();
     }
 
-    public static ApplicationInfo toAppInfoWithoutState(AndroidPackageApi pkg) {
+    public static ApplicationInfo toAppInfoWithoutState(AndroidPackage pkg) {
         return ((ParsingPackageHidden) pkg).toAppInfoWithoutState();
     }
 }
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index 11fb78f..70aca99 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -56,6 +56,7 @@
 import com.android.internal.util.Parcelling;
 import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
 import com.android.server.pm.parsing.PackageInfoUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.SELinuxUtil;
 import com.android.server.pm.pkg.component.ComponentMutateUtils;
 import com.android.server.pm.pkg.component.ParsedActivity;
@@ -102,7 +103,7 @@
  *
  * @hide
  */
-public class PackageImpl implements ParsedPackage, AndroidPackage,
+public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
         AndroidPackageHidden, ParsingPackage, ParsingPackageHidden, Parcelable {
 
     private static final SparseArray<int[]> EMPTY_INT_ARRAY_SPARSE_ARRAY = new SparseArray<>();
@@ -2591,7 +2592,7 @@
     }
 
     @Override
-    public AndroidPackage hideAsFinal() {
+    public AndroidPackageInternal hideAsFinal() {
         // TODO(b/135203078): Lock as immutable
         if (mStorageUuid == null) {
             assignDerivedFields();
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
index 38d87e2..d306341 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
@@ -18,17 +18,22 @@
 
 import android.content.pm.SigningDetails;
 
+import com.android.server.pm.pkg.AndroidPackage;
+
 /**
  * Methods used for mutation after direct package parsing, mostly done inside
  * {@link com.android.server.pm.PackageManagerService}.
  *
  * Java disallows defining this as an inner interface, so this must be a separate file.
  *
+ * TODO: Remove extending AndroidPackage, should be an isolated interface with only the methods
+ *  necessary to parse and install
+ *
  * @hide
  */
 public interface ParsedPackage extends AndroidPackage {
 
-    AndroidPackage hideAsFinal();
+    AndroidPackageInternal hideAsFinal();
 
     ParsedPackage addUsesLibrary(int index, String libraryName);
 
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index d5456e3..69e7bf1 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -23,14 +23,14 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PermissionInfo;
-import com.android.server.pm.pkg.component.ParsedPermission;
 import android.os.Build;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
 
 import com.android.server.pm.PackageManagerService;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.component.ParsedPermission;
 
 import libcore.util.EmptyArray;
 
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 3df412d..3b9f0ba 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -72,8 +72,8 @@
 import com.android.server.LocalServices;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.pm.UserManagerService;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerServiceInternal.HotwordDetectionServiceProvider;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 4c095fb..4a80c4a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -131,9 +131,8 @@
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.pm.UserManagerService;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.pkg.AndroidPackageApi;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.component.ComponentMutateUtils;
 import com.android.server.pm.pkg.component.ParsedPermission;
@@ -2612,7 +2611,7 @@
                     mPackageManagerInt.getSharedUserPackages(ps.getSharedUserAppId());
             int packagesSize = packages.size();
             for (int i = 0; i < packagesSize; i++) {
-                AndroidPackageApi sharedUserPackage =
+                AndroidPackage sharedUserPackage =
                         packages.valueAt(i).getAndroidPackage();
                 if (sharedUserPackage == null) {
                     continue;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 02d184e..930936b 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -25,9 +25,10 @@
 import android.content.pm.PermissionInfo;
 import android.content.pm.permission.SplitPermissionInfoParcelable;
 import android.permission.IOnPermissionsChangeListener;
+import android.permission.PermissionManager;
 import android.permission.PermissionManagerInternal;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 2d5ec39..f20620e 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -23,7 +23,7 @@
 import android.content.pm.PermissionInfo;
 import android.permission.PermissionManagerInternal;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/services/core/java/com/android/server/pm/pkg/AndroidPackageApi.java b/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
similarity index 99%
rename from services/core/java/com/android/server/pm/pkg/AndroidPackageApi.java
rename to services/core/java/com/android/server/pm/pkg/AndroidPackage.java
index a454bcd..6078d4a 100644
--- a/services/core/java/com/android/server/pm/pkg/AndroidPackageApi.java
+++ b/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -40,7 +40,6 @@
 import android.util.SparseIntArray;
 
 import com.android.internal.R;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.pkg.component.ParsedActivity;
 import com.android.server.pm.pkg.component.ParsedApexSystemService;
 import com.android.server.pm.pkg.component.ParsedAttribution;
@@ -66,7 +65,7 @@
  * @hide
  */
 //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-public interface AndroidPackageApi {
+public interface AndroidPackage {
 
     /**
      * @see ApplicationInfo#areAttributionsUserVisible()
diff --git a/services/core/java/com/android/server/pm/pkg/PackageState.java b/services/core/java/com/android/server/pm/pkg/PackageState.java
index b5e0e44..f0e386c 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageState.java
@@ -74,7 +74,7 @@
      * app once the device reboots or otherwise re-scans it.
      */
     @Nullable
-    AndroidPackageApi getAndroidPackage();
+    AndroidPackage getAndroidPackage();
 
     /**
      * The non-user-specific UID, or the UID if the user ID is
@@ -86,7 +86,7 @@
      * Value set through {@link PackageManager#setApplicationCategoryHint(String, int)}. Only
      * applied if the application itself does not declare a category.
      *
-     * @see AndroidPackageApi#getCategory()
+     * @see AndroidPackage#getCategory()
      */
     int getCategoryOverride();
 
@@ -121,7 +121,7 @@
 
     /**
      * Cached here in case the physical code directory on device is unmounted.
-     * @see AndroidPackageApi#getLongVersionCode()
+     * @see AndroidPackage#getLongVersionCode()
      */
     long getVersionCode();
 
@@ -134,14 +134,14 @@
     Map<String, Set<String>> getMimeGroups();
 
     /**
-     * @see AndroidPackageApi#getPackageName()
+     * @see AndroidPackage#getPackageName()
      */
     @NonNull
     String getPackageName();
 
     /**
      * TODO: Rename this to getCodePath
-     * @see AndroidPackageApi#getPath()
+     * @see AndroidPackage#getPath()
      */
     @NonNull
     File getPath();
@@ -227,13 +227,13 @@
     long[] getUsesStaticLibrariesVersions();
 
     /**
-     * @see AndroidPackageApi#getVolumeUuid()
+     * @see AndroidPackage#getVolumeUuid()
      */
     @Nullable
     String getVolumeUuid();
 
     /**
-     * @see AndroidPackageApi#isExternalStorage()
+     * @see AndroidPackage#isExternalStorage()
      */
     boolean isExternalStorage();
 
@@ -257,22 +257,22 @@
     boolean isInstallPermissionsFixed();
 
     /**
-     * @see AndroidPackageApi#isOdm()
+     * @see AndroidPackage#isOdm()
      */
     boolean isOdm();
 
     /**
-     * @see AndroidPackageApi#isOem()
+     * @see AndroidPackage#isOem()
      */
     boolean isOem();
 
     /**
-     * @see AndroidPackageApi#isPrivileged()
+     * @see AndroidPackage#isPrivileged()
      */
     boolean isPrivileged();
 
     /**
-     * @see AndroidPackageApi#isProduct()
+     * @see AndroidPackage#isProduct()
      */
     boolean isProduct();
 
@@ -282,12 +282,12 @@
     boolean isRequiredForSystemUser();
 
     /**
-     * @see AndroidPackageApi#isSystem()
+     * @see AndroidPackage#isSystem()
      */
     boolean isSystem();
 
     /**
-     * @see AndroidPackageApi#isSystemExt()
+     * @see AndroidPackage#isSystemExt()
      */
     boolean isSystemExt();
 
@@ -308,7 +308,7 @@
     boolean isApkInUpdatedApex();
 
     /**
-     * @see AndroidPackageApi#isVendor()
+     * @see AndroidPackage#isVendor()
      */
     boolean isVendor();
 }
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
index 878a837..eac0842 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
@@ -31,7 +31,6 @@
 import com.android.server.pm.PackageManagerService;
 import com.android.server.pm.PackageSetting;
 import com.android.server.pm.Settings;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import java.io.File;
 import java.util.List;
@@ -108,7 +107,7 @@
     }
 
     @Nullable
-    private final AndroidPackageApi mAndroidPackage;
+    private final AndroidPackage mAndroidPackage;
 
     @NonNull
     private final String mPackageName;
@@ -570,7 +569,7 @@
     }
 
     @DataClass.Generated.Member
-    public @Nullable AndroidPackageApi getAndroidPackage() {
+    public @Nullable AndroidPackage getAndroidPackage() {
         return mAndroidPackage;
     }
 
@@ -694,7 +693,7 @@
             time = 1644270981543L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java",
-            inputSignatures = "private  int mBooleans\nprivate final @android.annotation.Nullable com.android.server.pm.pkg.AndroidPackageApi mAndroidPackage\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mVolumeUuid\nprivate final  int mAppId\nprivate final  int mCategoryOverride\nprivate final @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate final  long mLastModifiedTime\nprivate final  long mLastUpdateTime\nprivate final  long mLongVersionCode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mMimeGroups\nprivate final @android.annotation.NonNull java.io.File mPath\nprivate final @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate final  boolean mHasSharedUser\nprivate final  int mSharedUserAppId\nprivate final @android.annotation.NonNull java.lang.String[] mUsesSdkLibraries\nprivate final @android.annotation.NonNull long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.NonNull java.lang.String[] mUsesStaticLibraries\nprivate final @android.annotation.NonNull long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> mUsesLibraryInfos\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesLibraryFiles\nprivate final @android.annotation.NonNull long[] mLastPackageUsageTime\nprivate final @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserState> mUserStates\npublic static  com.android.server.pm.pkg.PackageState copy(com.android.server.pm.pkg.PackageStateInternal)\nprivate  void setBoolean(int,boolean)\nprivate  boolean getBoolean(int)\npublic @java.lang.Override boolean isExternalStorage()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isOdm()\npublic @java.lang.Override boolean isOem()\npublic @java.lang.Override boolean isPrivileged()\npublic @java.lang.Override boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic @java.lang.Override boolean isSystem()\npublic @java.lang.Override boolean isSystemExt()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isVendor()\npublic @java.lang.Override long getVersionCode()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override int getSharedUserAppId()\nclass PackageStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageState]\nprivate static final  int SYSTEM\nprivate static final  int EXTERNAL_STORAGE\nprivate static final  int PRIVILEGED\nprivate static final  int OEM\nprivate static final  int VENDOR\nprivate static final  int PRODUCT\nprivate static final  int SYSTEM_EXT\nprivate static final  int REQUIRED_FOR_SYSTEM_USER\nprivate static final  int ODM\nprivate static final  int FORCE_QUERYABLE_OVERRIDE\nprivate static final  int HIDDEN_UNTIL_INSTALLED\nprivate static final  int INSTALL_PERMISSIONS_FIXED\nprivate static final  int UPDATE_AVAILABLE\nprivate static final  int UPDATED_SYSTEM_APP\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
+            inputSignatures = "private  int mBooleans\nprivate final @android.annotation.Nullable com.android.server.pm.pkg.AndroidPackage mAndroidPackage\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mVolumeUuid\nprivate final  int mAppId\nprivate final  int mCategoryOverride\nprivate final @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate final  long mLastModifiedTime\nprivate final  long mLastUpdateTime\nprivate final  long mLongVersionCode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mMimeGroups\nprivate final @android.annotation.NonNull java.io.File mPath\nprivate final @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate final  boolean mHasSharedUser\nprivate final  int mSharedUserAppId\nprivate final @android.annotation.NonNull java.lang.String[] mUsesSdkLibraries\nprivate final @android.annotation.NonNull long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.NonNull java.lang.String[] mUsesStaticLibraries\nprivate final @android.annotation.NonNull long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> mUsesLibraryInfos\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesLibraryFiles\nprivate final @android.annotation.NonNull long[] mLastPackageUsageTime\nprivate final @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserState> mUserStates\npublic static  com.android.server.pm.pkg.PackageState copy(com.android.server.pm.pkg.PackageStateInternal)\nprivate  void setBoolean(int,boolean)\nprivate  boolean getBoolean(int)\npublic @java.lang.Override boolean isExternalStorage()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isOdm()\npublic @java.lang.Override boolean isOem()\npublic @java.lang.Override boolean isPrivileged()\npublic @java.lang.Override boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic @java.lang.Override boolean isSystem()\npublic @java.lang.Override boolean isSystemExt()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isVendor()\npublic @java.lang.Override long getVersionCode()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override int getSharedUserAppId()\nclass PackageStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageState]\nprivate static final  int SYSTEM\nprivate static final  int EXTERNAL_STORAGE\nprivate static final  int PRIVILEGED\nprivate static final  int OEM\nprivate static final  int VENDOR\nprivate static final  int PRODUCT\nprivate static final  int SYSTEM_EXT\nprivate static final  int REQUIRED_FOR_SYSTEM_USER\nprivate static final  int ODM\nprivate static final  int FORCE_QUERYABLE_OVERRIDE\nprivate static final  int HIDDEN_UNTIL_INSTALLED\nprivate static final  int INSTALL_PERMISSIONS_FIXED\nprivate static final  int UPDATE_AVAILABLE\nprivate static final  int UPDATED_SYSTEM_APP\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
index 68a00a9..84799ea 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
@@ -24,7 +24,7 @@
 
 import com.android.server.pm.InstallSource;
 import com.android.server.pm.PackageKeySetData;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal;
 import com.android.server.pm.permission.LegacyPermissionState;
 
 import java.util.UUID;
@@ -35,7 +35,7 @@
 public interface PackageStateInternal extends PackageState {
 
     @NonNull
-    AndroidPackage getPkg();
+    AndroidPackageInternal getPkg();
 
     // TODO: Remove in favor of exposing APIs directly?
     @NonNull
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java b/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java
index 91e9b2f..a883a05 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java
@@ -20,11 +20,9 @@
 import android.annotation.Nullable;
 import android.content.pm.ComponentInfo;
 import android.content.pm.PackageManager;
-import com.android.server.pm.pkg.component.ParsedMainComponent;
-
 import android.util.SparseArray;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
 
 public class PackageStateUtils {
 
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
index 3bdebd1..15e3d0c 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
@@ -26,7 +26,6 @@
 import android.util.DebugUtils;
 import android.util.Slog;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.pkg.component.ParsedMainComponent;
 
 /** @hide */
diff --git a/services/core/java/com/android/server/pm/pkg/SharedUserApi.java b/services/core/java/com/android/server/pm/pkg/SharedUserApi.java
index 94a87f3..55c305c 100644
--- a/services/core/java/com/android/server/pm/pkg/SharedUserApi.java
+++ b/services/core/java/com/android/server/pm/pkg/SharedUserApi.java
@@ -22,7 +22,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.LegacyPermissionState;
 import com.android.server.pm.pkg.component.ParsedProcess;
 
diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
index 1d95e87..a19beea 100644
--- a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
@@ -51,7 +51,7 @@
 import com.android.server.pm.UserManagerService;
 import com.android.server.pm.UserNeedsBadgingCache;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.pm.pkg.PackageUserStateInternal;
diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java b/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java
index c01cecf..75d7162 100644
--- a/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java
+++ b/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java
@@ -32,8 +32,8 @@
 import com.android.server.pm.DumpState;
 import com.android.server.pm.UserManagerService;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageUserStateInternal;
 import com.android.server.pm.pkg.component.ParsedActivity;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
index e078120..adef808 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
@@ -22,8 +22,6 @@
 import android.compat.annotation.EnabledSince;
 import android.content.Intent;
 import android.content.IntentFilter;
-import com.android.server.pm.pkg.component.ParsedActivity;
-import com.android.server.pm.pkg.component.ParsedIntentInfo;
 import android.os.Build;
 import android.text.TextUtils;
 import android.util.ArraySet;
@@ -31,7 +29,9 @@
 
 import com.android.server.SystemConfig;
 import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
 
 import java.util.List;
 import java.util.Objects;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
index e06b608..d67613c 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
@@ -31,7 +31,7 @@
 
 import com.android.internal.util.CollectionUtils;
 import com.android.server.pm.Computer;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
 import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index 3cd7795..400af36 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -55,7 +55,7 @@
 import com.android.server.SystemService;
 import com.android.server.compat.PlatformCompat;
 import com.android.server.pm.Computer;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.pm.pkg.PackageUserStateInternal;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
index 8d1ae0b..cde72cd 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
@@ -29,7 +29,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.pm.Computer;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
 import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
index 058b605..3fd00c6 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
@@ -28,7 +28,7 @@
 import com.android.internal.util.CollectionUtils;
 import com.android.server.compat.PlatformCompat;
 import com.android.server.pm.PackageManagerService;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.Set;
 import java.util.regex.Matcher;
diff --git a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
index c8e46b6..752eb53 100644
--- a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
+++ b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
@@ -39,7 +39,7 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.verify.domain.DomainVerificationCollector;
 import com.android.server.pm.verify.domain.DomainVerificationDebug;
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 7602d33..ffb652e 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -96,8 +96,8 @@
 import com.android.server.SystemService;
 import com.android.server.notification.NotificationManagerInternal;
 import com.android.server.pm.UserManagerInternal;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
 import com.android.server.utils.TimingsTraceAndSlog;
 import com.android.server.wm.ActivityInterceptorCallback;
diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
index ab71355..33fc6fb 100644
--- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
+++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
@@ -42,7 +42,7 @@
 import android.provider.DeviceConfig;
 
 import com.android.server.LocalServices;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.Arrays;
 import java.util.HashSet;
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 5a2fb18..dad9584 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -571,7 +571,8 @@
     /**
      * Called when there has been user activity.
      */
-    public void onUserActivity(int displayGroupId, int event, int uid) {
+    public void onUserActivity(int displayGroupId, @PowerManager.UserActivityEvent int event,
+            int uid) {
         if (DEBUG) {
             Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid);
         }
diff --git a/services/core/java/com/android/server/power/PowerGroup.java b/services/core/java/com/android/server/power/PowerGroup.java
index fec61ac..9fe53fb 100644
--- a/services/core/java/com/android/server/power/PowerGroup.java
+++ b/services/core/java/com/android/server/power/PowerGroup.java
@@ -74,6 +74,8 @@
     private long mLastPowerOnTime;
     private long mLastUserActivityTime;
     private long mLastUserActivityTimeNoChangeLights;
+    @PowerManager.UserActivityEvent
+    private int mLastUserActivityEvent;
     /** Timestamp (milliseconds since boot) of the last time the power group was awoken.*/
     private long mLastWakeTime;
     /** Timestamp (milliseconds since boot) of the last time the power group was put to sleep. */
@@ -244,7 +246,7 @@
         return true;
     }
 
-    boolean dozeLocked(long eventTime, int uid, int reason) {
+    boolean dozeLocked(long eventTime, int uid, @PowerManager.GoToSleepReason int reason) {
         if (eventTime < getLastWakeTimeLocked() || !isInteractive(mWakefulness)) {
             return false;
         }
@@ -253,9 +255,14 @@
         try {
             reason = Math.min(PowerManager.GO_TO_SLEEP_REASON_MAX,
                     Math.max(reason, PowerManager.GO_TO_SLEEP_REASON_MIN));
+            long millisSinceLastUserActivity = eventTime - Math.max(
+                    mLastUserActivityTimeNoChangeLights, mLastUserActivityTime);
             Slog.i(TAG, "Powering off display group due to "
-                    + PowerManager.sleepReasonToString(reason)  + " (groupId= " + getGroupId()
-                    + ", uid= " + uid + ")...");
+                    + PowerManager.sleepReasonToString(reason)
+                    + " (groupId= " + getGroupId() + ", uid= " + uid
+                    + ", millisSinceLastUserActivity=" + millisSinceLastUserActivity
+                    + ", lastUserActivityEvent=" + PowerManager.userActivityEventToString(
+                    mLastUserActivityEvent) + ")...");
 
             setSandmanSummonedLocked(/* isSandmanSummoned= */ true);
             setWakefulnessLocked(WAKEFULNESS_DOZING, eventTime, uid, reason, /* opUid= */ 0,
@@ -266,14 +273,16 @@
         return true;
     }
 
-    boolean sleepLocked(long eventTime, int uid, int reason) {
+    boolean sleepLocked(long eventTime, int uid, @PowerManager.GoToSleepReason int reason) {
         if (eventTime < mLastWakeTime || getWakefulnessLocked() == WAKEFULNESS_ASLEEP) {
             return false;
         }
 
         Trace.traceBegin(Trace.TRACE_TAG_POWER, "sleepPowerGroup");
         try {
-            Slog.i(TAG, "Sleeping power group (groupId=" + getGroupId() + ", uid=" + uid + ")...");
+            Slog.i(TAG,
+                    "Sleeping power group (groupId=" + getGroupId() + ", uid=" + uid + ", reason="
+                            + PowerManager.sleepReasonToString(reason) + ")...");
             setSandmanSummonedLocked(/* isSandmanSummoned= */ true);
             setWakefulnessLocked(WAKEFULNESS_ASLEEP, eventTime, uid, reason, /* opUid= */0,
                     /* opPackageName= */ null, /* details= */ null);
@@ -287,16 +296,20 @@
         return mLastUserActivityTime;
     }
 
-    void setLastUserActivityTimeLocked(long lastUserActivityTime) {
+    void setLastUserActivityTimeLocked(long lastUserActivityTime,
+            @PowerManager.UserActivityEvent int event) {
         mLastUserActivityTime = lastUserActivityTime;
+        mLastUserActivityEvent = event;
     }
 
     public long getLastUserActivityTimeNoChangeLightsLocked() {
         return mLastUserActivityTimeNoChangeLights;
     }
 
-    public void setLastUserActivityTimeNoChangeLightsLocked(long time) {
+    public void setLastUserActivityTimeNoChangeLightsLocked(long time,
+            @PowerManager.UserActivityEvent int event) {
         mLastUserActivityTimeNoChangeLights = time;
+        mLastUserActivityEvent = event;
     }
 
     public int getUserActivitySummaryLocked() {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 9ee0df9..2d22b8f 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -1216,6 +1216,7 @@
                 return;
             }
 
+            Slog.i(TAG, "onFlip(): Face " + (isFaceDown ? "down." : "up."));
             mIsFaceDown = isFaceDown;
             if (isFaceDown) {
                 final long currentTime = mClock.uptimeMillis();
@@ -1937,12 +1938,13 @@
 
     // Called from native code.
     @SuppressWarnings("unused")
-    private void userActivityFromNative(long eventTime, int event, int displayId, int flags) {
+    private void userActivityFromNative(long eventTime, @PowerManager.UserActivityEvent int event,
+            int displayId, int flags) {
         userActivityInternal(displayId, eventTime, event, flags, Process.SYSTEM_UID);
     }
 
-    private void userActivityInternal(int displayId, long eventTime, int event, int flags,
-            int uid) {
+    private void userActivityInternal(int displayId, long eventTime,
+            @PowerManager.UserActivityEvent int event, int flags, int uid) {
         synchronized (mLock) {
             if (displayId == Display.INVALID_DISPLAY) {
                 if (userActivityNoUpdateLocked(eventTime, event, flags, uid)) {
@@ -1993,11 +1995,12 @@
 
     @GuardedBy("mLock")
     private boolean userActivityNoUpdateLocked(final PowerGroup powerGroup, long eventTime,
-            int event, int flags, int uid) {
+            @PowerManager.UserActivityEvent int event, int flags, int uid) {
         final int groupId = powerGroup.getGroupId();
         if (DEBUG_SPEW) {
             Slog.d(TAG, "userActivityNoUpdateLocked: groupId=" + groupId
-                    + ", eventTime=" + eventTime + ", event=" + event
+                    + ", eventTime=" + eventTime
+                    + ", event=" + PowerManager.userActivityEventToString(event)
                     + ", flags=0x" + Integer.toHexString(flags) + ", uid=" + uid);
         }
 
@@ -2032,7 +2035,7 @@
             if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
                 if (eventTime > powerGroup.getLastUserActivityTimeNoChangeLightsLocked()
                         && eventTime > powerGroup.getLastUserActivityTimeLocked()) {
-                    powerGroup.setLastUserActivityTimeNoChangeLightsLocked(eventTime);
+                    powerGroup.setLastUserActivityTimeNoChangeLightsLocked(eventTime, event);
                     mDirty |= DIRTY_USER_ACTIVITY;
                     if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
                         mDirty |= DIRTY_QUIESCENT;
@@ -2042,7 +2045,7 @@
                 }
             } else {
                 if (eventTime > powerGroup.getLastUserActivityTimeLocked()) {
-                    powerGroup.setLastUserActivityTimeLocked(eventTime);
+                    powerGroup.setLastUserActivityTimeLocked(eventTime, event);
                     mDirty |= DIRTY_USER_ACTIVITY;
                     if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
                         mDirty |= DIRTY_QUIESCENT;
@@ -2069,7 +2072,8 @@
             @WakeReason int reason, String details, int uid, String opPackageName, int opUid) {
         if (DEBUG_SPEW) {
             Slog.d(TAG, "wakePowerGroupLocked: eventTime=" + eventTime
-                    + ", groupId=" + powerGroup.getGroupId() + ", uid=" + uid);
+                    + ", groupId=" + powerGroup.getGroupId()
+                    + ", reason=" + PowerManager.wakeReasonToString(reason) + ", uid=" + uid);
         }
         if (mForceSuspendActive || !mSystemReady) {
             return;
@@ -2092,11 +2096,11 @@
 
     @GuardedBy("mLock")
     private boolean dozePowerGroupLocked(final PowerGroup powerGroup, long eventTime,
-            int reason, int uid) {
+            @GoToSleepReason int reason, int uid) {
         if (DEBUG_SPEW) {
             Slog.d(TAG, "dozePowerGroup: eventTime=" + eventTime
-                    + ", groupId=" + powerGroup.getGroupId() + ", reason=" + reason
-                    + ", uid=" + uid);
+                    + ", groupId=" + powerGroup.getGroupId()
+                    + ", reason=" + PowerManager.sleepReasonToString(reason) + ", uid=" + uid);
         }
 
         if (!mSystemReady || !mBootCompleted) {
@@ -2107,10 +2111,12 @@
     }
 
     @GuardedBy("mLock")
-    private boolean sleepPowerGroupLocked(final PowerGroup powerGroup, long eventTime, int reason,
-            int uid) {
+    private boolean sleepPowerGroupLocked(final PowerGroup powerGroup, long eventTime,
+            @GoToSleepReason int reason, int uid) {
         if (DEBUG_SPEW) {
-            Slog.d(TAG, "sleepPowerGroup: eventTime=" + eventTime + ", uid=" + uid);
+            Slog.d(TAG, "sleepPowerGroup: eventTime=" + eventTime
+                    + ", groupId=" + powerGroup.getGroupId()
+                    + ", reason=" + PowerManager.sleepReasonToString(reason) + ", uid=" + uid);
         }
         if (!mBootCompleted || !mSystemReady) {
             return false;
@@ -2172,7 +2178,10 @@
             case WAKEFULNESS_DOZING:
                 traceMethodName = "goToSleep";
                 Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason)
-                        + " (uid " + uid + ")...");
+                        + " (uid " + uid + ", screenOffTimeout=" + mScreenOffTimeoutSetting
+                        + ", activityTimeoutWM=" + mUserActivityTimeoutOverrideFromWindowManager
+                        + ", maxDimRatio=" + mMaximumScreenDimRatioConfig
+                        + ", maxDimDur=" + mMaximumScreenDimDurationConfig + ")...");
                 mLastGlobalSleepTime = eventTime;
                 mLastGlobalSleepReason = reason;
                 mLastGlobalSleepTimeRealtime = mClock.elapsedRealtime();
@@ -4258,7 +4267,7 @@
     void onUserActivity() {
         synchronized (mLock) {
             mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP).setLastUserActivityTimeLocked(
-                    mClock.uptimeMillis());
+                    mClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_OTHER);
         }
     }
 
@@ -5646,7 +5655,8 @@
         }
 
         @Override // Binder call
-        public void userActivity(int displayId, long eventTime, int event, int flags) {
+        public void userActivity(int displayId, long eventTime,
+                @PowerManager.UserActivityEvent int event, int flags) {
             final long now = mClock.uptimeMillis();
             if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER)
                     != PackageManager.PERMISSION_GRANTED
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 03a9642..c6128f9 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -178,7 +178,7 @@
     // TODO: remove "tcp" from network methods, since we measure total stats.
 
     // Current on-disk Parcel version. Must be updated when the format of the parcelable changes
-    public static final int VERSION = 209;
+    public static final int VERSION = 210;
 
     // The maximum number of names wakelocks we will keep track of
     // per uid; once the limit is reached, we batch the remaining wakelocks
@@ -5413,7 +5413,8 @@
     }
 
     @GuardedBy("this")
-    public void noteUserActivityLocked(int uid, int event, long elapsedRealtimeMs, long uptimeMs) {
+    public void noteUserActivityLocked(int uid, @PowerManager.UserActivityEvent int event,
+            long elapsedRealtimeMs, long uptimeMs) {
         if (mOnBatteryInternal) {
             uid = mapUid(uid);
             getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs).noteUserActivityLocked(event);
@@ -8846,14 +8847,14 @@
         }
 
         @Override
-        public void noteUserActivityLocked(int type) {
+        public void noteUserActivityLocked(@PowerManager.UserActivityEvent int event) {
             if (mUserActivityCounters == null) {
                 initUserActivityLocked();
             }
-            if (type >= 0 && type < NUM_USER_ACTIVITY_TYPES) {
-                mUserActivityCounters[type].stepAtomic();
+            if (event >= 0 && event < NUM_USER_ACTIVITY_TYPES) {
+                mUserActivityCounters[event].stepAtomic();
             } else {
-                Slog.w(TAG, "Unknown user activity type " + type + " was specified.",
+                Slog.w(TAG, "Unknown user activity type " + event + " was specified.",
                         new Throwable());
             }
         }
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 38e6b28..85d93f4 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -52,7 +52,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.RescueParty;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.File;
 import java.io.IOException;
diff --git a/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java b/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java
index 88e9fa5..1fb7cf5 100644
--- a/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java
+++ b/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java
@@ -18,19 +18,24 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.app.AlarmManager;
 import android.content.Context;
-import android.location.Location;
 import android.location.LocationListener;
 import android.location.LocationManager;
 import android.location.LocationManagerInternal;
 import android.location.LocationRequest;
 import android.location.LocationTime;
 import android.os.Binder;
+import android.os.Handler;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
 import android.os.SystemClock;
 import android.os.TimestampedValue;
+import android.util.LocalLog;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
 import com.android.server.FgThread;
@@ -41,6 +46,7 @@
 import java.io.PrintWriter;
 import java.time.Duration;
 import java.util.Objects;
+import java.util.concurrent.Executor;
 
 /**
  * Monitors the GNSS time.
@@ -87,7 +93,7 @@
                 // Instead of polling GNSS time periodically, passive location updates are enabled.
                 // Once an update is received, the gnss time will be queried and suggested to
                 // TimeDetectorService.
-                mService.requestGnssTimeUpdates();
+                mService.startGnssListeningInternal();
             }
         }
     }
@@ -95,15 +101,28 @@
     private static final Duration GNSS_TIME_UPDATE_ALARM_INTERVAL = Duration.ofHours(4);
     private static final String ATTRIBUTION_TAG = "GnssTimeUpdateService";
 
+    /**
+     * A log that records the decisions to fetch a GNSS time update.
+     * This is logged in bug reports to assist with debugging issues with GNSS time suggestions.
+     */
+    private final LocalLog mLocalLog = new LocalLog(10, false /* useLocalTimestamps */);
+    /** The executor used for async operations */
+    private final Executor mExecutor = FgThread.getExecutor();
+    /** The handler used for async operations */
+    private final Handler mHandler = FgThread.getHandler();
+
     private final Context mContext;
     private final TimeDetectorInternal mTimeDetectorInternal;
     private final AlarmManager mAlarmManager;
     private final LocationManager mLocationManager;
     private final LocationManagerInternal mLocationManagerInternal;
 
-    @Nullable private AlarmManager.OnAlarmListener mAlarmListener;
-    @Nullable private LocationListener mLocationListener;
-    @Nullable private TimestampedValue<Long> mLastSuggestedGnssTime;
+
+    private final Object mLock = new Object();
+    @GuardedBy("mLock") @Nullable private AlarmManager.OnAlarmListener mAlarmListener;
+    @GuardedBy("mLock") @Nullable private LocationListener mLocationListener;
+
+    @Nullable private volatile TimestampedValue<Long> mLastSuggestedGnssTime;
 
     @VisibleForTesting
     GnssTimeUpdateService(@NonNull Context context, @NonNull AlarmManager alarmManager,
@@ -118,87 +137,133 @@
     }
 
     /**
-     * Request passive location updates. Such a request will not trigger any active locations or
-     * power usage itself.
+     * Used by {@link com.android.server.timedetector.GnssTimeUpdateServiceShellCommand} to force
+     * the service into GNSS listening mode.
+     */
+    @RequiresPermission(android.Manifest.permission.SET_TIME)
+    boolean startGnssListening() {
+        mContext.enforceCallingPermission(
+                android.Manifest.permission.SET_TIME, "Start GNSS listening");
+        mLocalLog.log("startGnssListening() called");
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return startGnssListeningInternal();
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    /**
+     * Starts listening for passive location updates. Such a request will not trigger any active
+     * locations or power usage itself. Returns {@code true} if the service is listening after the
+     * method returns and {@code false} otherwise. At present this method only returns {@code false}
+     * if there is no GPS provider on the device.
+     *
+     * <p>If the service is already listening for locations this is a no-op. If the device is in a
+     * "sleeping" state between listening periods then it will return to listening.
      */
     @VisibleForTesting
-    void requestGnssTimeUpdates() {
-        if (D) {
-            Log.d(TAG, "requestGnssTimeUpdates()");
+    boolean startGnssListeningInternal() {
+        if (!mLocationManager.hasProvider(LocationManager.GPS_PROVIDER)) {
+            logError("GPS provider does not exist on this device");
+            return false;
         }
 
-        if (!mLocationManager.hasProvider(LocationManager.GPS_PROVIDER)) {
-            Log.e(TAG, "GPS provider does not exist on this device");
-            return;
+        synchronized (mLock) {
+            if (mLocationListener != null) {
+                logDebug("Already listening for GNSS updates");
+                return true;
+            }
+
+            // If startGnssListening() is called during manual tests to jump back into location
+            // listening then there will usually be an alarm set.
+            if (mAlarmListener != null) {
+                mAlarmManager.cancel(mAlarmListener);
+                mAlarmListener = null;
+            }
+
+            startGnssListeningLocked();
+            return true;
         }
+    }
+
+    @GuardedBy("mLock")
+    private void startGnssListeningLocked() {
+        logDebug("startGnssListeningLocked()");
 
         // Location Listener triggers onLocationChanged() when GNSS data is available, so
         // that the getGnssTimeMillis() function doesn't need to be continuously polled.
-        mLocationListener = new LocationListener() {
-            @Override
-            public void onLocationChanged(Location location) {
-                if (D) {
-                    Log.d(TAG, "onLocationChanged()");
-                }
-
-                // getGnssTimeMillis() can return null when the Master Location Switch for the
-                // foreground user is disabled.
-                LocationTime locationTime = mLocationManagerInternal.getGnssTimeMillis();
-                if (locationTime != null) {
-                    suggestGnssTime(locationTime);
-                } else {
-                    if (D) {
-                        Log.d(TAG, "getGnssTimeMillis() returned null");
-                    }
-                }
-
-                mLocationManager.removeUpdates(mLocationListener);
-                mLocationListener = null;
-
-                mAlarmListener = new AlarmManager.OnAlarmListener() {
-                    @Override
-                    public void onAlarm() {
-                        if (D) {
-                            Log.d(TAG, "onAlarm()");
-                        }
-                        mAlarmListener = null;
-                        requestGnssTimeUpdates();
-                    }
-                };
-
-                // Set next alarm to re-enable location updates.
-                long next = SystemClock.elapsedRealtime()
-                        + GNSS_TIME_UPDATE_ALARM_INTERVAL.toMillis();
-                mAlarmManager.set(
-                        AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                        next,
-                        TAG,
-                        mAlarmListener,
-                        FgThread.getHandler());
-            }
-        };
-
+        mLocationListener = location -> handleLocationAvailable();
         mLocationManager.requestLocationUpdates(
                 LocationManager.GPS_PROVIDER,
                 new LocationRequest.Builder(LocationRequest.PASSIVE_INTERVAL)
                         .setMinUpdateIntervalMillis(0)
                         .build(),
-                FgThread.getExecutor(),
+                mExecutor,
                 mLocationListener);
     }
 
+    private void handleLocationAvailable() {
+        logDebug("handleLocationAvailable()");
+
+        // getGnssTimeMillis() can return null when the Master Location Switch for the
+        // foreground user is disabled.
+        LocationTime locationTime = mLocationManagerInternal.getGnssTimeMillis();
+        if (locationTime != null) {
+            String msg = "Passive location time received: " + locationTime;
+            logDebug(msg);
+            mLocalLog.log(msg);
+            suggestGnssTime(locationTime);
+        } else {
+            logDebug("getGnssTimeMillis() returned null");
+        }
+
+        synchronized (mLock) {
+            if (mLocationListener == null) {
+                logWarning("mLocationListener unexpectedly null");
+            } else {
+                mLocationManager.removeUpdates(mLocationListener);
+                mLocationListener = null;
+            }
+
+            if (mAlarmListener != null) {
+                logWarning("mAlarmListener was unexpectedly non-null");
+                mAlarmManager.cancel(mAlarmListener);
+            }
+
+            // Set next alarm to re-enable location updates.
+            long next = SystemClock.elapsedRealtime()
+                    + GNSS_TIME_UPDATE_ALARM_INTERVAL.toMillis();
+            mAlarmListener = this::handleAlarmFired;
+            mAlarmManager.set(
+                    AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                    next,
+                    TAG,
+                    mAlarmListener,
+                    mHandler);
+        }
+    }
+
+    private void handleAlarmFired() {
+        logDebug("handleAlarmFired()");
+
+        synchronized (mLock) {
+            mAlarmListener = null;
+            startGnssListeningLocked();
+        }
+    }
+
     /**
      * Convert LocationTime to TimestampedValue. Then suggest TimestampedValue to Time Detector.
      */
     private void suggestGnssTime(LocationTime locationTime) {
-        if (D) {
-            Log.d(TAG, "suggestGnssTime()");
-        }
+        logDebug("suggestGnssTime()");
+
         long gnssTime = locationTime.getTime();
         long elapsedRealtimeMs = locationTime.getElapsedRealtimeNanos() / 1_000_000L;
 
-        TimestampedValue<Long> timeSignal = new TimestampedValue<>(
-                elapsedRealtimeMs, gnssTime);
+        TimestampedValue<Long> timeSignal = new TimestampedValue<>(elapsedRealtimeMs, gnssTime);
         mLastSuggestedGnssTime = timeSignal;
 
         GnssTimeSuggestion timeSuggestion = new GnssTimeSuggestion(timeSignal);
@@ -209,11 +274,38 @@
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
         pw.println("mLastSuggestedGnssTime: " + mLastSuggestedGnssTime);
-        pw.print("state: ");
-        if (mLocationListener != null) {
-            pw.println("time updates enabled");
-        } else {
-            pw.println("alarm enabled");
+        synchronized (mLock) {
+            pw.print("state: ");
+            if (mLocationListener != null) {
+                pw.println("time updates enabled");
+            } else {
+                pw.println("alarm enabled");
+            }
+        }
+        pw.println("Log:");
+        mLocalLog.dump(pw);
+    }
+
+    @Override
+    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+            String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+        new GnssTimeUpdateServiceShellCommand(this).exec(
+                this, in, out, err, args, callback, resultReceiver);
+    }
+
+    private void logError(String msg) {
+        Log.e(TAG, msg);
+        mLocalLog.log(msg);
+    }
+
+    private void logWarning(String msg) {
+        Log.w(TAG, msg);
+        mLocalLog.log(msg);
+    }
+
+    private void logDebug(String msg) {
+        if (D) {
+            Log.d(TAG, msg);
         }
     }
 }
diff --git a/services/core/java/com/android/server/timedetector/GnssTimeUpdateServiceShellCommand.java b/services/core/java/com/android/server/timedetector/GnssTimeUpdateServiceShellCommand.java
new file mode 100644
index 0000000..e757578
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/GnssTimeUpdateServiceShellCommand.java
@@ -0,0 +1,77 @@
+/*
+ * 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.server.timedetector;
+
+import android.annotation.NonNull;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+import java.util.Objects;
+
+/** Implements the shell command interface for {@link GnssTimeUpdateService}. */
+class GnssTimeUpdateServiceShellCommand extends ShellCommand {
+
+    /**
+     * The name of the service.
+     */
+    private static final String SHELL_COMMAND_SERVICE_NAME = "gnss_time_update_service";
+
+    /**
+     * A shell command that forces the service in to GNSS listening mode if it isn't already.
+     */
+    private static final String SHELL_COMMAND_START_GNSS_LISTENING = "start_gnss_listening";
+
+    @NonNull
+    private final GnssTimeUpdateService mGnssTimeUpdateService;
+
+    GnssTimeUpdateServiceShellCommand(GnssTimeUpdateService gnssTimeUpdateService) {
+        mGnssTimeUpdateService = Objects.requireNonNull(gnssTimeUpdateService);
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+
+        switch (cmd) {
+            case SHELL_COMMAND_START_GNSS_LISTENING:
+                return runStartGnssListening();
+            default: {
+                return handleDefaultCommands(cmd);
+            }
+        }
+    }
+
+    private int runStartGnssListening() {
+        boolean success = mGnssTimeUpdateService.startGnssListening();
+        getOutPrintWriter().println(success);
+        return 0;
+    }
+
+    @Override
+    public void onHelp() {
+        final PrintWriter pw = getOutPrintWriter();
+        pw.printf("Network Time Update Service (%s) commands:\n", SHELL_COMMAND_SERVICE_NAME);
+        pw.printf("  help\n");
+        pw.printf("    Print this help text.\n");
+        pw.printf("  %s\n", SHELL_COMMAND_START_GNSS_LISTENING);
+        pw.printf("    Forces the service in to GNSS listening mode (if it isn't already).\n");
+        pw.printf("    Prints true if the service is listening after this command.\n");
+        pw.println();
+    }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index cceb58d..ffe24c0 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -87,7 +87,7 @@
 import com.android.server.LocalServices;
 import com.android.server.Watchdog;
 import com.android.server.pm.KnownPackages;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.uri.NeededUriGrants;
 import com.android.server.vr.VrManagerInternal;
 
diff --git a/services/core/java/com/android/server/wm/AnrController.java b/services/core/java/com/android/server/wm/AnrController.java
index e0ac37a..01098de 100644
--- a/services/core/java/com/android/server/wm/AnrController.java
+++ b/services/core/java/com/android/server/wm/AnrController.java
@@ -19,6 +19,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
 import static com.android.server.wm.ActivityRecord.INVALID_PID;
+import static com.android.server.wm.ActivityTaskManagerService.getInputDispatchingTimeoutMillisLocked;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.NonNull;
@@ -72,6 +73,33 @@
                         + ". Dropping notifyNoFocusedWindowAnr request");
                 return;
             }
+
+            // App is unresponsive, but we are actively trying to give focus to a window.
+            // Blame the window if possible since the window may not belong to the app.
+            DisplayContent display = mService.mRoot.getDisplayContent(activity.getDisplayId());
+            IBinder focusToken = display == null ? null : display.getInputMonitor().mInputFocus;
+            InputTarget focusTarget = mService.getInputTargetFromToken(focusToken);
+
+            if (focusTarget != null) {
+                // Check if we have a recent focus request, newer than the dispatch timeout, then
+                // ignore the focus request.
+                WindowState targetWindowState = focusTarget.getWindowState();
+                boolean requestIsValid = SystemClock.uptimeMillis()
+                        - display.getInputMonitor().mInputFocusRequestTimeMillis
+                        >= getInputDispatchingTimeoutMillisLocked(
+                                targetWindowState.getActivityRecord());
+
+                if (requestIsValid) {
+                    if (notifyWindowUnresponsive(focusToken, timeoutRecord)) {
+                        Slog.i(TAG_WM, "Blamed " + focusTarget.getWindowState().getName()
+                                + " using pending focus request. Focused activity: "
+                                + activity.getName());
+                        return;
+                    }
+                }
+            }
+
+
             Slog.i(TAG_WM, "ANR in " + activity.getName() + ".  Reason: " + timeoutRecord.mReason);
             dumpAnrStateLocked(activity, null /* windowState */, timeoutRecord.mReason);
             mUnresponsiveAppByDisplay.put(activity.getDisplayId(), activity);
@@ -208,6 +236,7 @@
             }
         }
         mService.mAmInternal.inputDispatchingResumed(unresponsiveApp.getPid());
+        mUnresponsiveAppByDisplay.remove(newFocus.getDisplayId());
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 3e6e06a..14a1cd0 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -218,6 +218,12 @@
         if (dcTarget == null || mImeRequester == null) {
             return false;
         }
+        // Not ready to show if there is no IME control target.
+        final InsetsControlTarget controlTarget = mDisplayContent.getImeTarget(IME_TARGET_CONTROL);
+        if (controlTarget == null) {
+            return false;
+        }
+
         ProtoLog.d(WM_DEBUG_IME, "dcTarget: %s mImeRequester: %s",
                 dcTarget.getWindow().getName(), mImeRequester.getWindow() == null
                         ? mImeRequester : mImeRequester.getWindow().getName());
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 610ce35..7860b15 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -52,6 +52,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.InputConfig;
+import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.util.ArrayMap;
@@ -77,7 +78,8 @@
     private final WindowManagerService mService;
 
     // Current input focus token for keys and other non-touch events.  May be null.
-    private IBinder mInputFocus = null;
+    IBinder mInputFocus = null;
+    long mInputFocusRequestTimeMillis = 0;
 
     // When true, need to call updateInputWindowsLw().
     private boolean mUpdateInputWindowsNeeded = true;
@@ -479,6 +481,7 @@
         }
 
         mInputFocus = focusToken;
+        mInputFocusRequestTimeMillis = SystemClock.uptimeMillis();
         mInputTransaction.setFocusedWindow(mInputFocus, windowName, mDisplayId);
         EventLog.writeEvent(LOGTAG_INPUT_FOCUS, "Focus request " + windowName,
                 "reason=UpdateInputWindows");
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 1f6690ac..f784f71 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -97,7 +97,7 @@
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.internal.util.function.pooled.PooledPredicate;
 import com.android.server.am.HostingRecord;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 75d6647..32b7532 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -2120,8 +2120,12 @@
                 Slog.w(TAG, "Failed to capture screenshot for " + wc);
                 return false;
             }
+            final boolean isDisplayRotation = wc.asDisplayContent() != null
+                    && wc.asDisplayContent().isRotationChanging();
+            // Some tests may check the name "RotationLayer" to detect display rotation.
+            final String name = isDisplayRotation ? "RotationLayer" : "transition snapshot: " + wc;
             SurfaceControl snapshotSurface = wc.makeAnimationLeash()
-                    .setName("transition snapshot: " + wc.toString())
+                    .setName(name)
                     .setOpaque(true)
                     .setParent(wc.getSurfaceControl())
                     .setSecure(screenshotBuffer.containsSecureLayers())
@@ -2131,9 +2135,8 @@
             mFrozen.add(wc);
             final ChangeInfo changeInfo = Objects.requireNonNull(mChanges.get(wc));
             changeInfo.mSnapshot = snapshotSurface;
-            if (wc.asDisplayContent() != null) {
-                // This isn't cheap, so only do it for rotations: assume display-level is rotate
-                // since most of the time it is.
+            if (isDisplayRotation) {
+                // This isn't cheap, so only do it for display rotations.
                 changeInfo.mSnapshotLuma = RotationAnimationUtils.getMedianBorderLuma(
                         screenshotBuffer.getHardwareBuffer(), screenshotBuffer.getColorSpace());
             }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 89a2809..bb6bd4a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -375,7 +375,7 @@
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.pm.UserManagerInternal.UserRestrictionsListener;
 import com.android.server.pm.UserRestrictionsUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.storage.DeviceStorageMonitorInternal;
 import com.android.server.uri.NeededUriGrants;
 import com.android.server.uri.UriGrantsManagerInternal;
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index df1d244..3ef8586a 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -60,9 +60,9 @@
 import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
 import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
 import com.android.server.LocalServices;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.testing.shadows.ShadowApplicationPackageManager;
 import com.android.server.testing.shadows.ShadowUserManager;
 import com.android.server.wm.ActivityTaskManagerInternal;
diff --git a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
index 9c0f713..f3ac7d5 100644
--- a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
+++ b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
@@ -21,14 +21,25 @@
 import android.content.Context
 import android.content.pm.ApplicationInfo
 import android.content.pm.PackageManager
-import com.android.server.pm.pkg.component.ParsedActivity
 import android.os.Binder
 import android.os.UserHandle
 import android.util.ArrayMap
-import com.android.server.pm.*
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.AppsFilterImpl
+import com.android.server.pm.PackageManagerService
+import com.android.server.pm.PackageManagerServiceInjector
+import com.android.server.pm.PackageManagerServiceTestParams
+import com.android.server.pm.PackageManagerTracedLock
+import com.android.server.pm.PackageSetting
+import com.android.server.pm.PendingPackageBroadcasts
+import com.android.server.pm.Settings
+import com.android.server.pm.SharedLibrariesImpl
+import com.android.server.pm.UserManagerInternal
+import com.android.server.pm.UserManagerService
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal
 import com.android.server.pm.parsing.pkg.PackageImpl
 import com.android.server.pm.parsing.pkg.ParsedPackage
+import com.android.server.pm.pkg.AndroidPackage
+import com.android.server.pm.pkg.component.ParsedActivity
 import com.android.server.pm.resolution.ComponentResolver
 import com.android.server.pm.snapshot.PackageDataSnapshot
 import com.android.server.pm.test.override.PackageManagerComponentLabelIconOverrideTest.Companion.Params.AppType
@@ -168,7 +179,7 @@
     lateinit var params: Params
 
     private lateinit var mockPendingBroadcasts: PendingPackageBroadcasts
-    private lateinit var mockPkg: AndroidPackage
+    private lateinit var mockPkg: AndroidPackageInternal
     private lateinit var mockPkgSetting: PackageSetting
     private lateinit var service: PackageManagerService
 
@@ -287,7 +298,7 @@
                     .apply(block)
                     .hideAsFinal()
 
-    private fun makePkgSetting(pkgName: String, pkg: AndroidPackage) =
+    private fun makePkgSetting(pkgName: String, pkg: AndroidPackageInternal) =
         PackageSetting(
             pkgName, null, File("/test"),
             null, null, null, null, 0, 0, 0, 0, null, null, null, null, null,
@@ -297,7 +308,7 @@
                 this.flags = this.flags or ApplicationInfo.FLAG_SYSTEM
             }
             this.pkgState.isUpdatedSystemApp = params.isUpdatedSystemApp
-            this.pkg = pkg
+            setPkg(pkg)
         }
 
     private fun makeTestData() {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 391dd36..5361041 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -31,8 +31,8 @@
 import android.util.SparseArray
 import android.util.SparseIntArray
 import com.android.internal.R
-import com.android.server.pm.parsing.pkg.AndroidPackage
 import com.android.server.pm.parsing.pkg.PackageImpl
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.pkg.component.ParsedActivityImpl
 import com.android.server.pm.pkg.component.ParsedApexSystemServiceImpl
 import com.android.server.pm.pkg.component.ParsedAttributionImpl
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
index 652dc38..766ab94 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
@@ -18,14 +18,15 @@
 
 import android.content.Intent
 import android.content.pm.ApplicationInfo
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
 import android.os.Build
 import android.os.PatternMatcher
 import android.util.ArraySet
 import com.android.server.SystemConfig
 import com.android.server.compat.PlatformCompat
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal
+import com.android.server.pm.pkg.AndroidPackage
+import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
 import com.android.server.pm.verify.domain.DomainVerificationCollector
 import com.android.server.testutils.mockThrowOnUnmocked
 import com.android.server.testutils.whenever
@@ -87,7 +88,7 @@
 
     @Test
     fun verifyV1NoValidIntentFilter() {
-        val pkg = mockThrowOnUnmocked<AndroidPackage> {
+        val pkg = mockThrowOnUnmocked<AndroidPackageInternal> {
             whenever(packageName) { TEST_PKG_NAME }
             whenever(targetSdkVersion) { Build.VERSION_CODES.R }
 
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
index c9601de..e4d124e 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
@@ -29,7 +29,8 @@
 import android.util.SparseArray
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.pm.Computer
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageStateInternal
 import com.android.server.pm.pkg.PackageUserStateInternal
 import com.android.server.pm.pkg.component.ParsedActivityImpl
@@ -303,7 +304,7 @@
             )
         }
 
-        fun mockPkg(packageName: String) = mockThrowOnUnmocked<AndroidPackage> {
+        fun mockPkg(packageName: String) = mockThrowOnUnmocked<AndroidPackageInternal> {
             whenever(this.packageName) { packageName }
             whenever(targetSdkVersion) { Build.VERSION_CODES.S }
             whenever(isEnabled) { true }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
index 7273b0b..c22bb53 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
@@ -29,7 +29,8 @@
 import android.os.Process
 import android.util.ArraySet
 import android.util.SparseArray
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageStateInternal
 import com.android.server.pm.pkg.PackageUserStateInternal
 import com.android.server.pm.pkg.component.ParsedActivityImpl
@@ -520,7 +521,7 @@
         pkgUserState1: PackageStateInternal.() -> PackageUserStateInternal = {
             PackageUserStateInternal.DEFAULT }
     ) = mockThrowOnUnmocked<PackageStateInternal> {
-        val pkg = mockThrowOnUnmocked<AndroidPackage> {
+        val pkg = mockThrowOnUnmocked<AndroidPackageInternal> {
             whenever(packageName) { pkgName }
             whenever(targetSdkVersion) { Build.VERSION_CODES.S }
             whenever(isEnabled) { true }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
index ed60c50..e55ff3b 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
@@ -37,7 +37,8 @@
 import android.util.SparseArray
 import android.util.Xml
 import com.android.server.pm.Computer
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageStateInternal
 import com.android.server.pm.pkg.PackageUserStateInternal
 import com.android.server.pm.pkg.component.ParsedActivityImpl
@@ -1046,7 +1047,7 @@
         otherDomains: List<String> = listOf(),
         isSystemApp: Boolean = false
     ) = mockThrowOnUnmocked<PackageStateInternal> {
-        val pkg = mockThrowOnUnmocked<AndroidPackage> {
+        val pkg = mockThrowOnUnmocked<AndroidPackageInternal> {
             whenever(packageName) { pkgName }
             whenever(targetSdkVersion) { Build.VERSION_CODES.S }
             whenever(isEnabled) { true }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt
index 0a54094..b985c04 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt
@@ -29,7 +29,7 @@
 import android.os.UserHandle
 import android.util.ArraySet
 import com.android.server.DeviceIdleInternal
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.verify.domain.DomainVerificationCollector
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
index fc20c26..427b5b3 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
@@ -19,16 +19,16 @@
 import android.content.Context
 import android.content.Intent
 import android.content.pm.PackageManager
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
-import com.android.server.pm.pkg.PackageUserStateInternal
 import android.content.pm.verify.domain.DomainVerificationState
 import android.os.Build
 import android.os.Process
 import android.util.ArraySet
 import android.util.SparseArray
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal
 import com.android.server.pm.pkg.PackageStateInternal
+import com.android.server.pm.pkg.PackageUserStateInternal
+import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
 import com.android.server.pm.verify.domain.DomainVerificationService
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy
@@ -187,7 +187,7 @@
         }
 
 
-        fun mockPkg() = mockThrowOnUnmocked<AndroidPackage> {
+        fun mockPkg() = mockThrowOnUnmocked<AndroidPackageInternal> {
             whenever(packageName) { TEST_PKG }
             whenever(targetSdkVersion) { Build.VERSION_CODES.S }
             whenever(isEnabled) { true }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
index 589633c..6bb5f39 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
@@ -18,8 +18,6 @@
 
 import android.content.Intent
 import android.content.pm.PackageManager
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
 import android.content.pm.verify.domain.DomainVerificationManager
 import android.content.pm.verify.domain.DomainVerificationState
 import android.content.pm.verify.domain.DomainVerificationUserState
@@ -28,9 +26,12 @@
 import android.os.Process
 import android.util.ArraySet
 import android.util.SparseArray
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageStateInternal
 import com.android.server.pm.pkg.PackageUserStateInternal
+import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
 import com.android.server.pm.verify.domain.DomainVerificationService
 import com.android.server.testutils.mockThrowOnUnmocked
 import com.android.server.testutils.whenever
@@ -107,7 +108,7 @@
 
     fun mockPkgState(pkgName: String, domainSetId: UUID) =
         mockThrowOnUnmocked<PackageStateInternal> {
-            val pkg = mockThrowOnUnmocked<AndroidPackage> {
+            val pkg = mockThrowOnUnmocked<AndroidPackageInternal> {
                 whenever(packageName) { pkgName }
                 whenever(targetSdkVersion) { Build.VERSION_CODES.S }
                 whenever(isEnabled) { true }
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index f9a60b6..d9c622d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -167,9 +167,9 @@
 import com.android.server.DeviceIdleInternal;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.tare.EconomyManagerInternal;
 import com.android.server.usage.AppStandbyInternal;
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index 82334f2..9acc5b9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -58,7 +58,7 @@
 
 import com.android.dx.mockito.inline.extended.StaticMockitoSession;
 import com.android.server.LocalServices;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 import org.junit.After;
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index efc1b58..bb5b1d8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -62,7 +62,7 @@
 import com.android.server.extendedtestutils.wheneverStatic
 import com.android.server.pm.dex.DexManager
 import com.android.server.pm.parsing.PackageParser2
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.parsing.pkg.PackageImpl
 import com.android.server.pm.parsing.pkg.ParsedPackage
 import com.android.server.pm.permission.PermissionManagerServiceInternal
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt
index c9b36f0..987192d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt
@@ -21,7 +21,7 @@
 import android.os.Build
 import android.os.Process
 import android.util.Log
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.testutils.whenever
 import org.hamcrest.MatcherAssert.assertThat
 import org.hamcrest.Matchers.equalTo
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
index e59a404..8744f32 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
@@ -28,7 +28,7 @@
 import com.android.server.compat.PlatformCompat
 import com.android.server.extendedtestutils.wheneverStatic
 import com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.parsing.pkg.PackageImpl
 import com.android.server.pm.parsing.pkg.ParsedPackage
 import com.android.server.testutils.any
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerInternalTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerInternalTest.java
index 86a5c90..574bab2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerInternalTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerInternalTest.java
@@ -19,6 +19,8 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 
+import static com.android.server.pm.UserManagerInternal.PARENT_DISPLAY;
+
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertThrows;
@@ -119,9 +121,6 @@
                 () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
 
         Log.v(TAG, "Exception: " + e);
-        assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
-                .matches("Cannot.*" + PROFILE_USER_ID + ".*" + SECONDARY_DISPLAY_ID
-                        + ".*parent.*current.*" + PARENT_USER_ID + ".*");
         assertNoUserAssignedToDisplay();
     }
 
@@ -136,10 +135,6 @@
                 () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
 
         Log.v(TAG, "Exception: " + e);
-        assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
-                .matches("Cannot.*" + PROFILE_USER_ID + ".*" + SECONDARY_DISPLAY_ID
-                        + ".*parent.*current.*" + PARENT_USER_ID + ".*");
-
         assertNoUserAssignedToDisplay();
     }
 
@@ -173,7 +168,7 @@
         addDefaultProfileAndParent();
 
         mUmi.assignUserToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
-        mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+        mUmi.assignUserToDisplay(PROFILE_USER_ID, PARENT_DISPLAY);
 
         assertUsersAssignedToDisplays(PARENT_USER_ID, SECONDARY_DISPLAY_ID,
                 pair(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
@@ -185,13 +180,10 @@
         addDefaultProfileAndParent();
 
         mUmi.assignUserToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
-        IllegalStateException e = assertThrows(IllegalStateException.class,
-                () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, OTHER_SECONDARY_DISPLAY_ID));
+        IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+                () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
 
         Log.v(TAG, "Exception: " + e);
-        assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
-                .matches("Cannot.*" + PROFILE_USER_ID + ".*" + OTHER_SECONDARY_DISPLAY_ID
-                        + ".*parent.*" + PARENT_USER_ID + ".*" + SECONDARY_DISPLAY_ID + ".*");
         assertUserAssignedToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java
index 991053a1..538adb2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java
@@ -267,7 +267,7 @@
         mockCurrentUser(USER_ID);
 
         assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, INVALID_DISPLAY)
-                .that(isUserVisibleOnDisplay(USER_ID, INVALID_DISPLAY)).isTrue();
+                .that(isUserVisibleOnDisplay(USER_ID, INVALID_DISPLAY)).isFalse();
     }
 
     @Test
@@ -287,6 +287,49 @@
     }
 
     @Test
+    public void testIsUserVisibleOnDisplay_mumd_currentUserUnassignedSecondaryDisplay() {
+        enableUsersOnSecondaryDisplays();
+        mockCurrentUser(USER_ID);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID)
+                .that(isUserVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID)).isTrue();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_mumd_currentUserSecondaryDisplayAssignedToAnotherUser() {
+        enableUsersOnSecondaryDisplays();
+        mockCurrentUser(USER_ID);
+        assignUserToDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID)
+                .that(isUserVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID)).isFalse();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_mumd_startedProfileOfCurrentUserSecondaryDisplayAssignedToAnotherUser() {
+        enableUsersOnSecondaryDisplays();
+        addDefaultProfileAndParent();
+        startDefaultProfile();
+        mockCurrentUser(PARENT_USER_ID);
+        assignUserToDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, SECONDARY_DISPLAY_ID)
+                .that(isUserVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID)).isFalse();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_mumd_stoppedProfileOfCurrentUserSecondaryDisplayAssignedToAnotherUser() {
+        enableUsersOnSecondaryDisplays();
+        addDefaultProfileAndParent();
+        stopDefaultProfile();
+        mockCurrentUser(PARENT_USER_ID);
+        assignUserToDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, SECONDARY_DISPLAY_ID)
+                .that(isUserVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID)).isFalse();
+    }
+
+    @Test
     public void testIsUserVisibleOnDisplay_nonCurrentUserDefaultDisplay() {
         mockCurrentUser(OTHER_USER_ID);
 
@@ -358,7 +401,7 @@
     }
 
     @Test
-    public void testIsUserVisibleOnDisplay_bgUserOnSecondaryDisplay() {
+    public void testIsUserVisibleOnDisplay_mumd_bgUserOnSecondaryDisplay() {
         enableUsersOnSecondaryDisplays();
         mockCurrentUser(OTHER_USER_ID);
         assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
@@ -367,6 +410,16 @@
                 .that(isUserVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID)).isTrue();
     }
 
+    @Test
+    public void testIsUserVisibleOnDisplay_mumd_bgUserOnAnotherSecondaryDisplay() {
+        enableUsersOnSecondaryDisplays();
+        mockCurrentUser(OTHER_USER_ID);
+        assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID)
+                .that(isUserVisibleOnDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID)).isFalse();
+    }
+
     // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as
     // isUserVisibleOnDisplay() for bg users relies only on the user / display assignments
 
@@ -535,8 +588,7 @@
     }
 
     protected final void stopDefaultProfile() {
-        // TODO(b/244798930): should set it to STATE_STOPPING or STATE_SHUTDOWN instead
-        removeUserState(PROFILE_USER_ID);
+        setUserState(PROFILE_USER_ID, UserState.STATE_STOPPING);
     }
 
     // NOTE: should only called by tests that indirectly needs to check user assignments (like
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
index 831a69a..94fff22 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
@@ -18,6 +18,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.server.tare.TareTestUtils.assertLedgersEqual;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -89,6 +90,33 @@
     }
 
     @Test
+    public void testAppRemoval() {
+        final long consumptionLimit = 1_000_000L;
+        final long remainingCakes = consumptionLimit / 2;
+        mScribe.setConsumptionLimitLocked(consumptionLimit);
+        mScribe.adjustRemainingConsumableCakesLocked(remainingCakes - consumptionLimit);
+        assertEquals(remainingCakes, mScribe.getRemainingConsumableCakesLocked());
+
+        final int userId = 0;
+        final String pkgName = "com.test";
+        final Agent agent = new Agent(mIrs, mScribe, mAnalyst);
+        final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
+
+        doReturn(consumptionLimit).when(mIrs).getConsumptionLimitLocked();
+        doReturn(consumptionLimit).when(mEconomicPolicy)
+                .getMaxSatiatedBalance(anyInt(), anyString());
+
+        Ledger.Transaction transaction = new Ledger.Transaction(0, 0, 0, null, 5, 10);
+        agent.recordTransactionLocked(userId, pkgName, ledger, transaction, false);
+        assertEquals(5, ledger.getCurrentBalance());
+        assertEquals(remainingCakes - 10, mScribe.getRemainingConsumableCakesLocked());
+
+        agent.onPackageRemovedLocked(userId, pkgName);
+        assertEquals(remainingCakes - 10, mScribe.getRemainingConsumableCakesLocked());
+        assertLedgersEqual(new Ledger(), mScribe.getLedgerLocked(userId, pkgName));
+    }
+
+    @Test
     public void testRecordTransaction_UnderMax() {
         Agent agent = new Agent(mIrs, mScribe, mAnalyst);
         Ledger ledger = new Ledger();
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
index 5cf026e..4ce268f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
@@ -18,6 +18,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.server.tare.TareTestUtils.assertLedgersEqual;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -30,7 +31,6 @@
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.SparseArrayMap;
-import android.util.SparseLongArray;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -345,43 +345,6 @@
         assertEquals(900, mScribeUnderTest.getRemainingConsumableCakesLocked());
     }
 
-    private void assertLedgersEqual(Ledger expected, Ledger actual) {
-        if (expected == null) {
-            assertNull(actual);
-            return;
-        }
-        assertNotNull(actual);
-        assertEquals(expected.getCurrentBalance(), actual.getCurrentBalance());
-
-        List<Ledger.Transaction> expectedTransactions = expected.getTransactions();
-        List<Ledger.Transaction> actualTransactions = actual.getTransactions();
-        assertEquals(expectedTransactions.size(), actualTransactions.size());
-        for (int i = 0; i < expectedTransactions.size(); ++i) {
-            assertTransactionsEqual(expectedTransactions.get(i), actualTransactions.get(i));
-        }
-
-        List<Ledger.RewardBucket> expectedRewardBuckets = expected.getRewardBuckets();
-        List<Ledger.RewardBucket> actualRewardBuckets = actual.getRewardBuckets();
-        assertEquals(expectedRewardBuckets.size(), actualRewardBuckets.size());
-        for (int i = 0; i < expectedRewardBuckets.size(); ++i) {
-            assertRewardBucketsEqual(expectedRewardBuckets.get(i), actualRewardBuckets.get(i));
-        }
-    }
-
-    private void assertSparseLongArraysEqual(SparseLongArray expected, SparseLongArray actual) {
-        if (expected == null) {
-            assertNull(actual);
-            return;
-        }
-        assertNotNull(actual);
-        final int size = expected.size();
-        assertEquals(size, actual.size());
-        for (int i = 0; i < size; ++i) {
-            assertEquals(expected.keyAt(i), actual.keyAt(i));
-            assertEquals(expected.valueAt(i), actual.valueAt(i));
-        }
-    }
-
     private void assertReportListsEqual(List<Analyst.Report> expected,
             List<Analyst.Report> actual) {
         if (expected == null) {
@@ -425,31 +388,6 @@
         }
     }
 
-    private void assertRewardBucketsEqual(Ledger.RewardBucket expected,
-            Ledger.RewardBucket actual) {
-        if (expected == null) {
-            assertNull(actual);
-            return;
-        }
-        assertNotNull(actual);
-        assertEquals(expected.startTimeMs, actual.startTimeMs);
-        assertSparseLongArraysEqual(expected.cumulativeDelta, actual.cumulativeDelta);
-    }
-
-    private void assertTransactionsEqual(Ledger.Transaction expected, Ledger.Transaction actual) {
-        if (expected == null) {
-            assertNull(actual);
-            return;
-        }
-        assertNotNull(actual);
-        assertEquals(expected.startTimeMs, actual.startTimeMs);
-        assertEquals(expected.endTimeMs, actual.endTimeMs);
-        assertEquals(expected.eventId, actual.eventId);
-        assertEquals(expected.tag, actual.tag);
-        assertEquals(expected.delta, actual.delta);
-        assertEquals(expected.ctp, actual.ctp);
-    }
-
     private void addInstalledPackage(int userId, String pkgName) {
         PackageInfo pkgInfo = new PackageInfo();
         pkgInfo.packageName = pkgName;
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/TareTestUtils.java b/services/tests/mockingservicestests/src/com/android/server/tare/TareTestUtils.java
new file mode 100644
index 0000000..1e4684b
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/TareTestUtils.java
@@ -0,0 +1,89 @@
+/*
+ * 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.server.tare;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.util.SparseLongArray;
+
+import java.util.List;
+
+public class TareTestUtils {
+    static void assertLedgersEqual(Ledger expected, Ledger actual) {
+        if (expected == null) {
+            assertNull(actual);
+            return;
+        }
+        assertNotNull(actual);
+        assertEquals(expected.getCurrentBalance(), actual.getCurrentBalance());
+
+        List<Ledger.Transaction> expectedTransactions = expected.getTransactions();
+        List<Ledger.Transaction> actualTransactions = actual.getTransactions();
+        assertEquals(expectedTransactions.size(), actualTransactions.size());
+        for (int i = 0; i < expectedTransactions.size(); ++i) {
+            assertTransactionsEqual(expectedTransactions.get(i), actualTransactions.get(i));
+        }
+
+        List<Ledger.RewardBucket> expectedRewardBuckets = expected.getRewardBuckets();
+        List<Ledger.RewardBucket> actualRewardBuckets = actual.getRewardBuckets();
+        assertEquals(expectedRewardBuckets.size(), actualRewardBuckets.size());
+        for (int i = 0; i < expectedRewardBuckets.size(); ++i) {
+            assertRewardBucketsEqual(expectedRewardBuckets.get(i), actualRewardBuckets.get(i));
+        }
+    }
+
+
+    static void assertSparseLongArraysEqual(SparseLongArray expected, SparseLongArray actual) {
+        if (expected == null) {
+            assertNull(actual);
+            return;
+        }
+        assertNotNull(actual);
+        final int size = expected.size();
+        assertEquals(size, actual.size());
+        for (int i = 0; i < size; ++i) {
+            assertEquals(expected.keyAt(i), actual.keyAt(i));
+            assertEquals(expected.valueAt(i), actual.valueAt(i));
+        }
+    }
+
+    static void assertRewardBucketsEqual(Ledger.RewardBucket expected, Ledger.RewardBucket actual) {
+        if (expected == null) {
+            assertNull(actual);
+            return;
+        }
+        assertNotNull(actual);
+        assertEquals(expected.startTimeMs, actual.startTimeMs);
+        assertSparseLongArraysEqual(expected.cumulativeDelta, actual.cumulativeDelta);
+    }
+
+    static void assertTransactionsEqual(Ledger.Transaction expected, Ledger.Transaction actual) {
+        if (expected == null) {
+            assertNull(actual);
+            return;
+        }
+        assertNotNull(actual);
+        assertEquals(expected.startTimeMs, actual.startTimeMs);
+        assertEquals(expected.endTimeMs, actual.endTimeMs);
+        assertEquals(expected.eventId, actual.eventId);
+        assertEquals(expected.tag, actual.tag);
+        assertEquals(expected.delta, actual.delta);
+        assertEquals(expected.ctp, actual.ctp);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index db12092..fe079f4 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -48,6 +48,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Matchers.any;
@@ -64,7 +65,6 @@
 import static org.mockito.Mockito.validateMockitoUsage;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -90,6 +90,7 @@
 import android.os.storage.IStorageManager;
 import android.platform.test.annotations.Presubmit;
 import android.util.Log;
+import android.view.Display;
 
 import androidx.test.filters.SmallTest;
 
@@ -177,10 +178,11 @@
             doNothing().when(mInjector).activityManagerOnUserStopped(anyInt());
             doNothing().when(mInjector).clearBroadcastQueueForUser(anyInt());
             doNothing().when(mInjector).taskSupervisorRemoveUser(anyInt());
+            mockIsUsersOnSecondaryDisplaysEnabled(false);
             // All UserController params are set to default.
             mUserController = new UserController(mInjector);
             setUpUser(TEST_USER_ID, NO_USERINFO_FLAGS);
-            setUpUser(TEST_PRE_CREATED_USER_ID, NO_USERINFO_FLAGS, /* preCreated=*/ true, null);
+            setUpUser(TEST_PRE_CREATED_USER_ID, NO_USERINFO_FLAGS, /* preCreated= */ true, null);
         });
     }
 
@@ -199,11 +201,37 @@
         verify(mInjector.getWindowManager()).setSwitchingUser(true);
         verify(mInjector).clearAllLockedTasks(anyString());
         startForegroundUserAssertions();
+        verifyUserAssignedToDisplay(TEST_USER_ID, Display.DEFAULT_DISPLAY);
     }
 
     @Test
     public void testStartUser_background() {
-        mUserController.startUser(TEST_USER_ID, false /* foreground */);
+        boolean started = mUserController.startUser(TEST_USER_ID, /* foreground= */ false);
+        assertWithMessage("startUser(%s, foreground=false)", TEST_USER_ID).that(started).isTrue();
+        verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
+        verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
+        verify(mInjector, never()).clearAllLockedTasks(anyString());
+        startBackgroundUserAssertions();
+        verifyUserAssignedToDisplay(TEST_USER_ID, Display.DEFAULT_DISPLAY);
+    }
+
+    @Test
+    public void testStartUserOnSecondaryDisplay_defaultDisplay() {
+        assertThrows(IllegalArgumentException.class, () -> mUserController
+                .startUserOnSecondaryDisplay(TEST_USER_ID, Display.DEFAULT_DISPLAY));
+
+        verifyUserNeverAssignedToDisplay();
+    }
+
+    @Test
+    public void testStartUserOnSecondaryDisplay() {
+        boolean started = mUserController.startUserOnSecondaryDisplay(TEST_USER_ID, 42);
+
+        assertWithMessage("startUserOnSecondaryDisplay(%s, %s)", TEST_USER_ID, 42).that(started)
+                .isTrue();
+        verifyUserAssignedToDisplay(TEST_USER_ID, 42);
+
+        // TODO(b/239982558): might need to change assertions
         verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
         verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
         verify(mInjector, never()).clearAllLockedTasks(anyString());
@@ -611,6 +639,7 @@
         setUpAndStartUserInBackground(TEST_USER_ID1);
         assertThrows(IllegalArgumentException.class,
                 () -> mUserController.stopProfile(TEST_USER_ID1));
+        verifyUserUnassignedFromDisplayNeverCalled(TEST_USER_ID);
     }
 
     @Test
@@ -623,13 +652,26 @@
     @Test
     public void testStartProfile() throws Exception {
         setUpAndStartProfileInBackground(TEST_USER_ID1);
+
         startBackgroundUserAssertions();
+        verifyUserAssignedToDisplay(TEST_USER_ID1, Display.DEFAULT_DISPLAY);
+    }
+
+    @Test
+    public void testStartProfile_whenUsersOnSecondaryDisplaysIsEnabled() throws Exception {
+        mockIsUsersOnSecondaryDisplaysEnabled(true);
+
+        setUpAndStartProfileInBackground(TEST_USER_ID1);
+
+        startBackgroundUserAssertions();
+        verifyUserAssignedToDisplay(TEST_USER_ID1, UserManagerInternal.PARENT_DISPLAY);
     }
 
     @Test
     public void testStopProfile() throws Exception {
         setUpAndStartProfileInBackground(TEST_USER_ID1);
         assertProfileLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* expectLocking= */ true);
+        verifyUserUnassignedFromDisplay(TEST_USER_ID1);
     }
 
     /** Tests handleIncomingUser() for a variety of permissions and situations. */
@@ -680,7 +722,7 @@
                 eq(INTERACT_ACROSS_PROFILES), anyInt(), anyInt(), any())).thenReturn(false);
 
         checkHandleIncomingUser(user1a.id, user2.id, ALLOW_NON_FULL, true);
-        checkHandleIncomingUser(user1a.id, user2.id,  ALLOW_NON_FULL_IN_PROFILE, false);
+        checkHandleIncomingUser(user1a.id, user2.id, ALLOW_NON_FULL_IN_PROFILE, false);
         checkHandleIncomingUser(user1a.id, user2.id, ALLOW_FULL_ONLY, false);
         checkHandleIncomingUser(user1a.id, user2.id, ALLOW_PROFILES_OR_NON_FULL, true);
 
@@ -876,6 +918,26 @@
         }
     }
 
+    private void mockIsUsersOnSecondaryDisplaysEnabled(boolean value) {
+        when(mInjector.isUsersOnSecondaryDisplaysEnabled()).thenReturn(value);
+    }
+
+    private void verifyUserAssignedToDisplay(@UserIdInt int userId, int displayId) {
+        verify(mInjector.getUserManagerInternal()).assignUserToDisplay(userId, displayId);
+    }
+
+    private void verifyUserNeverAssignedToDisplay() {
+        verify(mInjector.getUserManagerInternal(), never()).assignUserToDisplay(anyInt(), anyInt());
+    }
+
+    private void verifyUserUnassignedFromDisplay(@UserIdInt int userId) {
+        verify(mInjector.getUserManagerInternal()).unassignUserFromDisplay(userId);
+    }
+
+    private void verifyUserUnassignedFromDisplayNeverCalled(@UserIdInt int userId) {
+        verify(mInjector.getUserManagerInternal(), never()).unassignUserFromDisplay(userId);
+    }
+
     // Should be public to allow mocking
     private static class TestInjector extends UserController.Injector {
         public final TestHandler mHandler;
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 821ce5e..3bcde6a 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -168,13 +168,13 @@
 import com.android.internal.util.test.FsUtil;
 import com.android.server.DeviceIdleInternal;
 import com.android.server.LocalServices;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.usage.AppStandbyInternal;
 
-import com.google.common.util.concurrent.AbstractFuture;
-
 import libcore.io.Streams;
 
+import com.google.common.util.concurrent.AbstractFuture;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
index 38125c7..8f6dd5d 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
@@ -23,7 +23,7 @@
 import android.os.Process
 import android.util.ArrayMap
 import com.android.server.om.OverlayActorEnforcer.ActorState
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.testutils.mockThrowOnUnmocked
 import com.android.server.testutils.whenever
 import com.google.common.truth.Truth.assertThat
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
index b793482..301697d 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
@@ -33,13 +33,11 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.Pair;
 
 import androidx.annotation.Nullable;
 
 import com.android.internal.content.om.OverlayConfig;
-import com.android.internal.util.CollectionUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Assert;
 import org.junit.Before;
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
index 876c845..7be4921 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
@@ -17,7 +17,7 @@
 package com.android.server.om
 
 import android.net.Uri
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.testutils.mockThrowOnUnmocked
 import com.android.server.testutils.whenever
 import com.google.common.truth.Truth.assertThat
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 66c3f07..050fbea 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -93,7 +93,7 @@
 import com.android.server.LocalServices;
 import com.android.server.notification.NotificationManagerInternal;
 import com.android.server.people.PeopleService;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import com.google.common.collect.Iterables;
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index 503ca69..a7739ed 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -47,7 +47,7 @@
 
 import com.android.server.pm.parsing.PackageParser2;
 import com.android.server.pm.parsing.TestPackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java
index af3b52f..c321639 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java
@@ -47,9 +47,9 @@
 import androidx.annotation.NonNull;
 
 import com.android.server.om.OverlayReferenceMapper;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.component.ParsedActivity;
 import com.android.server.pm.pkg.component.ParsedActivityImpl;
 import com.android.server.pm.pkg.component.ParsedComponentImpl;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index b32ace5..67eeb4e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -62,11 +62,11 @@
 import com.android.server.pm.parsing.PackageInfoUtils;
 import com.android.server.pm.parsing.PackageParser2;
 import com.android.server.pm.parsing.TestPackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.pm.permission.CompatibilityPermissionInfo;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageUserStateInternal;
 import com.android.server.pm.pkg.component.ParsedActivity;
 import com.android.server.pm.pkg.component.ParsedActivityImpl;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
index 94d8358..42be3d3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -19,7 +19,8 @@
 import android.content.pm.SigningDetails;
 import android.util.SparseArray;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageUserStateImpl;
 
 import java.io.File;
@@ -166,7 +167,7 @@
         packageSetting.setSignatures(mSigningDetails != null
                 ? new PackageSignatures(mSigningDetails)
                 : new PackageSignatures());
-        packageSetting.setPkg(mPkg);
+        packageSetting.setPkg((ParsedPackage) mPkg);
         packageSetting.setAppId(mAppId);
         packageSetting.setVolumeUuid(this.mVolumeUuid);
         if (mInstallSource != null) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
index 901b200..eb91671 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
@@ -26,9 +26,9 @@
 import android.platform.test.annotations.Presubmit;
 
 import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
index 9962a3c..1c3673e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
@@ -20,8 +20,8 @@
 import android.annotation.Nullable;
 import android.os.UserHandle;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 class ScanRequestBuilder {
     private final ParsedPackage mPkg;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index 8e53ca1..084f4f1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -43,8 +43,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.SharedLibraryInfo;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
 import android.content.res.TypedArray;
 import android.os.Environment;
 import android.os.UserHandle;
@@ -53,9 +51,11 @@
 
 import com.android.server.compat.PlatformCompat;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
 
 import org.hamcrest.BaseMatcher;
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index ba7a103..b7729bb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -55,9 +55,9 @@
 
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
index b7b55ba..b2843d8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
@@ -39,9 +39,9 @@
 import com.android.frameworks.servicestests.R;
 import com.android.server.pm.PackageManagerException;
 import com.android.server.pm.parsing.TestPackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Assert;
 import org.junit.Before;
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
index 7c8bbec..ad9f920 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
@@ -23,16 +23,16 @@
 import static org.junit.Assert.fail;
 
 import android.content.pm.SharedLibraryInfo;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
 import android.platform.test.annotations.Presubmit;
 import android.util.SparseArray;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
 
 import dalvik.system.DelegateLastClassLoader;
 import dalvik.system.DexClassLoader;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index f013ecc..9cd97ff3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -46,14 +46,13 @@
 import com.android.frameworks.servicestests.R;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.pm.PackageManagerException;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.component.ParsedActivityUtils;
 import com.android.server.pm.pkg.component.ParsedComponent;
 import com.android.server.pm.pkg.component.ParsedIntentInfo;
 import com.android.server.pm.pkg.component.ParsedPermission;
 import com.android.server.pm.pkg.component.ParsedPermissionUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 
 import com.google.common.truth.Expect;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
index 6b60042..d3107b0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
@@ -24,9 +24,9 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
index 70d85b6..36308d2 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
@@ -21,9 +21,9 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
index f536052..3782f5d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
@@ -23,9 +23,9 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
index 77197e3..a739607 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
@@ -25,9 +25,9 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.server.pm.parsing.library.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java
index 0b144dc..3977d0d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java
@@ -23,9 +23,9 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.server.SystemConfig;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java
index 404f29c..a31c781 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java
@@ -21,9 +21,9 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
index 95b8d3f..f5e3f4e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
@@ -23,9 +23,9 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
index b28446b..b3648b1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
@@ -23,16 +23,16 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import com.android.server.pm.pkg.parsing.ParsingPackage;
 import android.os.Build;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
 
 import org.junit.Assume;
 import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
index a71572f..2450a14 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
@@ -18,8 +18,8 @@
 
 import static org.junit.Assert.assertEquals;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.function.Supplier;
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
index 1122490..2825c69 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
@@ -24,9 +24,9 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
index 3cc8475..c0da8a7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
@@ -24,9 +24,9 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java
index 6402e12..3f550d0 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java
@@ -16,15 +16,18 @@
 
 package com.android.server.timedetector;
 
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyLong;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 import android.app.AlarmManager;
+import android.app.AlarmManager.OnAlarmListener;
 import android.content.Context;
 import android.location.Location;
 import android.location.LocationListener;
@@ -36,9 +39,6 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.server.LocalServices;
-
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -64,19 +64,13 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        when(mMockLocationManager.hasProvider(LocationManager.GPS_PROVIDER))
-                .thenReturn(true);
+        installGpsProviderInMockLocationManager();
 
         mGnssTimeUpdateService = new GnssTimeUpdateService(
                 mMockContext, mMockAlarmManager, mMockLocationManager, mMockLocationManagerInternal,
                 mMockTimeDetectorInternal);
     }
 
-    @After
-    public void tearDown() {
-        LocalServices.removeServiceForTest(LocationManagerInternal.class);
-    }
-
     @Test
     public void testLocationListenerOnLocationChanged_validLocationTime_suggestsGnssTime() {
         TimestampedValue<Long> timeSignal = new TimestampedValue<>(
@@ -85,9 +79,9 @@
         LocationTime locationTime = new LocationTime(GNSS_TIME, ELAPSED_REALTIME_NS);
         doReturn(locationTime).when(mMockLocationManagerInternal).getGnssTimeMillis();
 
-        mGnssTimeUpdateService.requestGnssTimeUpdates();
+        assertTrue(mGnssTimeUpdateService.startGnssListeningInternal());
 
-        ArgumentCaptor<LocationListener> argumentCaptor =
+        ArgumentCaptor<LocationListener> locationListenerCaptor =
                 ArgumentCaptor.forClass(LocationListener.class);
         verify(mMockLocationManager).requestLocationUpdates(
                 eq(LocationManager.GPS_PROVIDER),
@@ -95,8 +89,8 @@
                     .setMinUpdateIntervalMillis(0)
                     .build()),
                 any(),
-                argumentCaptor.capture());
-        LocationListener locationListener = argumentCaptor.getValue();
+                locationListenerCaptor.capture());
+        LocationListener locationListener = locationListenerCaptor.getValue();
         Location location = new Location(LocationManager.GPS_PROVIDER);
 
         locationListener.onLocationChanged(location);
@@ -115,9 +109,9 @@
     public void testLocationListenerOnLocationChanged_nullLocationTime_doesNotSuggestGnssTime() {
         doReturn(null).when(mMockLocationManagerInternal).getGnssTimeMillis();
 
-        mGnssTimeUpdateService.requestGnssTimeUpdates();
+        assertTrue(mGnssTimeUpdateService.startGnssListeningInternal());
 
-        ArgumentCaptor<LocationListener> argumentCaptor =
+        ArgumentCaptor<LocationListener> locationListenerCaptor =
                 ArgumentCaptor.forClass(LocationListener.class);
         verify(mMockLocationManager).requestLocationUpdates(
                 eq(LocationManager.GPS_PROVIDER),
@@ -125,14 +119,14 @@
                     .setMinUpdateIntervalMillis(0)
                     .build()),
                 any(),
-                argumentCaptor.capture());
-        LocationListener locationListener = argumentCaptor.getValue();
+                locationListenerCaptor.capture());
+        LocationListener locationListener = locationListenerCaptor.getValue();
         Location location = new Location(LocationManager.GPS_PROVIDER);
 
         locationListener.onLocationChanged(location);
 
         verify(mMockLocationManager).removeUpdates(locationListener);
-        verify(mMockTimeDetectorInternal, never()).suggestGnssTime(any());
+        verifyZeroInteractions(mMockTimeDetectorInternal);
         verify(mMockAlarmManager).set(
                 eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
                 anyLong(),
@@ -140,4 +134,90 @@
                 any(),
                 any());
     }
+
+    @Test
+    public void testLocationListeningRestartsAfterSleep() {
+        ArgumentCaptor<LocationListener> locationListenerCaptor =
+                ArgumentCaptor.forClass(LocationListener.class);
+        ArgumentCaptor<OnAlarmListener> alarmListenerCaptor =
+                ArgumentCaptor.forClass(OnAlarmListener.class);
+
+        advanceServiceToSleepingState(locationListenerCaptor, alarmListenerCaptor);
+
+        // Simulate the alarm manager's wake-up call.
+        OnAlarmListener wakeUpListener = alarmListenerCaptor.getValue();
+        wakeUpListener.onAlarm();
+
+        // Verify the service returned to location listening.
+        verify(mMockLocationManager).requestLocationUpdates(any(), any(), any(), any());
+        verifyZeroInteractions(mMockAlarmManager, mMockTimeDetectorInternal);
+    }
+
+    // Tests what happens when a call is made to startGnssListeningInternal() when service is
+    // sleeping. This can happen when the start_gnss_listening shell command is used.
+    @Test
+    public void testStartGnssListeningInternalCalledWhenSleeping() {
+        ArgumentCaptor<LocationListener> locationListenerCaptor =
+                ArgumentCaptor.forClass(LocationListener.class);
+        ArgumentCaptor<OnAlarmListener> alarmListenerCaptor =
+                ArgumentCaptor.forClass(OnAlarmListener.class);
+
+        advanceServiceToSleepingState(locationListenerCaptor, alarmListenerCaptor);
+
+        // Call startGnssListeningInternal(), as can happen if the start_gnss_listening shell
+        // command is used.
+        assertTrue(mGnssTimeUpdateService.startGnssListeningInternal());
+
+        // Verify the alarm manager is told to stopped sleeping and the location manager is
+        // listening again.
+        verify(mMockAlarmManager).cancel(alarmListenerCaptor.getValue());
+        verify(mMockLocationManager).requestLocationUpdates(any(), any(), any(), any());
+        verifyZeroInteractions(mMockTimeDetectorInternal);
+    }
+
+    private void advanceServiceToSleepingState(
+            ArgumentCaptor<LocationListener> locationListenerCaptor,
+            ArgumentCaptor<OnAlarmListener> alarmListenerCaptor) {
+        TimestampedValue<Long> timeSignal = new TimestampedValue<>(
+                ELAPSED_REALTIME_MS, GNSS_TIME);
+        GnssTimeSuggestion timeSuggestion = new GnssTimeSuggestion(timeSignal);
+        LocationTime locationTime = new LocationTime(GNSS_TIME, ELAPSED_REALTIME_NS);
+        doReturn(locationTime).when(mMockLocationManagerInternal).getGnssTimeMillis();
+
+        assertTrue(mGnssTimeUpdateService.startGnssListeningInternal());
+
+        verify(mMockLocationManager).requestLocationUpdates(
+                any(), any(), any(), locationListenerCaptor.capture());
+        LocationListener locationListener = locationListenerCaptor.getValue();
+        Location location = new Location(LocationManager.GPS_PROVIDER);
+        verifyZeroInteractions(mMockAlarmManager, mMockTimeDetectorInternal);
+
+        locationListener.onLocationChanged(location);
+
+        verify(mMockLocationManager).removeUpdates(locationListener);
+        verify(mMockTimeDetectorInternal).suggestGnssTime(timeSuggestion);
+
+        // Verify the service is now "sleeping", i.e. waiting for a period before listening for
+        // GNSS locations again.
+        verify(mMockAlarmManager).set(
+                eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+                anyLong(),
+                any(),
+                alarmListenerCaptor.capture(),
+                any());
+
+        // Reset mocks making it easier to verify the calls that follow.
+        reset(mMockAlarmManager, mMockTimeDetectorInternal, mMockLocationManager,
+                mMockLocationManagerInternal);
+        installGpsProviderInMockLocationManager();
+    }
+
+    /**
+     * Configures the mock response to ensure {@code
+     * locationManager.hasProvider(LocationManager.GPS_PROVIDER) == true }
+     */
+    private void installGpsProviderInMockLocationManager() {
+        when(mMockLocationManager.hasProvider(LocationManager.GPS_PROVIDER))
+                .thenReturn(true);
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 2204ae3..85e5bfd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -102,7 +102,7 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
 import com.android.server.wm.utils.MockTracker;
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
index ca8481a..c839d12 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
@@ -63,6 +63,7 @@
     public void testInputMethodInputTargetCanShowIme() {
         WindowState target = createWindow(null, TYPE_APPLICATION, "app");
         mDisplayContent.setImeLayeringTarget(target);
+        mDisplayContent.updateImeInputAndControlTarget(target);
         mImeProvider.scheduleShowImePostLayout(target);
         assertTrue(mImeProvider.isReadyToShowIme());
     }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
index c41c659..5f025f9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
@@ -76,7 +76,7 @@
     }
 
     /** {@inheritDoc} */
-    @Postsubmit
+    @Presubmit
     @Test
     override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt
index 1af8820..f4d8f5b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt
@@ -130,6 +130,7 @@
     @Presubmit
     @Test
     fun navBarLayerIsInvisibleInLandscapeGestural() {
+        Assume.assumeFalse(testSpec.isTablet)
         Assume.assumeTrue(testSpec.isLandscapeOrSeascapeAtStart)
         Assume.assumeTrue(testSpec.isGesturalNavigation)
         Assume.assumeTrue(isShellTransitionsEnabled)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
index 24f2ae9..8d349a6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
@@ -24,7 +24,6 @@
 import com.android.server.wm.flicker.annotation.Group1
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import org.junit.FixMethodOrder
-import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
@@ -59,91 +58,6 @@
             }
         }
 
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun statusBarLayerIsVisibleAtStartAndEnd() =
-        super.statusBarLayerIsVisibleAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun entireScreenCovered() = super.entireScreenCovered()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun notificationAppWindowVisibleAtEnd() = super.notificationAppWindowVisibleAtEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun notificationAppWindowOnTopAtEnd() = super.notificationAppWindowOnTopAtEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun notificationAppLayerVisibleAtEnd() = super.notificationAppLayerVisibleAtEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun appWindowBecomesTopWindow() = super.appWindowBecomesTopWindow()
-
-    /** {@inheritDoc} */
-    @Test
-    @Postsubmit
-    override fun appWindowBecomesVisible() = appWindowBecomesVisible_coldStart()
-
-    /** {@inheritDoc} */
-    @Test
-    @Postsubmit
-    override fun appLayerBecomesVisible() = appLayerBecomesVisible_coldStart()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun appWindowIsTopWindowAtEnd() =
-        super.appWindowIsTopWindowAtEnd()
-
     companion object {
         /**
          * Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index d09507f..f24f71e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -127,12 +127,6 @@
     override fun navBarLayerPositionAtStartAndEnd() =
         super.navBarLayerPositionAtStartAndEnd()
 
-    /** {@inheritDoc} */
-    @FlakyTest
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
     companion object {
         /**
          * Creates the test configurations.
diff --git a/tools/codegen/BUILD.bazel b/tools/codegen/BUILD.bazel
new file mode 100644
index 0000000..c14046d
--- /dev/null
+++ b/tools/codegen/BUILD.bazel
@@ -0,0 +1,21 @@
+# TODO(b/245731902): auto-generate these with bp2build.
+load("@rules_kotlin//kotlin:jvm_library.bzl", "kt_jvm_library")
+
+java_binary(
+    name = "codegen_cli",
+    main_class = "com.android.codegen.MainKt",
+    runtime_deps = [
+        ":codegen_cli_kt_lib",
+    ],
+)
+
+kt_jvm_library(
+    name = "codegen_cli_kt_lib",
+    srcs = glob(["src/**/*.kt"]),
+    deps = ["//external/javaparser"],
+)
+
+kt_jvm_library(
+    name = "codegen-version-info",
+    srcs = glob(["src/**/SharedConstants.kt"]),
+)