Merge "[SettingsProvider] perf test for null settings" into udc-dev
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 4caaa09..79a2659 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -79,6 +79,9 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
+import android.telephony.TelephonyCallback;
+import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
@@ -146,15 +149,17 @@
        label="deep";
 
        STATE_ACTIVE [
-         label="STATE_ACTIVE\nScreen on OR Charging OR Alarm going off soon",
+         label="STATE_ACTIVE\nScreen on OR charging OR alarm going off soon\n"
+             + "OR active emergency call",
          color=black,shape=diamond
        ]
        STATE_INACTIVE [
-         label="STATE_INACTIVE\nScreen off AND Not charging",color=black,shape=diamond
+         label="STATE_INACTIVE\nScreen off AND not charging AND no active emergency call",
+         color=black,shape=diamond
        ]
        STATE_QUICK_DOZE_DELAY [
          label="STATE_QUICK_DOZE_DELAY\n"
-             + "Screen off AND Not charging\n"
+             + "Screen off AND not charging AND no active emergency call\n"
              + "Location, motion detection, and significant motion monitoring turned off",
          color=black,shape=diamond
        ]
@@ -237,11 +242,12 @@
        label="light"
 
        LIGHT_STATE_ACTIVE [
-         label="LIGHT_STATE_ACTIVE\nScreen on OR Charging OR Alarm going off soon",
+         label="LIGHT_STATE_ACTIVE\n"
+             + "Screen on OR charging OR alarm going off soon OR active emergency call",
          color=black,shape=diamond
        ]
        LIGHT_STATE_INACTIVE [
-         label="LIGHT_STATE_INACTIVE\nScreen off AND Not charging",
+         label="LIGHT_STATE_INACTIVE\nScreen off AND not charging AND no active emergency call",
          color=black,shape=diamond
        ]
        LIGHT_STATE_IDLE [label="LIGHT_STATE_IDLE\n",color=red,shape=box]
@@ -411,6 +417,7 @@
     private static final int ACTIVE_REASON_FROM_BINDER_CALL = 5;
     private static final int ACTIVE_REASON_FORCED = 6;
     private static final int ACTIVE_REASON_ALARM = 7;
+    private static final int ACTIVE_REASON_EMERGENCY_CALL = 8;
     @VisibleForTesting
     static final int SET_IDLE_FACTOR_RESULT_UNINIT = -1;
     @VisibleForTesting
@@ -765,6 +772,8 @@
         }
     };
 
+    private final EmergencyCallListener mEmergencyCallListener = new EmergencyCallListener();
+
     /** Post stationary status only to this listener. */
     private void postStationaryStatus(DeviceIdleInternal.StationaryListener listener) {
         mHandler.obtainMessage(MSG_REPORT_STATIONARY_STATUS, listener).sendToTarget();
@@ -2323,6 +2332,39 @@
         }
     }
 
+    private class EmergencyCallListener extends TelephonyCallback implements
+            TelephonyCallback.OutgoingEmergencyCallListener,
+            TelephonyCallback.CallStateListener {
+        private volatile boolean mIsEmergencyCallActive;
+
+        @Override
+        public void onOutgoingEmergencyCall(EmergencyNumber placedEmergencyNumber,
+                int subscriptionId) {
+            mIsEmergencyCallActive = true;
+            if (DEBUG) Slog.d(TAG, "onOutgoingEmergencyCall(): subId = " + subscriptionId);
+            synchronized (DeviceIdleController.this) {
+                mActiveReason = ACTIVE_REASON_EMERGENCY_CALL;
+                becomeActiveLocked("emergency call", Process.myUid());
+            }
+        }
+
+        @Override
+        public void onCallStateChanged(int state) {
+            if (DEBUG) Slog.d(TAG, "onCallStateChanged(): state is " + state);
+            // An emergency call just finished
+            if (state == TelephonyManager.CALL_STATE_IDLE && mIsEmergencyCallActive) {
+                mIsEmergencyCallActive = false;
+                synchronized (DeviceIdleController.this) {
+                    becomeInactiveIfAppropriateLocked();
+                }
+            }
+        }
+
+        boolean isEmergencyCallActive() {
+            return mIsEmergencyCallActive;
+        }
+    }
+
     static class Injector {
         private final Context mContext;
         private ConnectivityManager mConnectivityManager;
@@ -2406,6 +2448,10 @@
             return mContext.getSystemService(SensorManager.class);
         }
 
+        TelephonyManager getTelephonyManager() {
+            return mContext.getSystemService(TelephonyManager.class);
+        }
+
         ConstraintController getConstraintController(Handler handler,
                 DeviceIdleInternal localService) {
             if (mContext.getPackageManager()
@@ -2634,6 +2680,9 @@
 
                 mLocalActivityTaskManager.registerScreenObserver(mScreenObserver);
 
+                mInjector.getTelephonyManager().registerTelephonyCallback(
+                        JobSchedulerBackgroundThread.getExecutor(), mEmergencyCallListener);
+
                 passWhiteListsToForceAppStandbyTrackerLocked();
                 updateInteractivityLocked();
             }
@@ -3435,6 +3484,7 @@
 
         final boolean isScreenBlockingInactive =
                 mScreenOn && (!mConstants.WAIT_FOR_UNLOCK || !mScreenLocked);
+        final boolean isEmergencyCallActive = mEmergencyCallListener.isEmergencyCallActive();
         if (DEBUG) {
             Slog.d(TAG, "becomeInactiveIfAppropriateLocked():"
                     + " isScreenBlockingInactive=" + isScreenBlockingInactive
@@ -3442,10 +3492,11 @@
                     + ", WAIT_FOR_UNLOCK=" + mConstants.WAIT_FOR_UNLOCK
                     + ", mScreenLocked=" + mScreenLocked + ")"
                     + " mCharging=" + mCharging
+                    + " emergencyCall=" + isEmergencyCallActive
                     + " mForceIdle=" + mForceIdle
             );
         }
-        if (!mForceIdle && (mCharging || isScreenBlockingInactive)) {
+        if (!mForceIdle && (mCharging || isScreenBlockingInactive || isEmergencyCallActive)) {
             return;
         }
         // Become inactive and determine if we will ultimately go idle.
@@ -3568,6 +3619,17 @@
         }
         EventLogTags.writeDeviceIdleLightStep();
 
+        if (mEmergencyCallListener.isEmergencyCallActive()) {
+            // The emergency call should have raised the state to ACTIVE and kept it there,
+            // so this method shouldn't be called. Don't proceed further.
+            Slog.wtf(TAG, "stepLightIdleStateLocked called when emergency call is active");
+            if (mLightState != LIGHT_STATE_ACTIVE) {
+                mActiveReason = ACTIVE_REASON_EMERGENCY_CALL;
+                becomeActiveLocked("emergency", Process.myUid());
+            }
+            return;
+        }
+
         switch (mLightState) {
             case LIGHT_STATE_INACTIVE:
                 mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
@@ -3650,6 +3712,17 @@
         if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState);
         EventLogTags.writeDeviceIdleStep();
 
+        if (mEmergencyCallListener.isEmergencyCallActive()) {
+            // The emergency call should have raised the state to ACTIVE and kept it there,
+            // so this method shouldn't be called. Don't proceed further.
+            Slog.wtf(TAG, "stepIdleStateLocked called when emergency call is active");
+            if (mState != STATE_ACTIVE) {
+                mActiveReason = ACTIVE_REASON_EMERGENCY_CALL;
+                becomeActiveLocked("emergency", Process.myUid());
+            }
+            return;
+        }
+
         if (isUpcomingAlarmClock()) {
             // Whoops, there is an upcoming alarm.  We don't actually want to go idle.
             if (mState != STATE_ACTIVE) {
@@ -3984,6 +4057,11 @@
         }
     }
 
+    @VisibleForTesting
+    boolean isEmergencyCallActive() {
+        return mEmergencyCallListener.isEmergencyCallActive();
+    }
+
     @GuardedBy("this")
     boolean isOpsInactiveLocked() {
         return mActiveIdleOpCount <= 0 && !mJobsActive && !mAlarmsActive;
diff --git a/core/api/current.txt b/core/api/current.txt
index 0536947..6d89717 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -375,7 +375,7 @@
   public static final class R.attr {
     ctor public R.attr();
     field public static final int absListViewStyle = 16842858; // 0x101006a
-    field public static final int accessibilityDataPrivate;
+    field public static final int accessibilityDataSensitive;
     field public static final int accessibilityEventTypes = 16843648; // 0x1010380
     field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
     field public static final int accessibilityFlags = 16843652; // 0x1010384
@@ -13594,12 +13594,11 @@
   }
 
   public static final class CreateCredentialRequest.Builder {
-    ctor public CreateCredentialRequest.Builder(@NonNull android.os.Bundle, @NonNull android.os.Bundle);
+    ctor public CreateCredentialRequest.Builder(@NonNull String, @NonNull android.os.Bundle, @NonNull android.os.Bundle);
     method @NonNull public android.credentials.CreateCredentialRequest build();
     method @NonNull public android.credentials.CreateCredentialRequest.Builder setAlwaysSendAppInfoToProvider(boolean);
     method @NonNull public android.credentials.CreateCredentialRequest.Builder setIsSystemProviderRequired(boolean);
     method @NonNull @RequiresPermission(android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN) public android.credentials.CreateCredentialRequest.Builder setOrigin(@NonNull String);
-    method @NonNull public android.credentials.CreateCredentialRequest.Builder setType(@NonNull String);
   }
 
   public final class CreateCredentialResponse implements android.os.Parcelable {
@@ -33834,6 +33833,7 @@
     method public android.os.Bundle getUserRestrictions();
     method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public android.os.Bundle getUserRestrictions(android.os.UserHandle);
     method public boolean hasUserRestriction(String);
+    method public boolean isAdminUser();
     method public boolean isDemoUser();
     method public static boolean isHeadlessSystemUserMode();
     method public boolean isManagedProfile();
@@ -39861,6 +39861,7 @@
     field public static final int TYPE_DATASET_AUTHENTICATION_SELECTED = 1; // 0x1
     field public static final int TYPE_DATASET_SELECTED = 0; // 0x0
     field public static final int TYPE_SAVE_SHOWN = 3; // 0x3
+    field public static final int TYPE_VIEW_REQUESTED_AUTOFILL = 6; // 0x6
     field public static final int UI_TYPE_DIALOG = 3; // 0x3
     field public static final int UI_TYPE_INLINE = 2; // 0x2
     field public static final int UI_TYPE_MENU = 1; // 0x1
@@ -40537,7 +40538,7 @@
     ctor public BeginCreateCredentialResponse();
     method public int describeContents();
     method @NonNull public java.util.List<android.service.credentials.CreateEntry> getCreateEntries();
-    method @Nullable public android.service.credentials.CreateEntry getRemoteCreateEntry();
+    method @Nullable public android.service.credentials.RemoteEntry getRemoteCreateEntry();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.BeginCreateCredentialResponse> CREATOR;
   }
@@ -40547,7 +40548,7 @@
     method @NonNull public android.service.credentials.BeginCreateCredentialResponse.Builder addCreateEntry(@NonNull android.service.credentials.CreateEntry);
     method @NonNull public android.service.credentials.BeginCreateCredentialResponse build();
     method @NonNull public android.service.credentials.BeginCreateCredentialResponse.Builder setCreateEntries(@NonNull java.util.List<android.service.credentials.CreateEntry>);
-    method @NonNull public android.service.credentials.BeginCreateCredentialResponse.Builder setRemoteCreateEntry(@Nullable android.service.credentials.CreateEntry);
+    method @NonNull public android.service.credentials.BeginCreateCredentialResponse.Builder setRemoteCreateEntry(@Nullable android.service.credentials.RemoteEntry);
   }
 
   public class BeginGetCredentialOption implements android.os.Parcelable {
@@ -40582,7 +40583,7 @@
     method @NonNull public java.util.List<android.service.credentials.Action> getActions();
     method @NonNull public java.util.List<android.service.credentials.Action> getAuthenticationActions();
     method @NonNull public java.util.List<android.service.credentials.CredentialEntry> getCredentialEntries();
-    method @Nullable public android.service.credentials.CredentialEntry getRemoteCredentialEntry();
+    method @Nullable public android.service.credentials.RemoteEntry getRemoteCredentialEntry();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.BeginGetCredentialResponse> CREATOR;
   }
@@ -40596,7 +40597,7 @@
     method @NonNull public android.service.credentials.BeginGetCredentialResponse.Builder setActions(@NonNull java.util.List<android.service.credentials.Action>);
     method @NonNull public android.service.credentials.BeginGetCredentialResponse.Builder setAuthenticationActions(@NonNull java.util.List<android.service.credentials.Action>);
     method @NonNull public android.service.credentials.BeginGetCredentialResponse.Builder setCredentialEntries(@NonNull java.util.List<android.service.credentials.CredentialEntry>);
-    method @NonNull public android.service.credentials.BeginGetCredentialResponse.Builder setRemoteCredentialEntry(@Nullable android.service.credentials.CredentialEntry);
+    method @NonNull public android.service.credentials.BeginGetCredentialResponse.Builder setRemoteCredentialEntry(@Nullable android.service.credentials.RemoteEntry);
   }
 
   public final class CallingAppInfo implements android.os.Parcelable {
@@ -40666,14 +40667,22 @@
   }
 
   public final class GetCredentialRequest implements android.os.Parcelable {
-    ctor public GetCredentialRequest(@NonNull android.service.credentials.CallingAppInfo, @NonNull android.credentials.CredentialOption);
+    ctor public GetCredentialRequest(@NonNull android.service.credentials.CallingAppInfo, @NonNull java.util.List<android.credentials.CredentialOption>);
     method public int describeContents();
     method @NonNull public android.service.credentials.CallingAppInfo getCallingAppInfo();
-    method @NonNull public android.credentials.CredentialOption getCredentialOption();
+    method @NonNull public java.util.List<android.credentials.CredentialOption> getCredentialOptions();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.GetCredentialRequest> CREATOR;
   }
 
+  public class RemoteEntry implements android.os.Parcelable {
+    ctor public RemoteEntry(@NonNull android.app.slice.Slice);
+    method public int describeContents();
+    method @NonNull public android.app.slice.Slice getSlice();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.RemoteEntry> CREATOR;
+  }
+
 }
 
 package android.service.dreams {
@@ -52022,8 +52031,8 @@
     method @Nullable public CharSequence getAccessibilityPaneTitle();
     method @IdRes public int getAccessibilityTraversalAfter();
     method @IdRes public int getAccessibilityTraversalBefore();
-    method @NonNull public String getAllowedHandwritingDelegatePackageName();
-    method @NonNull public String getAllowedHandwritingDelegatorPackageName();
+    method @Nullable public String getAllowedHandwritingDelegatePackageName();
+    method @Nullable public String getAllowedHandwritingDelegatorPackageName();
     method public float getAlpha();
     method public android.view.animation.Animation getAnimation();
     method @Nullable public android.graphics.Matrix getAnimationMatrix();
@@ -52217,7 +52226,7 @@
     method public void invalidate();
     method public void invalidateDrawable(@NonNull android.graphics.drawable.Drawable);
     method public void invalidateOutline();
-    method public boolean isAccessibilityDataPrivate();
+    method public boolean isAccessibilityDataSensitive();
     method public boolean isAccessibilityFocused();
     method public boolean isAccessibilityHeading();
     method public boolean isActivated();
@@ -52397,7 +52406,7 @@
     method public void scrollTo(int, int);
     method public void sendAccessibilityEvent(int);
     method public void sendAccessibilityEventUnchecked(android.view.accessibility.AccessibilityEvent);
-    method public void setAccessibilityDataPrivate(int);
+    method public void setAccessibilityDataSensitive(int);
     method public void setAccessibilityDelegate(@Nullable android.view.View.AccessibilityDelegate);
     method public void setAccessibilityHeading(boolean);
     method public void setAccessibilityLiveRegion(int);
@@ -52406,8 +52415,8 @@
     method public void setAccessibilityTraversalBefore(@IdRes int);
     method public void setActivated(boolean);
     method public void setAllowClickWhenDisabled(boolean);
-    method public void setAllowedHandwritingDelegatePackage(@NonNull String);
-    method public void setAllowedHandwritingDelegatorPackage(@NonNull String);
+    method public void setAllowedHandwritingDelegatePackage(@Nullable String);
+    method public void setAllowedHandwritingDelegatorPackage(@Nullable String);
     method public void setAlpha(@FloatRange(from=0.0, to=1.0) float);
     method public void setAnimation(android.view.animation.Animation);
     method public void setAnimationMatrix(@Nullable android.graphics.Matrix);
@@ -52583,9 +52592,9 @@
     method @CallSuper protected boolean verifyDrawable(@NonNull android.graphics.drawable.Drawable);
     method @Deprecated public boolean willNotCacheDrawing();
     method public boolean willNotDraw();
-    field public static final int ACCESSIBILITY_DATA_PRIVATE_AUTO = 0; // 0x0
-    field public static final int ACCESSIBILITY_DATA_PRIVATE_NO = 2; // 0x2
-    field public static final int ACCESSIBILITY_DATA_PRIVATE_YES = 1; // 0x1
+    field public static final int ACCESSIBILITY_DATA_SENSITIVE_AUTO = 0; // 0x0
+    field public static final int ACCESSIBILITY_DATA_SENSITIVE_NO = 2; // 0x2
+    field public static final int ACCESSIBILITY_DATA_SENSITIVE_YES = 1; // 0x1
     field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2
     field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
     field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
@@ -54055,11 +54064,11 @@
     method public int getSpeechStateChangeTypes();
     method public int getWindowChanges();
     method public void initFromParcel(android.os.Parcel);
-    method public boolean isAccessibilityDataPrivate();
+    method public boolean isAccessibilityDataSensitive();
     method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(int);
     method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(android.view.accessibility.AccessibilityEvent);
     method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain();
-    method public void setAccessibilityDataPrivate(boolean);
+    method public void setAccessibilityDataSensitive(boolean);
     method public void setAction(int);
     method public void setContentChangeTypes(int);
     method public void setEventTime(long);
@@ -54250,6 +54259,7 @@
     method public int getWindowId();
     method public boolean hasRequestInitialAccessibilityFocus();
     method public boolean hasRequestTouchPassthrough();
+    method public boolean isAccessibilityDataSensitive();
     method public boolean isAccessibilityFocused();
     method public boolean isCheckable();
     method public boolean isChecked();
@@ -54286,6 +54296,7 @@
     method public boolean removeAction(android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction);
     method public boolean removeChild(android.view.View);
     method public boolean removeChild(android.view.View, int);
+    method public void setAccessibilityDataSensitive(boolean);
     method public void setAccessibilityFocused(boolean);
     method public void setAvailableExtraData(java.util.List<java.lang.String>);
     method @Deprecated public void setBoundsInParent(android.graphics.Rect);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 9bab8cd..8a6faa1 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3247,7 +3247,6 @@
     method @NonNull public java.util.Set<android.content.ComponentName> getBlockedCrossTaskNavigations();
     method public int getDefaultActivityPolicy();
     method public int getDefaultNavigationPolicy();
-    method public int getDefaultRecentsPolicy();
     method public int getDevicePolicy(int);
     method public int getLockState();
     method @Nullable public String getName();
@@ -3264,8 +3263,8 @@
     field public static final int NAVIGATION_POLICY_DEFAULT_ALLOWED = 0; // 0x0
     field public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1; // 0x1
     field public static final int POLICY_TYPE_AUDIO = 1; // 0x1
+    field public static final int POLICY_TYPE_RECENTS = 2; // 0x2
     field public static final int POLICY_TYPE_SENSORS = 0; // 0x0
-    field public static final int RECENTS_POLICY_ALLOW_IN_HOST_DEVICE_RECENTS = 1; // 0x1
   }
 
   public static final class VirtualDeviceParams.Builder {
@@ -3278,7 +3277,6 @@
     method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setAudioRecordingSessionId(int);
     method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedActivities(@NonNull java.util.Set<android.content.ComponentName>);
     method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedCrossTaskNavigations(@NonNull java.util.Set<android.content.ComponentName>);
-    method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setDefaultRecentsPolicy(int);
     method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setDevicePolicy(int, int);
     method @NonNull @RequiresPermission(value=android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY, conditional=true) public android.companion.virtual.VirtualDeviceParams.Builder setLockState(int);
     method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setName(@NonNull String);
@@ -9123,8 +9121,7 @@
     method public int getProtocolCapability();
   }
 
-  public class IptvFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
-    method @NonNull public static android.media.tv.tuner.frontend.IptvFrontendSettings.Builder builder();
+  public final class IptvFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
     method @IntRange(from=0) public long getBitrate();
     method @NonNull public String getContentUrl();
     method @NonNull @Size(min=4, max=16) public byte[] getDstIpAddress();
@@ -9145,6 +9142,7 @@
   }
 
   public static final class IptvFrontendSettings.Builder {
+    ctor public IptvFrontendSettings.Builder();
     method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings build();
     method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setBitrate(@IntRange(from=0) long);
     method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setContentUrl(@NonNull String);
@@ -9157,8 +9155,7 @@
     method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettings.Builder setSrcPort(int);
   }
 
-  public class IptvFrontendSettingsFec {
-    method @NonNull public static android.media.tv.tuner.frontend.IptvFrontendSettingsFec.Builder builder();
+  public final class IptvFrontendSettingsFec {
     method @IntRange(from=0) public int getFecColNum();
     method @IntRange(from=0) public int getFecRowNum();
     method public int getFecType();
@@ -9169,6 +9166,7 @@
   }
 
   public static final class IptvFrontendSettingsFec.Builder {
+    ctor public IptvFrontendSettingsFec.Builder();
     method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettingsFec build();
     method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettingsFec.Builder setFecColNum(@IntRange(from=0) int);
     method @NonNull public android.media.tv.tuner.frontend.IptvFrontendSettingsFec.Builder setFecRowNum(@IntRange(from=0) int);
@@ -10001,34 +9999,65 @@
 
 package android.net.wifi.sharedconnectivity.app {
 
-  public final class DeviceInfo implements android.os.Parcelable {
+  public final class HotspotNetwork implements android.os.Parcelable {
     method public int describeContents();
-    method @IntRange(from=0, to=100) public int getBatteryPercentage();
-    method @IntRange(from=0, to=3) public int getConnectionStrength();
-    method @NonNull public String getDeviceName();
-    method public int getDeviceType();
-    method @NonNull public String getModelName();
+    method public long getDeviceId();
+    method public int getHostNetworkType();
+    method @Nullable public String getHotspotBssid();
+    method @NonNull public java.util.Set<java.lang.Integer> getHotspotSecurityTypes();
+    method @Nullable public String getHotspotSsid();
+    method @NonNull public String getNetworkName();
+    method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo getNetworkProviderInfo();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.sharedconnectivity.app.DeviceInfo> CREATOR;
-    field public static final int DEVICE_TYPE_LAPTOP = 3; // 0x3
-    field public static final int DEVICE_TYPE_PHONE = 1; // 0x1
-    field public static final int DEVICE_TYPE_TABLET = 2; // 0x2
-    field public static final int DEVICE_TYPE_UNKNOWN = 0; // 0x0
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.sharedconnectivity.app.HotspotNetwork> CREATOR;
+    field public static final int NETWORK_TYPE_CELLULAR = 1; // 0x1
+    field public static final int NETWORK_TYPE_ETHERNET = 3; // 0x3
+    field public static final int NETWORK_TYPE_UNKNOWN = 0; // 0x0
+    field public static final int NETWORK_TYPE_WIFI = 2; // 0x2
   }
 
-  public static final class DeviceInfo.Builder {
-    ctor public DeviceInfo.Builder();
-    method @NonNull public android.net.wifi.sharedconnectivity.app.DeviceInfo build();
-    method @NonNull public android.net.wifi.sharedconnectivity.app.DeviceInfo.Builder setBatteryPercentage(@IntRange(from=0, to=100) int);
-    method @NonNull public android.net.wifi.sharedconnectivity.app.DeviceInfo.Builder setConnectionStrength(@IntRange(from=0, to=3) int);
-    method @NonNull public android.net.wifi.sharedconnectivity.app.DeviceInfo.Builder setDeviceName(@NonNull String);
-    method @NonNull public android.net.wifi.sharedconnectivity.app.DeviceInfo.Builder setDeviceType(int);
-    method @NonNull public android.net.wifi.sharedconnectivity.app.DeviceInfo.Builder setModelName(@NonNull String);
+  public static final class HotspotNetwork.Builder {
+    ctor public HotspotNetwork.Builder();
+    method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder addHotspotSecurityType(int);
+    method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork build();
+    method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setDeviceId(long);
+    method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setHostNetworkType(int);
+    method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setHotspotBssid(@NonNull String);
+    method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setHotspotSsid(@NonNull String);
+    method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setNetworkName(@NonNull String);
+    method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork.Builder setNetworkProviderInfo(@NonNull android.net.wifi.sharedconnectivity.app.NetworkProviderInfo);
+  }
+
+  public final class HotspotNetworkConnectionStatus implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.os.Bundle getExtras();
+    method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetwork getHotspotNetwork();
+    method public int getStatus();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CONNECTION_STATUS_CONNECT_TO_HOTSPOT_FAILED = 9; // 0x9
+    field public static final int CONNECTION_STATUS_ENABLING_HOTSPOT = 1; // 0x1
+    field public static final int CONNECTION_STATUS_ENABLING_HOTSPOT_FAILED = 7; // 0x7
+    field public static final int CONNECTION_STATUS_ENABLING_HOTSPOT_TIMEOUT = 8; // 0x8
+    field public static final int CONNECTION_STATUS_NO_CELL_DATA = 6; // 0x6
+    field public static final int CONNECTION_STATUS_PROVISIONING_FAILED = 3; // 0x3
+    field public static final int CONNECTION_STATUS_TETHERING_TIMEOUT = 4; // 0x4
+    field public static final int CONNECTION_STATUS_TETHERING_UNSUPPORTED = 5; // 0x5
+    field public static final int CONNECTION_STATUS_UNKNOWN = 0; // 0x0
+    field public static final int CONNECTION_STATUS_UNKNOWN_ERROR = 2; // 0x2
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus> CREATOR;
+  }
+
+  public static final class HotspotNetworkConnectionStatus.Builder {
+    ctor public HotspotNetworkConnectionStatus.Builder();
+    method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus build();
+    method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus.Builder setExtras(@NonNull android.os.Bundle);
+    method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus.Builder setHotspotNetwork(@NonNull android.net.wifi.sharedconnectivity.app.HotspotNetwork);
+    method @NonNull public android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus.Builder setStatus(int);
   }
 
   public final class KnownNetwork implements android.os.Parcelable {
     method public int describeContents();
-    method @Nullable public android.net.wifi.sharedconnectivity.app.DeviceInfo getDeviceInfo();
+    method @Nullable public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo getNetworkProviderInfo();
     method public int getNetworkSource();
     method @NonNull public java.util.Set<java.lang.Integer> getSecurityTypes();
     method @NonNull public String getSsid();
@@ -10043,7 +10072,7 @@
     ctor public KnownNetwork.Builder();
     method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder addSecurityType(int);
     method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork build();
-    method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder setDeviceInfo(@Nullable android.net.wifi.sharedconnectivity.app.DeviceInfo);
+    method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder setNetworkProviderInfo(@Nullable android.net.wifi.sharedconnectivity.app.NetworkProviderInfo);
     method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder setNetworkSource(int);
     method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetwork.Builder setSsid(@NonNull String);
   }
@@ -10068,27 +10097,54 @@
     method @NonNull public android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus.Builder setStatus(int);
   }
 
+  public final class NetworkProviderInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @IntRange(from=0, to=100) public int getBatteryPercentage();
+    method @IntRange(from=0, to=3) public int getConnectionStrength();
+    method @NonNull public String getDeviceName();
+    method public int getDeviceType();
+    method @NonNull public String getModelName();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.sharedconnectivity.app.NetworkProviderInfo> CREATOR;
+    field public static final int DEVICE_TYPE_AUTO = 5; // 0x5
+    field public static final int DEVICE_TYPE_LAPTOP = 3; // 0x3
+    field public static final int DEVICE_TYPE_PHONE = 1; // 0x1
+    field public static final int DEVICE_TYPE_TABLET = 2; // 0x2
+    field public static final int DEVICE_TYPE_UNKNOWN = 0; // 0x0
+    field public static final int DEVICE_TYPE_WATCH = 4; // 0x4
+  }
+
+  public static final class NetworkProviderInfo.Builder {
+    ctor public NetworkProviderInfo.Builder(@NonNull String, @NonNull String);
+    method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo build();
+    method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setBatteryPercentage(@IntRange(from=0, to=100) int);
+    method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setConnectionStrength(@IntRange(from=0, to=3) int);
+    method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setDeviceName(@NonNull String);
+    method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setDeviceType(int);
+    method @NonNull public android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder setModelName(@NonNull String);
+  }
+
   public interface SharedConnectivityClientCallback {
+    method public void onHotspotNetworkConnectionStatusChanged(@NonNull android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus);
+    method public void onHotspotNetworksUpdated(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.HotspotNetwork>);
     method public void onKnownNetworkConnectionStatusChanged(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus);
     method public void onKnownNetworksUpdated(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.KnownNetwork>);
     method public void onRegisterCallbackFailed(@NonNull Exception);
     method public void onServiceConnected();
     method public void onServiceDisconnected();
     method public void onSharedConnectivitySettingsChanged(@NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState);
-    method public void onTetherNetworkConnectionStatusChanged(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus);
-    method public void onTetherNetworksUpdated(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.TetherNetwork>);
   }
 
   public class SharedConnectivityManager {
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean connectHotspotNetwork(@NonNull android.net.wifi.sharedconnectivity.app.HotspotNetwork);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean connectKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork);
-    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean connectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork);
-    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean disconnectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork);
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean disconnectHotspotNetwork(@NonNull android.net.wifi.sharedconnectivity.app.HotspotNetwork);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean forgetKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork);
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus getHotspotNetworkConnectionStatus();
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.sharedconnectivity.app.HotspotNetwork> getHotspotNetworks();
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus getKnownNetworkConnectionStatus();
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.sharedconnectivity.app.KnownNetwork> getKnownNetworks();
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState getSettingsState();
-    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus getTetherNetworkConnectionStatus();
-    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.sharedconnectivity.app.TetherNetwork> getTetherNetworks();
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean unregisterCallback(@NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback);
   }
@@ -10108,62 +10164,6 @@
     method @NonNull public android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState.Builder setInstantTetherEnabled(boolean);
   }
 
-  public final class TetherNetwork implements android.os.Parcelable {
-    method public int describeContents();
-    method public long getDeviceId();
-    method @NonNull public android.net.wifi.sharedconnectivity.app.DeviceInfo getDeviceInfo();
-    method @Nullable public String getHotspotBssid();
-    method @NonNull public java.util.Set<java.lang.Integer> getHotspotSecurityTypes();
-    method @Nullable public String getHotspotSsid();
-    method @NonNull public String getNetworkName();
-    method public int getNetworkType();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.sharedconnectivity.app.TetherNetwork> CREATOR;
-    field public static final int NETWORK_TYPE_CELLULAR = 1; // 0x1
-    field public static final int NETWORK_TYPE_ETHERNET = 3; // 0x3
-    field public static final int NETWORK_TYPE_UNKNOWN = 0; // 0x0
-    field public static final int NETWORK_TYPE_WIFI = 2; // 0x2
-  }
-
-  public static final class TetherNetwork.Builder {
-    ctor public TetherNetwork.Builder();
-    method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork.Builder addHotspotSecurityType(int);
-    method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork build();
-    method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork.Builder setDeviceId(long);
-    method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork.Builder setDeviceInfo(@NonNull android.net.wifi.sharedconnectivity.app.DeviceInfo);
-    method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork.Builder setHotspotBssid(@NonNull String);
-    method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork.Builder setHotspotSsid(@NonNull String);
-    method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork.Builder setNetworkName(@NonNull String);
-    method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork.Builder setNetworkType(int);
-  }
-
-  public final class TetherNetworkConnectionStatus implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public android.os.Bundle getExtras();
-    method public int getStatus();
-    method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetwork getTetherNetwork();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int CONNECTION_STATUS_CONNECT_TO_HOTSPOT_FAILED = 9; // 0x9
-    field public static final int CONNECTION_STATUS_ENABLING_HOTSPOT = 1; // 0x1
-    field public static final int CONNECTION_STATUS_ENABLING_HOTSPOT_FAILED = 7; // 0x7
-    field public static final int CONNECTION_STATUS_ENABLING_HOTSPOT_TIMEOUT = 8; // 0x8
-    field public static final int CONNECTION_STATUS_NO_CELL_DATA = 6; // 0x6
-    field public static final int CONNECTION_STATUS_PROVISIONING_FAILED = 3; // 0x3
-    field public static final int CONNECTION_STATUS_TETHERING_TIMEOUT = 4; // 0x4
-    field public static final int CONNECTION_STATUS_TETHERING_UNSUPPORTED = 5; // 0x5
-    field public static final int CONNECTION_STATUS_UNKNOWN = 0; // 0x0
-    field public static final int CONNECTION_STATUS_UNKNOWN_ERROR = 2; // 0x2
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus> CREATOR;
-  }
-
-  public static final class TetherNetworkConnectionStatus.Builder {
-    ctor public TetherNetworkConnectionStatus.Builder();
-    method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus build();
-    method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus.Builder setExtras(@NonNull android.os.Bundle);
-    method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus.Builder setStatus(int);
-    method @NonNull public android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus.Builder setTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork);
-  }
-
 }
 
 package android.net.wifi.sharedconnectivity.service {
@@ -10171,15 +10171,15 @@
   public abstract class SharedConnectivityService extends android.app.Service {
     ctor public SharedConnectivityService();
     method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
+    method public abstract void onConnectHotspotNetwork(@NonNull android.net.wifi.sharedconnectivity.app.HotspotNetwork);
     method public abstract void onConnectKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork);
-    method public abstract void onConnectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork);
-    method public abstract void onDisconnectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork);
+    method public abstract void onDisconnectHotspotNetwork(@NonNull android.net.wifi.sharedconnectivity.app.HotspotNetwork);
     method public abstract void onForgetKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork);
+    method public final void setHotspotNetworks(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.HotspotNetwork>);
     method public final void setKnownNetworks(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.KnownNetwork>);
     method public final void setSettingsState(@NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState);
-    method public final void setTetherNetworks(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.TetherNetwork>);
+    method public final void updateHotspotNetworkConnectionStatus(@NonNull android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus);
     method public final void updateKnownNetworkConnectionStatus(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus);
-    method public final void updateTetherNetworkConnectionStatus(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus);
   }
 
 }
@@ -10960,7 +10960,6 @@
     method @NonNull @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.MANAGE_USERS"}) public java.util.Set<android.os.UserHandle> getVisibleUsers();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean hasRestrictedProfiles();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean hasUserRestrictionForUser(@NonNull String, @NonNull android.os.UserHandle);
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isAdminUser();
     method public boolean isCloneProfile();
     method @Deprecated public boolean isCredentialSharableWithParent();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isGuestUser();
@@ -13789,7 +13788,7 @@
     field public static final String EXTRA_CALL_HAS_IN_BAND_RINGTONE = "android.telecom.extra.CALL_HAS_IN_BAND_RINGTONE";
     field public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE";
     field public static final String EXTRA_CALL_TECHNOLOGY_TYPE = "android.telecom.extra.CALL_TECHNOLOGY_TYPE";
-    field public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT";
+    field @Deprecated public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT";
     field public static final String EXTRA_CONNECTION_SERVICE = "android.telecom.extra.CONNECTION_SERVICE";
     field public static final String EXTRA_CURRENT_TTY_MODE = "android.telecom.extra.CURRENT_TTY_MODE";
     field public static final String EXTRA_IS_USER_INTENT_EMERGENCY_CALL = "android.telecom.extra.IS_USER_INTENT_EMERGENCY_CALL";
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 43fa6e2..1860f43 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3342,6 +3342,7 @@
     field public static final int DISPLAY_IME_POLICY_FALLBACK_DISPLAY = 1; // 0x1
     field public static final int DISPLAY_IME_POLICY_HIDE = 2; // 0x2
     field public static final int DISPLAY_IME_POLICY_LOCAL = 0; // 0x0
+    field public static final int LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP = 600; // 0x258
   }
 
   public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable {
@@ -3772,6 +3773,7 @@
   public final class TaskFragmentInfo implements android.os.Parcelable {
     method public boolean equalsForTaskFragmentOrganizer(@Nullable android.window.TaskFragmentInfo);
     method @NonNull public java.util.List<android.os.IBinder> getActivities();
+    method @NonNull public java.util.List<android.os.IBinder> getActivitiesRequestedInTaskFragment();
     method @NonNull public android.content.res.Configuration getConfiguration();
     method @NonNull public android.os.IBinder getFragmentToken();
     method @NonNull public android.graphics.Point getPositionInParent();
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index 44327af..b35e87b 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -598,6 +598,23 @@
     }
 
     /**
+     * Returns {@code true} if the activity was explicitly requested to be launched in the
+     * TaskFragment.
+     *
+     * @param activityToken The token of the Activity.
+     * @param taskFragmentToken The token of the TaskFragment.
+     */
+    public boolean isRequestedToLaunchInTaskFragment(IBinder activityToken,
+            IBinder taskFragmentToken) {
+        try {
+            return getActivityClientController().isRequestedToLaunchInTaskFragment(activityToken,
+                    taskFragmentToken);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Shows or hides a Camera app compat toggle for stretched issues with the requested state.
      *
      * @param token The token for the window that needs a control.
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index ba36d93..87fe215 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -630,7 +630,7 @@
             PROCESS_CAPABILITY_FOREGROUND_LOCATION,
             PROCESS_CAPABILITY_FOREGROUND_CAMERA,
             PROCESS_CAPABILITY_FOREGROUND_MICROPHONE,
-            PROCESS_CAPABILITY_NETWORK,
+            PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK,
             PROCESS_CAPABILITY_BFSL,
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -791,7 +791,7 @@
     public static final int PROCESS_CAPABILITY_ALL = PROCESS_CAPABILITY_FOREGROUND_LOCATION
             | PROCESS_CAPABILITY_FOREGROUND_CAMERA
             | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
-            | PROCESS_CAPABILITY_NETWORK
+            | PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
             | PROCESS_CAPABILITY_BFSL;
 
     /**
@@ -810,7 +810,7 @@
         pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0 ? 'L' : '-');
         pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0 ? 'C' : '-');
         pw.print((caps & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0 ? 'M' : '-');
-        pw.print((caps & PROCESS_CAPABILITY_NETWORK) != 0 ? 'N' : '-');
+        pw.print((caps & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0 ? 'N' : '-');
         pw.print((caps & PROCESS_CAPABILITY_BFSL) != 0 ? 'F' : '-');
     }
 
@@ -819,7 +819,7 @@
         sb.append((caps & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0 ? 'L' : '-');
         sb.append((caps & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0 ? 'C' : '-');
         sb.append((caps & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0 ? 'M' : '-');
-        sb.append((caps & PROCESS_CAPABILITY_NETWORK) != 0 ? 'N' : '-');
+        sb.append((caps & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0 ? 'N' : '-');
         sb.append((caps & PROCESS_CAPABILITY_BFSL) != 0 ? 'F' : '-');
     }
 
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index 5136b20..a3c5e1c 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -181,4 +181,14 @@
      * that started the task.
      */
     void enableTaskLocaleOverride(in IBinder token);
+
+    /**
+     * Return {@code true} if the activity was explicitly requested to be launched in the
+     * TaskFragment.
+     *
+     * @param activityToken The token of the Activity.
+     * @param taskFragmentToken The token of the TaskFragment.
+     */
+    boolean isRequestedToLaunchInTaskFragment(in IBinder activityToken,
+            in IBinder taskFragmentToken);
 }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 83e0153..dbba0c6 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -509,7 +509,7 @@
                 new ServiceFetcher<InputManager>() {
             @Override
             public InputManager getService(ContextImpl ctx) {
-                return InputManager.getInstance(ctx);
+                return InputManager.getInstance(ctx.getOuterContext());
             }});
 
         registerService(Context.DISPLAY_SERVICE, DisplayManager.class,
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index 9f3b601..3a60a69 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -140,7 +140,8 @@
      * a given policy type.
      * @hide
      */
-    @IntDef(prefix = "POLICY_TYPE_",  value = {POLICY_TYPE_SENSORS, POLICY_TYPE_AUDIO})
+    @IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_SENSORS, POLICY_TYPE_AUDIO,
+            POLICY_TYPE_RECENTS})
     @Retention(RetentionPolicy.SOURCE)
     @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
     public @interface PolicyType {}
@@ -169,22 +170,21 @@
      *     <li>{@link #DEVICE_POLICY_CUSTOM}: audio framework will assign device specific session
      *     ids to players and recorders constructed within device context. The session ids are
      *     used to re-route corresponding audio streams to VirtualAudioDevice.
-     * <ul/>
+     * </ul>
      */
     public static final int POLICY_TYPE_AUDIO = 1;
 
-    /** @hide */
-    @IntDef(flag = true, prefix = "RECENTS_POLICY_",
-            value = {RECENTS_POLICY_ALLOW_IN_HOST_DEVICE_RECENTS})
-    @Retention(RetentionPolicy.SOURCE)
-    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
-    public @interface RecentsPolicy {}
-
     /**
-     * If set, activities launched on this virtual device are allowed to appear in the host device
-     * of the recently launched activities list.
+     * Tells the activity manager how to handle recents entries for activities run on this device.
+     *
+     * <ul>
+     *     <li>{@link #DEVICE_POLICY_DEFAULT}: Activities launched on VirtualDisplays owned by this
+     *     device will appear in the host device recents.
+     *     <li>{@link #DEVICE_POLICY_CUSTOM}: Activities launched on VirtualDisplays owned by this
+     *      *     device will not appear in recents.
+     * </ul>
      */
-    public static final int RECENTS_POLICY_ALLOW_IN_HOST_DEVICE_RECENTS = 1 << 0;
+    public static final int POLICY_TYPE_RECENTS = 2;
 
     private final int mLockState;
     @NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
@@ -201,8 +201,6 @@
     @NonNull private final SparseIntArray mDevicePolicies;
     @NonNull private final List<VirtualSensorConfig> mVirtualSensorConfigs;
     @Nullable private final IVirtualSensorCallback mVirtualSensorCallback;
-    @RecentsPolicy
-    private final int mDefaultRecentsPolicy;
     private final int mAudioPlaybackSessionId;
     private final int mAudioRecordingSessionId;
 
@@ -219,7 +217,6 @@
             @NonNull SparseIntArray devicePolicies,
             @NonNull List<VirtualSensorConfig> virtualSensorConfigs,
             @Nullable IVirtualSensorCallback virtualSensorCallback,
-            @RecentsPolicy int defaultRecentsPolicy,
             int audioPlaybackSessionId,
             int audioRecordingSessionId) {
         mLockState = lockState;
@@ -237,10 +234,8 @@
         mDevicePolicies = Objects.requireNonNull(devicePolicies);
         mVirtualSensorConfigs = Objects.requireNonNull(virtualSensorConfigs);
         mVirtualSensorCallback = virtualSensorCallback;
-        mDefaultRecentsPolicy = defaultRecentsPolicy;
         mAudioPlaybackSessionId = audioPlaybackSessionId;
         mAudioRecordingSessionId = audioRecordingSessionId;
-
     }
 
     @SuppressWarnings("unchecked")
@@ -259,7 +254,6 @@
         parcel.readTypedList(mVirtualSensorConfigs, VirtualSensorConfig.CREATOR);
         mVirtualSensorCallback =
                 IVirtualSensorCallback.Stub.asInterface(parcel.readStrongBinder());
-        mDefaultRecentsPolicy = parcel.readInt();
         mAudioPlaybackSessionId = parcel.readInt();
         mAudioRecordingSessionId = parcel.readInt();
     }
@@ -396,16 +390,6 @@
     }
 
     /**
-     * Returns the policy of how to handle activities in recents.
-     *
-     * @see RecentsPolicy
-     */
-    @RecentsPolicy
-    public int getDefaultRecentsPolicy() {
-        return mDefaultRecentsPolicy;
-    }
-
-    /**
      * Returns device-specific audio session id for playback.
      *
      * @see Builder#setAudioPlaybackSessionId(int)
@@ -443,7 +427,6 @@
         dest.writeTypedList(mVirtualSensorConfigs);
         dest.writeStrongBinder(
                 mVirtualSensorCallback != null ? mVirtualSensorCallback.asBinder() : null);
-        dest.writeInt(mDefaultRecentsPolicy);
         dest.writeInt(mAudioPlaybackSessionId);
         dest.writeInt(mAudioRecordingSessionId);
     }
@@ -478,7 +461,6 @@
                 && Objects.equals(mBlockedActivities, that.mBlockedActivities)
                 && mDefaultActivityPolicy == that.mDefaultActivityPolicy
                 && Objects.equals(mName, that.mName)
-                && mDefaultRecentsPolicy == that.mDefaultRecentsPolicy
                 && mAudioPlaybackSessionId == that.mAudioPlaybackSessionId
                 && mAudioRecordingSessionId == that.mAudioRecordingSessionId;
     }
@@ -489,7 +471,7 @@
                 mLockState, mUsersWithMatchingAccounts, mAllowedCrossTaskNavigations,
                 mBlockedCrossTaskNavigations, mDefaultNavigationPolicy, mAllowedActivities,
                 mBlockedActivities, mDefaultActivityPolicy, mName, mDevicePolicies,
-                mDefaultRecentsPolicy, mAudioPlaybackSessionId, mAudioRecordingSessionId);
+                mAudioPlaybackSessionId, mAudioRecordingSessionId);
         for (int i = 0; i < mDevicePolicies.size(); i++) {
             hashCode = 31 * hashCode + mDevicePolicies.keyAt(i);
             hashCode = 31 * hashCode + mDevicePolicies.valueAt(i);
@@ -511,7 +493,6 @@
                 + " mDefaultActivityPolicy=" + mDefaultActivityPolicy
                 + " mName=" + mName
                 + " mDevicePolicies=" + mDevicePolicies
-                + " mDefaultRecentsPolicy=" + mDefaultRecentsPolicy
                 + " mAudioPlaybackSessionId=" + mAudioPlaybackSessionId
                 + " mAudioRecordingSessionId=" + mAudioRecordingSessionId
                 + ")";
@@ -548,7 +529,6 @@
         private boolean mDefaultActivityPolicyConfigured = false;
         @Nullable private String mName;
         @NonNull private SparseIntArray mDevicePolicies = new SparseIntArray();
-        private int mDefaultRecentsPolicy;
         private int mAudioPlaybackSessionId = AUDIO_SESSION_ID_GENERATE;
         private int mAudioRecordingSessionId = AUDIO_SESSION_ID_GENERATE;
 
@@ -821,17 +801,6 @@
         }
 
         /**
-         * Sets the policy to indicate how activities are handled in recents.
-         *
-         * @param defaultRecentsPolicy A policy specifying how to handle activities in recents.
-         */
-        @NonNull
-        public Builder setDefaultRecentsPolicy(@RecentsPolicy int defaultRecentsPolicy) {
-            mDefaultRecentsPolicy = defaultRecentsPolicy;
-            return this;
-        }
-
-        /**
          * Sets audio playback session id specific for this virtual device.
          *
          * <p>Audio players constructed within context associated with this virtual device
@@ -933,7 +902,6 @@
                     mDevicePolicies,
                     mVirtualSensorConfigs,
                     mVirtualSensorCallback,
-                    mDefaultRecentsPolicy,
                     mAudioPlaybackSessionId,
                     mAudioRecordingSessionId);
         }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index d0accb7..a412560 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -528,7 +528,7 @@
 
     /**
      * Flag for {@link #bindService}: allow the process hosting the target service to gain
-     * {@link ActivityManager#PROCESS_CAPABILITY_NETWORK}, which allows it be able
+     * {@link ActivityManager#PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK}, which allows it be able
      * to access network regardless of any power saving restrictions.
      *
      * @hide
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index f440ac7..b601275 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -28,6 +28,9 @@
       "path": "cts/hostsidetests/os/test_mappings/packagemanager"
     },
     {
+      "path": "cts/hostsidetests/appsearch"
+    },
+    {
       "path": "system/apex/tests"
     },
     {
@@ -46,6 +49,12 @@
       "name": "ApkVerityTest"
     },
     {
+      "name": "CtsSilentUpdateHostTestCases"
+    },
+    {
+      "name": "CtsSuspendAppsTestCases"
+    },
+    {
       "name": "CtsAppFgsTestCases",
       "file_patterns": ["(/|^)ServiceInfo[^/]*"],
       "options": [
@@ -111,39 +120,6 @@
       ]
     },
     {
-      "name": "CtsAppSearchHostTestCases",
-      "options": [
-        {
-          "exclude-annotation": "androidx.test.filters.FlakyTest"
-        },
-        {
-          "exclude-annotation": "org.junit.Ignore"
-        }
-      ]
-    },
-    {
-      "name": "CtsSilentUpdateHostTestCases",
-      "options": [
-        {
-          "exclude-annotation": "androidx.test.filters.FlakyTest"
-        },
-        {
-          "exclude-annotation": "org.junit.Ignore"
-        }
-      ]
-    },
-    {
-      "name": "CtsSuspendAppsTestCases",
-      "options": [
-        {
-          "exclude-annotation": "androidx.test.filters.FlakyTest"
-        },
-        {
-          "exclude-annotation": "org.junit.Ignore"
-        }
-      ]
-    },
-    {
       "name": "CtsSuspendAppsPermissionTestCases",
       "options": [
         {
diff --git a/core/java/android/credentials/CreateCredentialRequest.java b/core/java/android/credentials/CreateCredentialRequest.java
index c89a5c6..fc3dc79 100644
--- a/core/java/android/credentials/CreateCredentialRequest.java
+++ b/core/java/android/credentials/CreateCredentialRequest.java
@@ -260,11 +260,17 @@
         private String mOrigin;
 
         /**
+         * @param type the type of the credential to be stored
          * @param credentialData the full credential creation request data
          * @param candidateQueryData the partial request data that will be sent to the provider
          *                           during the initial creation candidate query stage
          */
-        public Builder(@NonNull Bundle credentialData, @NonNull Bundle candidateQueryData) {
+        public Builder(
+                @NonNull String type,
+                @NonNull Bundle credentialData,
+                @NonNull Bundle candidateQueryData) {
+            mType = Preconditions.checkStringNotEmpty(type,
+                    "type must not be null or empty");
             mCredentialData = requireNonNull(credentialData,
                     "credentialData must not be null");
             mCandidateQueryData = requireNonNull(candidateQueryData,
@@ -291,16 +297,6 @@
         }
 
         /**
-         * Sets the requested credential type.
-         */
-        @SuppressLint("MissingGetterMatchingBuilder")
-        @NonNull
-        public CreateCredentialRequest.Builder setType(@NonNull String type) {
-            mType = type;
-            return this;
-        }
-
-        /**
          * Sets whether the request must only be fulfilled by a system provider.
          * This defaults to false
          */
diff --git a/core/java/android/credentials/GetCredentialRequest.java b/core/java/android/credentials/GetCredentialRequest.java
index 951cbe4..c58d2dc 100644
--- a/core/java/android/credentials/GetCredentialRequest.java
+++ b/core/java/android/credentials/GetCredentialRequest.java
@@ -149,7 +149,6 @@
         mCredentialOptions = credentialOptions;
         AnnotationValidations.validate(NonNull.class, null, mCredentialOptions);
 
-
         Bundle data = in.readBundle();
         mData = data;
         AnnotationValidations.validate(NonNull.class, null, mData);
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index a33cd97..490589f 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -48,8 +48,6 @@
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.ServiceManager.ServiceNotFoundException;
 import android.os.SystemClock;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
@@ -305,8 +303,11 @@
 
     private static String sVelocityTrackerStrategy;
 
-    private InputManager(IInputManager im) {
-        mIm = im;
+    private InputManagerGlobal mGlobal;
+
+    private InputManager() {
+        mGlobal = InputManagerGlobal.getInstance();
+        mIm = mGlobal.getInputManagerService();
         try {
             sVelocityTrackerStrategy = mIm.getVelocityTrackerStrategy();
         } catch (RemoteException ex) {
@@ -324,7 +325,8 @@
     @VisibleForTesting
     public static InputManager resetInstance(IInputManager inputManagerService) {
         synchronized (InputManager.class) {
-            sInstance = new InputManager(inputManagerService);
+            InputManagerGlobal.resetInstance(inputManagerService);
+            sInstance = new InputManager();
             return sInstance;
         }
     }
@@ -337,6 +339,7 @@
     @VisibleForTesting
     public static void clearInstance() {
         synchronized (InputManager.class) {
+            InputManagerGlobal.clearInstance();
             sInstance = null;
         }
     }
@@ -364,13 +367,7 @@
     public static InputManager getInstance(Context context) {
         synchronized (InputManager.class) {
             if (sInstance == null) {
-                try {
-                    sInstance = new InputManager(IInputManager.Stub
-                            .asInterface(ServiceManager.getServiceOrThrow(Context.INPUT_SERVICE)));
-
-                } catch (ServiceNotFoundException e) {
-                    throw new IllegalStateException(e);
-                }
+                sInstance = new InputManager();
             }
             if (sInstance.mWeakContext == null || sInstance.mWeakContext.get() == null) {
                 sInstance.mWeakContext = new WeakReference(context);
diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java
new file mode 100644
index 0000000..82dddfc
--- /dev/null
+++ b/core/java/android/hardware/input/InputManagerGlobal.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.input;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.ServiceManager;
+
+/**
+ * Manages communication with the input manager service on behalf of
+ * an application process.  You're probably looking for {@link InputManager}.
+ *
+ * @hide
+ */
+public final class InputManagerGlobal {
+    private static final String TAG = "InputManagerGlobal";
+
+    private static InputManagerGlobal sInstance;
+
+    private final IInputManager mIm;
+
+    public InputManagerGlobal(IInputManager im) {
+        mIm = im;
+    }
+
+    /**
+     * Gets an instance of the input manager global singleton.
+     *
+     * @return The display manager instance, may be null early in system startup
+     * before the display manager has been fully initialized.
+     */
+    public static InputManagerGlobal getInstance() {
+        synchronized (InputManagerGlobal.class) {
+            if (sInstance == null) {
+                IBinder b = ServiceManager.getService(Context.INPUT_SERVICE);
+                if (b != null) {
+                    sInstance = new InputManagerGlobal(IInputManager.Stub.asInterface(b));
+                }
+            }
+            return sInstance;
+        }
+    }
+
+    public IInputManager getInputManagerService() {
+        return mIm;
+    }
+
+    /**
+     * Gets an instance of the input manager.
+     *
+     * @return The input manager instance.
+     */
+    public static InputManagerGlobal resetInstance(IInputManager inputManagerService) {
+        synchronized (InputManager.class) {
+            sInstance = new InputManagerGlobal(inputManagerService);
+            return sInstance;
+        }
+    }
+
+    /**
+     * Clear the instance of the input manager.
+     */
+    public static void clearInstance() {
+        synchronized (InputManagerGlobal.class) {
+            sInstance = null;
+        }
+    }
+}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 9341105..104a8b2 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -475,8 +475,8 @@
      *
      * @param uid The UID whose status needs to be checked.
      * @return {@link ConnectivityManager#RESTRICT_BACKGROUND_STATUS_DISABLED},
-     *         {@link ConnectivityManager##RESTRICT_BACKGROUND_STATUS_ENABLED},
-     *         or {@link ConnectivityManager##RESTRICT_BACKGROUND_STATUS_WHITELISTED} to denote
+     *         {@link ConnectivityManager#RESTRICT_BACKGROUND_STATUS_ENABLED},
+     *         or {@link ConnectivityManager#RESTRICT_BACKGROUND_STATUS_WHITELISTED} to denote
      *         the current status of the UID.
      * @hide
      */
@@ -769,6 +769,28 @@
     }
 
     /**
+     * Returns the default network capabilities
+     * ({@link ActivityManager#PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
+     * ActivityManager.PROCESS_CAPABILITY_*}) of the specified process state.
+     * This <b>DOES NOT</b> return all default process capabilities for a proc state.
+     * @hide
+     */
+    public static int getDefaultProcessNetworkCapabilities(int procState) {
+        switch (procState) {
+            case ActivityManager.PROCESS_STATE_PERSISTENT:
+            case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
+            case ActivityManager.PROCESS_STATE_TOP:
+                return ActivityManager.PROCESS_CAPABILITY_ALL;
+            case ActivityManager.PROCESS_STATE_BOUND_TOP:
+            case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
+            case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
+                return ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
+            default:
+                return ActivityManager.PROCESS_CAPABILITY_NONE;
+        }
+    }
+
+    /**
      * Returns true if {@param procState} is considered foreground and as such will be allowed
      * to access network when the device is idle or in battery saver mode. Otherwise, false.
      * @hide
@@ -784,7 +806,7 @@
     public static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(
             int procState, @ProcessCapability int capability) {
         return procState <= FOREGROUND_THRESHOLD_STATE
-                || (capability & ActivityManager.PROCESS_CAPABILITY_NETWORK) != 0;
+                || (capability & ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0;
     }
 
     /** @hide */
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 3cf3ea2..fcebb45 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -117,6 +117,7 @@
     boolean someUserHasAccount(in String accountName, in String accountType);
     String getProfileType(int userId);
     boolean isDemoUser(int userId);
+    boolean isAdminUser(int userId);
     boolean isPreCreated(int userId);
     UserInfo createProfileForUserEvenWhenDisallowedWithThrow(in String name, in String userType, int flags,
             int userId, in String[] disallowedPackages);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 8d8deaa..290f929 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2433,21 +2433,24 @@
     }
 
     /**
-     * Used to check if the context user is an admin user. An admin user is allowed to
+     * Used to check if the context user is an admin user. An admin user may be allowed to
      * modify or configure certain settings that aren't available to non-admin users,
      * create and delete additional users, etc. There can be more than one admin users.
      *
      * @return whether the context user is an admin user.
-     * @hide
      */
-    @SystemApi
-    @RequiresPermission(anyOf = {
-            Manifest.permission.MANAGE_USERS,
-            Manifest.permission.CREATE_USERS,
-            Manifest.permission.QUERY_USERS})
-    @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+    @UserHandleAware(
+            enabledSinceTargetSdkVersion = Build.VERSION_CODES.TIRAMISU,
+            requiresAnyOfPermissionsIfNotCallerProfileGroup = {
+                    Manifest.permission.MANAGE_USERS,
+                    Manifest.permission.CREATE_USERS,
+                    Manifest.permission.QUERY_USERS})
     public boolean isAdminUser() {
-        return isUserAdmin(getContextUserIfAppropriate());
+        try {
+            return mService.isAdminUser(getContextUserIfAppropriate());
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -3972,6 +3975,9 @@
      * time, the preferred user name and account information are used by the setup process for that
      * user.
      *
+     * This API should only be called if the current user is an {@link #isAdminUser() admin} user,
+     * as otherwise the returned intent will not be able to create a user.
+     *
      * @param userName Optional name to assign to the user.
      * @param accountName Optional account name that will be used by the setup wizard to initialize
      *                    the user.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d7cd61567..ef00774 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8289,6 +8289,15 @@
                 "accessibility_display_inversion_enabled";
 
         /**
+         * Flag that specifies whether font size has been changed. The flag will
+         * be set when users change the scaled value of font size for the first time.
+         * @hide
+         */
+        @Readable
+        public static final String ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED =
+                "accessibility_font_scaling_has_been_changed";
+
+        /**
          * Setting that specifies whether display color space adjustment is
          * enabled.
          *
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index b0e847c..5d58120 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -233,6 +233,22 @@
          */
         public static final int TYPE_DATASETS_SHOWN = 5;
 
+        /**
+         * The app/user requested for a field to be Autofilled.
+         *
+         * This event is fired when the view has been entered (by user or app) in order
+         * to differentiate from FillRequests that have been pretriggered for FillDialogs.
+         *
+         * For example, the user might navigate away from a screen without tapping any
+         * fields. In this case, a FillRequest/FillResponse has been generated, but was
+         * not used for Autofilling. The user did not intend to see an Autofill result,
+         * but a FillRequest was still generated. This is different from when the user
+         * did tap on a field after the pretriggered FillRequest, this event will appear
+         * in the FillEventHistory, signaling that the user did intend to Autofill
+         * something.
+         */
+        public static final int TYPE_VIEW_REQUESTED_AUTOFILL = 6;
+
         /** @hide */
         @IntDef(prefix = { "TYPE_" }, value = {
                 TYPE_DATASET_SELECTED,
@@ -240,7 +256,8 @@
                 TYPE_AUTHENTICATION_SELECTED,
                 TYPE_SAVE_SHOWN,
                 TYPE_CONTEXT_COMMITTED,
-                TYPE_DATASETS_SHOWN
+                TYPE_DATASETS_SHOWN,
+                TYPE_VIEW_REQUESTED_AUTOFILL
         })
         @Retention(RetentionPolicy.SOURCE)
         @interface EventIds{}
@@ -659,8 +676,8 @@
                 @Nullable AutofillId[] detectedFieldIds,
                 @Nullable FieldClassification[] detectedFieldClassifications,
                 int saveDialogNotShowReason, int uiType) {
-            mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_DATASETS_SHOWN,
-                    "eventType");
+            mEventType = Preconditions.checkArgumentInRange(eventType, 0,
+                    TYPE_VIEW_REQUESTED_AUTOFILL, "eventType");
             mDatasetId = datasetId;
             mClientState = clientState;
             mSelectedDatasetIds = selectedDatasetIds;
@@ -723,6 +740,8 @@
                     return "TYPE_CONTEXT_COMMITTED";
                 case TYPE_DATASETS_SHOWN:
                     return "TYPE_DATASETS_SHOWN";
+                case TYPE_VIEW_REQUESTED_AUTOFILL:
+                    return "TYPE_VIEW_REQUESTED_AUTOFILL";
                 default:
                     return "TYPE_UNKNOWN";
             }
diff --git a/core/java/android/service/credentials/BeginCreateCredentialResponse.java b/core/java/android/service/credentials/BeginCreateCredentialResponse.java
index f0f954d..eebd31c 100644
--- a/core/java/android/service/credentials/BeginCreateCredentialResponse.java
+++ b/core/java/android/service/credentials/BeginCreateCredentialResponse.java
@@ -32,7 +32,7 @@
  */
 public final class BeginCreateCredentialResponse implements Parcelable {
     private final @NonNull List<CreateEntry> mCreateEntries;
-    private final @Nullable CreateEntry mRemoteCreateEntry;
+    private final @Nullable RemoteEntry mRemoteCreateEntry;
 
     /**
      * Creates an empty response instance, to be used when there are no {@link CreateEntry}
@@ -46,7 +46,7 @@
         List<CreateEntry> createEntries = new ArrayList<>();
         in.readTypedList(createEntries, CreateEntry.CREATOR);
         mCreateEntries = createEntries;
-        mRemoteCreateEntry = in.readTypedObject(CreateEntry.CREATOR);
+        mRemoteCreateEntry = in.readTypedObject(RemoteEntry.CREATOR);
     }
 
     @Override
@@ -75,7 +75,7 @@
 
     /* package-private */ BeginCreateCredentialResponse(
             @NonNull List<CreateEntry> createEntries,
-            @Nullable CreateEntry remoteCreateEntry) {
+            @Nullable RemoteEntry remoteCreateEntry) {
         this.mCreateEntries = createEntries;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mCreateEntries);
@@ -88,7 +88,7 @@
     }
 
     /** Returns the remote create entry to be displayed on the UI. */
-    public @Nullable CreateEntry getRemoteCreateEntry() {
+    public @Nullable RemoteEntry getRemoteCreateEntry() {
         return mRemoteCreateEntry;
     }
 
@@ -98,7 +98,7 @@
     @SuppressWarnings("WeakerAccess") /* synthetic access */
     public static final class Builder {
         private @NonNull List<CreateEntry> mCreateEntries = new ArrayList<>();
-        private @Nullable CreateEntry mRemoteCreateEntry;
+        private @Nullable RemoteEntry mRemoteCreateEntry;
 
         /**
          * Sets the list of create entries to be shown on the UI.
@@ -138,7 +138,7 @@
          * {@link CredentialProviderService#EXTRA_CREATE_CREDENTIAL_RESPONSE} key should be populated
          * with a {@link android.credentials.CreateCredentialResponse} object.
          */
-        public @NonNull Builder setRemoteCreateEntry(@Nullable CreateEntry remoteCreateEntry) {
+        public @NonNull Builder setRemoteCreateEntry(@Nullable RemoteEntry remoteCreateEntry) {
             mRemoteCreateEntry = remoteCreateEntry;
             return this;
         }
diff --git a/core/java/android/service/credentials/BeginGetCredentialResponse.java b/core/java/android/service/credentials/BeginGetCredentialResponse.java
index 3652742..97f5079 100644
--- a/core/java/android/service/credentials/BeginGetCredentialResponse.java
+++ b/core/java/android/service/credentials/BeginGetCredentialResponse.java
@@ -42,7 +42,7 @@
     private final @NonNull List<Action> mActions;
 
     /** Remote credential entry to get the response from a different device. */
-    private final @Nullable CredentialEntry mRemoteCredentialEntry;
+    private final @Nullable RemoteEntry mRemoteCredentialEntry;
 
     /**
      * Creates an empty response instance, to be used when there are no {@link CredentialEntry},
@@ -57,7 +57,7 @@
 
     private BeginGetCredentialResponse(@NonNull List<CredentialEntry> credentialEntries,
             @NonNull List<Action> authenticationEntries, @NonNull List<Action> actions,
-            @Nullable CredentialEntry remoteCredentialEntry) {
+            @Nullable RemoteEntry remoteCredentialEntry) {
         mCredentialEntries = new ArrayList<>(credentialEntries);
         mAuthenticationEntries = new ArrayList<>(authenticationEntries);
         mActions = new ArrayList<>(actions);
@@ -74,7 +74,7 @@
         List<Action> actions = new ArrayList<>();
         in.readTypedList(actions, Action.CREATOR);
         mActions = actions;
-        mRemoteCredentialEntry = in.readTypedObject(CredentialEntry.CREATOR);
+        mRemoteCredentialEntry = in.readTypedObject(RemoteEntry.CREATOR);
     }
 
     public static final @NonNull Creator<BeginGetCredentialResponse> CREATOR =
@@ -127,7 +127,7 @@
     /**
      * Returns the remote credential entry to be displayed on the UI.
      */
-    public @Nullable CredentialEntry getRemoteCredentialEntry() {
+    public @Nullable RemoteEntry getRemoteCredentialEntry() {
         return mRemoteCredentialEntry;
     }
 
@@ -139,7 +139,7 @@
 
         private List<Action> mAuthenticationEntries = new ArrayList<>();
         private List<Action> mActions = new ArrayList<>();
-        private CredentialEntry mRemoteCredentialEntry;
+        private RemoteEntry mRemoteCredentialEntry;
 
         /**
          * Sets a remote credential entry to be shown on the UI. Provider must set this if they
@@ -155,7 +155,7 @@
          * {@link CredentialProviderService#EXTRA_GET_CREDENTIAL_RESPONSE} key should be populated
          * with a {@link android.credentials.Credential} object.
          */
-        public @NonNull Builder setRemoteCredentialEntry(@Nullable CredentialEntry
+        public @NonNull Builder setRemoteCredentialEntry(@Nullable RemoteEntry
                 remoteCredentialEntry) {
             mRemoteCredentialEntry = remoteCredentialEntry;
             return this;
diff --git a/core/java/android/service/credentials/GetCredentialRequest.java b/core/java/android/service/credentials/GetCredentialRequest.java
index 4f13922..5bad9ab 100644
--- a/core/java/android/service/credentials/GetCredentialRequest.java
+++ b/core/java/android/service/credentials/GetCredentialRequest.java
@@ -23,14 +23,16 @@
 
 import com.android.internal.util.AnnotationValidations;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 /**
  * Request for getting user's credential from a given credential provider.
  *
- * <p>Provider will receive this request once the user selects a given {@link CredentialEntry}
- * on the selector, that was sourced from provider's result to
- * {@link CredentialProviderService#onBeginGetCredential}.
+ * <p>A credential provider will receive this request once the user selects a
+ * given {@link CredentialEntry}, or {@link RemoteEntry} on the selector, that was sourced
+ * from provider's initial response to {@link CredentialProviderService#onBeginGetCredential}.
  */
 public final class GetCredentialRequest implements Parcelable {
     /** Calling package of the app requesting for credentials. */
@@ -38,24 +40,27 @@
     private final CallingAppInfo mCallingAppInfo;
 
     /**
-     * Holds parameters to be used for retrieving a specific type of credential.
+     * Holds a list of options (parameters) to be used for retrieving a specific type of credential.
      */
     @NonNull
-    private final CredentialOption mCredentialOption;
+    private final List<CredentialOption> mCredentialOptions;
 
     public GetCredentialRequest(@NonNull CallingAppInfo callingAppInfo,
-            @NonNull CredentialOption credentialOption) {
+            @NonNull List<CredentialOption> credentialOptions) {
         this.mCallingAppInfo = Objects.requireNonNull(callingAppInfo,
                 "callingAppInfo must not be null");
-        this.mCredentialOption = Objects.requireNonNull(credentialOption,
-                "credentialOption must not be null");
+        this.mCredentialOptions = Objects.requireNonNull(credentialOptions,
+                "credentialOptions must not be null");
     }
 
     private GetCredentialRequest(@NonNull Parcel in) {
         mCallingAppInfo = in.readTypedObject(CallingAppInfo.CREATOR);
         AnnotationValidations.validate(NonNull.class, null, mCallingAppInfo);
-        mCredentialOption = in.readTypedObject(CredentialOption.CREATOR);
-        AnnotationValidations.validate(NonNull.class, null, mCredentialOption);
+
+        List<CredentialOption> credentialOptions = new ArrayList<>();
+        in.readTypedList(credentialOptions, CredentialOption.CREATOR);
+        mCredentialOptions = credentialOptions;
+        AnnotationValidations.validate(NonNull.class, null, mCredentialOptions);
     }
 
     @NonNull public static final  Creator<GetCredentialRequest> CREATOR =
@@ -79,7 +84,7 @@
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeTypedObject(mCallingAppInfo, flags);
-        dest.writeTypedObject(mCredentialOption, flags);
+        dest.writeTypedList(mCredentialOptions, flags);
     }
 
     /**
@@ -91,10 +96,26 @@
     }
 
     /**
-     * Returns the parameters needed to return a given type of credential.
+     * Returns a list of options containing parameters needed to return a given type of credential.
+     * This is part of the request that the credential provider receives after the user has
+     * selected an entry on a selector UI.
+     *
+     * When the user selects a {@link CredentialEntry} and the credential provider receives a
+     * {@link GetCredentialRequest}, this list is expected to contain a single
+     * {@link CredentialOption} only. A {@link CredentialEntry} is always created for a given
+     * {@link BeginGetCredentialOption}, and hence when the user selects it, the provider
+     * receives a corresponding {@link CredentialOption} that contains all the required parameters
+     * to actually retrieve the credential.
+     *
+     * When the user selects a {@link RemoteEntry} and the credential provider receives a
+     * {@link GetCredentialRequest}, this list may contain greater than a single
+     * {@link CredentialOption}, representing the number of options specified by the developer
+     * in the original {@link android.credentials.GetCredentialRequest}. This is because a
+     * {@link RemoteEntry} indicates that the entire request will be processed on a different
+     * device and is not tied to a particular option.
      */
     @NonNull
-    public CredentialOption getCredentialOption() {
-        return mCredentialOption;
+    public List<CredentialOption> getCredentialOptions() {
+        return mCredentialOptions;
     }
 }
diff --git a/core/java/android/service/credentials/RemoteEntry.java b/core/java/android/service/credentials/RemoteEntry.java
new file mode 100644
index 0000000..716c00d
--- /dev/null
+++ b/core/java/android/service/credentials/RemoteEntry.java
@@ -0,0 +1,97 @@
+/*
+ * 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.service.credentials;
+
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.app.PendingIntent;
+import android.app.slice.Slice;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * An entry to be shown on the UI. This entry represents remote execution of a get/create flow
+ * whereby credentials are retrieved from, or stored to a remote device.
+ *
+ * <p>If user selects this entry, the corresponding {@link PendingIntent} set on the
+ * {@code slice} as a {@link androidx.slice.core.SliceAction} will get invoked.
+ * Once the resulting activity fulfills the required user engagement,
+ * the {@link android.app.Activity} result should be set to {@link android.app.Activity#RESULT_OK},
+ * and the result of the operation must be set as the activity result.
+ *
+ * For a get flow, invoked through {@link CredentialProviderService#onBeginGetCredential},
+ * providers must set a {@link android.credentials.GetCredentialResponse} on the activity result,
+ * against the key {@link CredentialProviderService#EXTRA_GET_CREDENTIAL_RESPONSE}.
+ *
+ * For a creates flow, invoked through {@link CredentialProviderService#onBeginCreateCredential},
+ * providers must set a {@link android.credentials.CreateCredentialResponse} on the activity
+ * result against the ket {@link CredentialProviderService#EXTRA_CREATE_CREDENTIAL_RESPONSE}.
+ *
+ * <p>Any class that extends this class must only add extra field values to the {@code slice}
+ * object passed into the constructor. Any other field will not be parceled through. If the
+ * derived class has custom parceling implementation, this class will not be able to unpack
+ * the parcel without having access to that implementation.
+ */
+@SuppressLint("ParcelNotFinal")
+public class RemoteEntry implements Parcelable {
+    private final @NonNull Slice mSlice;
+
+    private RemoteEntry(@NonNull Parcel in) {
+        mSlice = in.readTypedObject(Slice.CREATOR);
+    }
+
+    @NonNull
+    public static final Creator<RemoteEntry> CREATOR = new Creator<RemoteEntry>() {
+        @Override
+        public RemoteEntry createFromParcel(@NonNull Parcel in) {
+            return new RemoteEntry(in);
+        }
+
+        @Override
+        public RemoteEntry[] newArray(int size) {
+            return new RemoteEntry[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeTypedObject(mSlice, flags);
+    }
+
+    /**
+     * Constructs a RemoteEntry to be displayed on the UI.
+     *
+     * @param slice the display content to be displayed on the UI, along with this entry
+     */
+    public RemoteEntry(
+            @NonNull Slice slice) {
+        this.mSlice = slice;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mSlice);
+    }
+
+    /** Returns the content to be displayed with this remote entry on the UI. */
+    @NonNull
+    public Slice getSlice() {
+        return mSlice;
+    }
+}
diff --git a/core/java/android/service/dreams/DreamActivity.java b/core/java/android/service/dreams/DreamActivity.java
index ff14404..a389223 100644
--- a/core/java/android/service/dreams/DreamActivity.java
+++ b/core/java/android/service/dreams/DreamActivity.java
@@ -70,7 +70,7 @@
 
     @Override
     public void onDestroy() {
-        if (mCallback != null && !isFinishing()) {
+        if (mCallback != null) {
             mCallback.onActivityDestroyed();
         }
 
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index d79ea89..c7099fd 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -1588,7 +1588,8 @@
         // If DreamActivity is destroyed, wake up from Dream.
         void onActivityDestroyed() {
             mActivity = null;
-            onDestroy();
+            mWindow = null;
+            detach();
         }
     }
 
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index f53abce..26bc5d12 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -1543,14 +1543,14 @@
         void doVisibilityChanged(boolean visible) {
             if (!mDestroyed) {
                 mVisible = visible;
-                reportVisibility();
+                reportVisibility(false);
                 if (mReportedVisible) processLocalColors();
             } else {
                 AnimationHandler.requestAnimatorsEnabled(visible, this);
             }
         }
 
-        void reportVisibility() {
+        void reportVisibility(boolean forceReport) {
             if (mScreenshotSurfaceControl != null && mVisible) {
                 if (DEBUG) Log.v(TAG, "Frozen so don't report visibility change");
                 return;
@@ -1558,10 +1558,29 @@
             if (!mDestroyed) {
                 mDisplayState = mDisplay == null ? Display.STATE_UNKNOWN : mDisplay.getState();
                 boolean visible = mVisible && mDisplayState != Display.STATE_OFF;
-                if (mReportedVisible != visible) {
+                if (DEBUG) {
+                    Log.v(
+                            TAG,
+                            "reportVisibility"
+                                    + " mReportedVisible="
+                                    + mReportedVisible
+                                    + " mVisible="
+                                    + mVisible
+                                    + " mDisplayState="
+                                    + mDisplayState);
+                }
+                if (mReportedVisible != visible || forceReport) {
                     mReportedVisible = visible;
-                    if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + visible
-                            + "): " + this);
+                    if (DEBUG) {
+                        Log.v(
+                                TAG,
+                                "onVisibilityChanged("
+                                        + visible
+                                        + "): "
+                                        + this
+                                        + " forceReport="
+                                        + forceReport);
+                    }
                     if (visible) {
                         // If becoming visible, in preview mode the surface
                         // may have been destroyed so now we need to make
@@ -2205,22 +2224,22 @@
             }
         }
 
-        private final DisplayListener mDisplayListener = new DisplayListener() {
-            @Override
-            public void onDisplayChanged(int displayId) {
-                if (mDisplay.getDisplayId() == displayId) {
-                    reportVisibility();
-                }
-            }
+        private final DisplayListener mDisplayListener =
+                new DisplayListener() {
+                    @Override
+                    public void onDisplayChanged(int displayId) {
+                        if (mDisplay.getDisplayId() == displayId) {
+                            boolean forceReport = mDisplay.getState() != Display.STATE_DOZE_SUSPEND;
+                            reportVisibility(forceReport);
+                        }
+                    }
 
-            @Override
-            public void onDisplayRemoved(int displayId) {
-            }
+                    @Override
+                    public void onDisplayRemoved(int displayId) {}
 
-            @Override
-            public void onDisplayAdded(int displayId) {
-            }
-        };
+                    @Override
+                    public void onDisplayAdded(int displayId) {}
+                };
 
         private Surface getOrCreateBLASTSurface(int width, int height, int format) {
             Surface ret = null;
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index a746dc6..2ae882c 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -164,10 +164,10 @@
      */
     public static final String SETTINGS_AUDIO_ROUTING = "settings_audio_routing";
 
-    /** Flag to enable/disable flash alerts
+    /** Flag to enable/disable flash notifications
      *  @hide
      */
-    public static final String SETTINGS_FLASH_ALERTS = "settings_flash_alerts";
+    public static final String SETTINGS_FLASH_NOTIFICATIONS = "settings_flash_notifications";
 
     /**
      * Flag to disable/enable showing udfps enroll view in settings. If it's disabled, udfps enroll
@@ -232,7 +232,7 @@
         DEFAULT_FLAGS.put(SETTINGS_ACCESSIBILITY_HEARING_AID_PAGE, "false");
         DEFAULT_FLAGS.put(SETTINGS_PREFER_ACCESSIBILITY_MENU_IN_SYSTEM, "false");
         DEFAULT_FLAGS.put(SETTINGS_AUDIO_ROUTING, "false");
-        DEFAULT_FLAGS.put(SETTINGS_FLASH_ALERTS, "false");
+        DEFAULT_FLAGS.put(SETTINGS_FLASH_NOTIFICATIONS, "true");
         DEFAULT_FLAGS.put(SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, "true");
         DEFAULT_FLAGS.put(SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API, "false");
         DEFAULT_FLAGS.put(SETTINGS_REMOTE_DEVICE_CREDENTIAL_VALIDATION, "false");
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 3cf56c0..6804c5c 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -172,7 +172,7 @@
 
     private boolean isVisibleToAccessibilityService(View view) {
         return view != null && (mA11yManager.isRequestFromAccessibilityTool()
-                || !view.isAccessibilityDataPrivate());
+                || !view.isAccessibilityDataSensitive());
     }
 
     public void findAccessibilityNodeInfoByAccessibilityIdClientThread(
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 4a83bbe..8c4e90c 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -197,6 +197,7 @@
     private int mFPSDivisor = 1;
     private DisplayEventReceiver.VsyncEventData mLastVsyncEventData =
             new DisplayEventReceiver.VsyncEventData();
+    private final FrameData mFrameData = new FrameData();
 
     /**
      * Contains information about the current frame for jank-tracking,
@@ -789,7 +790,7 @@
                 Trace.traceBegin(Trace.TRACE_TAG_VIEW,
                         "Choreographer#doFrame " + vsyncEventData.preferredFrameTimeline().vsyncId);
             }
-            FrameData frameData = new FrameData(frameTimeNanos, vsyncEventData);
+            mFrameData.update(frameTimeNanos, vsyncEventData);
             synchronized (mLock) {
                 if (!mFrameScheduled) {
                     traceMessage("Frame not scheduled");
@@ -827,7 +828,7 @@
                                     + " ms in the past.");
                         }
                     }
-                    frameData = getUpdatedFrameData(frameTimeNanos, frameData, jitterNanos);
+                    mFrameData.update(frameTimeNanos, mDisplayEventReceiver, jitterNanos);
                 }
 
                 if (frameTimeNanos < mLastFrameTimeNanos) {
@@ -862,17 +863,16 @@
             AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
 
             mFrameInfo.markInputHandlingStart();
-            doCallbacks(Choreographer.CALLBACK_INPUT, frameData, frameIntervalNanos);
+            doCallbacks(Choreographer.CALLBACK_INPUT, frameIntervalNanos);
 
             mFrameInfo.markAnimationsStart();
-            doCallbacks(Choreographer.CALLBACK_ANIMATION, frameData, frameIntervalNanos);
-            doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameData,
-                    frameIntervalNanos);
+            doCallbacks(Choreographer.CALLBACK_ANIMATION, frameIntervalNanos);
+            doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameIntervalNanos);
 
             mFrameInfo.markPerformTraversalsStart();
-            doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameData, frameIntervalNanos);
+            doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameIntervalNanos);
 
-            doCallbacks(Choreographer.CALLBACK_COMMIT, frameData, frameIntervalNanos);
+            doCallbacks(Choreographer.CALLBACK_COMMIT, frameIntervalNanos);
         } finally {
             AnimationUtils.unlockAnimationClock();
             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
@@ -886,9 +886,9 @@
         }
     }
 
-    void doCallbacks(int callbackType, FrameData frameData, long frameIntervalNanos) {
+    void doCallbacks(int callbackType, long frameIntervalNanos) {
         CallbackRecord callbacks;
-        long frameTimeNanos = frameData.mFrameTimeNanos;
+        long frameTimeNanos = mFrameData.mFrameTimeNanos;
         synchronized (mLock) {
             // We use "now" to determine when callbacks become due because it's possible
             // for earlier processing phases in a frame to post callbacks that should run
@@ -925,7 +925,7 @@
                     }
                     frameTimeNanos = now - lastFrameOffset;
                     mLastFrameTimeNanos = frameTimeNanos;
-                    frameData = getUpdatedFrameData(frameTimeNanos, frameData, jitterNanos);
+                    mFrameData.update(frameTimeNanos, mDisplayEventReceiver, jitterNanos);
                 }
             }
         }
@@ -937,7 +937,7 @@
                             + ", action=" + c.action + ", token=" + c.token
                             + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
                 }
-                c.run(frameData);
+                c.run(mFrameData);
             }
         } finally {
             synchronized (mLock) {
@@ -1039,21 +1039,38 @@
 
     /** Holds data that describes one possible VSync frame event to render at. */
     public static class FrameTimeline {
-        FrameTimeline(long vsyncId, long expectedPresentTimeNanos, long deadlineNanos) {
-            this.mVsyncId = vsyncId;
-            this.mExpectedPresentTimeNanos = expectedPresentTimeNanos;
-            this.mDeadlineNanos = deadlineNanos;
+        private long mVsyncId = FrameInfo.INVALID_VSYNC_ID;
+        private long mExpectedPresentationTimeNanos = -1;
+        private long mDeadlineNanos = -1;
+        private boolean mInCallback = false;
+
+        FrameTimeline() {
+            // Intentionally empty; defined so that it is not API/public by default.
         }
 
-        private long mVsyncId;
-        private long mExpectedPresentTimeNanos;
-        private long mDeadlineNanos;
+        void setInCallback(boolean inCallback) {
+            mInCallback = inCallback;
+        }
+
+        private void checkInCallback() {
+            if (!mInCallback) {
+                throw new IllegalStateException(
+                        "FrameTimeline is not valid outside of the vsync callback");
+            }
+        }
+
+        void update(long vsyncId, long expectedPresentationTimeNanos, long deadlineNanos) {
+            mVsyncId = vsyncId;
+            mExpectedPresentationTimeNanos = expectedPresentationTimeNanos;
+            mDeadlineNanos = deadlineNanos;
+        }
 
         /**
          * The id that corresponds to this frame timeline, used to correlate a frame
          * produced by HWUI with the timeline data stored in Surface Flinger.
          */
         public long getVsyncId() {
+            checkInCallback();
             return mVsyncId;
         }
 
@@ -1062,13 +1079,15 @@
          * presented.
          */
         public long getExpectedPresentationTimeNanos() {
-            return mExpectedPresentTimeNanos;
+            checkInCallback();
+            return mExpectedPresentationTimeNanos;
         }
 
         /**
          * The time in  {@link System#nanoTime()} timebase which this frame needs to be ready by.
          */
         public long getDeadlineNanos() {
+            checkInCallback();
             return mDeadlineNanos;
         }
     }
@@ -1079,24 +1098,21 @@
      * information including deadline and expected present time.
      */
     public static class FrameData {
-        FrameData(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) {
-            this.mFrameTimeNanos = frameTimeNanos;
-            this.mFrameTimelines = convertFrameTimelines(vsyncEventData);
-            this.mPreferredFrameTimelineIndex =
-                    vsyncEventData.preferredFrameTimelineIndex;
-        }
-
         private long mFrameTimeNanos;
-        private final FrameTimeline[] mFrameTimelines;
+        private final FrameTimeline[] mFrameTimelines =
+                new FrameTimeline[DisplayEventReceiver.VsyncEventData.FRAME_TIMELINES_LENGTH];
         private int mPreferredFrameTimelineIndex;
+        private boolean mInCallback = false;
 
-        void updateFrameData(long frameTimeNanos, int newPreferredFrameTimelineIndex) {
-            mFrameTimeNanos = frameTimeNanos;
-            mPreferredFrameTimelineIndex = newPreferredFrameTimelineIndex;
+        FrameData() {
+            for (int i = 0; i < mFrameTimelines.length; i++) {
+                mFrameTimelines[i] = new FrameTimeline();
+            }
         }
 
         /** The time in nanoseconds when the frame started being rendered. */
         public long getFrameTimeNanos() {
+            checkInCallback();
             return mFrameTimeNanos;
         }
 
@@ -1104,58 +1120,83 @@
         @NonNull
         @SuppressLint("ArrayReturn") // For API consistency and speed.
         public FrameTimeline[] getFrameTimelines() {
+            checkInCallback();
             return mFrameTimelines;
         }
 
         /** The platform-preferred frame timeline. */
         @NonNull
         public FrameTimeline getPreferredFrameTimeline() {
+            checkInCallback();
             return mFrameTimelines[mPreferredFrameTimelineIndex];
         }
 
-        private FrameTimeline[] convertFrameTimelines(
-                DisplayEventReceiver.VsyncEventData vsyncEventData) {
-            FrameTimeline[] frameTimelines =
-                    new FrameTimeline[vsyncEventData.frameTimelines.length];
+        void setInCallback(boolean inCallback) {
+            mInCallback = inCallback;
+            for (int i = 0; i < mFrameTimelines.length; i++) {
+                mFrameTimelines[i].setInCallback(inCallback);
+            }
+        }
+
+        private void checkInCallback() {
+            if (!mInCallback) {
+                throw new IllegalStateException(
+                        "FrameData is not valid outside of the vsync callback");
+            }
+        }
+
+        /**
+         * Update the frame data with a {@code DisplayEventReceiver.VsyncEventData} received from
+         * native.
+         */
+        void update(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) {
+            if (vsyncEventData.frameTimelines.length != mFrameTimelines.length) {
+                throw new IllegalStateException(
+                        "Length of native frame timelines received does not match Java. Did "
+                                + "FRAME_TIMELINES_LENGTH or kFrameTimelinesLength (native) "
+                                + "change?");
+            }
+            mFrameTimeNanos = frameTimeNanos;
+            mPreferredFrameTimelineIndex = vsyncEventData.preferredFrameTimelineIndex;
             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);
+                mFrameTimelines[i].update(frameTimeline.vsyncId,
+                        frameTimeline.expectedPresentationTime, frameTimeline.deadline);
             }
-            return frameTimelines;
-        }
-    }
-
-    /**
-     * 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;
+        /**
+         * Update the frame data when the frame is late.
+         *
+         * @param jitterNanos currentTime - frameTime
+         */
+        void update(
+                long frameTimeNanos, DisplayEventReceiver displayEventReceiver, long jitterNanos) {
+            int newPreferredIndex = 0;
+            final long minimumDeadline =
+                    mFrameTimelines[mPreferredFrameTimelineIndex].mDeadlineNanos + 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 < mFrameTimelines.length - 1
+                    && mFrameTimelines[newPreferredIndex].mDeadlineNanos < minimumDeadline) {
+                newPreferredIndex++;
+            }
+
+            long newPreferredDeadline = mFrameTimelines[newPreferredIndex].mDeadlineNanos;
+            if (newPreferredDeadline < minimumDeadline) {
+                DisplayEventReceiver.VsyncEventData latestVsyncEventData =
+                        displayEventReceiver.getLatestVsyncEventData();
+                update(frameTimeNanos, latestVsyncEventData);
+            } else {
+                update(frameTimeNanos, newPreferredIndex);
+            }
+        }
+
+        void update(long frameTimeNanos, int newPreferredFrameTimelineIndex) {
+            mFrameTimeNanos = frameTimeNanos;
+            mPreferredFrameTimelineIndex = newPreferredFrameTimelineIndex;
         }
     }
 
@@ -1280,11 +1321,13 @@
         }
 
         void run(FrameData frameData) {
+            frameData.setInCallback(true);
             if (token == VSYNC_CALLBACK_TOKEN) {
                 ((VsyncCallback) action).onVsync(frameData);
             } else {
                 run(frameData.getFrameTimeNanos());
             }
+            frameData.setInCallback(false);
         }
     }
 
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index edce001..07ac597 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -145,11 +145,16 @@
 
         static final FrameTimeline[] INVALID_FRAME_TIMELINES =
                 {new FrameTimeline(FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE)};
+        // The amount of frame timeline choices.
+        // Must be in sync with VsyncEventData::kFrameTimelinesLength in
+        // frameworks/native/libs/gui/include/gui/VsyncEventData.h. If they do not match, a runtime
+        // assertion is thrown when Choreographer is processing VsyncEventData.
+        static final int FRAME_TIMELINES_LENGTH = 7;
 
         public static class FrameTimeline {
-            FrameTimeline(long vsyncId, long expectedPresentTime, long deadline) {
+            FrameTimeline(long vsyncId, long expectedPresentationTime, long deadline) {
                 this.vsyncId = vsyncId;
-                this.expectedPresentTime = expectedPresentTime;
+                this.expectedPresentationTime = expectedPresentationTime;
                 this.deadline = deadline;
             }
 
@@ -158,7 +163,7 @@
             public final long vsyncId;
 
             // The frame timestamp for when the frame is expected to be presented.
-            public final long expectedPresentTime;
+            public final long expectedPresentationTime;
 
             // The frame deadline timestamp in {@link System#nanoTime()} timebase that it is
             // allotted for the frame to be completed.
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 0368918..e31adcf 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -24,6 +24,7 @@
 import static android.view.DisplayInfoProto.LOGICAL_WIDTH;
 import static android.view.DisplayInfoProto.NAME;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.WindowConfiguration;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -37,6 +38,7 @@
 import android.os.Process;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
+import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.display.BrightnessSynchronizer;
@@ -348,6 +350,12 @@
      */
     public float hdrSdrRatio = Float.NaN;
 
+    /**
+     * RefreshRateRange limitation for @Temperature.ThrottlingStatus
+     */
+    @NonNull
+    public SparseArray<SurfaceControl.RefreshRateRange> refreshRateThermalThrottling =
+            new SparseArray<>();
 
     public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
         @Override
@@ -425,7 +433,8 @@
                 && installOrientation == other.installOrientation
                 && Objects.equals(displayShape, other.displayShape)
                 && Objects.equals(layoutLimitedRefreshRate, other.layoutLimitedRefreshRate)
-                && BrightnessSynchronizer.floatEquals(hdrSdrRatio, other.hdrSdrRatio);
+                && BrightnessSynchronizer.floatEquals(hdrSdrRatio, other.hdrSdrRatio)
+                && refreshRateThermalThrottling.contentEquals(other.refreshRateThermalThrottling);
     }
 
     @Override
@@ -482,6 +491,7 @@
         displayShape = other.displayShape;
         layoutLimitedRefreshRate = other.layoutLimitedRefreshRate;
         hdrSdrRatio = other.hdrSdrRatio;
+        refreshRateThermalThrottling = other.refreshRateThermalThrottling;
     }
 
     public void readFromParcel(Parcel source) {
@@ -544,6 +554,8 @@
         displayShape = source.readTypedObject(DisplayShape.CREATOR);
         layoutLimitedRefreshRate = source.readTypedObject(SurfaceControl.RefreshRateRange.CREATOR);
         hdrSdrRatio = source.readFloat();
+        refreshRateThermalThrottling = source.readSparseArray(null,
+                SurfaceControl.RefreshRateRange.class);
     }
 
     @Override
@@ -604,6 +616,7 @@
         dest.writeTypedObject(displayShape, flags);
         dest.writeTypedObject(layoutLimitedRefreshRate, flags);
         dest.writeFloat(hdrSdrRatio);
+        dest.writeSparseArray(refreshRateThermalThrottling);
     }
 
     @Override
@@ -871,6 +884,8 @@
         } else {
             sb.append(hdrSdrRatio);
         }
+        sb.append(", refreshRateThermalThrottling ");
+        sb.append(refreshRateThermalThrottling);
         sb.append("}");
         return sb.toString();
     }
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index 98f61a3..fa92612 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -172,9 +172,13 @@
                         if (candidateView == getConnectedView()) {
                             startHandwriting(candidateView);
                         } else if (candidateView.getHandwritingDelegatorCallback() != null) {
+                            String delegatePackageName =
+                                    candidateView.getAllowedHandwritingDelegatePackageName();
+                            if (delegatePackageName == null) {
+                                delegatePackageName = candidateView.getContext().getOpPackageName();
+                            }
                             mImm.prepareStylusHandwritingDelegation(
-                                    candidateView,
-                                    candidateView.getAllowedHandwritingDelegatePackageName());
+                                    candidateView, delegatePackageName);
                             candidateView.getHandwritingDelegatorCallback().run();
                         } else {
                             if (candidateView.getRevealOnFocusHint()) {
@@ -299,8 +303,12 @@
      */
     @VisibleForTesting
     public boolean tryAcceptStylusHandwritingDelegation(@NonNull View view) {
-        if (mImm.acceptStylusHandwritingDelegation(
-                view, view.getAllowedHandwritingDelegatorPackageName())) {
+        String delegatorPackageName =
+                view.getAllowedHandwritingDelegatorPackageName();
+        if (delegatorPackageName == null) {
+            delegatorPackageName = view.getContext().getOpPackageName();
+        }
+        if (mImm.acceptStylusHandwritingDelegation(view, delegatorPackageName)) {
             if (mState != null) {
                 mState.mHasInitiatedHandwriting = true;
                 mState.mShouldInitHandwriting = false;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index fee2051..869efc69 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3114,33 +3114,33 @@
      * Accessibility interactions from services without {@code isAccessibilityTool} set to true are
      * disallowed for any of the following conditions:
      * <li>this view sets {@link #getFilterTouchesWhenObscured()}.</li>
-     * <li>any parent of this view returns true from {@link #isAccessibilityDataPrivate()}.</li>
+     * <li>any parent of this view returns true from {@link #isAccessibilityDataSensitive()}.</li>
      * </p>
      */
-    public static final int ACCESSIBILITY_DATA_PRIVATE_AUTO = 0x00000000;
+    public static final int ACCESSIBILITY_DATA_SENSITIVE_AUTO = 0x00000000;
 
     /**
      * Only allow interactions from {@link android.accessibilityservice.AccessibilityService}s
      * with the {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool}
      * property set to true.
      */
-    public static final int ACCESSIBILITY_DATA_PRIVATE_YES = 0x00000001;
+    public static final int ACCESSIBILITY_DATA_SENSITIVE_YES = 0x00000001;
 
     /**
      * Allow interactions from all {@link android.accessibilityservice.AccessibilityService}s,
      * regardless of their
      * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property.
      */
-    public static final int ACCESSIBILITY_DATA_PRIVATE_NO = 0x00000002;
+    public static final int ACCESSIBILITY_DATA_SENSITIVE_NO = 0x00000002;
 
     /** @hide */
-    @IntDef(prefix = { "ACCESSIBILITY_DATA_PRIVATE_" }, value = {
-            ACCESSIBILITY_DATA_PRIVATE_AUTO,
-            ACCESSIBILITY_DATA_PRIVATE_YES,
-            ACCESSIBILITY_DATA_PRIVATE_NO,
+    @IntDef(prefix = { "ACCESSIBILITY_DATA_SENSITIVE_" }, value = {
+            ACCESSIBILITY_DATA_SENSITIVE_AUTO,
+            ACCESSIBILITY_DATA_SENSITIVE_YES,
+            ACCESSIBILITY_DATA_SENSITIVE_NO,
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface AccessibilityDataPrivate {}
+    public @interface AccessibilityDataSensitive {}
 
     /**
      * Mask for obtaining the bits which specify how to determine
@@ -4611,9 +4611,9 @@
      * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property
      * set to true.
      */
-    private int mExplicitAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_AUTO;
-    /** Used to calculate and cache {@link #isAccessibilityDataPrivate()}. */
-    private int mInferredAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_AUTO;
+    private int mExplicitAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_AUTO;
+    /** Used to calculate and cache {@link #isAccessibilityDataSensitive()}. */
+    private int mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_AUTO;
 
     /**
      * Specifies the id of a view for which this view serves as a label for
@@ -6016,9 +6016,9 @@
                     setImportantForAccessibility(a.getInt(attr,
                             IMPORTANT_FOR_ACCESSIBILITY_DEFAULT));
                     break;
-                case R.styleable.View_accessibilityDataPrivate:
-                    setAccessibilityDataPrivate(a.getInt(attr,
-                            ACCESSIBILITY_DATA_PRIVATE_AUTO));
+                case R.styleable.View_accessibilityDataSensitive:
+                    setAccessibilityDataSensitive(a.getInt(attr,
+                            ACCESSIBILITY_DATA_SENSITIVE_AUTO));
                     break;
                 case R.styleable.View_accessibilityLiveRegion:
                     setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT));
@@ -8660,9 +8660,9 @@
      * is responsible for handling this call.
      * </p>
      * <p>
-     * If this view sets {@link #isAccessibilityDataPrivate()} then this view should only append
+     * If this view sets {@link #isAccessibilityDataSensitive()} then this view should only append
      * sensitive information to an event that also sets
-     * {@link AccessibilityEvent#isAccessibilityDataPrivate()}.
+     * {@link AccessibilityEvent#isAccessibilityDataSensitive()}.
      * </p>
      * <p>
      * <em>Note:</em> Accessibility events of certain types are not dispatched for
@@ -10697,6 +10697,7 @@
         info.setVisibleToUser(isVisibleToUser());
 
         info.setImportantForAccessibility(isImportantForAccessibility());
+        info.setAccessibilityDataSensitive(isAccessibilityDataSensitive());
         info.setPackageName(mContext.getPackageName());
         info.setClassName(getAccessibilityClassName());
         info.setStateDescription(getStateDescription());
@@ -12437,11 +12438,7 @@
     public void setHandwritingDelegatorCallback(@Nullable Runnable callback) {
         mHandwritingDelegatorCallback = callback;
         if (callback != null) {
-            // By default, the delegate must be from the same package as the delegator view.
-            mAllowedHandwritingDelegatePackageName = mContext.getOpPackageName();
             setHandwritingArea(new Rect(0, 0, getWidth(), getHeight()));
-        } else {
-            mAllowedHandwritingDelegatePackageName = null;
         }
     }
 
@@ -12460,8 +12457,10 @@
      * view from the specified package. If this method is not called, delegators may only be used to
      * initiate handwriting mode for a delegate editor view from the same package as the delegator
      * view. This method allows specifying a different trusted package which may contain a delegate
-     * editor view linked to this delegator view. This should be called after {@link
-     * #setHandwritingDelegatorCallback}.
+     * editor view linked to this delegator view.
+     *
+     * <p>This method has no effect unless {@link #setHandwritingDelegatorCallback} is also called
+     * to configure this view to act as a handwriting delegator.
      *
      * <p>If this method is called on the delegator view, then {@link
      * #setAllowedHandwritingDelegatorPackage} should also be called on the delegate editor view.
@@ -12479,33 +12478,23 @@
      * delegateEditorView.setAllowedHandwritingDelegatorPackage(package1);</pre>
      *
      * @param allowedPackageName the package name of a delegate editor view linked to this delegator
-     *     view
-     * @throws IllegalStateException If the view has not been configured as a handwriting delegator
-     *     using {@link #setHandwritingDelegatorCallback}.
+     *     view, or {@code null} to restore the default behavior of only allowing delegate editor
+     *     views from the same package as this delegator view
      */
-    public void setAllowedHandwritingDelegatePackage(@NonNull String allowedPackageName) {
-        if (mHandwritingDelegatorCallback == null) {
-            throw new IllegalStateException("This view is not a handwriting delegator.");
-        }
+    public void setAllowedHandwritingDelegatePackage(@Nullable String allowedPackageName) {
         mAllowedHandwritingDelegatePackageName = allowedPackageName;
     }
 
     /**
      * Returns the allowed package for delegate editor views for which this view may act as a
-     * handwriting delegator. If {@link #setAllowedHandwritingDelegatePackage} has not been called,
-     * this will return this view's package name, since by default delegators may only be used to
-     * initiate handwriting mode for a delegate editor view from the same package as the delegator
-     * view. This will return a different allowed package if set by {@link
-     * #setAllowedHandwritingDelegatePackage}.
-     *
-     * @throws IllegalStateException If the view has not been configured as a handwriting delegator
-     *     using {@link #setHandwritingDelegatorCallback}.
+     * handwriting delegator, as set by {@link #setAllowedHandwritingDelegatePackage}. If {@link
+     * #setAllowedHandwritingDelegatePackage} has not been called, or called with {@code null}
+     * argument, this will return {@code null}, meaning that this delegator view may only be used to
+     * initiate handwriting mode for a delegate editor view from the same package as this delegator
+     * view.
      */
-    @NonNull
+    @Nullable
     public String getAllowedHandwritingDelegatePackageName() {
-        if (mHandwritingDelegatorCallback == null) {
-            throw new IllegalStateException("This view is not a handwriting delegator.");
-        }
         return mAllowedHandwritingDelegatePackageName;
     }
 
@@ -12519,12 +12508,6 @@
      */
     public void setIsHandwritingDelegate(boolean isHandwritingDelegate) {
         mIsHandwritingDelegate = isHandwritingDelegate;
-        if (mIsHandwritingDelegate) {
-            // By default, the delegator must be from the same package as the delegate view.
-            mAllowedHandwritingDelegatorPackageName = mContext.getOpPackageName();
-        } else {
-            mAllowedHandwritingDelegatePackageName = null;
-        }
     }
 
     /**
@@ -12537,41 +12520,34 @@
 
     /**
      * Specifies that a view from the specified package may act as a handwriting delegator for this
-     * delegate editor view. If this method is not called, only views from the same package as the
+     * delegate editor view. If this method is not called, only views from the same package as this
      * delegate editor view may act as a handwriting delegator. This method allows specifying a
      * different trusted package which may contain a delegator view linked to this delegate editor
-     * view. This should be called after {@link #setIsHandwritingDelegate}.
+     * view.
+     *
+     * <p>This method has no effect unless {@link #setIsHandwritingDelegate} is also called to
+     * configure this view to act as a handwriting delegate.
      *
      * <p>If this method is called on the delegate editor view, then {@link
      * #setAllowedHandwritingDelegatePackage} should also be called on the delegator view.
      *
      * @param allowedPackageName the package name of a delegator view linked to this delegate editor
-     *     view
-     * @throws IllegalStateException If the view has not been configured as a handwriting delegate
-     *     using {@link #setIsHandwritingDelegate}.
+     *     view, or {@code null} to restore the default behavior of only allowing delegator views
+     *     from the same package as this delegate editor view
      */
-    public void setAllowedHandwritingDelegatorPackage(@NonNull String allowedPackageName) {
-        if (!mIsHandwritingDelegate) {
-            throw new IllegalStateException("This view is not a handwriting delegate.");
-        }
+    public void setAllowedHandwritingDelegatorPackage(@Nullable String allowedPackageName) {
         mAllowedHandwritingDelegatorPackageName = allowedPackageName;
     }
 
     /**
      * Returns the allowed package for views which may act as a handwriting delegator for this
-     * delegate editor view. If {@link #setAllowedHandwritingDelegatorPackage} has not been called,
-     * this will return this view's package name, since by default only views from the same package
-     * as the delegator editor view may act as a handwriting delegator. This will return a different
-     * allowed package if set by {@link #setAllowedHandwritingDelegatorPackage}.
-     *
-     * @throws IllegalStateException If the view has not been configured as a handwriting delegate
-     *     using {@link #setIsHandwritingDelegate}.
+     * delegate editor view, as set by {@link #setAllowedHandwritingDelegatorPackage}. If {@link
+     * #setAllowedHandwritingDelegatorPackage} has not been called, or called with {@code null}
+     * argument, this will return {@code null}, meaning that only views from the same package as
+     * this delegator editor view may act as a handwriting delegator.
      */
-    @NonNull
+    @Nullable
     public String getAllowedHandwritingDelegatorPackageName() {
-        if (!mIsHandwritingDelegate) {
-            throw new IllegalStateException("This view is not a handwriting delegate.");
-        }
         return mAllowedHandwritingDelegatorPackageName;
     }
 
@@ -13606,7 +13582,7 @@
     public void setFilterTouchesWhenObscured(boolean enabled) {
         setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0,
                 FILTER_TOUCHES_WHEN_OBSCURED);
-        calculateAccessibilityDataPrivate();
+        calculateAccessibilityDataSensitive();
     }
 
     /**
@@ -14842,7 +14818,7 @@
             // source View's AccessibilityDataPrivate value, and then filtering is done when
             // AccessibilityManagerService propagates events to each recipient AccessibilityService.
             if (!AccessibilityManager.getInstance(mContext).isRequestFromAccessibilityTool()
-                    && isAccessibilityDataPrivate()) {
+                    && isAccessibilityDataSensitive()) {
                 return false;
             }
         }
@@ -14858,43 +14834,43 @@
      * set to true.
      *
      * <p>
-     * See default behavior provided by {@link #ACCESSIBILITY_DATA_PRIVATE_AUTO}. Otherwise,
-     * returns true for {@link #ACCESSIBILITY_DATA_PRIVATE_YES} or false for {@link
-     * #ACCESSIBILITY_DATA_PRIVATE_NO}.
+     * See default behavior provided by {@link #ACCESSIBILITY_DATA_SENSITIVE_AUTO}. Otherwise,
+     * returns true for {@link #ACCESSIBILITY_DATA_SENSITIVE_YES} or false for {@link
+     * #ACCESSIBILITY_DATA_SENSITIVE_NO}.
      * </p>
      *
      * @return True if this view should restrict accessibility service access to services that have
      * the isAccessibilityTool property.
      */
     @ViewDebug.ExportedProperty(category = "accessibility")
-    public boolean isAccessibilityDataPrivate() {
-        if (mInferredAccessibilityDataPrivate == ACCESSIBILITY_DATA_PRIVATE_AUTO) {
-            calculateAccessibilityDataPrivate();
+    public boolean isAccessibilityDataSensitive() {
+        if (mInferredAccessibilityDataSensitive == ACCESSIBILITY_DATA_SENSITIVE_AUTO) {
+            calculateAccessibilityDataSensitive();
         }
-        return mInferredAccessibilityDataPrivate == ACCESSIBILITY_DATA_PRIVATE_YES;
+        return mInferredAccessibilityDataSensitive == ACCESSIBILITY_DATA_SENSITIVE_YES;
     }
 
     /**
-     * Calculate and cache the inferred value for {@link #isAccessibilityDataPrivate()}.
+     * Calculate and cache the inferred value for {@link #isAccessibilityDataSensitive()}.
      *
      * <p>
      * <strong>Note:</strong> This method needs to be called any time one of the below conditions
      * changes, to recalculate the new value.
      * </p>
      */
-    void calculateAccessibilityDataPrivate() {
+    void calculateAccessibilityDataSensitive() {
         // Use the explicit value if set.
-        if (mExplicitAccessibilityDataPrivate != ACCESSIBILITY_DATA_PRIVATE_AUTO) {
-            mInferredAccessibilityDataPrivate = mExplicitAccessibilityDataPrivate;
+        if (mExplicitAccessibilityDataSensitive != ACCESSIBILITY_DATA_SENSITIVE_AUTO) {
+            mInferredAccessibilityDataSensitive = mExplicitAccessibilityDataSensitive;
         } else if (getFilterTouchesWhenObscured()) {
-            // Views that set filterTouchesWhenObscured default to accessibilityDataPrivate.
-            mInferredAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_YES;
-        } else if (mParent instanceof View && ((View) mParent).isAccessibilityDataPrivate()) {
-            // Descendants of an accessibilityDataPrivate View are also accessibilityDataPrivate.
-            mInferredAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_YES;
+            // Views that set filterTouchesWhenObscured default to accessibilityDataSensitive.
+            mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_YES;
+        } else if (mParent instanceof View && ((View) mParent).isAccessibilityDataSensitive()) {
+            // Descendants of accessibilityDataSensitive Views are also accessibilityDataSensitive.
+            mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_YES;
         } else {
-            // Otherwise, default to not accessibilityDataPrivate.
-            mInferredAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_NO;
+            // Otherwise, default to not accessibilityDataSensitive.
+            mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_NO;
         }
     }
 
@@ -14904,10 +14880,10 @@
      * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property
      * set to true.
      */
-    public void setAccessibilityDataPrivate(
-            @AccessibilityDataPrivate int accessibilityDataPrivate) {
-        mExplicitAccessibilityDataPrivate = accessibilityDataPrivate;
-        calculateAccessibilityDataPrivate();
+    public void setAccessibilityDataSensitive(
+            @AccessibilityDataSensitive int accessibilityDataSensitive) {
+        mExplicitAccessibilityDataSensitive = accessibilityDataSensitive;
+        calculateAccessibilityDataSensitive();
     }
 
     /**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 73d4471..46ae3ea 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3921,10 +3921,10 @@
     }
 
     @Override
-    void calculateAccessibilityDataPrivate() {
-        super.calculateAccessibilityDataPrivate();
+    void calculateAccessibilityDataSensitive() {
+        super.calculateAccessibilityDataSensitive();
         for (int i = 0; i < mChildrenCount; i++) {
-            mChildren[i].calculateAccessibilityDataPrivate();
+            mChildren[i].calculateAccessibilityDataSensitive();
         }
     }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 71a3a7b..807af5b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1650,6 +1650,7 @@
                 mAttachInfo.mThreadedRenderer = renderer;
                 renderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue);
                 updateColorModeIfNeeded(attrs.getColorMode());
+                updateRenderHdrSdrRatio();
                 updateForceDarkMode();
                 mAttachInfo.mHardwareAccelerated = true;
                 mAttachInfo.mHardwareAccelerationRequested = true;
@@ -5379,6 +5380,11 @@
         }
     }
 
+    private void updateRenderHdrSdrRatio() {
+        mRenderHdrSdrRatio = mDisplay.getHdrSdrRatio();
+        mUpdateHdrSdrRatioInfo = true;
+    }
+
     private void updateColorModeIfNeeded(@ActivityInfo.ColorMode int colorMode) {
         if (mAttachInfo.mThreadedRenderer == null) {
             return;
@@ -5396,8 +5402,7 @@
         float desiredRatio = mAttachInfo.mThreadedRenderer.setColorMode(colorMode);
         if (desiredRatio != mDesiredHdrSdrRatio) {
             mDesiredHdrSdrRatio = desiredRatio;
-            mRenderHdrSdrRatio = mDisplay.getHdrSdrRatio();
-            mUpdateHdrSdrRatioInfo = true;
+            updateRenderHdrSdrRatio();
 
             if (mDesiredHdrSdrRatio < 1.01f) {
                 mDisplay.unregisterHdrSdrRatioChangedListener(mHdrSdrRatioChangedListener);
@@ -8496,6 +8501,7 @@
             if (mAttachInfo.mThreadedRenderer != null) {
                 mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue);
             }
+            updateRenderHdrSdrRatio();
             if (mPreviousTransformHint != transformHint) {
                 mPreviousTransformHint = transformHint;
                 dispatchTransformHintChanged(transformHint);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index e7cefd6..f863678 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -817,6 +817,15 @@
     }
 
     /**
+     * If the display {@link Configuration#smallestScreenWidthDp} is greater or equal to this value,
+     * we will treat it as a large screen device, which will have some multi window features enabled
+     * by default.
+     * @hide
+     */
+    @TestApi
+    int LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP = 600;
+
+    /**
      * Application level {@link android.content.pm.PackageManager.Property PackageManager
      * .Property} for an app to inform the system that the app can be opted-in or opted-out
      * from the compatibility treatment that avoids {@link
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 33b763b..0acc022 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -56,7 +56,7 @@
  * accessibility service has not requested to retrieve the window content the event will
  * not contain reference to its source. <strong>Note: </strong> for events of type
  * {@link #TYPE_NOTIFICATION_STATE_CHANGED} the source is never available, and Views that set
- * {@link android.view.View#isAccessibilityDataPrivate()} may not populate all event properties on
+ * {@link android.view.View#isAccessibilityDataSensitive()} may not populate all event properties on
  * events sent from higher up in the view hierarchy.
  * </p>
  * <p>
@@ -1168,17 +1168,17 @@
      * set to true.
      *
      * <p>
-     * Initial value matches the {@link android.view.View#isAccessibilityDataPrivate} property from
-     * the event's source node, if present, or false by default.
+     * Initial value matches the {@link android.view.View#isAccessibilityDataSensitive} property
+     * from the event's source node, if present, or false by default.
      * </p>
      *
      * @return True if the event should be delivered only to isAccessibilityTool services, false
      * otherwise.
-     * @see #setAccessibilityDataPrivate
+     * @see #setAccessibilityDataSensitive
      */
     @Override
-    public boolean isAccessibilityDataPrivate() {
-        return super.isAccessibilityDataPrivate();
+    public boolean isAccessibilityDataSensitive() {
+        return super.isAccessibilityDataSensitive();
     }
 
     /**
@@ -1193,13 +1193,13 @@
      * no source) then this method must be called explicitly if you want non-default behavior.
      * </p>
      *
-     * @param accessibilityDataPrivate True if the event should be delivered only to
+     * @param accessibilityDataSensitive True if the event should be delivered only to
      *                                 isAccessibilityTool services, false otherwise.
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     @Override
-    public void setAccessibilityDataPrivate(boolean accessibilityDataPrivate) {
-        super.setAccessibilityDataPrivate(accessibilityDataPrivate);
+    public void setAccessibilityDataSensitive(boolean accessibilityDataSensitive) {
+        super.setAccessibilityDataSensitive(accessibilityDataSensitive);
     }
 
     /**
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 247e026..9d82b79 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -834,6 +834,8 @@
 
     private static final int BOOLEAN_PROPERTY_REQUEST_TOUCH_PASSTHROUGH = 1 << 25;
 
+    private static final int BOOLEAN_PROPERTY_ACCESSIBILITY_DATA_SENSITIVE = 1 << 26;
+
     /**
      * Bits that provide the id of a virtual descendant of a view.
      */
@@ -2644,6 +2646,34 @@
     }
 
     /**
+     * Gets if the node's accessibility data is considered sensitive.
+     *
+     * @return True if the node is editable, false otherwise.
+     * @see View#isAccessibilityDataSensitive()
+     */
+    public boolean isAccessibilityDataSensitive() {
+        return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_DATA_SENSITIVE);
+    }
+
+    /**
+     * Sets whether this node's accessibility data is considered sensitive.
+     *
+     * <p>
+     * <strong>Note:</strong> Cannot be called from an {@link AccessibilityService}.
+     * This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param accessibilityDataSensitive True if the node's accessibility data is considered
+     *                                   sensitive.
+     * @throws IllegalStateException If called from an AccessibilityService.
+     * @see View#setAccessibilityDataSensitive
+     */
+    public void setAccessibilityDataSensitive(boolean accessibilityDataSensitive) {
+        setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_DATA_SENSITIVE,
+                accessibilityDataSensitive);
+    }
+
+    /**
      * If this node represents a visually distinct region of the screen that may update separately
      * from the rest of the window, it is considered a pane. Set the pane title to indicate that
      * the node is a pane, and to provide a title for it.
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index 789c740..38b564a 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -72,7 +72,7 @@
     private static final int PROPERTY_FULL_SCREEN = 0x00000080;
     private static final int PROPERTY_SCROLLABLE = 0x00000100;
     private static final int PROPERTY_IMPORTANT_FOR_ACCESSIBILITY = 0x00000200;
-    private static final int PROPERTY_ACCESSIBILITY_DATA_PRIVATE = 0x00000400;
+    private static final int PROPERTY_ACCESSIBILITY_DATA_SENSITIVE = 0x00000400;
 
     private static final int GET_SOURCE_PREFETCH_FLAGS =
             AccessibilityNodeInfo.FLAG_PREFETCH_ANCESTORS
@@ -160,8 +160,8 @@
             important = root.isImportantForAccessibility();
             rootViewId = root.getAccessibilityViewId();
             mSourceWindowId = root.getAccessibilityWindowId();
-            setBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_PRIVATE,
-                    root.isAccessibilityDataPrivate());
+            setBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_SENSITIVE,
+                    root.isAccessibilityDataSensitive());
         }
         setBooleanProperty(PROPERTY_IMPORTANT_FOR_ACCESSIBILITY, important);
         mSourceNodeId = AccessibilityNodeInfo.makeNodeId(rootViewId, virtualDescendantId);
@@ -391,20 +391,20 @@
     }
 
     /**
-     * @see AccessibilityEvent#isAccessibilityDataPrivate
+     * @see AccessibilityEvent#isAccessibilityDataSensitive
      * @hide
      */
-    boolean isAccessibilityDataPrivate() {
-        return getBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_PRIVATE);
+    boolean isAccessibilityDataSensitive() {
+        return getBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_SENSITIVE);
     }
 
     /**
-     * @see AccessibilityEvent#setAccessibilityDataPrivate
+     * @see AccessibilityEvent#setAccessibilityDataSensitive
      * @hide
      */
-    void setAccessibilityDataPrivate(boolean accessibilityDataPrivate) {
+    void setAccessibilityDataSensitive(boolean accessibilityDataSensitive) {
         enforceNotSealed();
-        setBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_PRIVATE, accessibilityDataPrivate);
+        setBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_SENSITIVE, accessibilityDataSensitive);
     }
 
     /**
@@ -962,7 +962,7 @@
         appendUnless(false, PROPERTY_FULL_SCREEN, builder);
         appendUnless(false, PROPERTY_SCROLLABLE, builder);
         appendUnless(false, PROPERTY_IMPORTANT_FOR_ACCESSIBILITY, builder);
-        appendUnless(false, PROPERTY_ACCESSIBILITY_DATA_PRIVATE, builder);
+        appendUnless(false, PROPERTY_ACCESSIBILITY_DATA_SENSITIVE, builder);
 
         append(builder, "BeforeText", mBeforeText);
         append(builder, "FromIndex", mFromIndex);
@@ -996,8 +996,8 @@
             case PROPERTY_SCROLLABLE: return "Scrollable";
             case PROPERTY_IMPORTANT_FOR_ACCESSIBILITY:
                 return "ImportantForAccessibility";
-            case PROPERTY_ACCESSIBILITY_DATA_PRIVATE:
-                return "AccessibilityDataPrivate";
+            case PROPERTY_ACCESSIBILITY_DATA_SENSITIVE:
+                return "AccessibilityDataSensitive";
             default: return Integer.toHexString(prop);
         }
     }
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index d84e0fb..13ac329 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -839,6 +839,7 @@
         mConnectionId = UNDEFINED_WINDOW_ID;
         mAnchorId = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
         mTitle = null;
+        mTransitionTime = 0;
     }
 
     /**
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index b7f03e1..62044aa 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -182,6 +182,10 @@
     /** @hide */
     public static final int FLUSH_REASON_VIEW_TREE_APPEARED = 10;
 
+    /**
+     * After {@link UPSIDE_DOWN_CAKE}, {@link #notifyViewsDisappeared(AutofillId, long[])} wraps
+     * the virtual children with a pair of view tree appearing and view tree appeared events.
+     */
     @ChangeId
     @EnabledSince(targetSdkVersion = UPSIDE_DOWN_CAKE)
     static final long NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS = 258825825L;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index fd8f549..1600a16 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -13221,10 +13221,10 @@
     public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         super.onPopulateAccessibilityEventInternal(event);
 
-        if (this.isAccessibilityDataPrivate() && !event.isAccessibilityDataPrivate()) {
-            // This view's accessibility data is private, but another view that generated this event
-            // is not, so don't append this view's text to the event in order to prevent sharing
-            // this view's contents with non-accessibility-tool services.
+        if (this.isAccessibilityDataSensitive() && !event.isAccessibilityDataSensitive()) {
+            // This view's accessibility data is sensitive, but another view that generated this
+            // event is not, so don't append this view's text to the event in order to prevent
+            // sharing this view's contents with non-accessibility-tool services.
             return;
         }
 
diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java
index a881a05..fa51957 100644
--- a/core/java/android/window/TaskFragmentInfo.java
+++ b/core/java/android/window/TaskFragmentInfo.java
@@ -66,6 +66,13 @@
     @NonNull
     private final List<IBinder> mActivities = new ArrayList<>();
 
+    /**
+     * List of Activity tokens that were explicitly requested to be launched in this TaskFragment.
+     * It only contains Activities that belong to the organizer process for security.
+     */
+    @NonNull
+    private final List<IBinder> mInRequestedTaskFragmentActivities = new ArrayList<>();
+
     /** Relative position of the fragment's top left corner in the parent container. */
     private final Point mPositionInParent = new Point();
 
@@ -99,15 +106,18 @@
     public TaskFragmentInfo(
             @NonNull IBinder fragmentToken, @NonNull WindowContainerToken token,
             @NonNull Configuration configuration, int runningActivityCount,
-            boolean isVisible, @NonNull List<IBinder> activities, @NonNull Point positionInParent,
-            boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip,
-            boolean isClearedForReorderActivityToFront, @NonNull Point minimumDimensions) {
+            boolean isVisible, @NonNull List<IBinder> activities,
+            @NonNull List<IBinder> inRequestedTaskFragmentActivities,
+            @NonNull Point positionInParent, boolean isTaskClearedForReuse,
+            boolean isTaskFragmentClearedForPip, boolean isClearedForReorderActivityToFront,
+            @NonNull Point minimumDimensions) {
         mFragmentToken = requireNonNull(fragmentToken);
         mToken = requireNonNull(token);
         mConfiguration.setTo(configuration);
         mRunningActivityCount = runningActivityCount;
         mIsVisible = isVisible;
         mActivities.addAll(activities);
+        mInRequestedTaskFragmentActivities.addAll(inRequestedTaskFragmentActivities);
         mPositionInParent.set(positionInParent);
         mIsTaskClearedForReuse = isTaskClearedForReuse;
         mIsTaskFragmentClearedForPip = isTaskFragmentClearedForPip;
@@ -151,6 +161,11 @@
         return mActivities;
     }
 
+    @NonNull
+    public List<IBinder> getActivitiesRequestedInTaskFragment() {
+        return mInRequestedTaskFragmentActivities;
+    }
+
     /** Returns the relative position of the fragment's top left corner in the parent container. */
     @NonNull
     public Point getPositionInParent() {
@@ -215,6 +230,8 @@
                 && mIsVisible == that.mIsVisible
                 && getWindowingMode() == that.getWindowingMode()
                 && mActivities.equals(that.mActivities)
+                && mInRequestedTaskFragmentActivities.equals(
+                        that.mInRequestedTaskFragmentActivities)
                 && mPositionInParent.equals(that.mPositionInParent)
                 && mIsTaskClearedForReuse == that.mIsTaskClearedForReuse
                 && mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip
@@ -229,6 +246,7 @@
         mRunningActivityCount = in.readInt();
         mIsVisible = in.readBoolean();
         in.readBinderList(mActivities);
+        in.readBinderList(mInRequestedTaskFragmentActivities);
         mPositionInParent.readFromParcel(in);
         mIsTaskClearedForReuse = in.readBoolean();
         mIsTaskFragmentClearedForPip = in.readBoolean();
@@ -245,6 +263,7 @@
         dest.writeInt(mRunningActivityCount);
         dest.writeBoolean(mIsVisible);
         dest.writeBinderList(mActivities);
+        dest.writeBinderList(mInRequestedTaskFragmentActivities);
         mPositionInParent.writeToParcel(dest, flags);
         dest.writeBoolean(mIsTaskClearedForReuse);
         dest.writeBoolean(mIsTaskFragmentClearedForPip);
@@ -274,6 +293,7 @@
                 + " runningActivityCount=" + mRunningActivityCount
                 + " isVisible=" + mIsVisible
                 + " activities=" + mActivities
+                + " inRequestedTaskFragmentActivities" + mInRequestedTaskFragmentActivities
                 + " positionInParent=" + mPositionInParent
                 + " isTaskClearedForReuse=" + mIsTaskClearedForReuse
                 + " isTaskFragmentClearedForPip=" + mIsTaskFragmentClearedForPip
diff --git a/core/java/com/android/internal/jank/EventLogTags.logtags b/core/java/com/android/internal/jank/EventLogTags.logtags
index 7af5d8f..ad47b81 100644
--- a/core/java/com/android/internal/jank/EventLogTags.logtags
+++ b/core/java/com/android/internal/jank/EventLogTags.logtags
@@ -3,8 +3,8 @@
 option java_package com.android.internal.jank;
 
 # Marks a request to start tracing a CUJ. Doesn't mean the request was executed.
-37001 jank_cuj_events_begin_request (CUJ Type|1|5),(Elapsed Time Ns|2|3),(Uptime Ns|2|3)
+37001 jank_cuj_events_begin_request (CUJ Type|1|5),(Unix Time Ns|2|3),(Elapsed Time Ns|2|3),(Uptime Ns|2|3)
 # Marks a request to end tracing a CUJ. Doesn't mean the request was executed.
-37002 jank_cuj_events_end_request (CUJ Type|1|5),(Elapsed Time Ns|2|3),(Uptime Time Ns|2|3)
+37002 jank_cuj_events_end_request (CUJ Type|1|5),(Unix Time Ns|2|3),(Elapsed Time Ns|2|3),(Uptime Time Ns|2|3)
 # Marks a request to cancel tracing a CUJ. Doesn't mean the request was executed.
-37003 jank_cuj_events_cancel_request (CUJ Type|1|5),(Elapsed Time Ns|2|3),(Uptime Time Ns|2|3)
+37003 jank_cuj_events_cancel_request (CUJ Type|1|5),(Unix Time Ns|2|3),(Elapsed Time Ns|2|3),(Uptime Time Ns|2|3)
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index d93fff9..7ae63b1 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -128,6 +128,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.time.Instant;
 import java.util.Locale;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
@@ -578,8 +579,10 @@
     public boolean begin(@NonNull Configuration.Builder builder) {
         try {
             final Configuration config = builder.build();
-            EventLogTags.writeJankCujEventsBeginRequest(
-                    config.mCujType, SystemClock.elapsedRealtimeNanos(), SystemClock.uptimeNanos());
+            postEventLogToWorkerThread((unixNanos, elapsedNanos, realtimeNanos) -> {
+                EventLogTags.writeJankCujEventsBeginRequest(
+                        config.mCujType, unixNanos, elapsedNanos, realtimeNanos);
+            });
             final TrackerResult result = new TrackerResult();
             final boolean success = config.getHandler().runWithScissors(
                     () -> result.mResult = beginInternal(config), EXECUTOR_TASK_TIMEOUT);
@@ -653,8 +656,10 @@
      * @return boolean true if the tracker is ended successfully, false otherwise.
      */
     public boolean end(@CujType int cujType) {
-        EventLogTags.writeJankCujEventsEndRequest(cujType, SystemClock.elapsedRealtimeNanos(),
-                SystemClock.uptimeNanos());
+        postEventLogToWorkerThread((unixNanos, elapsedNanos, realtimeNanos) -> {
+            EventLogTags.writeJankCujEventsEndRequest(
+                    cujType, unixNanos, elapsedNanos, realtimeNanos);
+        });
         FrameTracker tracker = getTracker(cujType);
         // Skip this call since we haven't started a trace yet.
         if (tracker == null) return false;
@@ -692,8 +697,10 @@
      * @return boolean true if the tracker is cancelled successfully, false otherwise.
      */
     public boolean cancel(@CujType int cujType) {
-        EventLogTags.writeJankCujEventsCancelRequest(cujType, SystemClock.elapsedRealtimeNanos(),
-                SystemClock.uptimeNanos());
+        postEventLogToWorkerThread((unixNanos, elapsedNanos, realtimeNanos) -> {
+            EventLogTags.writeJankCujEventsCancelRequest(
+                    cujType, unixNanos, elapsedNanos, realtimeNanos);
+        });
         return cancel(cujType, REASON_CANCEL_NORMAL);
     }
 
@@ -951,7 +958,7 @@
             case CUJ_IME_INSETS_ANIMATION:
                 return "IME_INSETS_ANIMATION";
             case CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION:
-                return "CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION";
+                return "LOCKSCREEN_CLOCK_MOVE_ANIMATION";
         }
         return "UNKNOWN";
     }
@@ -1284,4 +1291,21 @@
             return mReason;
         }
     }
+
+    @FunctionalInterface
+    private interface TimeFunction {
+        void invoke(long unixNanos, long elapsedNanos, long realtimeNanos);
+    }
+
+    private void postEventLogToWorkerThread(TimeFunction logFunction) {
+        final Instant now = Instant.now();
+        final long unixNanos = TimeUnit.NANOSECONDS.convert(now.getEpochSecond(), TimeUnit.SECONDS)
+                + now.getNano();
+        final long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+        final long realtimeNanos = SystemClock.uptimeNanos();
+
+        mWorker.getThreadHandler().post(() -> {
+            logFunction.invoke(unixNanos, elapsedNanos, realtimeNanos);
+        });
+    }
 }
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index 65655b7..70514c3 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -80,10 +80,6 @@
     /** Stores user time and system time in jiffies. */
     private final long[] mProcessStatsData = new long[4];
 
-    /** Stores user time and system time in jiffies.  Used for
-     * public API to retrieve CPU use for a process.  Must lock while in use. */
-    private final long[] mSinglePidStatsData = new long[4];
-
     private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] {
         PROC_SPACE_TERM,
         PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING,    // 2: name
@@ -629,17 +625,15 @@
      * executing in both user and system code. Safe to call without lock held.
      */
     public long getCpuTimeForPid(int pid) {
-        synchronized (mSinglePidStatsData) {
-            final String statFile = "/proc/" + pid + "/stat";
-            final long[] statsData = mSinglePidStatsData;
-            if (Process.readProcFile(statFile, PROCESS_STATS_FORMAT,
-                    null, statsData, null)) {
-                long time = statsData[PROCESS_STAT_UTIME]
+        final String statFile = "/proc/" + pid + "/stat";
+        final long[] statsData = new long[4];
+        if (Process.readProcFile(statFile, PROCESS_STATS_FORMAT,
+                null, statsData, null)) {
+            long time = statsData[PROCESS_STAT_UTIME]
                         + statsData[PROCESS_STAT_STIME];
-                return time * mJiffyMillis;
-            }
-            return 0;
+            return time * mJiffyMillis;
         }
+        return 0;
     }
 
     /**
@@ -647,15 +641,13 @@
      * in the runqueue. Safe to call without lock held.
      */
     public long getCpuDelayTimeForPid(int pid) {
-        synchronized (mSinglePidStatsData) {
-            final String statFile = "/proc/" + pid + "/schedstat";
-            final long[] statsData = mSinglePidStatsData;
-            if (Process.readProcFile(statFile, PROCESS_SCHEDSTATS_FORMAT,
-                    null, statsData, null)) {
-                return statsData[PROCESS_SCHEDSTAT_CPU_DELAY_TIME] / 1_000_000;
-            }
-            return 0;
+        final String statFile = "/proc/" + pid + "/schedstat";
+        final long[] statsData = new long[4];
+        if (Process.readProcFile(statFile, PROCESS_SCHEDSTATS_FORMAT,
+                null, statsData, null)) {
+            return statsData[PROCESS_SCHEDSTAT_CPU_DELAY_TIME] / 1_000_000;
         }
+        return 0;
     }
 
     /**
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 59f6d2b..b86020e 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -133,6 +133,21 @@
     })
     public @interface CredentialType {}
 
+    public static String credentialTypeToString(int credentialType) {
+        switch (credentialType) {
+            case CREDENTIAL_TYPE_NONE:
+                return "NONE";
+            case CREDENTIAL_TYPE_PATTERN:
+                return "PATTERN";
+            case CREDENTIAL_TYPE_PIN:
+                return "PIN";
+            case CREDENTIAL_TYPE_PASSWORD:
+                return "PASSWORD";
+            default:
+                return "UNKNOWN_" + credentialType;
+        }
+    }
+
     /**
      * Flag provided to {@link #verifyCredential(LockscreenCredential, int, int)} . If set, the
      * method will return a handle to the Gatekeeper Password in the
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 8caf127..a5d287c 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -95,6 +95,8 @@
         optional SettingProto hearing_aid_media_routing = 48 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto hearing_aid_system_sounds_routing = 49 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto accessibility_magnification_joystick_enabled = 50 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // Settings for font scaling
+        optional SettingProto accessibility_font_scaling_has_been_changed = 51 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Accessibility accessibility = 2;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 85d1765..b736230 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3707,7 +3707,8 @@
 
     <!-- @SystemApi @hide Allows an application to set a device owner on retail demo devices.-->
     <permission android:name="android.permission.PROVISION_DEMO_DEVICE"
-                android:protectionLevel="signature|setup" />
+                android:protectionLevel="signature|setup|knownSigner"
+                android:knownCerts="@array/demo_device_provisioning_known_signers" />
 
     <!-- @TestApi @hide Allows an application to reset the record of previous system update freeze
          periods. -->
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 4468ebe..b35481d 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -227,4 +227,10 @@
     <string-array name="device_state_notification_thermal_contents">
         <item>@string/concurrent_display_notification_thermal_content</item>
     </string-array>
+
+    <!-- Certificate digests for trusted apps that will be allowed to obtain the knownSigner of the
+         demo device provisioning permissions. -->
+    <string-array name="demo_device_provisioning_known_signers">
+        <item>@string/config_retailDemoPackageSignature</item>
+    </string-array>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9252b14..2a67b44 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3201,8 +3201,8 @@
 
         <!-- Describes whether this view should allow interactions from AccessibilityServices only
              if the service sets the isAccessibilityTool property. -->
-        <attr name="accessibilityDataPrivate" format="integer">
-            <!-- The system determines whether the view's accessibility data is private
+        <attr name="accessibilityDataSensitive" format="integer">
+            <!-- The system determines whether the view's accessibility data is sensitive
                  - default (recommended). -->
             <enum name="auto" value="0" />
             <!-- Allow interactions from AccessibilityServices only if the service sets the
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 733e0ea..ffb602d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3988,7 +3988,7 @@
     <!-- Whether the device supports non-resizable activity in multi windowing modes.
          -1: The device doesn't support non-resizable in multi windowing modes.
           0: The device supports non-resizable in multi windowing modes only if this is a large
-             screen (smallest width >= {@link config_largeScreenSmallestScreenWidthDp}).
+             screen (smallest width >= {@link WindowManager#LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP}).
           1: The device always supports non-resizable in multi windowing modes.
     -->
     <integer name="config_supportsNonResizableMultiWindow">0</integer>
@@ -3998,9 +3998,9 @@
          -1: The device ignores the activity min width/height when determining if it can be shown in
              multi windowing modes.
           0: If this is a small screen (smallest width <
-             {@link config_largeScreenSmallestScreenWidthDp}), the device compares the activity min
-             width/height with the min multi windowing modes dimensions the device supports to
-             determine if the activity can be shown in multi windowing modes
+             {@link WindowManager#LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP}), the device compares the
+             activity min width/height with the min multi windowing modes dimensions the device
+             supports to determine if the activity can be shown in multi windowing modes
           1: The device always compare the activity min width/height with the min multi windowing
              modes dimensions {@link config_minPercentageMultiWindowSupportWidth} the device
              supports to determine if the activity can be shown in multi windowing modes.
@@ -4023,11 +4023,6 @@
     -->
     <item name="config_minPercentageMultiWindowSupportWidth" format="float" type="dimen">0.5</item>
 
-    <!-- If the display smallest screen width is greater or equal to this value, we will treat it
-         as a large screen device, which will have some multi window features enabled by default.
-    -->
-    <integer name="config_largeScreenSmallestScreenWidthDp">600</integer>
-
     <!-- True if the device is using legacy split. -->
     <bool name="config_useLegacySplit">false</bool>
 
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 973b3a7..ebda172 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -123,7 +123,7 @@
     <java-symbol type="bool" name="config_enhanced_iwlan_handover_check" />
 
     <!-- Whether using the new SubscriptionManagerService or the old SubscriptionController -->
-    <bool name="config_using_subscription_manager_service">false</bool>
+    <bool name="config_using_subscription_manager_service">true</bool>
     <java-symbol type="bool" name="config_using_subscription_manager_service" />
 
     <!-- Whether asynchronously update the subscription database or not. Async mode increases
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index ee02100..69d5fef 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -114,7 +114,7 @@
     <public name="handwritingBoundsOffsetTop" />
     <public name="handwritingBoundsOffsetRight" />
     <public name="handwritingBoundsOffsetBottom" />
-    <public name="accessibilityDataPrivate" />
+    <public name="accessibilityDataSensitive" />
     <public name="enableTextStylingShortcuts" />
     <public name="requiredDisplayCategory"/>
     <public name="removed_maxConcurrentSessionsCount" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e2b46d0..92dc569 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -405,7 +405,6 @@
   <java-symbol type="integer" name="config_respectsActivityMinWidthHeightMultiWindow" />
   <java-symbol type="dimen" name="config_minPercentageMultiWindowSupportHeight" />
   <java-symbol type="dimen" name="config_minPercentageMultiWindowSupportWidth" />
-  <java-symbol type="integer" name="config_largeScreenSmallestScreenWidthDp" />
   <java-symbol type="bool" name="config_useLegacySplit" />
   <java-symbol type="bool" name="config_noHomeScreen" />
   <java-symbol type="bool" name="config_supportsSystemDecorsOnSecondaryDisplays" />
diff --git a/core/res/res/xml/irq_device_map.xml b/core/res/res/xml/irq_device_map.xml
index 86a44d6..4fae8fb 100644
--- a/core/res/res/xml/irq_device_map.xml
+++ b/core/res/res/xml/irq_device_map.xml
@@ -17,14 +17,15 @@
 */
 -->
 <irq-device-map>
-  <!--  This file maps devices (chips) that can send IRQs to the CPU (and bring it out of sleep) to
-        logical subsystems in userspace code. Since each Android device has its own uniquely
-        designed chipset, this mapping is expected to be empty by default and should be overridden
-        by device specific configs.
+  <!--  This file maps devices (chips) that can send interrupts to the main processor (and bring it
+        out of sleep) to logical subsystems in userspace code. Since each Android device has its own
+        uniquely designed chipset, this mapping is expected to be empty by default and should be
+        overridden by device-specific configs.
         This mapping helps the system to meaningfully attribute CPU wakeups to logical work that
         happened on the device. The devices are referred to by their names as defined in the kernel.
-        Currently defined subsystems are:
+        Currently, defined subsystems are:
         - Alarm: Use this to denote wakeup alarms requested by apps via the AlarmManager API.
+        - Wifi: Use this to denote network traffic that uses the wifi transport.
 
         The overlay should use tags <device> and <subsystem> to describe this mapping in the
         following way:
diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
index ee1b2aa..e48f8a0 100644
--- a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
+++ b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
@@ -132,9 +132,13 @@
             }
             .forEach { (table, sp) ->
                 try {
-                    assertWithMessage("convertSpToDp(%s) on table: %s", sp, table)
-                        .that(table.convertSpToDp(sp))
-                        .isFinite()
+                    // Truth is slow because it creates a bunch of
+                    // objects. Don't use it unless we need to.
+                    if (!table.convertSpToDp(sp).isFinite()) {
+                        assertWithMessage("convertSpToDp(%s) on table: %s", sp, table)
+                            .that(table.convertSpToDp(sp))
+                            .isFinite()
+                    }
                 } catch (e: Exception) {
                     throw AssertionError("Exception during convertSpToDp($sp) on table: $table", e)
                 }
diff --git a/core/tests/coretests/src/android/credentials/CredentialManagerTest.java b/core/tests/coretests/src/android/credentials/CredentialManagerTest.java
index 25664fb..43334ab 100644
--- a/core/tests/coretests/src/android/credentials/CredentialManagerTest.java
+++ b/core/tests/coretests/src/android/credentials/CredentialManagerTest.java
@@ -101,8 +101,9 @@
         mGetRequest = new GetCredentialRequest.Builder(Bundle.EMPTY).addCredentialOption(
                 new CredentialOption(Credential.TYPE_PASSWORD_CREDENTIAL, Bundle.EMPTY,
                         Bundle.EMPTY, false)).build();
-        mCreateRequest = new CreateCredentialRequest.Builder(Bundle.EMPTY, Bundle.EMPTY)
-                .setType(Credential.TYPE_PASSWORD_CREDENTIAL)
+        mCreateRequest = new CreateCredentialRequest.Builder(
+                Credential.TYPE_PASSWORD_CREDENTIAL,
+                Bundle.EMPTY, Bundle.EMPTY)
                 .setIsSystemProviderRequired(false)
                 .setAlwaysSendAppInfoToProvider(false)
                 .build();
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
index 6d635af..3d4918b 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
@@ -58,7 +58,7 @@
 
     // The number of flags held in boolean properties. Their values should also be double-checked
     // in the methods above.
-    private static final int NUM_BOOLEAN_PROPERTIES = 26;
+    private static final int NUM_BOOLEAN_PROPERTIES = 27;
 
     @Test
     public void testStandardActions_serializationFlagIsValid() {
diff --git a/core/tests/overlaytests/device/Android.bp b/core/tests/overlaytests/device/Android.bp
index 0d3b15a..2b22344 100644
--- a/core/tests/overlaytests/device/Android.bp
+++ b/core/tests/overlaytests/device/Android.bp
@@ -29,6 +29,7 @@
     static_libs: [
         "androidx.test.rules",
         "testng",
+        "compatibility-device-util-axt",
     ],
     test_suites: ["device-tests"],
     data: [
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
index 8e4b9ef..fcf71ed 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
@@ -37,10 +37,12 @@
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.compatibility.common.util.AmUtils;
 import com.android.internal.util.ArrayUtils;
 import com.android.overlaytest.view.TestTextView;
 
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -70,6 +72,13 @@
         mMode = mode;
     }
 
+    @BeforeClass
+    public static void setUpClass() {
+        // Wait for package_added broadcasts to be handled so that OverlayManagerService
+        // can update it's internal state with the new packages.
+        AmUtils.waitForBroadcastBarrier();
+    }
+
     @Before
     public void setUp() {
         mContext = InstrumentationRegistry.getContext();
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 3d81d37..05e1772 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -271,6 +271,12 @@
       "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
       "at": "com\/android\/server\/wm\/AppTransition.java"
     },
+    "-1868518158": {
+      "message": "Pending back animation due to another animation is running",
+      "level": "WARN",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
     "-1868124841": {
       "message": "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, orientationSensorEnabled=%b, keyguardDrawComplete=%b, windowManagerDrawComplete=%b",
       "level": "VERBOSE",
@@ -1549,6 +1555,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/DragState.java"
     },
+    "-692907078": {
+      "message": "Handling the deferred animation after transition finished",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
     "-677449371": {
       "message": "moveTaskToRootTask: moving task=%d to rootTaskId=%d toTop=%b",
       "level": "DEBUG",
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index a39dd08..8dd23b7 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -2001,7 +2001,7 @@
         checkPixelAccess(x, y);
 
         final ColorSpace cs = getColorSpace();
-        if (cs.equals(ColorSpace.get(ColorSpace.Named.SRGB))) {
+        if (cs == null || cs.equals(ColorSpace.get(ColorSpace.Named.SRGB))) {
             return Color.valueOf(nativeGetPixel(mNativePtr, x, y));
         }
         // The returned value is in kRGBA_F16_SkColorType, which is packed as
diff --git a/graphics/java/android/graphics/Gainmap.java b/graphics/java/android/graphics/Gainmap.java
index a7c508c..feedb7d 100644
--- a/graphics/java/android/graphics/Gainmap.java
+++ b/graphics/java/android/graphics/Gainmap.java
@@ -63,20 +63,20 @@
  * as follows:
  *
  * First, let W be a weight parameter determining how much the gainmap will be applied.
- *   W = clamp((log(H)               - log(displayRatioHdr)) /
- *             (log(displayRatioHdr) - log(displayRatioSdr), 0, 1)
+ *   W = clamp((log(H)                      - log(minDisplayRatioForHdrTransition)) /
+ *             (log(displayRatioForFullHdr) - log(minDisplayRatioForHdrTransition), 0, 1)
  *
  * Next, let L be the gainmap value in log space. We compute this from the value G that was
  * sampled from the texture as follows:
- *   L = mix(log(gainmapRatioMin), log(gainmapRatioMax), pow(G, gainmapGamma))
+ *   L = mix(log(ratioMin), log(ratioMax), pow(G, gamma))
  *
  * Finally, apply the gainmap to compute D, the displayed pixel. If the base image is SDR then
  * compute:
  *   D = (B + epsilonSdr) * exp(L * W) - epsilonHdr
- * If the base image is HDR then compute:
- *   D = (B + epsilonHdr) * exp(L * (W - 1)) - epsilonSdr
  *
- * In the above math, log() is a natural logarithm and exp() is natural exponentiation.
+ * In the above math, log() is a natural logarithm and exp() is natural exponentiation. The base
+ * for these functions cancels out and does not affect the result, so other bases may be used
+ * if preferred.
  */
 public final class Gainmap implements Parcelable {
 
diff --git a/graphics/java/android/graphics/text/LineBreaker.java b/graphics/java/android/graphics/text/LineBreaker.java
index 67eb117..babcfc3 100644
--- a/graphics/java/android/graphics/text/LineBreaker.java
+++ b/graphics/java/android/graphics/text/LineBreaker.java
@@ -22,7 +22,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Px;
-import android.os.Trace;
 
 import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
@@ -476,26 +475,19 @@
             @NonNull MeasuredText measuredPara,
             @NonNull ParagraphConstraints constraints,
             @IntRange(from = 0) int lineNumber) {
-        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "compute line break");
-        long result = 0;
-        try {
-            result = nComputeLineBreaks(
-                    mNativePtr,
+        return new Result(nComputeLineBreaks(
+                mNativePtr,
 
-                    // Inputs
-                    measuredPara.getChars(),
-                    measuredPara.getNativePtr(),
-                    measuredPara.getChars().length,
-                    constraints.mFirstWidth,
-                    constraints.mFirstWidthLineCount,
-                    constraints.mWidth,
-                    constraints.mVariableTabStops,
-                    constraints.mDefaultTabStop,
-                    lineNumber);
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-        }
-        return new Result(result);
+                // Inputs
+                measuredPara.getChars(),
+                measuredPara.getNativePtr(),
+                measuredPara.getChars().length,
+                constraints.mFirstWidth,
+                constraints.mFirstWidthLineCount,
+                constraints.mWidth,
+                constraints.mVariableTabStops,
+                constraints.mDefaultTabStop,
+                lineNumber));
     }
 
     @FastNative
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 9f3c19b..caefb2e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -752,8 +752,6 @@
     @GuardedBy("mLock")
     void onActivityCreated(@NonNull WindowContainerTransaction wct,
             @NonNull Activity launchedActivity) {
-        // TODO(b/229680885): we don't support launching into primary yet because we want to always
-        // launch the new activity on top.
         resolveActivityToContainer(wct, launchedActivity, false /* isOnReparent */);
         updateCallbackIfNecessary();
     }
@@ -789,6 +787,13 @@
             return true;
         }
 
+        final TaskFragmentContainer container = getContainerWithActivity(activity);
+        if (!isOnReparent && container != null
+                && container.getTaskContainer().getTopTaskFragmentContainer() != container) {
+            // Do not resolve if the launched activity is not the top-most container in the Task.
+            return true;
+        }
+
         /*
          * We will check the following to see if there is any embedding rule matched:
          * 1. Whether the new launched activity should always expand.
@@ -811,6 +816,13 @@
             return true;
         }
 
+        // Skip resolving the following split-rules if the launched activity has been requested
+        // to be launched into its current container.
+        if (container != null && container.isActivityInRequestedTaskFragment(
+                activity.getActivityToken())) {
+            return true;
+        }
+
         // 3. Whether the new launched activity has already been in a split with a rule matched.
         if (isNewActivityInSplitWithRuleMatched(activity)) {
             return true;
@@ -2066,6 +2078,12 @@
                         if (!container.hasActivity(activityToken)
                                 && container.getTaskFragmentToken()
                                 .equals(initialTaskFragmentToken)) {
+                            if (ActivityClient.getInstance().isRequestedToLaunchInTaskFragment(
+                                    activityToken, initialTaskFragmentToken)) {
+                                container.addPendingAppearedInRequestedTaskFragmentActivity(
+                                        activity);
+                            }
+
                             // The onTaskFragmentInfoChanged callback containing this activity has
                             // not reached the client yet, so add the activity to the pending
                             // appeared activities.
@@ -2157,6 +2175,14 @@
             // TODO(b/232042367): Consolidate the activity create handling so that we can handle
             // cross-process the same as normal.
 
+            // Early return if the launching taskfragment is already been set.
+            if (options.getBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN) != null) {
+                synchronized (mLock) {
+                    mCurrentIntent = intent;
+                }
+                return super.onStartActivity(who, intent, options);
+            }
+
             final Activity launchingActivity;
             if (who instanceof Activity) {
                 // We will check if the new activity should be split with the activity that launched
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index b38f824..6c553a8 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -86,6 +86,12 @@
     @Nullable
     private Intent mPendingAppearedIntent;
 
+    /**
+     * The activities that were explicitly requested to be launched in its current TaskFragment,
+     * but haven't been added to {@link #mInfo} yet.
+     */
+    final ArrayList<IBinder> mPendingAppearedInRequestedTaskFragmentActivities = new ArrayList<>();
+
     /** Containers that are dependent on this one and should be completely destroyed on exit. */
     private final List<TaskFragmentContainer> mContainersToFinishOnExit =
             new ArrayList<>();
@@ -296,6 +302,8 @@
 
     void removePendingAppearedActivity(@NonNull IBinder activityToken) {
         mPendingAppearedActivities.remove(activityToken);
+        // Also remove the activity from the mPendingInRequestedTaskFragmentActivities.
+        mPendingAppearedInRequestedTaskFragmentActivities.remove(activityToken);
     }
 
     @GuardedBy("mController.mLock")
@@ -424,7 +432,7 @@
         for (int i = mPendingAppearedActivities.size() - 1; i >= 0; --i) {
             final IBinder activityToken = mPendingAppearedActivities.get(i);
             if (infoActivities.contains(activityToken)) {
-                mPendingAppearedActivities.remove(i);
+                removePendingAppearedActivity(activityToken);
             }
         }
     }
@@ -720,6 +728,29 @@
         mLastCompanionTaskFragment = fragmentToken;
     }
 
+    /**
+     * Adds the pending appeared activity that has requested to be launched in this task fragment.
+     * @see android.app.ActivityClient#isRequestedToLaunchInTaskFragment
+     */
+    void addPendingAppearedInRequestedTaskFragmentActivity(Activity activity) {
+        final IBinder activityToken = activity.getActivityToken();
+        if (hasActivity(activityToken)) {
+            return;
+        }
+        mPendingAppearedInRequestedTaskFragmentActivities.add(activity.getActivityToken());
+    }
+
+    /**
+     * Checks if the given activity has requested to be launched in this task fragment.
+     * @see #addPendingAppearedInRequestedTaskFragmentActivity
+     */
+    boolean isActivityInRequestedTaskFragment(IBinder activityToken) {
+        if (mInfo != null && mInfo.getActivitiesRequestedInTaskFragment().contains(activityToken)) {
+            return true;
+        }
+        return mPendingAppearedInRequestedTaskFragmentActivities.contains(activityToken);
+    }
+
     /** Gets the parent leaf Task id. */
     int getTaskId() {
         return mTaskContainer.getTaskId();
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java
index 459ec9f..a069ac7 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java
@@ -177,6 +177,7 @@
                 1,
                 isVisible,
                 Collections.singletonList(activity.getActivityToken()),
+                new ArrayList<>(),
                 new Point(),
                 false /* isTaskClearedForReuse */,
                 false /* isTaskFragmentClearedForPip */,
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
index bbb454d..dd087e8 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
@@ -124,7 +124,7 @@
     private TaskFragmentInfo createMockInfo(TaskFragmentContainer container) {
         return new TaskFragmentInfo(container.getTaskFragmentToken(),
                 mock(WindowContainerToken.class), new Configuration(), 0 /* runningActivityCount */,
-                false /* isVisible */, new ArrayList<>(), new Point(),
+                false /* isVisible */, new ArrayList<>(), new ArrayList<>(), new Point(),
                 false /* isTaskClearedForReuse */, false /* isTaskFragmentClearedForPip */,
                 false /* isClearedForReorderActivityToFront */, new Point());
     }
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 61cd748..3d0e1c8 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -700,7 +700,7 @@
         final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
                 false /* isOnReparent */);
 
-        assertFalse(result);
+        assertTrue(result);
         verify(mSplitPresenter, never()).startActivityToSide(any(), any(), any(), any(), any(),
                 any(), anyBoolean());
     }
@@ -734,7 +734,7 @@
         final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
                 false /* isOnReparent */);
 
-        assertFalse(result);
+        assertTrue(result);
         verify(mSplitPresenter, never()).startActivityToSide(any(), any(), any(), any(), any(),
                 any(), anyBoolean());
     }
@@ -808,7 +808,7 @@
         final Activity launchedActivity = createMockActivity();
         primaryContainer.addPendingAppearedActivity(launchedActivity);
 
-        assertFalse(mSplitController.resolveActivityToContainer(mTransaction, launchedActivity,
+        assertTrue(mSplitController.resolveActivityToContainer(mTransaction, launchedActivity,
                 false /* isOnReparent */));
     }
 
@@ -944,7 +944,7 @@
         boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
                 false /* isOnReparent */);
 
-        assertFalse(result);
+        assertTrue(result);
         assertEquals(primaryContainer, mSplitController.getContainerWithActivity(mActivity));
 
 
diff --git a/libs/WindowManager/Shell/res/color/split_divider_background.xml b/libs/WindowManager/Shell/res/color-night/taskbar_background.xml
similarity index 83%
rename from libs/WindowManager/Shell/res/color/split_divider_background.xml
rename to libs/WindowManager/Shell/res/color-night/taskbar_background.xml
index 0499808..9473cdd6 100644
--- a/libs/WindowManager/Shell/res/color/split_divider_background.xml
+++ b/libs/WindowManager/Shell/res/color-night/taskbar_background.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
+  ~ Copyright (C) 2023 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -14,6 +14,7 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
+<!-- Should be the same as in packages/apps/Launcher3/res/color-night-v31/taskbar_background.xml -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:color="@android:color/system_neutral1_500" android:lStar="15" />
 </selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/color/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background.xml
index b3d26029..0e165fc 100644
--- a/libs/WindowManager/Shell/res/color/taskbar_background.xml
+++ b/libs/WindowManager/Shell/res/color/taskbar_background.xml
@@ -16,5 +16,5 @@
   -->
 <!-- Should be the same as in packages/apps/Launcher3/res/color-v31/taskbar_background.xml -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@android:color/system_neutral1_500" android:lStar="15" />
+    <item android:color="@android:color/system_neutral1_500" android:lStar="95" />
 </selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml
index 9167382..c6e634c 100644
--- a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml
+++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml
@@ -17,6 +17,6 @@
 <shape android:shape="rectangle"
        xmlns:android="http://schemas.android.com/apk/res/android">
     <solid android:color="@android:color/white" />
-    <corners android:radius="20dp" />
+    <corners android:radius="@dimen/caption_menu_corner_radius" />
     <stroke android:width="1dp" android:color="#b3b3b3"/>
 </shape>
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml
index f6e3f2e..f9aeb6a 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml
@@ -21,7 +21,6 @@
     android:layout_height="match_parent"
     android:orientation="vertical"
     android:background="@drawable/desktop_mode_decor_menu_background"
-    android:elevation="@dimen/caption_menu_elevation"
     android:divider="?android:attr/dividerHorizontal"
     android:showDividers="middle"
     android:dividerPadding="18dip">
@@ -63,38 +62,46 @@
             android:layout_width="0dp"
             android:layout_height="1dp"
             android:layout_weight="0.5" />
-        <Button
+        <ImageButton
             style="@style/CaptionWindowingButtonStyle"
             android:id="@+id/fullscreen_button"
             android:contentDescription="@string/fullscreen_text"
-            android:background="@drawable/caption_fullscreen_button"/>
+            android:src="@drawable/caption_fullscreen_button"
+            android:scaleType="fitCenter"
+            android:background="?android:selectableItemBackgroundBorderless"/>
         <Space
             android:layout_width="0dp"
             android:layout_height="1dp"
             android:layout_weight="1" />
-        <Button
+        <ImageButton
             style="@style/CaptionWindowingButtonStyle"
             android:id="@+id/split_screen_button"
             android:contentDescription="@string/split_screen_text"
-            android:background="@drawable/caption_split_screen_button"/>
+            android:src="@drawable/caption_split_screen_button"
+            android:scaleType="fitCenter"
+            android:background="?android:selectableItemBackgroundBorderless"/>
         <Space
             android:layout_width="0dp"
             android:layout_height="1dp"
             android:layout_weight="1" />
-        <Button
+        <ImageButton
             style="@style/CaptionWindowingButtonStyle"
             android:id="@+id/floating_button"
             android:contentDescription="@string/float_button_text"
-            android:background="@drawable/caption_floating_button"/>
+            android:src="@drawable/caption_floating_button"
+            android:scaleType="fitCenter"
+            android:background="?android:selectableItemBackgroundBorderless"/>
         <Space
             android:layout_width="0dp"
             android:layout_height="1dp"
             android:layout_weight="1" />
-        <Button
+        <ImageButton
             style="@style/CaptionWindowingButtonStyle"
             android:id="@+id/desktop_button"
             android:contentDescription="@string/desktop_text"
-            android:background="@drawable/caption_desktop_button"/>
+            android:src="@drawable/caption_desktop_button"
+            android:scaleType="fitCenter"
+            android:background="?android:selectableItemBackgroundBorderless"/>
         <Space
             android:layout_width="0dp"
             android:layout_height="1dp"
diff --git a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
index e8edad1..413cfd7 100644
--- a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
+++ b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
@@ -16,9 +16,7 @@
 <com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:background="@android:color/system_neutral1_900">
+    style="@style/LetterboxDialog">
 
     <!-- The background of the top-level layout acts as the background dim. -->
 
diff --git a/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml
index ba9852c..5aff415 100644
--- a/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml
+++ b/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml
@@ -16,14 +16,10 @@
 <com.android.wm.shell.compatui.RestartDialogLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:background="@android:color/system_neutral1_900">
+    style="@style/LetterboxDialog">
 
     <!-- The background of the top-level layout acts as the background dim. -->
 
-    <!--TODO (b/266288912): Resolve overdraw warning -->
-
     <!-- Vertical margin will be set dynamically since it depends on task bounds.
          Setting the alpha of the dialog container to 0, since it shouldn't be visible until the
          enter animation starts. -->
diff --git a/libs/WindowManager/Shell/res/values-night/colors.xml b/libs/WindowManager/Shell/res/values-night/colors.xml
index 83c4d93..5c6bb57 100644
--- a/libs/WindowManager/Shell/res/values-night/colors.xml
+++ b/libs/WindowManager/Shell/res/values-night/colors.xml
@@ -15,6 +15,7 @@
   -->
 
 <resources>
+    <color name="docked_divider_handle">#ffffff</color>
     <!-- Bubbles -->
     <color name="bubbles_icon_tint">@color/GM2_grey_200</color>
     <!-- Splash screen-->
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index 6e750a3..6fb70006 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -17,7 +17,8 @@
  */
 -->
 <resources>
-    <color name="docked_divider_handle">#ffffff</color>
+    <color name="docked_divider_handle">#000000</color>
+    <color name="split_divider_background">@color/taskbar_background</color>
     <drawable name="forced_resizable_background">#59000000</drawable>
     <color name="minimize_dock_shadow_start">#60000000</color>
     <color name="minimize_dock_shadow_end">#00000000</color>
@@ -41,6 +42,9 @@
     <color name="letterbox_education_accent_primary">@android:color/system_accent1_100</color>
     <color name="letterbox_education_text_secondary">@android:color/system_neutral2_200</color>
 
+    <!-- Letterbox Dialog -->
+    <color name="letterbox_dialog_background">@android:color/system_neutral1_900</color>
+
     <!-- GM2 colors -->
     <color name="GM2_grey_200">#E8EAED</color>
     <color name="GM2_grey_700">#5F6368</color>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 336c156..680ad51 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -370,6 +370,10 @@
 
     <dimen name="freeform_resize_corner">44dp</dimen>
 
-    <dimen name="caption_menu_elevation">4dp</dimen>
+    <!-- The radius of the caption menu shadow. -->
+    <dimen name="caption_menu_shadow_radius">4dp</dimen>
+
+    <!-- The radius of the caption menu corners. -->
+    <dimen name="caption_menu_corner_radius">20dp</dimen>
 
 </resources>
diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml
index 0a0c49f..bc2e71d 100644
--- a/libs/WindowManager/Shell/res/values/styles.xml
+++ b/libs/WindowManager/Shell/res/values/styles.xml
@@ -38,11 +38,9 @@
     </style>
 
     <style name="CaptionWindowingButtonStyle">
-        <item name="android:layout_width">32dp</item>
-        <item name="android:layout_height">32dp</item>
+        <item name="android:layout_width">40dp</item>
+        <item name="android:layout_height">40dp</item>
         <item name="android:padding">4dp</item>
-        <item name="android:layout_marginTop">5dp</item>
-        <item name="android:layout_marginBottom">5dp</item>
     </style>
 
     <style name="CaptionMenuButtonStyle" parent="@style/Widget.AppCompat.Button.Borderless">
@@ -80,6 +78,12 @@
         <item name="android:textColor">@color/tv_pip_edu_text</item>
     </style>
 
+    <style name="LetterboxDialog" parent="@android:style/Theme.Holo">
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:background">@color/letterbox_dialog_background</item>
+    </style>
+
     <style name="RestartDialogTitleText">
         <item name="android:textSize">24sp</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index b3fff1d..0b87598 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -552,6 +552,9 @@
         if (runner.isWaitingAnimation()) {
             ProtoLog.w(WM_SHELL_BACK_PREVIEW, "Gesture released, but animation didn't ready.");
             return;
+        } else if (runner.isAnimationCancelled()) {
+            invokeOrCancelBack();
+            return;
         }
         startPostCommitAnimation();
     }
@@ -653,7 +656,19 @@
             }
 
             @Override
-            public void onAnimationCancelled() { }
+            public void onAnimationCancelled() {
+                mShellExecutor.execute(() -> {
+                    final BackAnimationRunner runner = mAnimationDefinition.get(
+                            mBackNavigationInfo.getType());
+                    if (runner == null) {
+                        return;
+                    }
+                    runner.cancelAnimation();
+                    if (!mBackGestureStarted) {
+                        invokeOrCancelBack();
+                    }
+                });
+            }
         };
         mBackAnimationAdapter = new BackAnimationAdapter(runner);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java
index d70b8f5..82c523f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java
@@ -41,6 +41,9 @@
     // Whether we are waiting to receive onAnimationStart
     private boolean mWaitingAnimation;
 
+    /** True when the back animation is cancelled */
+    private boolean mAnimationCancelled;
+
     BackAnimationRunner(@NonNull IOnBackInvokedCallback callback,
             @NonNull IRemoteAnimationRunner runner) {
         mCallback = callback;
@@ -81,9 +84,19 @@
 
     void startGesture() {
         mWaitingAnimation = true;
+        mAnimationCancelled = false;
     }
 
     boolean isWaitingAnimation() {
         return mWaitingAnimation;
     }
+
+    void cancelAnimation() {
+        mWaitingAnimation = false;
+        mAnimationCancelled = true;
+    }
+
+    boolean isAnimationCancelled() {
+        return mAnimationCancelled;
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 7ac4d51..b447a54 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -120,6 +120,7 @@
     private int mOrientation;
     private int mRotation;
     private int mDensity;
+    private int mUiMode;
 
     private final boolean mDimNonImeSide;
     private ValueAnimator mDividerFlingAnimator;
@@ -295,10 +296,12 @@
         final Rect rootBounds = configuration.windowConfiguration.getBounds();
         final int orientation = configuration.orientation;
         final int density = configuration.densityDpi;
+        final int uiMode = configuration.uiMode;
 
         if (mOrientation == orientation
                 && mRotation == rotation
                 && mDensity == density
+                && mUiMode == uiMode
                 && mRootBounds.equals(rootBounds)) {
             return false;
         }
@@ -310,6 +313,7 @@
         mRootBounds.set(rootBounds);
         mRotation = rotation;
         mDensity = density;
+        mUiMode = uiMode;
         mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null);
         updateDividerConfig(mContext);
         initDividerPosition(mTempRect);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 8895fca..73123b1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -25,16 +25,14 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.graphics.Insets;
-import android.graphics.Matrix;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.os.Handler;
 import android.view.LayoutInflater;
 import android.view.SurfaceControl;
-import android.view.SyncRtSurfaceTransactionApplier;
 import android.view.View;
 import android.view.ViewRootImpl;
 import android.view.WindowManagerGlobal;
+import android.window.SurfaceSyncGroup;
 
 import androidx.annotation.Nullable;
 
@@ -71,12 +69,6 @@
     // exiting the move menu instead of showing the regular button menu.
     private boolean mCloseAfterExitMoveMenu;
 
-    private SyncRtSurfaceTransactionApplier mApplier;
-    private SyncRtSurfaceTransactionApplier mBackgroundApplier;
-    RectF mTmpSourceRectF = new RectF();
-    RectF mTmpDestinationRectF = new RectF();
-    Matrix mMoveTransform = new Matrix();
-
     public TvPipMenuController(Context context, TvPipBoundsState tvPipBoundsState,
             SystemWindows systemWindows, Handler mainHandler) {
         mContext = context;
@@ -324,44 +316,36 @@
      */
     @Override
     public void resizePipMenu(@Nullable SurfaceControl pipLeash,
-            @Nullable SurfaceControl.Transaction t,
-            Rect destinationBounds) {
+            @Nullable SurfaceControl.Transaction pipTx,
+            Rect pipBounds) {
         ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                "%s: resizePipMenu: %s", TAG, destinationBounds.toShortString());
-        if (destinationBounds.isEmpty()) {
+                "%s: resizePipMenu: %s", TAG, pipBounds.toShortString());
+        if (pipBounds.isEmpty()) {
             return;
         }
 
-        if (!maybeCreateSyncApplier()) {
+        if (!isMenuReadyToMove()) {
             return;
         }
 
-        final Rect menuBounds = calculateMenuSurfaceBounds(destinationBounds);
 
         final SurfaceControl frontSurface = getSurfaceControl(mPipMenuView);
-        final SyncRtSurfaceTransactionApplier.SurfaceParams frontParams =
-                new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(frontSurface)
-                        .withWindowCrop(menuBounds)
-                        .build();
-
         final SurfaceControl backSurface = getSurfaceControl(mPipBackgroundView);
-        final SyncRtSurfaceTransactionApplier.SurfaceParams backParams =
-                new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(backSurface)
-                        .withWindowCrop(menuBounds)
-                        .build();
-
-        // TODO(b/226580399): switch to using SurfaceSyncer (see b/200284684) to synchronize the
-        // animations of the pip surface with the content of the front and back menu surfaces
-        mBackgroundApplier.scheduleApply(backParams);
-        if (pipLeash != null && t != null) {
-            final SyncRtSurfaceTransactionApplier.SurfaceParams
-                    pipParams = new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(pipLeash)
-                    .withMergeTransaction(t)
-                    .build();
-            mApplier.scheduleApply(frontParams, pipParams);
-        } else {
-            mApplier.scheduleApply(frontParams);
+        final Rect menuBounds = calculateMenuSurfaceBounds(pipBounds);
+        if (pipTx == null) {
+            pipTx = new SurfaceControl.Transaction();
         }
+        pipTx.setWindowCrop(frontSurface, menuBounds.width(), menuBounds.height());
+        pipTx.setWindowCrop(backSurface, menuBounds.width(), menuBounds.height());
+
+        // Synchronize drawing the content in the front and back surfaces together with the pip
+        // transaction and the window crop for the front and back surfaces
+        final SurfaceSyncGroup syncGroup = new SurfaceSyncGroup("TvPip");
+        syncGroup.add(mPipMenuView.getRootSurfaceControl(), null);
+        syncGroup.add(mPipBackgroundView.getRootSurfaceControl(), null);
+        updateMenuBounds(pipBounds);
+        syncGroup.addTransaction(pipTx);
+        syncGroup.markSyncReady();
     }
 
     private SurfaceControl getSurfaceControl(View v) {
@@ -369,102 +353,66 @@
     }
 
     @Override
-    public void movePipMenu(SurfaceControl pipLeash, SurfaceControl.Transaction transaction,
-            Rect pipDestBounds) {
+    public void movePipMenu(SurfaceControl pipLeash, SurfaceControl.Transaction pipTx,
+            Rect pipBounds) {
         ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                "%s: movePipMenu: %s", TAG, pipDestBounds.toShortString());
+                "%s: movePipMenu: %s", TAG, pipBounds.toShortString());
 
-        if (pipDestBounds.isEmpty()) {
-            if (transaction == null) {
+        if (pipBounds.isEmpty()) {
+            if (pipTx == null) {
                 ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                         "%s: no transaction given", TAG);
             }
             return;
         }
-        if (!maybeCreateSyncApplier()) {
+        if (!isMenuReadyToMove()) {
             return;
         }
 
-        final Rect menuDestBounds = calculateMenuSurfaceBounds(pipDestBounds);
-        final Rect tmpSourceBounds = new Rect();
-        // If there is no pip leash supplied, that means the PiP leash is already finalized
-        // resizing and the PiP menu is also resized. We then want to do a scale from the current
-        // new menu bounds.
-        if (pipLeash != null && transaction != null) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: tmpSourceBounds based on mPipMenuView.getBoundsOnScreen()", TAG);
-            mPipMenuView.getBoundsOnScreen(tmpSourceBounds);
-        } else {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: tmpSourceBounds based on menu width and height", TAG);
-            tmpSourceBounds.set(0, 0, menuDestBounds.width(), menuDestBounds.height());
-        }
-
-        mTmpSourceRectF.set(tmpSourceBounds);
-        mTmpDestinationRectF.set(menuDestBounds);
-        mMoveTransform.setTranslate(mTmpDestinationRectF.left, mTmpDestinationRectF.top);
-
         final SurfaceControl frontSurface = getSurfaceControl(mPipMenuView);
-        final SyncRtSurfaceTransactionApplier.SurfaceParams frontParams =
-                new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(frontSurface)
-                        .withMatrix(mMoveTransform)
-                        .build();
-
         final SurfaceControl backSurface = getSurfaceControl(mPipBackgroundView);
-        final SyncRtSurfaceTransactionApplier.SurfaceParams backParams =
-                new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(backSurface)
-                        .withMatrix(mMoveTransform)
-                        .build();
-
-        // TODO(b/226580399): switch to using SurfaceSyncer (see b/200284684) to synchronize the
-        // animations of the pip surface with the content of the front and back menu surfaces
-        mBackgroundApplier.scheduleApply(backParams);
-        if (pipLeash != null && transaction != null) {
-            final SyncRtSurfaceTransactionApplier.SurfaceParams pipParams =
-                    new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(pipLeash)
-                            .withMergeTransaction(transaction)
-                            .build();
-            mApplier.scheduleApply(frontParams, pipParams);
-        } else {
-            mApplier.scheduleApply(frontParams);
+        final Rect menuDestBounds = calculateMenuSurfaceBounds(pipBounds);
+        if (pipTx == null) {
+            pipTx = new SurfaceControl.Transaction();
         }
+        pipTx.setPosition(frontSurface, menuDestBounds.left, menuDestBounds.top);
+        pipTx.setPosition(backSurface, menuDestBounds.left, menuDestBounds.top);
 
-        updateMenuBounds(pipDestBounds);
+        // Synchronize drawing the content in the front and back surfaces together with the pip
+        // transaction and the position change for the front and back surfaces
+        final SurfaceSyncGroup syncGroup = new SurfaceSyncGroup("TvPip");
+        syncGroup.add(mPipMenuView.getRootSurfaceControl(), null);
+        syncGroup.add(mPipBackgroundView.getRootSurfaceControl(), null);
+        updateMenuBounds(pipBounds);
+        syncGroup.addTransaction(pipTx);
+        syncGroup.markSyncReady();
     }
 
-    private boolean maybeCreateSyncApplier() {
-        if (mPipMenuView == null || mPipMenuView.getViewRootImpl() == null) {
+    private boolean isMenuReadyToMove() {
+        final boolean ready = mPipMenuView != null && mPipMenuView.getViewRootImpl() != null
+                && mPipBackgroundView != null && mPipBackgroundView.getViewRootImpl() != null;
+        if (!ready) {
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                     "%s: Not going to move PiP, either menu or its parent is not created.", TAG);
-            return false;
         }
-
-        if (mApplier == null) {
-            mApplier = new SyncRtSurfaceTransactionApplier(mPipMenuView);
-        }
-        if (mBackgroundApplier == null) {
-            mBackgroundApplier = new SyncRtSurfaceTransactionApplier(mPipBackgroundView);
-        }
-        return true;
+        return ready;
     }
 
     private void detachPipMenu() {
         if (mPipMenuView != null) {
-            mApplier = null;
             mSystemWindows.removeView(mPipMenuView);
             mPipMenuView = null;
         }
 
         if (mPipBackgroundView != null) {
-            mBackgroundApplier = null;
             mSystemWindows.removeView(mPipBackgroundView);
             mPipBackgroundView = null;
         }
     }
 
     @Override
-    public void updateMenuBounds(Rect destinationBounds) {
-        final Rect menuBounds = calculateMenuSurfaceBounds(destinationBounds);
+    public void updateMenuBounds(Rect pipBounds) {
+        final Rect menuBounds = calculateMenuSurfaceBounds(pipBounds);
         ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                 "%s: updateMenuBounds: %s", TAG, menuBounds.toShortString());
         mSystemWindows.updateViewLayout(mPipBackgroundView,
@@ -473,9 +421,8 @@
         mSystemWindows.updateViewLayout(mPipMenuView,
                 getPipMenuLayoutParams(mContext, MENU_WINDOW_TITLE, menuBounds.width(),
                         menuBounds.height()));
-
         if (mPipMenuView != null) {
-            mPipMenuView.updateBounds(destinationBounds);
+            mPipMenuView.updateBounds(pipBounds);
         }
     }
 
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 427d79e..2252587 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
@@ -20,7 +20,6 @@
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED;
 import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -661,6 +660,7 @@
             @Nullable Bundle options2, @SplitPosition int splitPosition, float splitRatio,
             @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
+        prepareEvictChildTasksIfSplitActive(wct);
         setSideStagePosition(splitPosition, wct);
         options1 = options1 != null ? options1 : new Bundle();
         addActivityOptions(options1, mSideStage);
@@ -675,6 +675,7 @@
             @SplitPosition int splitPosition, float splitRatio,
             @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
+        prepareEvictChildTasksIfSplitActive(wct);
         setSideStagePosition(splitPosition, wct);
         options1 = options1 != null ? options1 : new Bundle();
         addActivityOptions(options1, mSideStage);
@@ -688,6 +689,7 @@
             int taskId, @Nullable Bundle options2, @SplitPosition int splitPosition,
             float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
+        prepareEvictChildTasksIfSplitActive(wct);
         setSideStagePosition(splitPosition, wct);
         options1 = options1 != null ? options1 : new Bundle();
         addActivityOptions(options1, mSideStage);
@@ -706,10 +708,7 @@
     private void startWithTask(WindowContainerTransaction wct, int mainTaskId,
             @Nullable Bundle mainOptions, float splitRatio,
             @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
-        if (mMainStage.isActive()) {
-            mMainStage.evictAllChildren(wct);
-            mSideStage.evictAllChildren(wct);
-        } else {
+        if (!mMainStage.isActive()) {
             // Build a request WCT that will launch both apps such that task 0 is on the main stage
             // while task 1 is on the side stage.
             mMainStage.activate(wct, false /* reparent */);
@@ -1020,6 +1019,13 @@
         mSideStage.evictInvisibleChildren(wct);
     }
 
+    void prepareEvictChildTasksIfSplitActive(WindowContainerTransaction wct) {
+        if (mMainStage.isActive()) {
+            mMainStage.evictAllChildren(wct);
+            mSideStage.evictAllChildren(wct);
+        }
+    }
+
     Bundle resolveStartStage(@StageType int stage, @SplitPosition int position,
             @Nullable Bundle options, @Nullable WindowContainerTransaction wct) {
         switch (stage) {
@@ -2160,19 +2166,11 @@
                 }
             } else if (isOpening && inFullscreen) {
                 final int activityType = triggerTask.getActivityType();
-                if (activityType == ACTIVITY_TYPE_ASSISTANT) {
-                    // We don't want assistant panel to dismiss split screen, so do nothing.
-                } else if (activityType == ACTIVITY_TYPE_HOME
+                if (activityType == ACTIVITY_TYPE_HOME
                         || activityType == ACTIVITY_TYPE_RECENTS) {
                     // Enter overview panel, so start recent transition.
                     mSplitTransitions.setRecentTransition(transition, request.getRemoteTransition(),
                             mRecentTransitionFinishedCallback);
-                } else if (mSplitTransitions.mPendingRecent == null) {
-                    // If split-task is not controlled by recents animation
-                    // and occluded by the other fullscreen task, dismiss both.
-                    prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
-                    mSplitTransitions.setDismissTransition(
-                            transition, STAGE_TYPE_UNDEFINED, EXIT_REASON_UNKNOWN);
                 }
             }
         } else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java
index ac52235..2e2f569 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java
@@ -21,6 +21,7 @@
 import android.os.Build;
 import android.os.SystemClock;
 import android.util.Pair;
+import android.view.SurfaceControl;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -75,6 +76,7 @@
     @VisibleForTesting
     public void init() {
         ProtoLog.v(WM_SHELL_INIT, "Initializing Shell Components: %d", mInitCallbacks.size());
+        SurfaceControl.setDebugUsageAfterRelease(true);
         // Init in order of registration
         for (int i = 0; i < mInitCallbacks.size(); i++) {
             final Pair<String, Runnable> info = mInitCallbacks.get(i);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java
index 145f759..8c6e1e7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java
@@ -16,18 +16,40 @@
 
 package com.android.wm.shell.util;
 
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.view.RemoteAnimationTarget.MODE_CHANGING;
+import static android.view.RemoteAnimationTarget.MODE_CLOSING;
+import static android.view.RemoteAnimationTarget.MODE_OPENING;
+import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
 import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
+import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
+import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
+
+import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.app.ActivityManager;
+import android.app.WindowConfiguration;
+import android.graphics.Rect;
+import android.util.ArrayMap;
+import android.util.SparseBooleanArray;
+import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.window.TransitionInfo;
 
+import java.util.function.Predicate;
+
 /** Various utility functions for transitions. */
 public class TransitionUtil {
 
@@ -54,4 +76,189 @@
         return false;
     }
 
+    /** Returns `true` if `change` is a wallpaper. */
+    public static boolean isWallpaper(TransitionInfo.Change change) {
+        return (change.getTaskInfo() == null)
+                && change.hasFlags(FLAG_IS_WALLPAPER)
+                && !change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY);
+    }
+
+    /** Returns `true` if `change` is not an app window or wallpaper. */
+    public static boolean isNonApp(TransitionInfo.Change change) {
+        return (change.getTaskInfo() == null)
+                && !change.hasFlags(FLAG_IS_WALLPAPER)
+                && !change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY);
+    }
+
+    /**
+     * Filter that selects leaf-tasks only. THIS IS ORDER-DEPENDENT! For it to work properly, you
+     * MUST call `test` in the same order that the changes appear in the TransitionInfo.
+     */
+    public static class LeafTaskFilter implements Predicate<TransitionInfo.Change> {
+        private final SparseBooleanArray mChildTaskTargets = new SparseBooleanArray();
+
+        @Override
+        public boolean test(TransitionInfo.Change change) {
+            final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
+            // Children always come before parent since changes are in top-to-bottom z-order.
+            if ((taskInfo == null) || mChildTaskTargets.get(taskInfo.taskId)) {
+                // has children, so not a leaf. Skip.
+                return false;
+            }
+            if (taskInfo.hasParentTask()) {
+                mChildTaskTargets.put(taskInfo.parentTaskId, true);
+            }
+            return true;
+        }
+    }
+
+
+    private static int newModeToLegacyMode(int newMode) {
+        switch (newMode) {
+            case WindowManager.TRANSIT_OPEN:
+            case WindowManager.TRANSIT_TO_FRONT:
+                return MODE_OPENING;
+            case WindowManager.TRANSIT_CLOSE:
+            case WindowManager.TRANSIT_TO_BACK:
+                return MODE_CLOSING;
+            default:
+                return MODE_CHANGING;
+        }
+    }
+
+    /**
+     * Very similar to Transitions#setupAnimHierarchy but specialized for leashes.
+     */
+    @SuppressLint("NewApi")
+    private static void setupLeash(@NonNull SurfaceControl leash,
+            @NonNull TransitionInfo.Change change, int layer,
+            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) {
+        final boolean isOpening = TransitionUtil.isOpeningType(info.getType());
+        // Put animating stuff above this line and put static stuff below it.
+        int zSplitLine = info.getChanges().size();
+        // changes should be ordered top-to-bottom in z
+        final int mode = change.getMode();
+
+        t.reparent(leash, info.getRootLeash());
+        final Rect absBounds =
+                (mode == TRANSIT_OPEN) ? change.getEndAbsBounds() : change.getStartAbsBounds();
+        t.setPosition(leash, absBounds.left - info.getRootOffset().x,
+                absBounds.top - info.getRootOffset().y);
+
+        // Put all the OPEN/SHOW on top
+        if (TransitionUtil.isOpeningType(mode)) {
+            if (isOpening) {
+                t.setLayer(leash, zSplitLine + info.getChanges().size() - layer);
+                if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) == 0) {
+                    // if transferred, it should be left visible.
+                    t.setAlpha(leash, 0.f);
+                }
+            } else {
+                // put on bottom and leave it visible
+                t.setLayer(leash, zSplitLine - layer);
+            }
+        } else if (TransitionUtil.isClosingType(mode)) {
+            if (isOpening) {
+                // put on bottom and leave visible
+                t.setLayer(leash, zSplitLine - layer);
+            } else {
+                // put on top
+                t.setLayer(leash, zSplitLine + info.getChanges().size() - layer);
+            }
+        } else { // CHANGE
+            t.setLayer(leash, zSplitLine + info.getChanges().size() - layer);
+        }
+    }
+
+    @SuppressLint("NewApi")
+    private static SurfaceControl createLeash(TransitionInfo info, TransitionInfo.Change change,
+            int order, SurfaceControl.Transaction t) {
+        // TODO: once we can properly sync transactions across process, then get rid of this leash.
+        if (change.getParent() != null && (change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
+            // Special case for wallpaper atm. Normally these are left alone; but, a quirk of
+            // making leashes means we have to handle them specially.
+            return change.getLeash();
+        }
+        SurfaceControl leashSurface = new SurfaceControl.Builder()
+                .setName(change.getLeash().toString() + "_transition-leash")
+                .setContainerLayer()
+                // Initial the surface visible to respect the visibility of the original surface.
+                .setHidden(false)
+                .setParent(info.getRootLeash())
+                .build();
+        // Copied Transitions setup code (which expects bottom-to-top order, so we swap here)
+        setupLeash(leashSurface, change, info.getChanges().size() - order, info, t);
+        t.reparent(change.getLeash(), leashSurface);
+        t.setAlpha(change.getLeash(), 1.0f);
+        t.show(change.getLeash());
+        t.setPosition(change.getLeash(), 0, 0);
+        t.setLayer(change.getLeash(), 0);
+        return leashSurface;
+    }
+
+    /**
+     * Creates a new RemoteAnimationTarget from the provided change info
+     */
+    public static RemoteAnimationTarget newTarget(TransitionInfo.Change change, int order,
+            TransitionInfo info, SurfaceControl.Transaction t,
+            @Nullable ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
+        final SurfaceControl leash = createLeash(info, change, order, t);
+        if (leashMap != null) {
+            leashMap.put(change.getLeash(), leash);
+        }
+        return newTarget(change, order, leash);
+    }
+
+    /**
+     * Creates a new RemoteAnimationTarget from the provided change and leash
+     */
+    public static RemoteAnimationTarget newTarget(TransitionInfo.Change change, int order,
+            SurfaceControl leash) {
+        int taskId;
+        boolean isNotInRecents;
+        ActivityManager.RunningTaskInfo taskInfo;
+        WindowConfiguration windowConfiguration;
+
+        taskInfo = change.getTaskInfo();
+        if (taskInfo != null) {
+            taskId = taskInfo.taskId;
+            isNotInRecents = !taskInfo.isRunning;
+            windowConfiguration = taskInfo.configuration.windowConfiguration;
+        } else {
+            taskId = INVALID_TASK_ID;
+            isNotInRecents = true;
+            windowConfiguration = new WindowConfiguration();
+        }
+
+        Rect localBounds = new Rect(change.getEndAbsBounds());
+        localBounds.offsetTo(change.getEndRelOffset().x, change.getEndRelOffset().y);
+
+        RemoteAnimationTarget target = new RemoteAnimationTarget(
+                taskId,
+                newModeToLegacyMode(change.getMode()),
+                // TODO: once we can properly sync transactions across process,
+                // then get rid of this leash.
+                leash,
+                (change.getFlags() & TransitionInfo.FLAG_TRANSLUCENT) != 0,
+                null,
+                // TODO(shell-transitions): we need to send content insets? evaluate how its used.
+                new Rect(0, 0, 0, 0),
+                order,
+                null,
+                localBounds,
+                new Rect(change.getEndAbsBounds()),
+                windowConfiguration,
+                isNotInRecents,
+                null,
+                new Rect(change.getStartAbsBounds()),
+                taskInfo,
+                change.getAllowEnterPip(),
+                (change.getFlags() & FLAG_IS_DIVIDER_BAR) != 0
+                        ? TYPE_DOCK_DIVIDER : INVALID_WINDOW_TYPE
+        );
+        target.setWillShowImeOnTarget(
+                (change.getFlags() & TransitionInfo.FLAG_WILL_IME_SHOWN) != 0);
+        target.setRotationChange(change.getEndRotation() - change.getStartRotation());
+        return target;
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 0779f1d..72da108 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -74,6 +74,8 @@
     private boolean mDesktopActive;
     private AdditionalWindow mHandleMenu;
     private final int mHandleMenuWidthId = R.dimen.freeform_decor_caption_menu_width;
+    private final int mHandleMenuShadowRadiusId = R.dimen.caption_menu_shadow_radius;
+    private final int mHandleMenuCornerRadiusId = R.dimen.caption_menu_corner_radius;
     private PointF mHandleMenuPosition = new PointF();
 
     DesktopModeWindowDecoration(
@@ -353,19 +355,16 @@
                 .windowConfiguration.getBounds().width();
         final int menuWidth = loadDimensionPixelSize(resources, mHandleMenuWidthId);
         final int menuHeight = loadDimensionPixelSize(resources, mCaptionMenuHeightId);
-
-        // Elevation gives the appearance of a changed x/y coordinate; this is to fix that
-        int elevationOffset = 2 * loadDimensionPixelSize(resources,
-                R.dimen.caption_menu_elevation);
+        final int shadowRadius = loadDimensionPixelSize(resources, mHandleMenuShadowRadiusId);
+        final int cornerRadius = loadDimensionPixelSize(resources, mHandleMenuCornerRadiusId);
 
         final int x = mRelayoutParams.mCaptionX + (captionWidth / 2) - (menuWidth / 2)
-                - mResult.mDecorContainerOffsetX - elevationOffset;
-        final int y =
-                mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY - elevationOffset;
+                - mResult.mDecorContainerOffsetX;
+        final int y = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY;
         mHandleMenuPosition.set(x, y);
         String namePrefix = "Caption Menu";
         mHandleMenu = addWindow(R.layout.desktop_mode_decor_handle_menu, namePrefix, t, x, y,
-                menuWidth, menuHeight, 2 * elevationOffset);
+                menuWidth, menuHeight, shadowRadius, cornerRadius);
         mSyncQueue.runInSync(transaction -> {
             transaction.merge(t);
             t.close();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 91b0aa1..7a7ac47 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -391,11 +391,12 @@
      * @param yPos y position of new window
      * @param width width of new window
      * @param height height of new window
-     * @param cropPadding padding to add to window crop to ensure shadows display properly
-     * @return
+     * @param shadowRadius radius of the shadow of the new window
+     * @param cornerRadius radius of the corners of the new window
+     * @return the {@link AdditionalWindow} that was added.
      */
     AdditionalWindow addWindow(int layoutId, String namePrefix, SurfaceControl.Transaction t,
-            int xPos, int yPos, int width, int height, int cropPadding) {
+            int xPos, int yPos, int width, int height, int shadowRadius, int cornerRadius) {
         final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
         SurfaceControl windowSurfaceControl = builder
                 .setName(namePrefix + " of Task=" + mTaskInfo.taskId)
@@ -404,9 +405,10 @@
                 .build();
         View v = LayoutInflater.from(mDecorWindowContext).inflate(layoutId, null);
 
-        t.setPosition(
-                windowSurfaceControl, xPos, yPos)
-                .setWindowCrop(windowSurfaceControl, width + cropPadding, height + cropPadding)
+        t.setPosition(windowSurfaceControl, xPos, yPos)
+                .setWindowCrop(windowSurfaceControl, width, height)
+                .setShadowRadius(windowSurfaceControl, shadowRadius)
+                .setCornerRadius(windowSurfaceControl, cornerRadius)
                 .show(windowSurfaceControl);
         final WindowManager.LayoutParams lp =
                 new WindowManager.LayoutParams(width, height,
diff --git a/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
index fac0461..47a116b 100644
--- a/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
@@ -20,6 +20,7 @@
     package="com.android.wm.shell.tests">
 
     <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+    <uses-permission android:name="android.permission.VIBRATE"/>
 
     <application android:debuggable="true" android:largeHeap="true">
         <uses-library android:name="android.test.mock" />
diff --git a/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml b/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml
index 27d40b2..aa1b241 100644
--- a/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml
@@ -24,4 +24,6 @@
     <dimen name="test_window_decor_bottom_outset">40dp</dimen>
     <dimen name="test_window_decor_shadow_radius">5dp</dimen>
     <dimen name="test_window_decor_resize_handle">10dp</dimen>
+    <dimen name="test_caption_menu_shadow_radius">4dp</dimen>
+    <dimen name="test_caption_menu_corner_radius">20dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index ed0ac5f..3901dab 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -284,41 +284,6 @@
 
     @Test
     @UiThreadTest
-    public void testDismissFromBeingOccluded() {
-        enterSplit();
-
-        ActivityManager.RunningTaskInfo normalTask = new TestRunningTaskInfoBuilder()
-                .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
-                .build();
-
-        // Create a request to bring a normal task forward
-        TransitionRequestInfo request =
-                new TransitionRequestInfo(TRANSIT_TO_FRONT, normalTask, null);
-        IBinder transition = mock(IBinder.class);
-        WindowContainerTransaction result = mStageCoordinator.handleRequest(transition, request);
-
-        assertTrue(containsSplitExit(result));
-
-        // make sure we haven't made any local changes yet (need to wait until transition is ready)
-        assertTrue(mStageCoordinator.isSplitScreenVisible());
-
-        // simulate the transition
-        TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TO_FRONT, 0)
-                .addChange(TRANSIT_TO_FRONT, normalTask)
-                .addChange(TRANSIT_TO_BACK, mMainChild)
-                .addChange(TRANSIT_TO_BACK, mSideChild)
-                .build();
-        mMainStage.onTaskVanished(mMainChild);
-        mSideStage.onTaskVanished(mSideChild);
-        mStageCoordinator.startAnimation(transition, info,
-                mock(SurfaceControl.Transaction.class),
-                mock(SurfaceControl.Transaction.class),
-                mock(Transitions.TransitionFinishCallback.class));
-        assertFalse(mStageCoordinator.isSplitScreenVisible());
-    }
-
-    @Test
-    @UiThreadTest
     public void testDismissFromMultiWindowSupport() {
         enterSplit();
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index b80edce..7e39b5b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -108,6 +108,8 @@
     private SurfaceControl.Transaction mMockSurfaceControlAddWindowT;
     private WindowDecoration.RelayoutParams mRelayoutParams = new WindowDecoration.RelayoutParams();
     private int mCaptionMenuWidthId;
+    private int mCaptionMenuShadowRadiusId;
+    private int mCaptionMenuCornerRadiusId;
 
     @Before
     public void setUp() {
@@ -118,6 +120,8 @@
         mRelayoutParams.mLayoutResId = 0;
         mRelayoutParams.mCaptionHeightId = R.dimen.test_freeform_decor_caption_height;
         mCaptionMenuWidthId = R.dimen.test_freeform_decor_caption_menu_width;
+        mCaptionMenuShadowRadiusId = R.dimen.test_caption_menu_shadow_radius;
+        mCaptionMenuCornerRadiusId = R.dimen.test_caption_menu_corner_radius;
         mRelayoutParams.mShadowRadiusId = R.dimen.test_window_decor_shadow_radius;
 
         doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory)
@@ -431,7 +435,19 @@
         verify(additionalWindowSurfaceBuilder).setParent(decorContainerSurface);
         verify(additionalWindowSurfaceBuilder).build();
         verify(mMockSurfaceControlAddWindowT).setPosition(additionalWindowSurface, 20, 40);
-        verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, 442, 74);
+        final int width = WindowDecoration.loadDimensionPixelSize(
+                mContext.getResources(), mCaptionMenuWidthId);
+        final int height = WindowDecoration.loadDimensionPixelSize(
+                mContext.getResources(), mRelayoutParams.mCaptionHeightId);
+        verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, width, height);
+        final int shadowRadius = WindowDecoration.loadDimensionPixelSize(mContext.getResources(),
+                mCaptionMenuShadowRadiusId);
+        verify(mMockSurfaceControlAddWindowT)
+                .setShadowRadius(additionalWindowSurface, shadowRadius);
+        final int cornerRadius = WindowDecoration.loadDimensionPixelSize(mContext.getResources(),
+                mCaptionMenuCornerRadiusId);
+        verify(mMockSurfaceControlAddWindowT)
+                .setCornerRadius(additionalWindowSurface, cornerRadius);
         verify(mMockSurfaceControlAddWindowT).show(additionalWindowSurface);
         verify(mMockSurfaceControlViewHostFactory, Mockito.times(2))
                 .create(any(), eq(defaultDisplay), any());
@@ -559,13 +575,15 @@
             int y = mRelayoutParams.mCaptionY;
             int width = loadDimensionPixelSize(resources, mCaptionMenuWidthId);
             int height = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionHeightId);
+            int shadowRadius = loadDimensionPixelSize(resources, mCaptionMenuShadowRadiusId);
+            int cornerRadius = loadDimensionPixelSize(resources, mCaptionMenuCornerRadiusId);
             String name = "Test Window";
             WindowDecoration.AdditionalWindow additionalWindow =
                     addWindow(R.layout.desktop_mode_decor_handle_menu, name,
                             mMockSurfaceControlAddWindowT,
                             x - mRelayoutResult.mDecorContainerOffsetX,
                             y - mRelayoutResult.mDecorContainerOffsetY,
-                            width, height, 10);
+                            width, height, shadowRadius, cornerRadius);
             return additionalWindow;
         }
     }
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index ecf6cfc..b3eaa0c 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -463,6 +463,13 @@
     if (hasGainmap() && format == JavaCompressFormat::Jpeg) {
         SkBitmap baseBitmap = getSkBitmap();
         SkBitmap gainmapBitmap = gainmap()->bitmap->getSkBitmap();
+        if (gainmapBitmap.colorType() == SkColorType::kAlpha_8_SkColorType) {
+            SkBitmap greyGainmap;
+            auto greyInfo = gainmapBitmap.info().makeColorType(SkColorType::kGray_8_SkColorType);
+            greyGainmap.setInfo(greyInfo, gainmapBitmap.rowBytes());
+            greyGainmap.setPixelRef(sk_ref_sp(gainmapBitmap.pixelRef()), 0, 0);
+            gainmapBitmap = std::move(greyGainmap);
+        }
         SkJpegEncoder::Options options{.fQuality = quality};
         return SkJpegGainmapEncoder::EncodeHDRGM(stream, baseBitmap.pixmap(), options,
                                                  gainmapBitmap.pixmap(), options, gainmap()->info);
diff --git a/media/java/android/media/tv/tuner/frontend/IptvFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/IptvFrontendSettings.java
index ba75102..65247a1 100644
--- a/media/java/android/media/tv/tuner/frontend/IptvFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/IptvFrontendSettings.java
@@ -34,7 +34,7 @@
  * @hide
  */
 @SystemApi
-public class IptvFrontendSettings extends FrontendSettings {
+public final class IptvFrontendSettings extends FrontendSettings {
     /** @hide */
     @IntDef(prefix = "PROTOCOL_",
             value = {PROTOCOL_UNDEFINED, PROTOCOL_UDP, PROTOCOL_RTP})
@@ -181,14 +181,6 @@
     }
 
     /**
-     * Creates a builder for {@link IptvFrontendSettings}.
-     */
-    @NonNull
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    /**
      * Builder for {@link IptvFrontendSettings}.
      */
     public static final class Builder {
@@ -202,7 +194,7 @@
         private long mBitrate = 0;
         private String mContentUrl = "";
 
-        private Builder() {
+        public Builder() {
         }
 
         /**
@@ -309,8 +301,8 @@
          */
         @NonNull
         public IptvFrontendSettings build() {
-            return new IptvFrontendSettings(mSrcIpAddress, mDstIpAddress, mSrcPort,
-                    mDstPort, mFec, mProtocol, mIgmp, mBitrate, mContentUrl);
+            return new IptvFrontendSettings(mSrcIpAddress, mDstIpAddress, mSrcPort, mDstPort,
+                    mFec, mProtocol, mIgmp, mBitrate, mContentUrl);
         }
     }
 
diff --git a/media/java/android/media/tv/tuner/frontend/IptvFrontendSettingsFec.java b/media/java/android/media/tv/tuner/frontend/IptvFrontendSettingsFec.java
index a70af17..12eebee 100644
--- a/media/java/android/media/tv/tuner/frontend/IptvFrontendSettingsFec.java
+++ b/media/java/android/media/tv/tuner/frontend/IptvFrontendSettingsFec.java
@@ -31,7 +31,7 @@
  * @hide
  */
 @SystemApi
-public class IptvFrontendSettingsFec {
+public final class IptvFrontendSettingsFec {
     /** @hide */
     @IntDef(prefix = "FEC_TYPE_",
             value = {FEC_TYPE_UNDEFINED, FEC_TYPE_COLUMN, FEC_TYPE_ROW, FEC_TYPE_COLUMN_ROW})
@@ -93,14 +93,6 @@
     }
 
     /**
-     * Creates a builder for {@link IptvFrontendSettingsFec}.
-     */
-    @NonNull
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    /**
      * Builder for {@link IptvFrontendSettingsFec}.
      */
     public static final class Builder {
@@ -108,7 +100,7 @@
         private int mFecRowNum;
         private int mFecColNum;
 
-        private Builder() {
+        public Builder() {
         }
 
         /**
diff --git a/packages/CredentialManager/Android.bp b/packages/CredentialManager/Android.bp
index 00d42bd..28b9bc0 100644
--- a/packages/CredentialManager/Android.bp
+++ b/packages/CredentialManager/Android.bp
@@ -20,6 +20,7 @@
     },
 
     static_libs: [
+        "PlatformComposeCore",
         "androidx.activity_activity-compose",
         "androidx.appcompat_appcompat",
         "androidx.compose.animation_animation-core",
diff --git a/packages/CredentialManager/res/drawable/ic_other_devices.xml b/packages/CredentialManager/res/drawable/ic_other_devices.xml
deleted file mode 100644
index 754648c..0000000
--- a/packages/CredentialManager/res/drawable/ic_other_devices.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    tools:ignore="VectorPath"
-    android:name="vector"
-    android:width="20dp"
-    android:height="20dp"
-    android:viewportWidth="20"
-    android:viewportHeight="20">
-    <path
-        android:name="path"
-        android:pathData="M 7.6 4.72 L 7.6 7.6 L 4.72 7.6 L 4.72 4.72 L 7.6 4.72 Z M 9.04 3.28 L 3.28 3.28 L 3.28 9.04 L 9.04 9.04 L 9.04 3.28 Z M 7.6 12.4 L 7.6 15.28 L 4.72 15.28 L 4.72 12.4 L 7.6 12.4 Z M 9.04 10.96 L 3.28 10.96 L 3.28 16.72 L 9.04 16.72 L 9.04 10.96 Z M 15.28 4.72 L 15.28 7.6 L 12.4 7.6 L 12.4 4.72 L 15.28 4.72 Z M 16.72 3.28 L 10.96 3.28 L 10.96 9.04 L 16.72 9.04 L 16.72 3.28 Z M 10.96 10.96 L 12.4 10.96 L 12.4 12.4 L 10.96 12.4 L 10.96 10.96 Z M 12.4 12.4 L 13.84 12.4 L 13.84 13.84 L 12.4 13.84 L 12.4 12.4 Z M 13.84 10.96 L 15.28 10.96 L 15.28 12.4 L 13.84 12.4 L 13.84 10.96 Z M 10.96 13.84 L 12.4 13.84 L 12.4 15.28 L 10.96 15.28 L 10.96 13.84 Z M 12.4 15.28 L 13.84 15.28 L 13.84 16.72 L 12.4 16.72 L 12.4 15.28 Z M 13.84 13.84 L 15.28 13.84 L 15.28 15.28 L 13.84 15.28 L 13.84 13.84 Z M 15.28 12.4 L 16.72 12.4 L 16.72 13.84 L 15.28 13.84 L 15.28 12.4 Z M 15.28 15.28 L 16.72 15.28 L 16.72 16.72 L 15.28 16.72 L 15.28 15.28 Z M 19.6 5.2 L 17.68 5.2 L 17.68 2.32 L 14.8 2.32 L 14.8 0.4 L 19.6 0.4 L 19.6 5.2 Z M 19.6 19.6 L 19.6 14.8 L 17.68 14.8 L 17.68 17.68 L 14.8 17.68 L 14.8 19.6 L 19.6 19.6 Z M 0.4 19.6 L 5.2 19.6 L 5.2 17.68 L 2.32 17.68 L 2.32 14.8 L 0.4 14.8 L 0.4 19.6 Z M 0.4 0.4 L 0.4 5.2 L 2.32 5.2 L 2.32 2.32 L 5.2 2.32 L 5.2 0.4 L 0.4 0.4 Z"
-        android:fillColor="#000000"
-        android:strokeWidth="1"/>
-</vector>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/drawable/ic_other_sign_in.xml b/packages/CredentialManager/res/drawable/ic_other_sign_in.xml
deleted file mode 100644
index 8150197..0000000
--- a/packages/CredentialManager/res/drawable/ic_other_sign_in.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<!--
-  ~ Copyright (C) 2022 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    tools:ignore="VectorPath"
-    android:name="vector"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-    <path
-        android:name="path"
-        android:pathData="M 20 19 L 12 19 L 12 21 L 20 21 C 21.1 21 22 20.1 22 19 L 22 5 C 22 3.9 21.1 3 20 3 L 12 3 L 12 5 L 20 5 L 20 19 Z"
-        android:fillColor="#000"
-        android:strokeWidth="1"/>
-    <path
-        android:name="path_1"
-        android:pathData="M 12 7 L 10.6 8.4 L 13.2 11 L 8.85 11 C 8.42 9.55 7.09 8.5 5.5 8.5 C 3.57 8.5 2 10.07 2 12 C 2 13.93 3.57 15.5 5.5 15.5 C 7.09 15.5 8.42 14.45 8.85 13 L 13.2 13 L 10.6 15.6 L 12 17 L 17 12 L 12 7 Z M 5.5 13.5 C 4.67 13.5 4 12.83 4 12 C 4 11.17 4.67 10.5 5.5 10.5 C 6.33 10.5 7 11.17 7 12 C 7 12.83 6.33 13.5 5.5 13.5 Z"
-        android:fillColor="#000"
-        android:strokeWidth="1"/>
-</vector>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/drawable/ic_other_sign_in_24.xml b/packages/CredentialManager/res/drawable/ic_other_sign_in_24.xml
new file mode 100644
index 0000000..ce2aeb2
--- /dev/null
+++ b/packages/CredentialManager/res/drawable/ic_other_sign_in_24.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ 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.
+  -->
+
+<vector
+    android:alpha="0.8"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+>
+<group>
+    <clip-path android:pathData="M0,0h24v24h-24z"/>
+    <path android:fillColor="#444746" android:pathData="M20,19H12V21H20C21.1,21 22,20.1 22,19V5C22,3.9 21.1,3 20,3H12V5H20V19Z"/>
+    <path android:fillColor="#444746" android:pathData="M12,7L10.6,8.4L13.2,11H8.85C8.42,9.55 7.09,8.5 5.5,8.5C3.57,8.5 2,10.07 2,12C2,13.93 3.57,15.5 5.5,15.5C7.09,15.5 8.42,14.45 8.85,13H13.2L10.6,15.6L12,17L17,12L12,7ZM5.5,13.5C4.67,13.5 4,12.83 4,12C4,11.17 4.67,10.5 5.5,10.5C6.33,10.5 7,11.17 7,12C7,12.83 6.33,13.5 5.5,13.5Z"/>
+</group>
+</vector>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/drawable/ic_passkey.xml b/packages/CredentialManager/res/drawable/ic_passkey.xml
deleted file mode 100644
index 041a321..0000000
--- a/packages/CredentialManager/res/drawable/ic_passkey.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="28dp"
-    android:height="24dp"
-    android:viewportWidth="28"
-    android:viewportHeight="24">
-  <path
-      android:pathData="M27.453,13.253C27.453,14.952 26.424,16.411 24.955,17.041L26.21,18.295L24.839,19.666L26.21,21.037L23.305,23.942L22.012,22.65L22.012,17.156C20.385,16.605 19.213,15.066 19.213,13.253C19.213,10.977 21.058,9.133 23.333,9.133C25.609,9.133 27.453,10.977 27.453,13.253ZM25.47,13.254C25.47,14.434 24.514,15.39 23.334,15.39C22.154,15.39 21.197,14.434 21.197,13.254C21.197,12.074 22.154,11.118 23.334,11.118C24.514,11.118 25.47,12.074 25.47,13.254Z"
-      android:fillColor="#00639B"
-      android:fillType="evenOdd"/>
-  <path
-      android:pathData="M17.85,5.768C17.85,8.953 15.268,11.536 12.083,11.536C8.897,11.536 6.315,8.953 6.315,5.768C6.315,2.582 8.897,0 12.083,0C15.268,0 17.85,2.582 17.85,5.768Z"
-      android:fillColor="#00639B"/>
-  <path
-      android:pathData="M0.547,20.15C0.547,16.32 8.23,14.382 12.083,14.382C13.59,14.382 15.684,14.679 17.674,15.269C18.116,16.454 18.952,17.447 20.022,18.089V23.071H0.547V20.15Z"
-      android:fillColor="#00639B"/>
-</vector>
diff --git a/packages/CredentialManager/res/drawable/ic_passkey_24.xml b/packages/CredentialManager/res/drawable/ic_passkey_24.xml
new file mode 100644
index 0000000..a2c4f37
--- /dev/null
+++ b/packages/CredentialManager/res/drawable/ic_passkey_24.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector
+    android:alpha="0.8"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+  <path android:fillColor="#4C463C" android:fillType="evenOdd" android:pathData="M22.18,14.09C22.18,15.364 21.408,16.459 20.306,16.931L21.247,17.872L20.219,18.9L21.247,19.928L19.068,22.107L18.099,21.138L18.099,17.017C16.878,16.604 16,15.45 16,14.09C16,12.383 17.383,11 19.09,11C20.796,11 22.18,12.383 22.18,14.09ZM20.692,14.091C20.692,14.976 19.975,15.693 19.09,15.693C18.205,15.693 17.488,14.976 17.488,14.091C17.488,13.206 18.205,12.488 19.09,12.488C19.975,12.488 20.692,13.206 20.692,14.091Z"/>
+  <path android:fillColor="#4C463C" android:pathData="M14.978,8.476C14.978,10.865 13.041,12.802 10.652,12.802C8.263,12.802 6.326,10.865 6.326,8.476C6.326,6.087 8.263,4.15 10.652,4.15C13.041,4.15 14.978,6.087 14.978,8.476Z"/>
+  <path android:fillColor="#4C463C" android:pathData="M2,19.263C2,16.39 7.762,14.937 10.652,14.937C11.782,14.937 13.353,15.16 14.845,15.602C15.177,16.491 15.804,17.236 16.607,17.717V21.454H2V19.263Z"/>
+</vector>
diff --git a/packages/CredentialManager/res/drawable/ic_password.xml b/packages/CredentialManager/res/drawable/ic_password.xml
deleted file mode 100644
index bf3056a..0000000
--- a/packages/CredentialManager/res/drawable/ic_password.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-  ~ Copyright (C) 2022 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    tools:ignore="VectorPath"
-    android:name="vector"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-    <path
-        android:name="path"
-        android:pathData="M 8.71 10.29 C 8.52 10.1 8.28 10 8 10 L 7.75 10 L 7.75 8.75 C 7.75 7.98 7.48 7.33 6.95 6.8 C 6.42 6.27 5.77 6 5 6 C 4.23 6 3.58 6.27 3.05 6.8 C 2.52 7.33 2.25 7.98 2.25 8.75 L 2.25 10 L 2 10 C 1.72 10 1.48 10.1 1.29 10.29 C 1.1 10.48 1 10.72 1 11 L 1 16 C 1 16.28 1.1 16.52 1.29 16.71 C 1.48 16.9 1.72 17 2 17 L 8 17 C 8.28 17 8.52 16.9 8.71 16.71 C 8.9 16.52 9 16.28 9 16 L 9 11 C 9 10.72 8.9 10.48 8.71 10.29 Z M 6.25 10 L 3.75 10 L 3.75 8.75 C 3.75 8.4 3.87 8.1 4.11 7.86 C 4.35 7.62 4.65 7.5 5 7.5 C 5.35 7.5 5.65 7.62 5.89 7.86 C 6.13 8.1 6.25 8.4 6.25 8.75 L 6.25 10 Z M 10 14 L 23 14 L 23 16 L 10 16 Z M 21.5 9 C 21.102 9 20.721 9.158 20.439 9.439 C 20.158 9.721 20 10.102 20 10.5 C 20 10.898 20.158 11.279 20.439 11.561 C 20.721 11.842 21.102 12 21.5 12 C 21.898 12 22.279 11.842 22.561 11.561 C 22.842 11.279 23 10.898 23 10.5 C 23 10.102 22.842 9.721 22.561 9.439 C 22.279 9.158 21.898 9 21.5 9 Z M 16.5 9 C 16.102 9 15.721 9.158 15.439 9.439 C 15.158 9.721 15 10.102 15 10.5 C 15 10.898 15.158 11.279 15.439 11.561 C 15.721 11.842 16.102 12 16.5 12 C 16.898 12 17.279 11.842 17.561 11.561 C 17.842 11.279 18 10.898 18 10.5 C 18 10.102 17.842 9.721 17.561 9.439 C 17.279 9.158 16.898 9 16.5 9 Z M 11.5 9 C 11.102 9 10.721 9.158 10.439 9.439 C 10.158 9.721 10 10.102 10 10.5 C 10 10.898 10.158 11.279 10.439 11.561 C 10.721 11.842 11.102 12 11.5 12 C 11.898 12 12.279 11.842 12.561 11.561 C 12.842 11.279 13 10.898 13 10.5 C 13 10.102 12.842 9.721 12.561 9.439 C 12.279 9.158 11.898 9 11.5 9 Z"
-        android:fillColor="#000"
-        android:strokeWidth="1"/>
-</vector>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/drawable/ic_password_24.xml b/packages/CredentialManager/res/drawable/ic_password_24.xml
new file mode 100644
index 0000000..8b24e88
--- /dev/null
+++ b/packages/CredentialManager/res/drawable/ic_password_24.xml
@@ -0,0 +1,34 @@
+<!--
+  ~ 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.
+  -->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:ignore="VectorPath"
+    android:name="vector"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <group>
+        <clip-path android:pathData="M0,0h24v24h-24z"/>
+        <path android:fillColor="#4C463C" android:pathData="M8.46,10.29C8.27,10.1 8.03,10 7.75,10H7.5V8.75C7.5,7.98 7.23,7.33 6.7,6.8C6.17,6.27 5.52,6 4.75,6C3.98,6 3.33,6.27 2.8,6.8C2.27,7.33 2,7.98 2,8.75V10H1.75C1.47,10 1.23,10.1 1.04,10.29C0.85,10.48 0.75,10.72 0.75,11V16C0.75,16.28 0.85,16.52 1.04,16.71C1.23,16.9 1.47,17 1.75,17H7.75C8.03,17 8.27,16.9 8.46,16.71C8.65,16.52 8.75,16.28 8.75,16V11C8.75,10.72 8.65,10.48 8.46,10.29ZM6,10H3.5V8.75C3.5,8.4 3.62,8.1 3.86,7.86C4.1,7.62 4.4,7.5 4.75,7.5C5.1,7.5 5.4,7.62 5.64,7.86C5.88,8.1 6,8.4 6,8.75V10Z"/>
+        <path android:fillColor="#4C463C" android:pathData="M23.5,14H10.5V16H23.5V14Z"/>
+        <path android:fillColor="#4C463C" android:pathData="M22,12C22.828,12 23.5,11.328 23.5,10.5C23.5,9.672 22.828,9 22,9C21.172,9 20.5,9.672 20.5,10.5C20.5,11.328 21.172,12 22,12Z"/>
+        <path android:fillColor="#4C463C" android:pathData="M17,12C17.828,12 18.5,11.328 18.5,10.5C18.5,9.672 17.828,9 17,9C16.172,9 15.5,9.672 15.5,10.5C15.5,11.328 16.172,12 17,12Z"/>
+        <path android:fillColor="#4C463C" android:pathData="M12,12C12.828,12 13.5,11.328 13.5,10.5C13.5,9.672 12.828,9 12,9C11.172,9 10.5,9.672 10.5,10.5C10.5,11.328 11.172,12 12,12Z"/>
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/values/themes.xml b/packages/CredentialManager/res/values/themes.xml
index c7e4796..82aebb7 100644
--- a/packages/CredentialManager/res/values/themes.xml
+++ b/packages/CredentialManager/res/values/themes.xml
@@ -5,7 +5,5 @@
     <item name="android:windowNoTitle">true</item>
     <item name="android:windowBackground">@android:color/transparent</item>
     <item name="android:windowIsTranslucent">true</item>
-    <item name="android:statusBarColor">@android:color/transparent</item>
-    <item name="android:navigationBarColor">@android:color/transparent</item>
   </style>
 </resources>
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
index 0e604ce..a2d1e4d 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
@@ -73,7 +73,7 @@
         requestInfo = intent.extras?.getParcelable(
             RequestInfo.EXTRA_REQUEST_INFO,
             RequestInfo::class.java
-        ) ?: testCreatePasskeyRequestInfo()
+        ) ?: testGetRequestInfo()
 
         val originName: String? = when (requestInfo.type) {
             RequestInfo.TYPE_CREATE -> requestInfo.createCredentialRequest?.origin
@@ -407,8 +407,8 @@
         val credentialData = request.credentialData
         return RequestInfo.newCreateRequestInfo(
                 Binder(),
-                CreateCredentialRequest.Builder(credentialData, Bundle())
-                        .setType("androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL")
+                CreateCredentialRequest.Builder("androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL",
+                credentialData, Bundle())
                         .setIsSystemProviderRequired(false)
                         .setAlwaysSendAppInfoToProvider(true)
                         .build(),
@@ -420,8 +420,8 @@
         val request = CreatePasswordRequest("beckett-bakert@gmail.com", "password123")
         return RequestInfo.newCreateRequestInfo(
                 Binder(),
-                CreateCredentialRequest.Builder(request.credentialData, request.candidateQueryData)
-                        .setType(TYPE_PASSWORD_CREDENTIAL)
+                CreateCredentialRequest.Builder(TYPE_PASSWORD_CREDENTIAL,
+                request.credentialData, request.candidateQueryData)
                         .setIsSystemProviderRequired(false)
                         .setAlwaysSendAppInfoToProvider(true)
                         .build(),
@@ -438,8 +438,7 @@
         )
         return RequestInfo.newCreateRequestInfo(
                 Binder(),
-                CreateCredentialRequest.Builder(data, Bundle())
-                        .setType("other-sign-ins")
+                CreateCredentialRequest.Builder("other-sign-ins", data, Bundle())
                         .setIsSystemProviderRequired(false)
                         .setAlwaysSendAppInfoToProvider(true)
                         .build(),
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index a834994..43912c2 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -52,9 +52,7 @@
 import androidx.credentials.CreatePasswordRequest
 import androidx.credentials.CredentialOption
 import androidx.credentials.CreatePublicKeyCredentialRequest
-import androidx.credentials.CreatePublicKeyCredentialRequestPrivileged
 import androidx.credentials.GetPublicKeyCredentialOption
-import androidx.credentials.GetPublicKeyCredentialOptionPrivileged
 import androidx.credentials.PublicKeyCredential.Companion.TYPE_PUBLIC_KEY_CREDENTIAL
 import androidx.credentials.provider.Action
 import androidx.credentials.provider.AuthenticationAction
@@ -186,8 +184,6 @@
                 )
                 if (credentialOptionJetpack is GetPublicKeyCredentialOption) {
                     credentialOptionJetpack.preferImmediatelyAvailableCredentials
-                } else if (credentialOptionJetpack is GetPublicKeyCredentialOptionPrivileged) {
-                    credentialOptionJetpack.preferImmediatelyAvailableCredentials
                 } else {
                     false
                 }
@@ -224,7 +220,7 @@
                             credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(),
                             userName = credentialEntry.username.toString(),
                             displayName = credentialEntry.displayName?.toString(),
-                            icon = credentialEntry.icon?.loadDrawable(context),
+                            icon = credentialEntry.icon.loadDrawable(context),
                             lastUsedTimeMillis = credentialEntry.lastUsedTime,
                         ))
                     }
@@ -239,7 +235,7 @@
                             credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(),
                             userName = credentialEntry.username.toString(),
                             displayName = credentialEntry.displayName?.toString(),
-                            icon = credentialEntry.icon?.loadDrawable(context),
+                            icon = credentialEntry.icon.loadDrawable(context),
                             lastUsedTimeMillis = credentialEntry.lastUsedTime,
                         ))
                     }
@@ -254,7 +250,7 @@
                             credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(),
                             userName = credentialEntry.title.toString(),
                             displayName = credentialEntry.subtitle?.toString(),
-                            icon = credentialEntry.icon?.loadDrawable(context),
+                            icon = credentialEntry.icon.loadDrawable(context),
                             lastUsedTimeMillis = credentialEntry.lastUsedTime,
                         ))
                     }
@@ -436,7 +432,7 @@
                     createCredentialRequestJetpack.password,
                     CredentialType.PASSWORD,
                     appLabel,
-                    context.getDrawable(R.drawable.ic_password) ?: return null,
+                    context.getDrawable(R.drawable.ic_password_24) ?: return null,
                     preferImmediatelyAvailableCredentials = false,
                 )
                 is CreatePublicKeyCredentialRequest -> {
@@ -448,27 +444,18 @@
                         createCredentialRequestJetpack.preferImmediatelyAvailableCredentials,
                     )
                 }
-                is CreatePublicKeyCredentialRequestPrivileged -> {
-                    newRequestDisplayInfoFromPasskeyJson(
-                        requestJson = createCredentialRequestJetpack.requestJson,
-                        appLabel = appLabel,
-                        context = context,
-                        preferImmediatelyAvailableCredentials =
-                        createCredentialRequestJetpack.preferImmediatelyAvailableCredentials,
-                    )
-                }
                 is CreateCustomCredentialRequest -> {
                     // TODO: directly use the display info once made public
                     val displayInfo = CreateCredentialRequest.DisplayInfo
                         .parseFromCredentialDataBundle(createCredentialRequest.credentialData)
                         ?: return null
                     RequestDisplayInfo(
-                        title = displayInfo.userId,
-                        subtitle = displayInfo.userDisplayName,
+                        title = displayInfo.userId.toString(),
+                        subtitle = displayInfo.userDisplayName?.toString(),
                         type = CredentialType.UNKNOWN,
                         appName = appLabel,
                         typeIcon = displayInfo.credentialTypeIcon?.loadDrawable(context)
-                            ?: context.getDrawable(R.drawable.ic_other_sign_in) ?: return null,
+                            ?: context.getDrawable(R.drawable.ic_other_sign_in_24) ?: return null,
                         preferImmediatelyAvailableCredentials = false,
                     )
                 }
@@ -656,7 +643,7 @@
                 displayName,
                 CredentialType.PASSKEY,
                 appLabel,
-                context.getDrawable(R.drawable.ic_passkey) ?: return null,
+                context.getDrawable(R.drawable.ic_passkey_24) ?: return null,
                 preferImmediatelyAvailableCredentials,
             )
         }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/TestUtils.kt b/packages/CredentialManager/src/com/android/credentialmanager/TestUtils.kt
index 9216429..75b12ff 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/TestUtils.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/TestUtils.kt
@@ -25,7 +25,10 @@
 import android.credentials.ui.AuthenticationEntry
 import android.credentials.ui.Entry
 import android.net.Uri
+import android.os.Bundle
 import android.provider.Settings
+import androidx.credentials.provider.BeginGetPasswordOption
+import androidx.credentials.provider.BeginGetPublicKeyCredentialOption
 import androidx.credentials.provider.CreateEntry
 import androidx.credentials.provider.PasswordCredentialEntry
 import androidx.credentials.provider.PublicKeyCredentialEntry
@@ -82,7 +85,9 @@
             return Entry(
                 key,
                 subkey,
-                RemoteCredentialEntry(pendingIntent).slice
+                RemoteCredentialEntry(pendingIntent, BeginGetPublicKeyCredentialOption(
+                    Bundle(), "id", "requestjson"
+                )).slice
             )
         }
 
@@ -137,7 +142,8 @@
                 intent, (PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
                 or PendingIntent.FLAG_ONE_SHOT)
             )
-            val passwordEntry = PasswordCredentialEntry.Builder(context, userName, pendingIntent)
+            val passwordEntry = PasswordCredentialEntry.Builder(
+                context, userName, pendingIntent, BeginGetPasswordOption(Bundle(), "id"))
                 .setDisplayName(userDisplayName).setLastUsedTime(lastUsedTime).build()
             return Entry(key, subkey, passwordEntry.slice, Intent())
         }
@@ -158,8 +164,12 @@
                 intent, (PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
                 or PendingIntent.FLAG_ONE_SHOT)
             )
-            val passkeyEntry = PublicKeyCredentialEntry.Builder(context, userName, pendingIntent)
-                .setDisplayName(userDisplayName).setLastUsedTime(lastUsedTime).build()
+            val passkeyEntry = PublicKeyCredentialEntry.Builder(
+                context,
+                userName,
+                pendingIntent,
+                BeginGetPublicKeyCredentialOption(Bundle(), "id", "requestjson")
+            ).setDisplayName(userDisplayName).setLastUsedTime(lastUsedTime).build()
             return Entry(key, subkey, passkeyEntry.slice, Intent())
         }
     }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt
index 335d58a..307d953 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt
@@ -306,10 +306,6 @@
  * @param sheetContentColor The preferred content color provided by the bottom sheet to its
  * children. Defaults to the matching content color for [sheetBackgroundColor], or if that is not
  * a color from the theme, this will keep the same content color set above the bottom sheet.
- * @param scrimColor The color of the scrim that is applied to the rest of the screen when the
- * bottom sheet is visible. If the color passed is [Color.Unspecified], then a scrim will no
- * longer be applied and the bottom sheet will not block interaction with the rest of the screen
- * when visible.
  * @param content The content of rest of the screen.
  */
 @Composable
@@ -322,7 +318,6 @@
     sheetElevation: Dp = ModalBottomSheetDefaults.Elevation,
     sheetBackgroundColor: Color = MaterialTheme.colorScheme.surface,
     sheetContentColor: Color = contentColorFor(sheetBackgroundColor),
-    scrimColor: Color = ModalBottomSheetDefaults.scrimColor,
     content: @Composable () -> Unit
 ) {
     val scope = rememberCoroutineScope()
@@ -332,7 +327,7 @@
         Box(Modifier.fillMaxSize()) {
             content()
             Scrim(
-                color = scrimColor,
+                color = ModalBottomSheetDefaults.scrimColor,
                 onDismiss = {
                     if (sheetState.confirmStateChange(Hidden)) {
                         scope.launch { sheetState.hide() }
@@ -505,5 +500,5 @@
      */
     val scrimColor: Color
         @Composable
-        get() = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.32f)
+        get() = MaterialTheme.colorScheme.scrim.copy(alpha = .32f)
 }
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
index c4d96cc..0cb2bb0 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
@@ -39,11 +39,12 @@
         skipHalfExpanded = true
     )
     ModalBottomSheetLayout(
-        sheetBackgroundColor = MaterialTheme.colorScheme.surface,
+        sheetBackgroundColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
+            ElevationTokens.Level1
+        ),
         modifier = Modifier.background(Color.Transparent),
         sheetState = state,
         sheetContent = sheetContent,
-        scrimColor = MaterialTheme.colorScheme.scrim.copy(alpha = 0.8f),
         sheetShape = EntryShape.TopRoundedCorner,
     ) {}
     LaunchedEffect(state.currentValue) {
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt
index cc73089..c535268 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt
@@ -31,6 +31,7 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
+import com.android.credentialmanager.ui.theme.Shapes
 
 /**
  * Container card for the whole sheet.
@@ -83,7 +84,7 @@
 ) {
     Card(
         modifier = modifier.fillMaxWidth().wrapContentHeight(),
-        shape = MaterialTheme.shapes.medium,
+        shape = Shapes.medium,
         border = null,
         colors = CardDefaults.cardColors(
             containerColor = Color.Transparent,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
index bffa40e..1e2a280 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
@@ -74,6 +74,12 @@
     /** If true, draws a trailing lock icon. */
     isLockedAuthEntry: Boolean = false,
 ) {
+    val iconPadding = Modifier.wrapContentSize().padding(
+        // Horizontal padding should be 16dp, but the suggestion chip itself
+        // has 8dp horizontal elements padding
+        start = 8.dp, top = 16.dp, bottom = 16.dp
+    )
+    val iconSize = Modifier.size(24.dp)
     SuggestionChip(
         modifier = modifier.fillMaxWidth().wrapContentHeight(),
         onClick = onClick,
@@ -81,7 +87,11 @@
         label = {
             Row(
                 horizontalArrangement = Arrangement.SpaceBetween,
-                modifier = Modifier.fillMaxWidth().padding(all = 16.dp),
+                modifier = Modifier.fillMaxWidth().padding(
+                    // Total end padding should be 16dp, but the suggestion chip itself
+                    // has 8dp horizontal elements padding
+                    horizontal = 8.dp, vertical = 16.dp,
+                ),
                 verticalAlignment = Alignment.CenterVertically,
             ) {
                 Column(modifier = Modifier.wrapContentSize()) {
@@ -121,7 +131,7 @@
                     }
                 }
                 if (isLockedAuthEntry) {
-                    Box(modifier = Modifier.wrapContentSize().padding(end = 16.dp)) {
+                    Box(modifier = Modifier.wrapContentSize()) {
                         Icon(
                             imageVector = Icons.Outlined.Lock,
                             // Decorative purpose only.
@@ -137,10 +147,9 @@
         if (iconImageBitmap != null) {
             if (shouldApplyIconImageBitmapTint) {
                 {
-                    Box(modifier = Modifier.wrapContentSize()
-                        .padding(start = 16.dp, top = 16.dp, bottom = 16.dp)) {
+                    Box(modifier = iconPadding) {
                         Icon(
-                            modifier = Modifier.size(24.dp),
+                            modifier = iconSize,
                             bitmap = iconImageBitmap,
                             tint = MaterialTheme.colorScheme.onSurfaceVariant,
                             // Decorative purpose only.
@@ -150,10 +159,9 @@
                 }
             } else {
                 {
-                    Box(modifier = Modifier.wrapContentSize()
-                        .padding(start = 16.dp, top = 16.dp, bottom = 16.dp)) {
+                    Box(modifier = iconPadding) {
                         Image(
-                            modifier = Modifier.size(24.dp),
+                            modifier = iconSize,
                             bitmap = iconImageBitmap,
                             // Decorative purpose only.
                             contentDescription = null,
@@ -163,10 +171,9 @@
             }
         } else if (iconImageVector != null) {
             {
-                Box(modifier = Modifier.wrapContentSize()
-                    .padding(start = 16.dp, top = 16.dp, bottom = 16.dp)) {
+                Box(modifier = iconPadding) {
                     Icon(
-                        modifier = Modifier.size(24.dp),
+                        modifier = iconSize,
                         imageVector = iconImageVector,
                         tint = MaterialTheme.colorScheme.onSurfaceVariant,
                         // Decorative purpose only.
@@ -176,10 +183,9 @@
             }
         } else if (iconPainter != null) {
             {
-                Box(modifier = Modifier.wrapContentSize()
-                    .padding(start = 16.dp, top = 16.dp, bottom = 16.dp)) {
+                Box(modifier = iconPadding) {
                     Icon(
-                        modifier = Modifier.size(24.dp),
+                        modifier = iconSize,
                         painter = iconPainter,
                         tint = MaterialTheme.colorScheme.onSurfaceVariant,
                         // Decorative purpose only.
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SystemUiControllerUtils.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SystemUiControllerUtils.kt
new file mode 100644
index 0000000..2f14584
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/SystemUiControllerUtils.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.common.ui
+
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.graphics.Color
+import com.android.compose.SystemUiController
+import com.android.credentialmanager.common.material.ModalBottomSheetDefaults
+
+@Composable
+fun setTransparentSystemBarsColor(sysUiController: SystemUiController) {
+    sysUiController.setSystemBarsColor(color = Color.Transparent, darkIcons = false)
+}
+
+@Composable
+fun setBottomSheetSystemBarsColor(sysUiController: SystemUiController) {
+    sysUiController.setStatusBarColor(
+        color = ModalBottomSheetDefaults.scrimColor,
+        darkIcons = false
+    )
+    sysUiController.setNavigationBarColor(
+        color = MaterialTheme.colorScheme.surfaceColorAtElevation(
+            ElevationTokens.Level1
+        ),
+        darkIcons = false
+    )
+}
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index 00b7d00..5b175bf 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -20,6 +20,7 @@
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.outlined.NewReleases
 import androidx.compose.material.icons.filled.Add
+import androidx.compose.material.icons.outlined.QrCodeScanner
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.mutableStateOf
@@ -31,6 +32,7 @@
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import androidx.core.graphics.drawable.toBitmap
+import com.android.compose.rememberSystemUiController
 import com.android.credentialmanager.CredentialSelectorViewModel
 import com.android.credentialmanager.R
 import com.android.credentialmanager.common.BaseEntry
@@ -51,6 +53,7 @@
 import com.android.credentialmanager.common.ui.SheetContainerCard
 import com.android.credentialmanager.common.ui.PasskeyBenefitRow
 import com.android.credentialmanager.common.ui.HeadlineText
+import com.android.credentialmanager.common.ui.setBottomSheetSystemBarsColor
 
 @Composable
 fun CreateCredentialScreen(
@@ -58,6 +61,8 @@
     createCredentialUiState: CreateCredentialUiState,
     providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
 ) {
+    val sysUiController = rememberSystemUiController()
+    setBottomSheetSystemBarsColor(sysUiController)
     ModalBottomSheet(
         sheetContent = {
             // Hide the sheet content as opposed to the whole bottom sheet to maintain the scrim
@@ -325,7 +330,8 @@
             else onBackCreationSelectionButtonSelected,
         )
     }) {
-        item { Divider(thickness = 16.dp, color = Color.Transparent) }
+        item { Divider(thickness = 8.dp, color = Color.Transparent) } // Top app bar has a 8dp
+                                                                      // bottom padding already
         item {
             CredentialContainerCard {
                 Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
@@ -511,7 +517,7 @@
     onConfirm: () -> Unit,
 ) {
     SheetContainerCard {
-        item { HeadlineIcon(painter = painterResource(R.drawable.ic_other_devices)) }
+        item { HeadlineIcon(imageVector = Icons.Outlined.QrCodeScanner) }
         item { Divider(thickness = 16.dp, color = Color.Transparent) }
         item { HeadlineText(text = stringResource(R.string.create_passkey_in_other_device_title)) }
         item { Divider(thickness = 24.dp, color = Color.Transparent) }
@@ -690,7 +696,7 @@
 ) {
     Entry(
         onClick = { onRemoteEntrySelected(remoteInfo) },
-        iconPainter = painterResource(R.drawable.ic_other_devices),
+        iconImageVector = Icons.Outlined.QrCodeScanner,
         entryHeadlineText = stringResource(R.string.another_device),
     )
 }
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index c5028c2..9a826f2 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -28,6 +28,8 @@
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.wrapContentHeight
 import androidx.compose.foundation.lazy.items
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.QrCodeScanner
 import androidx.compose.material3.Divider
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
@@ -39,6 +41,7 @@
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import androidx.core.graphics.drawable.toBitmap
+import com.android.compose.rememberSystemUiController
 import com.android.credentialmanager.CredentialSelectorViewModel
 import com.android.credentialmanager.R
 import com.android.credentialmanager.common.BaseEntry
@@ -57,6 +60,8 @@
 import com.android.credentialmanager.common.ui.HeadlineText
 import com.android.credentialmanager.common.ui.CredentialListSectionHeader
 import com.android.credentialmanager.common.ui.Snackbar
+import com.android.credentialmanager.common.ui.setTransparentSystemBarsColor
+import com.android.credentialmanager.common.ui.setBottomSheetSystemBarsColor
 
 @Composable
 fun GetCredentialScreen(
@@ -64,13 +69,16 @@
     getCredentialUiState: GetCredentialUiState,
     providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
 ) {
+    val sysUiController = rememberSystemUiController()
     if (getCredentialUiState.currentScreenState == GetScreenState.REMOTE_ONLY) {
+        setTransparentSystemBarsColor(sysUiController)
         RemoteCredentialSnackBarScreen(
             onClick = viewModel::getFlowOnMoreOptionOnSnackBarSelected,
             onCancel = viewModel::onUserCancel,
         )
     } else if (getCredentialUiState.currentScreenState
         == GetScreenState.UNLOCKED_AUTH_ENTRIES_ONLY) {
+        setTransparentSystemBarsColor(sysUiController)
         EmptyAuthEntrySnackBarScreen(
             authenticationEntryList =
             getCredentialUiState.providerDisplayInfo.authenticationEntryList,
@@ -78,6 +86,7 @@
             onLastLockedAuthEntryNotFound = viewModel::onLastLockedAuthEntryNotFoundError,
         )
     } else {
+        setBottomSheetSystemBarsColor(sysUiController)
         ModalBottomSheet(
             sheetContent = {
                 // Hide the sheet content as opposed to the whole bottom sheet to maintain the scrim
@@ -338,7 +347,7 @@
         ) {
             Entry(
                 onClick = { onEntrySelected(remoteEntry) },
-                iconPainter = painterResource(R.drawable.ic_other_devices),
+                iconImageVector = Icons.Outlined.QrCodeScanner,
                 entryHeadlineText = stringResource(
                     R.string.get_dialog_option_headline_use_a_different_device
                 ),
@@ -399,7 +408,7 @@
         iconImageBitmap = credentialEntryInfo.icon?.toBitmap()?.asImageBitmap(),
         // Fall back to iconPainter if iconImageBitmap isn't available
         iconPainter =
-        if (credentialEntryInfo.icon == null) painterResource(R.drawable.ic_other_sign_in)
+        if (credentialEntryInfo.icon == null) painterResource(R.drawable.ic_other_sign_in_24)
         else null,
         entryHeadlineText = credentialEntryInfo.userName,
         entrySecondLineText = if (
diff --git a/packages/SettingsLib/Spa/spa/build.gradle b/packages/SettingsLib/Spa/spa/build.gradle
index 640aa01..4563b7d 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle
+++ b/packages/SettingsLib/Spa/spa/build.gradle
@@ -48,11 +48,11 @@
         }
     }
     compileOptions {
-        sourceCompatibility JavaVersion.VERSION_11
-        targetCompatibility JavaVersion.VERSION_11
+        sourceCompatibility JavaVersion.VERSION_17
+        targetCompatibility JavaVersion.VERSION_17
     }
     kotlinOptions {
-        jvmTarget = '11'
+        jvmTarget = '17'
         freeCompilerArgs = ["-Xjvm-default=all"]
     }
     buildFeatures {
diff --git a/packages/SettingsLib/Spa/testutils/build.gradle b/packages/SettingsLib/Spa/testutils/build.gradle
index 536829e..e7f7db2 100644
--- a/packages/SettingsLib/Spa/testutils/build.gradle
+++ b/packages/SettingsLib/Spa/testutils/build.gradle
@@ -38,11 +38,11 @@
         }
     }
     compileOptions {
-        sourceCompatibility JavaVersion.VERSION_11
-        targetCompatibility JavaVersion.VERSION_11
+        sourceCompatibility JavaVersion.VERSION_17
+        targetCompatibility JavaVersion.VERSION_17
     }
     kotlinOptions {
-        jvmTarget = '11'
+        jvmTarget = '17'
         freeCompilerArgs = ["-Xjvm-default=all"]
     }
     buildFeatures {
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
index 28353ab..52f3111 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
@@ -169,8 +169,11 @@
      */
     public static boolean maybeShowBatterySaverConfirmation(Context context, Bundle extras) {
         if (Secure.getInt(context.getContentResolver(),
-                Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 0) != 0) {
-            return false; // Already shown.
+                Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 0) != 0
+                && Secure.getInt(context.getContentResolver(),
+                Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, 0) != 0) {
+            // Already shown.
+            return false;
         }
         context.sendBroadcast(
                 getSystemUiBroadcast(ACTION_SHOW_START_SAVER_CONFIRMATION, extras));
@@ -190,8 +193,10 @@
     }
 
     private static void setBatterySaverConfirmationAcknowledged(Context context) {
-        Secure.putIntForUser(context.getContentResolver(), Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1,
-                UserHandle.USER_CURRENT);
+        Secure.putIntForUser(context.getContentResolver(),
+                Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1, UserHandle.USER_CURRENT);
+        Secure.putIntForUser(context.getContentResolver(),
+                Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, 1, UserHandle.USER_CURRENT);
     }
 
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsUtils.java b/packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsUtils.java
index dc8a862..31f014c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsUtils.java
@@ -62,16 +62,7 @@
      */
     public Point getTouchInNativeCoordinates(int idx, MotionEvent event,
             UdfpsOverlayParams udfpsOverlayParams) {
-        Point portraitTouch = new Point((int) event.getRawX(idx), (int) event.getRawY(idx));
-        int rot = udfpsOverlayParams.getRotation();
-        if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
-            RotationUtils.rotatePoint(
-                    portraitTouch,
-                    RotationUtils.deltaRotation(rot, Surface.ROTATION_0),
-                    udfpsOverlayParams.getLogicalDisplayWidth(),
-                    udfpsOverlayParams.getLogicalDisplayHeight()
-            );
-        }
+        Point portraitTouch = getPortraitTouch(idx, event, udfpsOverlayParams);
 
         // Scale the coordinates to native resolution.
         float scale = udfpsOverlayParams.getScaleFactor();
@@ -81,13 +72,25 @@
     }
 
     /**
+     * @param idx                The pointer identifier.
+     * @param event              The MotionEvent object containing full information about the event.
+     * @param udfpsOverlayParams The [UdfpsOverlayParams] used.
+     * @return Whether the touch event is within sensor area.
+     */
+    public boolean isWithinSensorArea(int idx, MotionEvent event,
+            UdfpsOverlayParams udfpsOverlayParams) {
+        Point portraitTouch = getPortraitTouch(idx, event, udfpsOverlayParams);
+        return udfpsOverlayParams.getSensorBounds().contains(portraitTouch.x, portraitTouch.y);
+    }
+
+    /**
      * This function computes the angle of touch relative to the sensor and maps the angle to a list
      * of help messages which are announced if accessibility is enabled.
      *
      * @return Whether the announcing string is null
      */
-    public String onTouchOutsideOfSensorArea(boolean touchExplorationEnabled,
-            Context context, int touchX, int touchY, UdfpsOverlayParams udfpsOverlayParams) {
+    public String onTouchOutsideOfSensorArea(boolean touchExplorationEnabled, Context context,
+            int scaledTouchX, int scaledTouchY, UdfpsOverlayParams udfpsOverlayParams) {
         if (!touchExplorationEnabled) {
             return null;
         }
@@ -106,8 +109,8 @@
         String theStr =
                 onTouchOutsideOfSensorAreaImpl(
                         touchHints,
-                        touchX,
-                        touchY,
+                        scaledTouchX,
+                        scaledTouchY,
                         scaledSensorX,
                         scaledSensorY,
                         udfpsOverlayParams.getRotation()
@@ -156,4 +159,22 @@
         }
         return touchHints[index];
     }
+
+    /**
+     * Map the touch to portrait mode if the device is in landscape mode.
+     */
+    private Point getPortraitTouch(int idx, MotionEvent event,
+            UdfpsOverlayParams udfpsOverlayParams) {
+        Point portraitTouch = new Point((int) event.getRawX(idx), (int) event.getRawY(idx));
+        int rot = udfpsOverlayParams.getRotation();
+        if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
+            RotationUtils.rotatePoint(
+                    portraitTouch,
+                    RotationUtils.deltaRotation(rot, Surface.ROTATION_0),
+                    udfpsOverlayParams.getLogicalDisplayWidth(),
+                    udfpsOverlayParams.getLogicalDisplayHeight()
+            );
+        }
+        return portraitTouch;
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java
index a15fe9f..ad022a6 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java
@@ -69,6 +69,7 @@
     @Test
     public void testSetPowerSaveMode_enable_firstCall_needWarning() {
         Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null");
+        Secure.putString(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, "null");
         Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null");
 
         assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)).isFalse();
@@ -77,15 +78,18 @@
         verify(mMockPowerManager, times(0)).setPowerSaveModeEnabled(anyBoolean());
 
         // They shouldn't have changed.
+        assertEquals(-1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
         assertEquals(-1,
-                Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
+                Secure.getInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, -1));
         assertEquals(-2,
                 Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
     }
 
     @Test
     public void testSetPowerSaveMode_enable_secondCall_needWarning() {
-        Secure.putInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1); // Already acked.
+        // Already acked.
+        Secure.putInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1);
+        Secure.putInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, 1);
         Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null");
 
         assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)).isTrue();
@@ -94,12 +98,17 @@
         verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(true));
 
         assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
-        assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
+        assertEquals(1,
+                Secure.getInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, -1));
+        assertEquals(1,
+                Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
     }
 
     @Test
     public void testSetPowerSaveMode_enable_thridCall_needWarning() {
-        Secure.putInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1); // Already acked.
+        // Already acked.
+        Secure.putInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1);
+        Secure.putInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, 1);
         Secure.putInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, 1);
 
         assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)).isTrue();
@@ -108,12 +117,16 @@
         verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(true));
 
         assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
-        assertEquals(2, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
+        assertEquals(1,
+                Secure.getInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, -1));
+        assertEquals(2,
+                Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
     }
 
     @Test
     public void testSetPowerSaveMode_enable_firstCall_noWarning() {
         Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null");
+        Secure.putString(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, "null");
         Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null");
 
         assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, false)).isTrue();
@@ -122,12 +135,15 @@
         verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(true));
 
         assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
+        assertEquals(1,
+                Secure.getInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, -1));
         assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
     }
 
     @Test
     public void testSetPowerSaveMode_disable_firstCall_noWarning() {
         Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null");
+        Secure.putString(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, "null");
         Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null");
 
         // When disabling, needFirstTimeWarning doesn't matter.
@@ -137,6 +153,8 @@
         verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(false));
 
         assertEquals(-1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
+        assertEquals(-1,
+                Secure.getInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, -1));
         assertEquals(-2,
                 Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
     }
@@ -144,6 +162,7 @@
     @Test
     public void testSetPowerSaveMode_disable_firstCall_needWarning() {
         Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null");
+        Secure.putString(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, "null");
         Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null");
 
         // When disabling, needFirstTimeWarning doesn't matter.
@@ -153,6 +172,8 @@
         verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(false));
 
         assertEquals(-1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
+        assertEquals(-1,
+                Secure.getInt(mMockResolver, Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, -1));
         assertEquals(-2,
                 Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
     }
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 93394f3..f66fcba 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -239,5 +239,6 @@
         Settings.Secure.HEARING_AID_CALL_ROUTING,
         Settings.Secure.HEARING_AID_MEDIA_ROUTING,
         Settings.Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING,
+        Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 9657862..558e19f 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -376,5 +376,6 @@
                 new DiscreteValueValidator(new String[] {"0", "1", "2"}));
         VALIDATORS.put(Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING,
                 new DiscreteValueValidator(new String[] {"0", "1", "2"}));
+        VALIDATORS.put(Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED, BOOLEAN_VALIDATOR);
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index fb3c313..1a69208 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1852,6 +1852,9 @@
         dumpSetting(s, p,
                 Settings.Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING,
                 SecureSettingsProto.Accessibility.HEARING_AID_SYSTEM_SOUNDS_ROUTING);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
+                SecureSettingsProto.Accessibility.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED);
         p.end(accessibilityToken);
 
         final long adaptiveSleepToken = p.start(SecureSettingsProto.ADAPTIVE_SLEEP);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 90bec42..d02e569 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -721,6 +721,7 @@
     <!-- Permission required for CTS test - CtsTelephonyTestCases -->
     <uses-permission android:name="android.permission.BIND_TELECOM_CONNECTION_SERVICE" />
     <uses-permission android:name="android.permission.MODIFY_CELL_BROADCASTS" />
+    <uses-permission android:name="android.permission.SATELLITE_COMMUNICATION" />
 
     <!-- Permission required for CTS test - CtsPersistentDataBlockManagerTestCases -->
     <uses-permission android:name="android.permission.ACCESS_PDB_STATE" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 4e18222..71f438e 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -341,6 +341,8 @@
 
     <uses-permission android:name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS" />
 
+    <uses-permission android:name="android.permission.MONITOR_KEYBOARD_BACKLIGHT" />
+
     <protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
     <protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
     <protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
diff --git a/packages/SystemUI/animation/src/com/android/systemui/util/AnimatorExtensions.kt b/packages/SystemUI/animation/src/com/android/systemui/util/AnimatorExtensions.kt
new file mode 100644
index 0000000..35dbb89
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/util/AnimatorExtensions.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util
+
+import androidx.core.animation.Animator
+
+/**
+ * Add an action which will be invoked when the animation has ended.
+ *
+ * @return the [Animator.AnimatorListener] added to the Animator
+ * @see Animator.end
+ */
+inline fun Animator.doOnEnd(
+    crossinline action: (animator: Animator) -> Unit
+): Animator.AnimatorListener = addListener(onEnd = action)
+
+/**
+ * Add an action which will be invoked when the animation has started.
+ *
+ * @return the [Animator.AnimatorListener] added to the Animator
+ * @see Animator.start
+ */
+inline fun Animator.doOnStart(
+    crossinline action: (animator: Animator) -> Unit
+): Animator.AnimatorListener = addListener(onStart = action)
+
+/**
+ * Add an action which will be invoked when the animation has been cancelled.
+ *
+ * @return the [Animator.AnimatorListener] added to the Animator
+ * @see Animator.cancel
+ */
+inline fun Animator.doOnCancel(
+    crossinline action: (animator: Animator) -> Unit
+): Animator.AnimatorListener = addListener(onCancel = action)
+
+/**
+ * Add an action which will be invoked when the animation has repeated.
+ *
+ * @return the [Animator.AnimatorListener] added to the Animator
+ */
+inline fun Animator.doOnRepeat(
+    crossinline action: (animator: Animator) -> Unit
+): Animator.AnimatorListener = addListener(onRepeat = action)
+
+/**
+ * Add a listener to this Animator using the provided actions.
+ *
+ * @return the [Animator.AnimatorListener] added to the Animator
+ */
+inline fun Animator.addListener(
+    crossinline onEnd: (animator: Animator) -> Unit = {},
+    crossinline onStart: (animator: Animator) -> Unit = {},
+    crossinline onCancel: (animator: Animator) -> Unit = {},
+    crossinline onRepeat: (animator: Animator) -> Unit = {}
+): Animator.AnimatorListener {
+    val listener =
+        object : Animator.AnimatorListener {
+            override fun onAnimationRepeat(animator: Animator) = onRepeat(animator)
+            override fun onAnimationEnd(animator: Animator) = onEnd(animator)
+            override fun onAnimationCancel(animator: Animator) = onCancel(animator)
+            override fun onAnimationStart(animator: Animator) = onStart(animator)
+        }
+    addListener(listener)
+    return listener
+}
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/DynamicColor.java b/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/DynamicColor.java
index 3a6b362..e6b2c2f 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/DynamicColor.java
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/DynamicColor.java
@@ -350,7 +350,7 @@
         if (bgDynamicColor != null) {
             final boolean bgHasBg =
                     bgDynamicColor.background != null && bgDynamicColor.background.apply(scheme)
-                            == null;
+                            != null;
             final double standardRatio =
                     Contrast.ratioOfTones(tone.apply(scheme), bgDynamicColor.tone.apply(scheme));
             if (decreasingContrast) {
@@ -358,15 +358,15 @@
                         Contrast.ratioOfTones(
                                 toneMinContrast.apply(scheme),
                                 bgDynamicColor.toneMinContrast.apply(scheme));
-                minRatio = bgHasBg ? 1.0 : minContrastRatio;
+                minRatio = bgHasBg ? minContrastRatio : 1.0;
                 maxRatio = standardRatio;
             } else {
                 final double maxContrastRatio =
                         Contrast.ratioOfTones(
                                 toneMaxContrast.apply(scheme),
                                 bgDynamicColor.toneMaxContrast.apply(scheme));
-                minRatio = !bgHasBg ? 1.0 : min(maxContrastRatio, standardRatio);
-                maxRatio = !bgHasBg ? 21.0 : max(maxContrastRatio, standardRatio);
+                minRatio = bgHasBg ? min(maxContrastRatio, standardRatio) : 1.0;
+                maxRatio = bgHasBg ? max(maxContrastRatio, standardRatio) : 21.0;
             }
         }
 
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index caf3233..b6a78f5 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -82,7 +82,7 @@
     <!-- The vertical margin between the date and the owner info. -->
 
     <!-- The translation for disappearing security views after having solved them. -->
-    <dimen name="disappear_y_translation">-50dp</dimen>
+    <dimen name="disappear_y_translation">-32dp</dimen>
 
     <!-- Dimens for animation for the Bouncer PIN view -->
     <dimen name="pin_view_trans_y_entry">120dp</dimen>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 51f507c..11b4d79 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -56,7 +56,7 @@
     <string name="keyguard_plugged_in_charging_limited"><xliff:g id="percentage">%s</xliff:g> • Charging optimized to protect battery</string>
 
     <!-- When the lock screen is showing and the phone plugged in with incompatible charger. -->
-    <string name="keyguard_plugged_in_incompatible_charger"><xliff:g id="percentage">%s</xliff:g> • Incompatible charging</string>
+    <string name="keyguard_plugged_in_incompatible_charger"><xliff:g id="percentage">%s</xliff:g> • Issue with charging accessory</string>
 
     <!-- On the keyguard screen, when pattern lock is disabled, only tell them to press menu to unlock.  This is shown in small font at the bottom. -->
     <string name="keyguard_instructions_when_pattern_disabled">Press Menu to unlock.</string>
diff --git a/packages/SystemUI/res-product/values/strings.xml b/packages/SystemUI/res-product/values/strings.xml
index 75c8286..a677c12 100644
--- a/packages/SystemUI/res-product/values/strings.xml
+++ b/packages/SystemUI/res-product/values/strings.xml
@@ -122,6 +122,12 @@
        Try again in <xliff:g id="number">%3$d</xliff:g> seconds.
     </string>
 
+    <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (tablet) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]-->
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet.\n\nPressing the power button turns off the screen.</string>
+    <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (device) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]-->
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device.\n\nPressing the power button turns off the screen.</string>
+    <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (default) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]-->
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone.\n\nPressing the power button turns off the screen.</string>
 
     <!-- Text shown when viewing global actions while phone is locked and additional controls are hidden [CHAR LIMIT=NONE] -->
     <string name="global_action_lock_message" product="default">Unlock your phone for more options</string>
@@ -134,4 +140,7 @@
     <string name="media_transfer_playing_this_device" product="default">Playing on this phone</string>
     <!-- Text informing the user that their media is now playing on this tablet device. [CHAR LIMIT=50] -->
     <string name="media_transfer_playing_this_device" product="tablet">Playing on this tablet</string>
+
+
+
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 738cfd7..e65c327 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -500,8 +500,8 @@
      space -->
     <bool name="config_showBatteryEstimateQSBH">false</bool>
 
-    <!-- Whether to show a severe low battery dialog. -->
-    <bool name="config_severe_battery_dialog">false</bool>
+    <!-- Whether to show extra battery saver confirmation dialog. -->
+    <bool name="config_extra_battery_saver_confirmation">false</bool>
 
     <!-- A path representing a shield. Will sometimes be displayed with the battery icon when
          needed. This path is a 10px wide and 13px tall. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 8972715..aba3fc4 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -573,7 +573,7 @@
     <dimen name="qs_tile_margin_horizontal">8dp</dimen>
     <dimen name="qs_tile_margin_vertical">@dimen/qs_tile_margin_horizontal</dimen>
     <dimen name="qs_tile_margin_top_bottom">4dp</dimen>
-    <dimen name="qs_brightness_margin_top">12dp</dimen>
+    <dimen name="qs_brightness_margin_top">8dp</dimen>
     <dimen name="qs_brightness_margin_bottom">16dp</dimen>
     <dimen name="qqs_layout_margin_top">16dp</dimen>
     <dimen name="qqs_layout_padding_bottom">24dp</dimen>
@@ -625,7 +625,7 @@
     <dimen name="qs_header_row_min_height">48dp</dimen>
 
     <dimen name="qs_header_non_clickable_element_height">24dp</dimen>
-    <dimen name="new_qs_header_non_clickable_element_height">20dp</dimen>
+    <dimen name="new_qs_header_non_clickable_element_height">24dp</dimen>
 
     <dimen name="qs_footer_padding">20dp</dimen>
     <dimen name="qs_security_footer_height">88dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a988813..4d989a6 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -407,12 +407,6 @@
 
     <!-- Message shown when the system-provided fingerprint dialog is shown, asking for authentication -->
     <string name="fingerprint_dialog_touch_sensor">Touch the fingerprint sensor</string>
-    <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (tablet) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]-->
-    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet.\n\nPressing the power button turns off the screen.</string>
-    <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (device) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]-->
-    <string name="security_settings_sfps_enroll_find_sensor_message" product="device">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device.\n\nPressing the power button turns off the screen.</string>
-    <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (default) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]-->
-    <string name="security_settings_sfps_enroll_find_sensor_message" product="default">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone.\n\nPressing the power button turns off the screen.</string>
     <!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] -->
     <string name="fingerprint_dialog_use_fingerprint_instead">Can\u2019t recognize face. Use fingerprint instead.</string>
     <!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index ae68618..44f9d43 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -16,30 +16,9 @@
 
 package com.android.systemui.shared.system;
 
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.view.RemoteAnimationTarget.MODE_CHANGING;
-import static android.view.RemoteAnimationTarget.MODE_CLOSING;
-import static android.view.RemoteAnimationTarget.MODE_OPENING;
-import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
-import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
-import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
-
-import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.app.ActivityManager;
-import android.app.WindowConfiguration;
-import android.graphics.Rect;
 import android.util.ArrayMap;
-import android.util.SparseBooleanArray;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
-import android.view.WindowManager;
 import android.window.TransitionInfo;
 import android.window.TransitionInfo.Change;
 
@@ -53,156 +32,6 @@
  */
 public class RemoteAnimationTargetCompat {
 
-    private static int newModeToLegacyMode(int newMode) {
-        switch (newMode) {
-            case WindowManager.TRANSIT_OPEN:
-            case WindowManager.TRANSIT_TO_FRONT:
-                return MODE_OPENING;
-            case WindowManager.TRANSIT_CLOSE:
-            case WindowManager.TRANSIT_TO_BACK:
-                return MODE_CLOSING;
-            default:
-                return MODE_CHANGING;
-        }
-    }
-
-    /**
-     * Almost a copy of Transitions#setupStartState.
-     * TODO: remove when there is proper cross-process transaction sync.
-     */
-    @SuppressLint("NewApi")
-    private static void setupLeash(@NonNull SurfaceControl leash,
-            @NonNull TransitionInfo.Change change, int layer,
-            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) {
-        final boolean isOpening = TransitionUtil.isOpeningType(info.getType());
-        // Put animating stuff above this line and put static stuff below it.
-        int zSplitLine = info.getChanges().size();
-        // changes should be ordered top-to-bottom in z
-        final int mode = change.getMode();
-
-        t.reparent(leash, info.getRootLeash());
-        final Rect absBounds =
-                (mode == TRANSIT_OPEN) ? change.getEndAbsBounds() : change.getStartAbsBounds();
-        t.setPosition(leash, absBounds.left - info.getRootOffset().x,
-                absBounds.top - info.getRootOffset().y);
-
-        // Put all the OPEN/SHOW on top
-        if (TransitionUtil.isOpeningType(mode)) {
-            if (isOpening) {
-                t.setLayer(leash, zSplitLine + info.getChanges().size() - layer);
-                if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) == 0) {
-                    // if transferred, it should be left visible.
-                    t.setAlpha(leash, 0.f);
-                }
-            } else {
-                // put on bottom and leave it visible
-                t.setLayer(leash, zSplitLine - layer);
-            }
-        } else if (TransitionUtil.isClosingType(mode)) {
-            if (isOpening) {
-                // put on bottom and leave visible
-                t.setLayer(leash, zSplitLine - layer);
-            } else {
-                // put on top
-                t.setLayer(leash, zSplitLine + info.getChanges().size() - layer);
-            }
-        } else { // CHANGE
-            t.setLayer(leash, zSplitLine + info.getChanges().size() - layer);
-        }
-    }
-
-    @SuppressLint("NewApi")
-    private static SurfaceControl createLeash(TransitionInfo info, TransitionInfo.Change change,
-            int order, SurfaceControl.Transaction t) {
-        // TODO: once we can properly sync transactions across process, then get rid of this leash.
-        if (change.getParent() != null && (change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
-            // Special case for wallpaper atm. Normally these are left alone; but, a quirk of
-            // making leashes means we have to handle them specially.
-            return change.getLeash();
-        }
-        SurfaceControl leashSurface = new SurfaceControl.Builder()
-                .setName(change.getLeash().toString() + "_transition-leash")
-                .setContainerLayer()
-                // Initial the surface visible to respect the visibility of the original surface.
-                .setHidden(false)
-                .setParent(info.getRootLeash())
-                .build();
-        // Copied Transitions setup code (which expects bottom-to-top order, so we swap here)
-        setupLeash(leashSurface, change, info.getChanges().size() - order, info, t);
-        t.reparent(change.getLeash(), leashSurface);
-        t.setAlpha(change.getLeash(), 1.0f);
-        t.show(change.getLeash());
-        t.setPosition(change.getLeash(), 0, 0);
-        t.setLayer(change.getLeash(), 0);
-        return leashSurface;
-    }
-
-    /**
-     * Creates a new RemoteAnimationTarget from the provided change info
-     */
-    public static RemoteAnimationTarget newTarget(TransitionInfo.Change change, int order,
-            TransitionInfo info, SurfaceControl.Transaction t,
-            @Nullable ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
-        final SurfaceControl leash = createLeash(info, change, order, t);
-        if (leashMap != null) {
-            leashMap.put(change.getLeash(), leash);
-        }
-        return newTarget(change, order, leash);
-    }
-
-    /**
-     * Creates a new RemoteAnimationTarget from the provided change and leash
-     */
-    public static RemoteAnimationTarget newTarget(TransitionInfo.Change change, int order,
-            SurfaceControl leash) {
-        int taskId;
-        boolean isNotInRecents;
-        ActivityManager.RunningTaskInfo taskInfo;
-        WindowConfiguration windowConfiguration;
-
-        taskInfo = change.getTaskInfo();
-        if (taskInfo != null) {
-            taskId = taskInfo.taskId;
-            isNotInRecents = !taskInfo.isRunning;
-            windowConfiguration = taskInfo.configuration.windowConfiguration;
-        } else {
-            taskId = INVALID_TASK_ID;
-            isNotInRecents = true;
-            windowConfiguration = new WindowConfiguration();
-        }
-
-        Rect localBounds = new Rect(change.getEndAbsBounds());
-        localBounds.offsetTo(change.getEndRelOffset().x, change.getEndRelOffset().y);
-
-        RemoteAnimationTarget target = new RemoteAnimationTarget(
-                taskId,
-                newModeToLegacyMode(change.getMode()),
-                // TODO: once we can properly sync transactions across process,
-                // then get rid of this leash.
-                leash,
-                (change.getFlags() & TransitionInfo.FLAG_TRANSLUCENT) != 0,
-                null,
-                // TODO(shell-transitions): we need to send content insets? evaluate how its used.
-                new Rect(0, 0, 0, 0),
-                order,
-                null,
-                localBounds,
-                new Rect(change.getEndAbsBounds()),
-                windowConfiguration,
-                isNotInRecents,
-                null,
-                new Rect(change.getStartAbsBounds()),
-                taskInfo,
-                change.getAllowEnterPip(),
-                (change.getFlags() & FLAG_IS_DIVIDER_BAR) != 0
-                        ? TYPE_DOCK_DIVIDER : INVALID_WINDOW_TYPE
-        );
-        target.setWillShowImeOnTarget(
-                (change.getFlags() & TransitionInfo.FLAG_WILL_IME_SHOWN) != 0);
-        target.setRotationChange(change.getEndRotation() - change.getStartRotation());
-        return target;
-    }
-
     /**
      * Represents a TransitionInfo object as an array of old-style app targets
      *
@@ -211,7 +40,7 @@
      */
     public static RemoteAnimationTarget[] wrapApps(TransitionInfo info,
             SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
-        return wrap(info, t, leashMap, new LeafTaskFilter());
+        return wrap(info, t, leashMap, new TransitionUtil.LeafTaskFilter());
     }
 
     /**
@@ -224,8 +53,8 @@
      */
     public static RemoteAnimationTarget[] wrapNonApps(TransitionInfo info, boolean wallpapers,
             SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
-        return wrap(info, t, leashMap, (change) ->
-                (wallpapers ? isWallpaper(change) : isNonApp(change)));
+        return wrap(info, t, leashMap, (change) -> (wallpapers
+                ? TransitionUtil.isWallpaper(change) : TransitionUtil.isNonApp(change)));
     }
 
     private static RemoteAnimationTarget[] wrap(TransitionInfo info,
@@ -235,45 +64,10 @@
         for (int i = 0; i < info.getChanges().size(); i++) {
             TransitionInfo.Change change = info.getChanges().get(i);
             if (filter.test(change)) {
-                out.add(newTarget(change, info.getChanges().size() - i, info, t, leashMap));
+                out.add(TransitionUtil.newTarget(
+                        change, info.getChanges().size() - i, info, t, leashMap));
             }
         }
         return out.toArray(new RemoteAnimationTarget[out.size()]);
     }
-
-    /** Returns `true` if `change` is a wallpaper. */
-    public static boolean isWallpaper(Change change) {
-        return (change.getTaskInfo() == null)
-                && change.hasFlags(FLAG_IS_WALLPAPER)
-                && !change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY);
-    }
-
-    /** Returns `true` if `change` is not an app window or wallpaper. */
-    public static boolean isNonApp(Change change) {
-        return (change.getTaskInfo() == null)
-                && !change.hasFlags(FLAG_IS_WALLPAPER)
-                && !change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY);
-    }
-
-    /**
-     * Filter that selects leaf-tasks only. THIS IS ORDER-DEPENDENT! For it to work properly, you
-     * MUST call `test` in the same order that the changes appear in the TransitionInfo.
-     */
-    public static class LeafTaskFilter implements Predicate<Change> {
-        private final SparseBooleanArray mChildTaskTargets = new SparseBooleanArray();
-
-        @Override
-        public boolean test(Change change) {
-            final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
-            // Children always come before parent since changes are in top-to-bottom z-order.
-            if ((taskInfo == null) || mChildTaskTargets.get(taskInfo.taskId)) {
-                // has children, so not a leaf. Skip.
-                return false;
-            }
-            if (taskInfo.hasParentTask()) {
-                mChildTaskTargets.put(taskInfo.parentTaskId, true);
-            }
-            return true;
-        }
-    }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index 70a36ce..fca55b1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -21,8 +21,6 @@
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
 
-import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.newTarget;
-
 import android.annotation.SuppressLint;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
@@ -45,7 +43,6 @@
 import android.window.WindowContainerTransaction;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.wm.shell.util.TransitionUtil;
 
 import java.util.ArrayList;
@@ -58,7 +55,7 @@
 
     /** Constructor specifically for recents animation */
     public static RemoteTransition newRemoteTransition(RecentsAnimationListener recents,
-            RecentsAnimationControllerCompat controller, IApplicationThread appThread) {
+            IApplicationThread appThread) {
         IRemoteTransition remote = new IRemoteTransition.Stub() {
             final RecentsControllerWrap mRecentsSession = new RecentsControllerWrap();
             IBinder mToken = null;
@@ -69,7 +66,7 @@
                     IRemoteTransitionFinishedCallback finishedCallback) {
                 // TODO(b/177438007): Move this set-up logic into launcher's animation impl.
                 mToken = transition;
-                mRecentsSession.start(controller, recents, mToken, info, t, finishedCallback);
+                mRecentsSession.start(recents, mToken, info, t, finishedCallback);
             }
 
             @Override
@@ -98,9 +95,8 @@
      * TODO(b/177438007): Remove this once Launcher handles shell transitions directly.
      */
     @VisibleForTesting
-    static class RecentsControllerWrap extends RecentsAnimationControllerCompat {
+    static class RecentsControllerWrap extends IRecentsAnimationController.Default {
         private RecentsAnimationListener mListener = null;
-        private RecentsAnimationControllerCompat mWrapped = null;
         private IRemoteTransitionFinishedCallback mFinishCB = null;
 
         /**
@@ -137,7 +133,7 @@
         /** The latest state that the recents animation is operating in. */
         private int mState = STATE_NORMAL;
 
-        void start(RecentsAnimationControllerCompat wrapped, RecentsAnimationListener listener,
+        void start(RecentsAnimationListener listener,
                 IBinder transition, TransitionInfo info, SurfaceControl.Transaction t,
                 IRemoteTransitionFinishedCallback finishedCallback) {
             if (mInfo != null) {
@@ -145,7 +141,6 @@
                         + " recents is already active.");
             }
             mListener = listener;
-            mWrapped = wrapped;
             mInfo = info;
             mFinishCB = finishedCallback;
             mPausingTasks = new ArrayList<>();
@@ -160,16 +155,15 @@
 
             final ArrayList<RemoteAnimationTarget> apps = new ArrayList<>();
             final ArrayList<RemoteAnimationTarget> wallpapers = new ArrayList<>();
-            RemoteAnimationTargetCompat.LeafTaskFilter leafTaskFilter =
-                    new RemoteAnimationTargetCompat.LeafTaskFilter();
+            TransitionUtil.LeafTaskFilter leafTaskFilter = new TransitionUtil.LeafTaskFilter();
             // About layering: we divide up the "layer space" into 3 regions (each the size of
             // the change count). This lets us categorize things into above/below/between
             // while maintaining their relative ordering.
             for (int i = 0; i < info.getChanges().size(); ++i) {
                 final TransitionInfo.Change change = info.getChanges().get(i);
                 final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
-                if (RemoteAnimationTargetCompat.isWallpaper(change)) {
-                    final RemoteAnimationTarget target = newTarget(change,
+                if (TransitionUtil.isWallpaper(change)) {
+                    final RemoteAnimationTarget target = TransitionUtil.newTarget(change,
                             // wallpapers go into the "below" layer space
                             info.getChanges().size() - i, info, t, mLeashMap);
                     wallpapers.add(target);
@@ -177,7 +171,7 @@
                     t.setAlpha(target.leash, 1);
                 } else if (leafTaskFilter.test(change)) {
                     // start by putting everything into the "below" layer space.
-                    final RemoteAnimationTarget target = newTarget(change,
+                    final RemoteAnimationTarget target = TransitionUtil.newTarget(change,
                             info.getChanges().size() - i, info, t, mLeashMap);
                     apps.add(target);
                     if (TransitionUtil.isClosingType(change.getMode())) {
@@ -203,7 +197,8 @@
                 }
             }
             t.apply();
-            mListener.onAnimationStart(this, apps.toArray(new RemoteAnimationTarget[apps.size()]),
+            mListener.onAnimationStart(new RecentsAnimationControllerCompat(this),
+                    apps.toArray(new RemoteAnimationTarget[apps.size()]),
                     wallpapers.toArray(new RemoteAnimationTarget[wallpapers.size()]),
                     new Rect(0, 0, 0, 0), new Rect());
         }
@@ -217,8 +212,8 @@
             TransitionInfo.Change recentsOpening = null;
             boolean foundRecentsClosing = false;
             boolean hasChangingApp = false;
-            final RemoteAnimationTargetCompat.LeafTaskFilter leafTaskFilter =
-                    new RemoteAnimationTargetCompat.LeafTaskFilter();
+            final TransitionUtil.LeafTaskFilter leafTaskFilter =
+                    new TransitionUtil.LeafTaskFilter();
             for (int i = 0; i < info.getChanges().size(); ++i) {
                 final TransitionInfo.Change change = info.getChanges().get(i);
                 final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
@@ -246,6 +241,13 @@
                         closingTasks.add(change);
                     }
                 } else if (change.getMode() == TRANSIT_CHANGE) {
+                    // Finish recents animation if the display is changed, so the default
+                    // transition handler can play the animation such as rotation effect.
+                    if (change.hasFlags(TransitionInfo.FLAG_IS_DISPLAY)) {
+                        mListener.onSwitchToScreenshot(() -> finish(false /* toHome */,
+                                false /* userLeaveHint */));
+                        return false;
+                    }
                     hasChangingApp = true;
                 }
             }
@@ -301,7 +303,8 @@
                     int pausingIdx = TaskState.indexOf(mPausingTasks, change);
                     if (pausingIdx >= 0) {
                         // Something is showing/opening a previously-pausing app.
-                        targets[i] = newTarget(change, layer, mPausingTasks.get(pausingIdx).mLeash);
+                        targets[i] = TransitionUtil.newTarget(change, layer,
+                                mPausingTasks.get(pausingIdx).mLeash);
                         mOpeningTasks.add(mPausingTasks.remove(pausingIdx));
                         // Setup hides opening tasks initially, so make it visible again (since we
                         // are already showing it).
@@ -309,7 +312,7 @@
                         t.setAlpha(change.getLeash(), 1.f);
                     } else {
                         // We are receiving new opening tasks, so convert to onTasksAppeared.
-                        targets[i] = newTarget(change, layer, info, t, mLeashMap);
+                        targets[i] = TransitionUtil.newTarget(change, layer, info, t, mLeashMap);
                         t.reparent(targets[i].leash, mInfo.getRootLeash());
                         t.setLayer(targets[i].leash, layer);
                         mOpeningTasks.add(new TaskState(change, targets[i].leash));
@@ -337,13 +340,9 @@
             }
         }
 
-        @Override public ThumbnailData screenshotTask(int taskId) {
+        @Override public TaskSnapshot screenshotTask(int taskId) {
             try {
-                final TaskSnapshot snapshot =
-                        ActivityTaskManager.getService().takeTaskSnapshot(taskId);
-                if (snapshot != null) {
-                    return new ThumbnailData(snapshot);
-                }
+                return ActivityTaskManager.getService().takeTaskSnapshot(taskId);
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to screenshot task", e);
             }
@@ -351,30 +350,24 @@
         }
 
         @Override public void setInputConsumerEnabled(boolean enabled) {
-            if (enabled) {
-                // transient launches don't receive focus automatically. Since we are taking over
-                // the gesture now, take focus explicitly.
-                // This also moves recents back to top if the user gestured before a switch
-                // animation finished.
-                try {
-                    ActivityTaskManager.getService().setFocusedTask(mRecentsTaskId);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Failed to set focused task", e);
-                }
+            if (!enabled) return;
+            // transient launches don't receive focus automatically. Since we are taking over
+            // the gesture now, take focus explicitly.
+            // This also moves recents back to top if the user gestured before a switch
+            // animation finished.
+            try {
+                ActivityTaskManager.getService().setFocusedTask(mRecentsTaskId);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to set focused task", e);
             }
-            if (mWrapped != null) mWrapped.setInputConsumerEnabled(enabled);
         }
 
         @Override public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars) {
-            if (mWrapped != null) mWrapped.setAnimationTargetsBehindSystemBars(behindSystemBars);
         }
 
         @Override public void setFinishTaskTransaction(int taskId,
                 PictureInPictureSurfaceTransaction finishTransaction, SurfaceControl overlay) {
             mPipTransaction = finishTransaction;
-            if (mWrapped != null) {
-                mWrapped.setFinishTaskTransaction(taskId, finishTransaction, overlay);
-            }
         }
 
         @Override
@@ -384,7 +377,6 @@
                 Log.e(TAG, "Duplicate call to finish", new RuntimeException());
                 return;
             }
-            if (mWrapped != null) mWrapped.finish(toHome, sendUserLeaveHint);
             final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
             final WindowContainerTransaction wct = new WindowContainerTransaction();
 
@@ -457,7 +449,6 @@
             // for releasing the leashes created by local.
             mInfo.releaseAllSurfaces();
             // Reset all members.
-            mWrapped = null;
             mListener = null;
             mFinishCB = null;
             mPausingTasks = null;
@@ -471,23 +462,20 @@
         }
 
         @Override public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
-            if (mWrapped != null) mWrapped.setDeferCancelUntilNextTransition(defer, screenshot);
         }
 
         @Override public void cleanupScreenshot() {
-            if (mWrapped != null) mWrapped.cleanupScreenshot();
         }
 
         @Override public void setWillFinishToHome(boolean willFinishToHome) {
             mWillFinishToHome = willFinishToHome;
-            if (mWrapped != null) mWrapped.setWillFinishToHome(willFinishToHome);
         }
 
         /**
          * @see IRecentsAnimationController#removeTask
          */
         @Override public boolean removeTask(int taskId) {
-            return mWrapped != null ? mWrapped.removeTask(taskId) : false;
+            return false;
         }
 
         /**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index c1fae9e..33bea02 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -69,6 +69,7 @@
 
     private Interpolator mLinearOutSlowInInterpolator;
     private Interpolator mFastOutLinearInInterpolator;
+    private DisappearAnimationListener mDisappearAnimationListener;
 
     public KeyguardPasswordView(Context context) {
         this(context, null);
@@ -186,9 +187,13 @@
                                 return;
                             }
                             Insets shownInsets = controller.getShownStateInsets();
-                            Insets insets = Insets.add(shownInsets, Insets.of(0, 0, 0,
-                                    (int) (-shownInsets.bottom / 4
-                                            * anim.getAnimatedFraction())));
+                            int dist = (int) (-shownInsets.bottom / 4
+                                    * anim.getAnimatedFraction());
+                            Insets insets = Insets.add(shownInsets, Insets.of(0, 0, 0, dist));
+                            if (mDisappearAnimationListener != null) {
+                                mDisappearAnimationListener.setTranslationY(-dist);
+                            }
+
                             controller.setInsetsAndAlpha(insets,
                                     (float) animation.getAnimatedValue(),
                                     anim.getAnimatedFraction());
@@ -209,6 +214,7 @@
                                     controller.finish(false);
                                     runOnFinishImeAnimationRunnable();
                                     finishRunnable.run();
+                                    mDisappearAnimationListener = null;
                                     Trace.endSection();
                                 });
                             }
@@ -286,4 +292,19 @@
             }
         });
     }
+
+    /**
+     * Listens to the progress of the disappear animation and handles it.
+     */
+    interface DisappearAnimationListener {
+        void setTranslationY(int transY);
+    }
+
+    /**
+     * Set an instance of the disappear animation listener to this class. This will be
+     * removed when the animation completes.
+     */
+    public void setDisappearAnimationListener(DisappearAnimationListener listener) {
+        mDisappearAnimationListener = listener;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index c6f0eee..2949616 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -39,6 +39,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.app.Activity;
@@ -173,6 +174,17 @@
     private @Mode int mCurrentMode = MODE_UNINITIALIZED;
     private int mWidth = -1;
 
+    /**
+     * This callback is used to animate KeyguardSecurityContainer and its child views based on
+     * the interaction with the ime. After
+     * {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)},
+     * {@link #onApplyWindowInsets} is called where we
+     * set the bottom padding to be the height of the keyboard. We use this padding to determine
+     * the delta of vertical distance for y-translation animations.
+     * Note that bottom padding is not set when the disappear animation is started because
+     * we are deferring the y translation logic to the animator in
+     * {@link KeyguardPasswordView#startDisappearAnimation(Runnable)}
+     */
     private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
             new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
 
@@ -213,7 +225,6 @@
                             continue;
                         }
                         interpolatedFraction = animation.getInterpolatedFraction();
-
                         final int paddingBottom = (int) MathUtils.lerp(
                                 start, end,
                                 interpolatedFraction);
@@ -568,13 +579,21 @@
      */
     public void startDisappearAnimation(SecurityMode securitySelection) {
         mDisappearAnimRunning = true;
-        mViewMode.startDisappearAnimation(securitySelection);
+        if (securitySelection == SecurityMode.Password
+                && mSecurityViewFlipper.getSecurityView() instanceof KeyguardPasswordView) {
+            ((KeyguardPasswordView) mSecurityViewFlipper.getSecurityView())
+                    .setDisappearAnimationListener(this::setTranslationY);
+        } else {
+            mViewMode.startDisappearAnimation(securitySelection);
+        }
     }
 
     /**
      * This will run when the bouncer shows in all cases except when the user drags the bouncer up.
      */
     public void startAppearAnimation(SecurityMode securityMode) {
+        setTranslationY(0f);
+        setAlpha(1f);
         updateChildren(0 /* translationY */, 1f /* alpha */);
         mViewMode.startAppearAnimation(securityMode);
     }
@@ -623,7 +642,13 @@
         int inset = max(bottomInset, imeInset);
         int paddingBottom = max(inset, getContext().getResources()
                 .getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin));
-        setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom);
+        // If security mode is password, we rely on the animation value of defined in
+        // KeyguardPasswordView to determine the y translation animation.
+        // This means that we will prevent the WindowInsetsAnimationCallback from setting any y
+        // translation values by preventing the setting of the padding here.
+        if (!mDisappearAnimRunning) {
+            setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom);
+        }
         return insets.inset(0, 0, 0, inset);
     }
 
@@ -1043,10 +1068,13 @@
 
             int yTranslation = mResources.getDimensionPixelSize(R.dimen.disappear_y_translation);
 
+            AnimatorSet anims = new AnimatorSet();
             ObjectAnimator yAnim = ObjectAnimator.ofFloat(mView, View.TRANSLATION_Y, yTranslation);
-            yAnim.setInterpolator(Interpolators.STANDARD_ACCELERATE);
-            yAnim.setDuration(500);
-            yAnim.start();
+            ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(mView, View.ALPHA, 0f);
+
+            anims.setInterpolator(Interpolators.STANDARD_ACCELERATE);
+            anims.playTogether(alphaAnim, yAnim);
+            anims.start();
         }
 
         private void setupUserSwitcher() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 06258b2..f1abdc6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -637,17 +637,12 @@
 
     public void startAppearAnimation() {
         if (mCurrentSecurityMode != SecurityMode.None) {
-            setAlpha(1f);
+            mView.setAlpha(1f);
             mView.startAppearAnimation(mCurrentSecurityMode);
             getCurrentSecurityController().startAppearAnimation();
         }
     }
 
-    /** Set the alpha of the security container view */
-    public void setAlpha(float alpha) {
-        mView.setAlpha(alpha);
-    }
-
     public boolean startDisappearAnimation(Runnable onFinishRunnable) {
         boolean didRunAnimation = false;
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index a4ec8e1..866b502 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -685,7 +685,10 @@
     public void onTrustManagedChanged(boolean managed, int userId) {
         Assert.isMainThread();
         mUserTrustIsManaged.put(userId, managed);
-        mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId));
+        boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userId);
+        mLogger.logTrustUsuallyManagedUpdated(userId, mUserTrustIsUsuallyManaged.get(userId),
+                trustUsuallyManaged, "onTrustManagedChanged");
+        mUserTrustIsUsuallyManaged.put(userId, trustUsuallyManaged);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -2393,8 +2396,12 @@
         updateSecondaryLockscreenRequirement(user);
         List<UserInfo> allUsers = mUserManager.getUsers();
         for (UserInfo userInfo : allUsers) {
+            boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userInfo.id);
+            mLogger.logTrustUsuallyManagedUpdated(userInfo.id,
+                    mUserTrustIsUsuallyManaged.get(userInfo.id),
+                    trustUsuallyManaged, "init from constructor");
             mUserTrustIsUsuallyManaged.put(userInfo.id,
-                    mTrustManager.isTrustUsuallyManaged(userInfo.id));
+                    trustUsuallyManaged);
         }
         updateAirplaneModeState();
 
@@ -2434,9 +2441,11 @@
     }
 
     private void updateFaceEnrolled(int userId) {
-        mIsFaceEnrolled = mFaceManager != null && !mFaceSensorProperties.isEmpty()
+        Boolean isFaceEnrolled = mFaceManager != null && !mFaceSensorProperties.isEmpty()
                 && mBiometricEnabledForUser.get(userId)
                 && mAuthController.isFaceAuthEnrolled(userId);
+        mIsFaceEnrolled = isFaceEnrolled;
+        mLogger.logFaceEnrolledUpdated(mIsFaceEnrolled, isFaceEnrolled);
     }
 
     public boolean isFaceSupported() {
@@ -3103,9 +3112,13 @@
     @VisibleForTesting
     boolean isUnlockWithFingerprintPossible(int userId) {
         // TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once.
-        mIsUnlockWithFingerprintPossible.put(userId, mFpm != null
+        boolean fpEnrolled = mFpm != null
                 && !mFingerprintSensorProperties.isEmpty()
-                && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId));
+                && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId);
+        mLogger.logFpEnrolledUpdated(userId,
+                mIsUnlockWithFingerprintPossible.getOrDefault(userId, false),
+                fpEnrolled);
+        mIsUnlockWithFingerprintPossible.put(userId, fpEnrolled);
         return mIsUnlockWithFingerprintPossible.get(userId);
     }
 
@@ -3221,7 +3234,10 @@
     void handleUserSwitching(int userId, CountDownLatch latch) {
         Assert.isMainThread();
         clearBiometricRecognized();
-        mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId));
+        boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userId);
+        mLogger.logTrustUsuallyManagedUpdated(userId, mUserTrustIsUsuallyManaged.get(userId),
+                trustUsuallyManaged, "userSwitching");
+        mUserTrustIsUsuallyManaged.put(userId, trustUsuallyManaged);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index e53f6ad..fb2c02a 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -26,6 +26,7 @@
 import com.android.keyguard.KeyguardListenModel
 import com.android.keyguard.KeyguardUpdateMonitorCallback
 import com.android.keyguard.TrustGrantFlags
+import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog
 import com.android.systemui.plugins.log.LogBuffer
 import com.android.systemui.plugins.log.LogLevel
 import com.android.systemui.plugins.log.LogLevel.DEBUG
@@ -33,18 +34,15 @@
 import com.android.systemui.plugins.log.LogLevel.INFO
 import com.android.systemui.plugins.log.LogLevel.VERBOSE
 import com.android.systemui.plugins.log.LogLevel.WARNING
-import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog
 import com.google.errorprone.annotations.CompileTimeConstant
 import javax.inject.Inject
 
 private const val TAG = "KeyguardUpdateMonitorLog"
 
-/**
- * Helper class for logging for [com.android.keyguard.KeyguardUpdateMonitor]
- */
-class KeyguardUpdateMonitorLogger @Inject constructor(
-        @KeyguardUpdateMonitorLog private val logBuffer: LogBuffer
-) {
+/** Helper class for logging for [com.android.keyguard.KeyguardUpdateMonitor] */
+class KeyguardUpdateMonitorLogger
+@Inject
+constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) {
     fun d(@CompileTimeConstant msg: String) = log(msg, DEBUG)
 
     fun e(@CompileTimeConstant msg: String) = log(msg, ERROR)
@@ -56,15 +54,16 @@
     fun log(@CompileTimeConstant msg: String, level: LogLevel) = logBuffer.log(TAG, level, msg)
 
     fun logActiveUnlockTriggered(reason: String?) {
-        logBuffer.log("ActiveUnlock", DEBUG,
-                { str1 = reason },
-                { "initiate active unlock triggerReason=$str1" })
+        logBuffer.log(
+            "ActiveUnlock",
+            DEBUG,
+            { str1 = reason },
+            { "initiate active unlock triggerReason=$str1" }
+        )
     }
 
     fun logAuthInterruptDetected(active: Boolean) {
-        logBuffer.log(TAG, DEBUG,
-                { bool1 = active },
-                { "onAuthInterruptDetected($bool1)" })
+        logBuffer.log(TAG, DEBUG, { bool1 = active }, { "onAuthInterruptDetected($bool1)" })
     }
 
     fun logBroadcastReceived(action: String?) {
@@ -72,9 +71,12 @@
     }
 
     fun logDeviceProvisionedState(deviceProvisioned: Boolean) {
-        logBuffer.log(TAG, DEBUG,
-                { bool1 = deviceProvisioned },
-                { "DEVICE_PROVISIONED state = $bool1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { bool1 = deviceProvisioned },
+            { "DEVICE_PROVISIONED state = $bool1" }
+        )
     }
 
     fun logException(ex: Exception, @CompileTimeConstant logMsg: String) {
@@ -82,46 +84,56 @@
     }
 
     fun logFaceAcquired(acquireInfo: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = acquireInfo },
-                { "Face acquired acquireInfo=$int1" })
+        logBuffer.log(TAG, DEBUG, { int1 = acquireInfo }, { "Face acquired acquireInfo=$int1" })
     }
 
     fun logFaceAuthDisabledForUser(userId: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = userId },
-                { "Face authentication disabled by DPM for userId: $int1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { int1 = userId },
+            { "Face authentication disabled by DPM for userId: $int1" }
+        )
     }
     fun logFaceAuthError(msgId: Int, originalErrMsg: String) {
-        logBuffer.log(TAG, DEBUG, {
-                    str1 = originalErrMsg
-                    int1 = msgId
-                }, { "Face error received: $str1 msgId= $int1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                str1 = originalErrMsg
+                int1 = msgId
+            },
+            { "Face error received: $str1 msgId= $int1" }
+        )
     }
 
     fun logFaceAuthForWrongUser(authUserId: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = authUserId },
-                { "Face authenticated for wrong user: $int1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { int1 = authUserId },
+            { "Face authenticated for wrong user: $int1" }
+        )
     }
 
     fun logFaceAuthHelpMsg(msgId: Int, helpMsg: String?) {
-        logBuffer.log(TAG, DEBUG, {
-                    int1 = msgId
-                    str1 = helpMsg
-                }, { "Face help received, msgId: $int1 msg: $str1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                int1 = msgId
+                str1 = helpMsg
+            },
+            { "Face help received, msgId: $int1 msg: $str1" }
+        )
     }
 
     fun logFaceAuthRequested(reason: String?) {
-        logBuffer.log(TAG, DEBUG, {
-            str1 = reason
-        }, { "requestFaceAuth() reason=$str1" })
+        logBuffer.log(TAG, DEBUG, { str1 = reason }, { "requestFaceAuth() reason=$str1" })
     }
 
     fun logFaceAuthSuccess(userId: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = userId },
-                { "Face auth succeeded for user $int1" })
+        logBuffer.log(TAG, DEBUG, { int1 = userId }, { "Face auth succeeded for user $int1" })
     }
 
     fun logFaceLockoutReset(@LockoutMode mode: Int) {
@@ -133,21 +145,30 @@
     }
 
     fun logFaceUnlockPossible(isFaceUnlockPossible: Boolean) {
-        logBuffer.log(TAG, DEBUG,
-                { bool1 = isFaceUnlockPossible },
-                {"isUnlockWithFacePossible: $bool1"})
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { bool1 = isFaceUnlockPossible },
+            { "isUnlockWithFacePossible: $bool1" }
+        )
     }
 
     fun logFingerprintAuthForWrongUser(authUserId: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = authUserId },
-                { "Fingerprint authenticated for wrong user: $int1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { int1 = authUserId },
+            { "Fingerprint authenticated for wrong user: $int1" }
+        )
     }
 
     fun logFingerprintDisabledForUser(userId: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = userId },
-                { "Fingerprint disabled by DPM for userId: $int1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { int1 = userId },
+            { "Fingerprint disabled by DPM for userId: $int1" }
+        )
     }
 
     fun logFingerprintLockoutReset(@LockoutMode mode: Int) {
@@ -155,16 +176,24 @@
     }
 
     fun logFingerprintRunningState(fingerprintRunningState: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = fingerprintRunningState },
-                { "fingerprintRunningState: $int1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { int1 = fingerprintRunningState },
+            { "fingerprintRunningState: $int1" }
+        )
     }
 
     fun logFingerprintSuccess(userId: Int, isStrongBiometric: Boolean) {
-        logBuffer.log(TAG, DEBUG, {
-            int1 = userId
-            bool1 = isStrongBiometric
-        }, {"Fingerprint auth successful: userId: $int1, isStrongBiometric: $bool1"})
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                int1 = userId
+                bool1 = isStrongBiometric
+            },
+            { "Fingerprint auth successful: userId: $int1, isStrongBiometric: $bool1" }
+        )
     }
 
     fun logFaceDetected(userId: Int, isStrongBiometric: Boolean) {
@@ -182,29 +211,42 @@
     }
 
     fun logFingerprintError(msgId: Int, originalErrMsg: String) {
-        logBuffer.log(TAG, DEBUG, {
-            str1 = originalErrMsg
-            int1 = msgId
-        }, { "Fingerprint error received: $str1 msgId= $int1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                str1 = originalErrMsg
+                int1 = msgId
+            },
+            { "Fingerprint error received: $str1 msgId= $int1" }
+        )
     }
 
     fun logInvalidSubId(subId: Int) {
-        logBuffer.log(TAG, INFO,
-                { int1 = subId },
-                { "Previously active sub id $int1 is now invalid, will remove" })
+        logBuffer.log(
+            TAG,
+            INFO,
+            { int1 = subId },
+            { "Previously active sub id $int1 is now invalid, will remove" }
+        )
     }
 
     fun logPrimaryKeyguardBouncerChanged(
-            primaryBouncerIsOrWillBeShowing: Boolean,
-            primaryBouncerFullyShown: Boolean
+        primaryBouncerIsOrWillBeShowing: Boolean,
+        primaryBouncerFullyShown: Boolean
     ) {
-        logBuffer.log(TAG, DEBUG, {
-            bool1 = primaryBouncerIsOrWillBeShowing
-            bool2 = primaryBouncerFullyShown
-        }, {
-            "handlePrimaryBouncerChanged " +
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                bool1 = primaryBouncerIsOrWillBeShowing
+                bool2 = primaryBouncerFullyShown
+            },
+            {
+                "handlePrimaryBouncerChanged " +
                     "primaryBouncerIsOrWillBeShowing=$bool1 primaryBouncerFullyShown=$bool2"
-        })
+            }
+        )
     }
 
     fun logKeyguardListenerModel(model: KeyguardListenModel) {
@@ -212,98 +254,134 @@
     }
 
     fun logKeyguardShowingChanged(showing: Boolean, occluded: Boolean, visible: Boolean) {
-        logBuffer.log(TAG, DEBUG, {
-            bool1 = showing
-            bool2 = occluded
-            bool3 = visible
-        }, {
-            "keyguardShowingChanged(showing=$bool1 occluded=$bool2 visible=$bool3)"
-        })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                bool1 = showing
+                bool2 = occluded
+                bool3 = visible
+            },
+            { "keyguardShowingChanged(showing=$bool1 occluded=$bool2 visible=$bool3)" }
+        )
     }
 
     fun logMissingSupervisorAppError(userId: Int) {
-        logBuffer.log(TAG, ERROR,
-                { int1 = userId },
-                { "No Profile Owner or Device Owner supervision app found for User $int1" })
+        logBuffer.log(
+            TAG,
+            ERROR,
+            { int1 = userId },
+            { "No Profile Owner or Device Owner supervision app found for User $int1" }
+        )
     }
 
     fun logPhoneStateChanged(newState: String?) {
-        logBuffer.log(TAG, DEBUG,
-                { str1 = newState },
-                { "handlePhoneStateChanged($str1)" })
+        logBuffer.log(TAG, DEBUG, { str1 = newState }, { "handlePhoneStateChanged($str1)" })
     }
 
     fun logRegisterCallback(callback: KeyguardUpdateMonitorCallback?) {
-        logBuffer.log(TAG, VERBOSE,
-                { str1 = "$callback" },
-                { "*** register callback for $str1" })
+        logBuffer.log(TAG, VERBOSE, { str1 = "$callback" }, { "*** register callback for $str1" })
     }
 
     fun logRetryingAfterFaceHwUnavailable(retryCount: Int) {
-        logBuffer.log(TAG, WARNING,
-                { int1 = retryCount },
-                { "Retrying face after HW unavailable, attempt $int1" })
+        logBuffer.log(
+            TAG,
+            WARNING,
+            { int1 = retryCount },
+            { "Retrying face after HW unavailable, attempt $int1" }
+        )
     }
 
     fun logRetryAfterFpErrorWithDelay(msgId: Int, errString: String?, delay: Int) {
-        logBuffer.log(TAG, DEBUG, {
-            int1 = msgId
-            int2 = delay
-            str1 = "$errString"
-        }, {
-            "Fingerprint scheduling retry auth after $int2 ms due to($int1) -> $str1"
-        })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                int1 = msgId
+                int2 = delay
+                str1 = "$errString"
+            },
+            { "Fingerprint scheduling retry auth after $int2 ms due to($int1) -> $str1" }
+        )
     }
 
     fun logRetryAfterFpHwUnavailable(retryCount: Int) {
-        logBuffer.log(TAG, WARNING,
-                { int1 = retryCount },
-                { "Retrying fingerprint attempt: $int1" })
+        logBuffer.log(
+            TAG,
+            WARNING,
+            { int1 = retryCount },
+            { "Retrying fingerprint attempt: $int1" }
+        )
     }
 
     fun logSendPrimaryBouncerChanged(
         primaryBouncerIsOrWillBeShowing: Boolean,
         primaryBouncerFullyShown: Boolean,
     ) {
-        logBuffer.log(TAG, DEBUG, {
-            bool1 = primaryBouncerIsOrWillBeShowing
-            bool2 = primaryBouncerFullyShown
-        }, {
-            "sendPrimaryBouncerChanged primaryBouncerIsOrWillBeShowing=$bool1 " +
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                bool1 = primaryBouncerIsOrWillBeShowing
+                bool2 = primaryBouncerFullyShown
+            },
+            {
+                "sendPrimaryBouncerChanged primaryBouncerIsOrWillBeShowing=$bool1 " +
                     "primaryBouncerFullyShown=$bool2"
-        })
+            }
+        )
     }
 
     fun logServiceStateChange(subId: Int, serviceState: ServiceState?) {
-        logBuffer.log(TAG, DEBUG, {
-            int1 = subId
-            str1 = "$serviceState"
-        }, { "handleServiceStateChange(subId=$int1, serviceState=$str1)" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                int1 = subId
+                str1 = "$serviceState"
+            },
+            { "handleServiceStateChange(subId=$int1, serviceState=$str1)" }
+        )
     }
 
     fun logServiceStateIntent(action: String?, serviceState: ServiceState?, subId: Int) {
-        logBuffer.log(TAG, VERBOSE, {
-            str1 = action
-            str2 = "$serviceState"
-            int1 = subId
-        }, { "action $str1 serviceState=$str2 subId=$int1" })
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            {
+                str1 = action
+                str2 = "$serviceState"
+                int1 = subId
+            },
+            { "action $str1 serviceState=$str2 subId=$int1" }
+        )
     }
 
     fun logSimState(subId: Int, slotId: Int, state: Int) {
-        logBuffer.log(TAG, DEBUG, {
-            int1 = subId
-            int2 = slotId
-            long1 = state.toLong()
-        }, { "handleSimStateChange(subId=$int1, slotId=$int2, state=$long1)" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                int1 = subId
+                int2 = slotId
+                long1 = state.toLong()
+            },
+            { "handleSimStateChange(subId=$int1, slotId=$int2, state=$long1)" }
+        )
     }
 
     fun logSimStateFromIntent(action: String?, extraSimState: String?, slotId: Int, subId: Int) {
-        logBuffer.log(TAG, VERBOSE, {
-            str1 = action
-            str2 = extraSimState
-            int1 = slotId
-            int2 = subId
-        }, { "action $str1 state: $str2 slotId: $int1 subid: $int2" })
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            {
+                str1 = action
+                str2 = extraSimState
+                int1 = slotId
+                int2 = subId
+            },
+            { "action $str1 state: $str2 slotId: $int1 subid: $int2" }
+        )
     }
 
     fun logSimUnlocked(subId: Int) {
@@ -311,78 +389,98 @@
     }
 
     fun logStartedListeningForFace(faceRunningState: Int, faceAuthUiEvent: FaceAuthUiEvent) {
-        logBuffer.log(TAG, VERBOSE, {
-            int1 = faceRunningState
-            str1 = faceAuthUiEvent.reason
-            str2 = faceAuthUiEvent.extraInfoToString()
-        }, { "startListeningForFace(): $int1, reason: $str1 $str2" })
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            {
+                int1 = faceRunningState
+                str1 = faceAuthUiEvent.reason
+                str2 = faceAuthUiEvent.extraInfoToString()
+            },
+            { "startListeningForFace(): $int1, reason: $str1 $str2" }
+        )
     }
 
     fun logStartedListeningForFaceFromWakeUp(faceRunningState: Int, @WakeReason pmWakeReason: Int) {
-        logBuffer.log(TAG, VERBOSE, {
-            int1 = faceRunningState
-            str1 = PowerManager.wakeReasonToString(pmWakeReason)
-        }, { "startListeningForFace(): $int1, reason: wakeUp-$str1" })
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            {
+                int1 = faceRunningState
+                str1 = PowerManager.wakeReasonToString(pmWakeReason)
+            },
+            { "startListeningForFace(): $int1, reason: wakeUp-$str1" }
+        )
     }
 
     fun logStoppedListeningForFace(faceRunningState: Int, faceAuthReason: String) {
-        logBuffer.log(TAG, VERBOSE, {
-            int1 = faceRunningState
-            str1 = faceAuthReason
-        }, { "stopListeningForFace(): currentFaceRunningState: $int1, reason: $str1" })
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            {
+                int1 = faceRunningState
+                str1 = faceAuthReason
+            },
+            { "stopListeningForFace(): currentFaceRunningState: $int1, reason: $str1" }
+        )
     }
 
     fun logSubInfo(subInfo: SubscriptionInfo?) {
-        logBuffer.log(TAG, VERBOSE,
-                { str1 = "$subInfo" },
-                { "SubInfo:$str1" })
+        logBuffer.log(TAG, VERBOSE, { str1 = "$subInfo" }, { "SubInfo:$str1" })
     }
 
     fun logTimeFormatChanged(newTimeFormat: String?) {
-        logBuffer.log(TAG, DEBUG,
-                { str1 = newTimeFormat },
-                { "handleTimeFormatUpdate timeFormat=$str1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { str1 = newTimeFormat },
+            { "handleTimeFormatUpdate timeFormat=$str1" }
+        )
     }
     fun logUdfpsPointerDown(sensorId: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = sensorId },
-                { "onUdfpsPointerDown, sensorId: $int1" })
+        logBuffer.log(TAG, DEBUG, { int1 = sensorId }, { "onUdfpsPointerDown, sensorId: $int1" })
     }
 
     fun logUdfpsPointerUp(sensorId: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = sensorId },
-                { "onUdfpsPointerUp, sensorId: $int1" })
+        logBuffer.log(TAG, DEBUG, { int1 = sensorId }, { "onUdfpsPointerUp, sensorId: $int1" })
     }
 
     fun logUnexpectedFaceCancellationSignalState(faceRunningState: Int, unlockPossible: Boolean) {
-        logBuffer.log(TAG, ERROR, {
-                    int1 = faceRunningState
-                    bool1 = unlockPossible
-                }, {
-                    "Cancellation signal is not null, high chance of bug in " +
-                            "face auth lifecycle management. " +
-                            "Face state: $int1, unlockPossible: $bool1"
-                })
+        logBuffer.log(
+            TAG,
+            ERROR,
+            {
+                int1 = faceRunningState
+                bool1 = unlockPossible
+            },
+            {
+                "Cancellation signal is not null, high chance of bug in " +
+                    "face auth lifecycle management. " +
+                    "Face state: $int1, unlockPossible: $bool1"
+            }
+        )
     }
 
     fun logUnexpectedFpCancellationSignalState(
         fingerprintRunningState: Int,
         unlockPossible: Boolean
     ) {
-        logBuffer.log(TAG, ERROR, {
-                    int1 = fingerprintRunningState
-                    bool1 = unlockPossible
-                }, {
-                    "Cancellation signal is not null, high chance of bug in " +
-                            "fp auth lifecycle management. FP state: $int1, unlockPossible: $bool1"
-                })
+        logBuffer.log(
+            TAG,
+            ERROR,
+            {
+                int1 = fingerprintRunningState
+                bool1 = unlockPossible
+            },
+            {
+                "Cancellation signal is not null, high chance of bug in " +
+                    "fp auth lifecycle management. FP state: $int1, unlockPossible: $bool1"
+            }
+        )
     }
 
     fun logUnregisterCallback(callback: KeyguardUpdateMonitorCallback?) {
-        logBuffer.log(TAG, VERBOSE,
-                { str1 = "$callback" },
-                { "*** unregister callback for $str1" })
+        logBuffer.log(TAG, VERBOSE, { str1 = "$callback" }, { "*** unregister callback for $str1" })
     }
 
     fun logUserRequestedUnlock(
@@ -390,75 +488,149 @@
         reason: String?,
         dismissKeyguard: Boolean
     ) {
-        logBuffer.log("ActiveUnlock", DEBUG, {
-                    str1 = requestOrigin?.name
-                    str2 = reason
-                    bool1 = dismissKeyguard
-                }, { "reportUserRequestedUnlock origin=$str1 reason=$str2 dismissKeyguard=$bool1" })
+        logBuffer.log(
+            "ActiveUnlock",
+            DEBUG,
+            {
+                str1 = requestOrigin?.name
+                str2 = reason
+                bool1 = dismissKeyguard
+            },
+            { "reportUserRequestedUnlock origin=$str1 reason=$str2 dismissKeyguard=$bool1" }
+        )
     }
 
     fun logTrustGrantedWithFlags(
-            flags: Int,
-            newlyUnlocked: Boolean,
-            userId: Int,
-            message: String?
+        flags: Int,
+        newlyUnlocked: Boolean,
+        userId: Int,
+        message: String?
     ) {
-        logBuffer.log(TAG, DEBUG, {
-            int1 = flags
-            bool1 = newlyUnlocked
-            int2 = userId
-            str1 = message
-        }, { "trustGrantedWithFlags[user=$int2] newlyUnlocked=$bool1 " +
-                "flags=${TrustGrantFlags(int1)} message=$str1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                int1 = flags
+                bool1 = newlyUnlocked
+                int2 = userId
+                str1 = message
+            },
+            {
+                "trustGrantedWithFlags[user=$int2] newlyUnlocked=$bool1 " +
+                    "flags=${TrustGrantFlags(int1)} message=$str1"
+            }
+        )
     }
 
-    fun logTrustChanged(
-            wasTrusted: Boolean,
-            isNowTrusted: Boolean,
-            userId: Int
-    ) {
-        logBuffer.log(TAG, DEBUG, {
-            bool1 = wasTrusted
-            bool2 = isNowTrusted
-            int1 = userId
-        }, { "onTrustChanged[user=$int1] wasTrusted=$bool1 isNowTrusted=$bool2" })
+    fun logTrustChanged(wasTrusted: Boolean, isNowTrusted: Boolean, userId: Int) {
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                bool1 = wasTrusted
+                bool2 = isNowTrusted
+                int1 = userId
+            },
+            { "onTrustChanged[user=$int1] wasTrusted=$bool1 isNowTrusted=$bool2" }
+        )
     }
 
     fun logKeyguardStateUpdate(
-            secure: Boolean,
-            canDismissLockScreen: Boolean,
-            trusted: Boolean,
-            trustManaged: Boolean
-
+        secure: Boolean,
+        canDismissLockScreen: Boolean,
+        trusted: Boolean,
+        trustManaged: Boolean
     ) {
-        logBuffer.log("KeyguardState", DEBUG, {
-            bool1 = secure
-            bool2 = canDismissLockScreen
-            bool3 = trusted
-            bool4 = trustManaged
-        }, { "#update secure=$bool1 canDismissKeyguard=$bool2" +
-                " trusted=$bool3 trustManaged=$bool4" })
+        logBuffer.log(
+            "KeyguardState",
+            DEBUG,
+            {
+                bool1 = secure
+                bool2 = canDismissLockScreen
+                bool3 = trusted
+                bool4 = trustManaged
+            },
+            {
+                "#update secure=$bool1 canDismissKeyguard=$bool2" +
+                    " trusted=$bool3 trustManaged=$bool4"
+            }
+        )
     }
 
     fun logSkipUpdateFaceListeningOnWakeup(@WakeReason pmWakeReason: Int) {
-        logBuffer.log(TAG, VERBOSE, {
-            str1 = PowerManager.wakeReasonToString(pmWakeReason)
-        }, { "Skip updating face listening state on wakeup from $str1"})
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            { str1 = PowerManager.wakeReasonToString(pmWakeReason) },
+            { "Skip updating face listening state on wakeup from $str1" }
+        )
     }
 
     fun logTaskStackChangedForAssistant(assistantVisible: Boolean) {
-        logBuffer.log(TAG, VERBOSE, {
-            bool1 = assistantVisible
-        }, {
-            "TaskStackChanged for ACTIVITY_TYPE_ASSISTANT, assistant visible: $bool1"
-        })
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            { bool1 = assistantVisible },
+            { "TaskStackChanged for ACTIVITY_TYPE_ASSISTANT, assistant visible: $bool1" }
+        )
     }
 
     fun logAssistantVisible(assistantVisible: Boolean) {
-        logBuffer.log(TAG, VERBOSE, {
-            bool1 = assistantVisible
-        }, {
-            "Updating mAssistantVisible to new value: $bool1"
-        })
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            { bool1 = assistantVisible },
+            { "Updating mAssistantVisible to new value: $bool1" }
+        )
+    }
+
+    fun logFaceEnrolledUpdated(oldValue: Boolean, newValue: Boolean) {
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                bool1 = oldValue
+                bool2 = newValue
+            },
+            { "Face enrolled state changed: old: $bool1, new: $bool2" }
+        )
+    }
+
+    fun logFpEnrolledUpdated(userId: Int, oldValue: Boolean, newValue: Boolean) {
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                int1 = userId
+                bool1 = oldValue
+                bool2 = newValue
+            },
+            { "Fp enrolled state changed for userId: $int1 old: $bool1, new: $bool2" }
+        )
+    }
+
+    fun logTrustUsuallyManagedUpdated(
+        userId: Int,
+        oldValue: Boolean,
+        newValue: Boolean,
+        context: String
+    ) {
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                int1 = userId
+                bool1 = oldValue
+                bool2 = newValue
+                str1 = context
+            },
+            {
+                "trustUsuallyManaged changed for " +
+                    "userId: $int1 " +
+                    "old: $bool1, " +
+                    "new: $bool2 " +
+                    "context: $context"
+            }
+        )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index ce42534..0002ae9 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -38,7 +38,6 @@
 import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.LayoutInflater;
-import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -347,10 +346,9 @@
                 }
                 if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
                 updatePercentText();
-                addView(mBatteryPercentView,
-                        new ViewGroup.LayoutParams(
-                                LayoutParams.WRAP_CONTENT,
-                                LayoutParams.MATCH_PARENT));
+                addView(mBatteryPercentView, new LayoutParams(
+                        LayoutParams.WRAP_CONTENT,
+                        LayoutParams.MATCH_PARENT));
             }
         } else {
             if (showing) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
index 72c3a94..217f4d8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
@@ -84,7 +84,7 @@
         private val BIND_FLAGS_PANEL = Context.BIND_AUTO_CREATE or Context.BIND_NOT_PERCEPTIBLE
     }
 
-    private val intent = Intent().apply {
+    private val intent = Intent(ControlsProviderService.SERVICE_CONTROLS).apply {
         component = componentName
         putExtra(CALLBACK_BUNDLE, Bundle().apply {
             putBinder(CALLBACK_TOKEN, token)
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index c96946b..7a1abf4 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -75,6 +75,7 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.connectivity.ConnectivityModule;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
@@ -257,9 +258,7 @@
     abstract FingerprintInteractiveToAuthProvider optionalFingerprintInteractiveToAuthProvider();
 
     @BindsOptionalOf
-    //TODO(b/269430792 remove full qualifier. Full qualifier is used to avoid merge conflict.)
-    abstract com.android.systemui.statusbar.events.SystemStatusAnimationScheduler
-    optionalSystemStatusAnimationScheduler();
+    abstract SystemStatusAnimationScheduler optionalSystemStatusAnimationScheduler();
 
     @SysUISingleton
     @Binds
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index febb45e..3608b91 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -625,11 +625,6 @@
     @JvmField
     val OUTPUT_SWITCHER_DEVICE_STATUS = releasedFlag(2502, "output_switcher_device_status")
 
-    // TODO(b/20911786): Tracking Bug
-    @JvmField
-    val OUTPUT_SWITCHER_SHOW_API_ENABLED =
-        releasedFlag(2503, "output_switcher_show_api_enabled", teamfood = true)
-
     // 2700 - unfold transitions
     // TODO(b/265764985): Tracking Bug
     @Keep
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index 949bcfb..e43f83b 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -2056,6 +2056,10 @@
                     || Intent.ACTION_SCREEN_OFF.equals(action)) {
                 String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
                 if (!SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
+                    // These broadcasts are usually received when locking the device, swiping up to
+                    // home (which collapses the shade), etc. In those cases, we usually don't want
+                    // to animate this dialog back into the view, so we disable the exit animations.
+                    mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations();
                     mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISMISS, reason));
                 }
             } else if (TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
index 70faf40..dd5c5d3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
@@ -18,15 +18,19 @@
 package com.android.systemui.keyboard.data.repository
 
 import android.hardware.input.InputManager
+import android.hardware.input.InputManager.KeyboardBacklightListener
+import android.hardware.input.KeyboardBacklightState
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.keyboard.data.model.BacklightModel
+import java.util.concurrent.Executor
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.SendChannel
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
@@ -51,24 +55,22 @@
 
     private val connectedDeviceIds: Flow<Set<Int>> =
         conflatedCallbackFlow {
-                fun send(element: Set<Int>) = trySendWithFailureLogging(element, TAG)
-
                 var connectedKeyboards = inputManager.inputDeviceIds.toSet()
                 val listener =
                     object : InputManager.InputDeviceListener {
                         override fun onInputDeviceAdded(deviceId: Int) {
                             connectedKeyboards = connectedKeyboards + deviceId
-                            send(connectedKeyboards)
+                            sendWithLogging(connectedKeyboards)
                         }
 
                         override fun onInputDeviceChanged(deviceId: Int) = Unit
 
                         override fun onInputDeviceRemoved(deviceId: Int) {
                             connectedKeyboards = connectedKeyboards - deviceId
-                            send(connectedKeyboards)
+                            sendWithLogging(connectedKeyboards)
                         }
                     }
-                send(connectedKeyboards)
+                sendWithLogging(connectedKeyboards)
                 inputManager.registerInputDeviceListener(listener, /* handler= */ null)
                 awaitClose { inputManager.unregisterInputDeviceListener(listener) }
             }
@@ -78,6 +80,16 @@
                 replay = 1,
             )
 
+    private val backlightStateListener: Flow<KeyboardBacklightState> = conflatedCallbackFlow {
+        val listener = KeyboardBacklightListener { _, state, isTriggeredByKeyPress ->
+            if (isTriggeredByKeyPress) {
+                sendWithLogging(state)
+            }
+        }
+        inputManager.registerKeyboardBacklightListener(Executor(Runnable::run), listener)
+        awaitClose { inputManager.unregisterKeyboardBacklightListener(listener) }
+    }
+
     override val keyboardConnected: Flow<Boolean> =
         connectedDeviceIds
             .map { it.any { deviceId -> isPhysicalFullKeyboard(deviceId) } }
@@ -85,9 +97,13 @@
             .flowOn(backgroundDispatcher)
 
     override val backlight: Flow<BacklightModel> =
-        conflatedCallbackFlow {
-            // TODO(b/268645734) register BacklightListener
-        }
+        backlightStateListener
+            .map { BacklightModel(it.brightnessLevel, it.maxBrightnessLevel) }
+            .flowOn(backgroundDispatcher)
+
+    private fun <T> SendChannel<T>.sendWithLogging(element: T) {
+        trySendWithFailureLogging(element, TAG)
+    }
 
     private fun isPhysicalFullKeyboard(deviceId: Int): Boolean {
         val device = inputManager.getInputDevice(deviceId)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 76f20d25..a3b3d0f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -80,9 +80,6 @@
      */
     val isKeyguardShowing: Flow<Boolean>
 
-    /** Is the keyguard in a unlocked state? */
-    val isKeyguardUnlocked: Flow<Boolean>
-
     /** Is an activity showing over the keyguard? */
     val isKeyguardOccluded: Flow<Boolean>
 
@@ -281,31 +278,6 @@
             }
             .distinctUntilChanged()
 
-    override val isKeyguardUnlocked: Flow<Boolean> =
-        conflatedCallbackFlow {
-                val callback =
-                    object : KeyguardStateController.Callback {
-                        override fun onUnlockedChanged() {
-                            trySendWithFailureLogging(
-                                keyguardStateController.isUnlocked,
-                                TAG,
-                                "updated isKeyguardUnlocked"
-                            )
-                        }
-                    }
-
-                keyguardStateController.addCallback(callback)
-                // Adding the callback does not send an initial update.
-                trySendWithFailureLogging(
-                    keyguardStateController.isUnlocked,
-                    TAG,
-                    "initial isKeyguardUnlocked"
-                )
-
-                awaitClose { keyguardStateController.removeCallback(callback) }
-            }
-            .distinctUntilChanged()
-
     override val isKeyguardGoingAway: Flow<Boolean> = conflatedCallbackFlow {
         val callback =
             object : KeyguardStateController.Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index 100bc59..0c4bca6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -68,11 +68,8 @@
     /**
      * Begin a transition from one state to another. Transitions are interruptible, and will issue a
      * [TransitionStep] with state = [TransitionState.CANCELED] before beginning the next one.
-     *
-     * When canceled, there are two options: to continue from the current position of the prior
-     * transition, or to reset the position. When [resetIfCanceled] == true, it will do the latter.
      */
-    fun startTransition(info: TransitionInfo, resetIfCanceled: Boolean = false): UUID?
+    fun startTransition(info: TransitionInfo): UUID?
 
     /**
      * Allows manual control of a transition. When calling [startTransition], the consumer must pass
@@ -133,10 +130,7 @@
         )
     }
 
-    override fun startTransition(
-        info: TransitionInfo,
-        resetIfCanceled: Boolean,
-    ): UUID? {
+    override fun startTransition(info: TransitionInfo): UUID? {
         if (lastStep.from == info.from && lastStep.to == info.to) {
             Log.i(TAG, "Duplicate call to start the transition, rejecting: $info")
             return null
@@ -144,11 +138,7 @@
         val startingValue =
             if (lastStep.transitionState != TransitionState.FINISHED) {
                 Log.i(TAG, "Transition still active: $lastStep, canceling")
-                if (resetIfCanceled) {
-                    0f
-                } else {
-                    lastStep.value
-                }
+                lastStep.value
             } else {
                 0f
             }
@@ -237,7 +227,10 @@
     }
 
     private fun trace(step: TransitionStep, isManual: Boolean) {
-        if (step.transitionState == TransitionState.RUNNING) {
+        if (
+            step.transitionState != TransitionState.STARTED &&
+                step.transitionState != TransitionState.FINISHED
+        ) {
             return
         }
         val traceName =
@@ -250,10 +243,7 @@
         val traceCookie = traceName.hashCode()
         if (step.transitionState == TransitionState.STARTED) {
             Trace.beginAsyncSection(traceName, traceCookie)
-        } else if (
-            step.transitionState == TransitionState.FINISHED ||
-                step.transitionState == TransitionState.CANCELED
-        ) {
+        } else if (step.transitionState == TransitionState.FINISHED) {
             Trace.endAsyncSection(traceName, traceCookie)
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 3beac0b..8715d1f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -34,6 +34,7 @@
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
 
@@ -56,7 +57,14 @@
 
     private fun listenForDreamingToLockscreen() {
         scope.launch {
-            keyguardInteractor.isAbleToDream
+            // Dependending on the dream, either dream state or occluded change will change first,
+            // so listen for both
+            combine(keyguardInteractor.isAbleToDream, keyguardInteractor.isKeyguardOccluded) {
+                    isAbleToDream,
+                    isKeyguardOccluded ->
+                    isAbleToDream && isKeyguardOccluded
+                }
+                .distinctUntilChanged()
                 .sample(
                     combine(
                         keyguardInteractor.dozeTransitionModel,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 911861d..d01f489 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -130,59 +130,55 @@
             shadeRepository.shadeModel
                 .sample(
                     combine(
-                        keyguardTransitionInteractor.startedKeyguardTransitionStep,
+                        keyguardTransitionInteractor.finishedKeyguardState,
                         keyguardInteractor.statusBarState,
-                        keyguardInteractor.isKeyguardUnlocked,
-                        ::toTriple
+                        ::Pair
                     ),
-                    ::toQuad
+                    ::toTriple
                 )
-                .collect { (shadeModel, keyguardState, statusBarState, isKeyguardUnlocked) ->
+                .collect { (shadeModel, keyguardState, statusBarState) ->
                     val id = transitionId
                     if (id != null) {
-                        if (keyguardState.to == KeyguardState.PRIMARY_BOUNCER) {
-                            // An existing `id` means a transition is started, and calls to
-                            // `updateTransition` will control it until FINISHED or CANCELED
-                            var nextState =
-                                if (shadeModel.expansionAmount == 0f) {
-                                    TransitionState.FINISHED
-                                } else if (shadeModel.expansionAmount == 1f) {
-                                    TransitionState.CANCELED
-                                } else {
-                                    TransitionState.RUNNING
-                                }
-                            keyguardTransitionRepository.updateTransition(
-                                id,
-                                1f - shadeModel.expansionAmount,
-                                nextState,
-                            )
-
-                            if (
-                                nextState == TransitionState.CANCELED ||
-                                    nextState == TransitionState.FINISHED
-                            ) {
-                                transitionId = null
+                        // An existing `id` means a transition is started, and calls to
+                        // `updateTransition` will control it until FINISHED or CANCELED
+                        var nextState =
+                            if (shadeModel.expansionAmount == 0f) {
+                                TransitionState.FINISHED
+                            } else if (shadeModel.expansionAmount == 1f) {
+                                TransitionState.CANCELED
+                            } else {
+                                TransitionState.RUNNING
                             }
+                        keyguardTransitionRepository.updateTransition(
+                            id,
+                            1f - shadeModel.expansionAmount,
+                            nextState,
+                        )
 
-                            // If canceled, just put the state back
-                            if (nextState == TransitionState.CANCELED) {
-                                keyguardTransitionRepository.startTransition(
-                                    TransitionInfo(
-                                        ownerName = name,
-                                        from = KeyguardState.PRIMARY_BOUNCER,
-                                        to = KeyguardState.LOCKSCREEN,
-                                        animator = getAnimator(0.milliseconds)
-                                    )
+                        if (
+                            nextState == TransitionState.CANCELED ||
+                                nextState == TransitionState.FINISHED
+                        ) {
+                            transitionId = null
+                        }
+
+                        // If canceled, just put the state back
+                        if (nextState == TransitionState.CANCELED) {
+                            keyguardTransitionRepository.startTransition(
+                                TransitionInfo(
+                                    ownerName = name,
+                                    from = KeyguardState.PRIMARY_BOUNCER,
+                                    to = KeyguardState.LOCKSCREEN,
+                                    animator = getAnimator(0.milliseconds)
                                 )
-                            }
+                            )
                         }
                     } else {
                         // TODO (b/251849525): Remove statusbarstate check when that state is
                         // integrated into KeyguardTransitionRepository
                         if (
-                            keyguardState.to == KeyguardState.LOCKSCREEN &&
+                            keyguardState == KeyguardState.LOCKSCREEN &&
                                 shadeModel.isUserDragging &&
-                                !isKeyguardUnlocked &&
                                 statusBarState == KEYGUARD
                         ) {
                             transitionId =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index 94961cb..b59b413 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -17,9 +17,6 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import android.animation.ValueAnimator
-import com.android.keyguard.KeyguardSecurityModel
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Password
-import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
@@ -29,8 +26,6 @@
 import com.android.systemui.keyguard.shared.model.WakefulnessState
 import com.android.systemui.util.kotlin.sample
 import javax.inject.Inject
-import kotlin.time.Duration
-import kotlin.time.Duration.Companion.milliseconds
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.launch
@@ -42,8 +37,7 @@
     @Application private val scope: CoroutineScope,
     private val keyguardInteractor: KeyguardInteractor,
     private val keyguardTransitionRepository: KeyguardTransitionRepository,
-    private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
-    private val keyguardSecurityModel: KeyguardSecurityModel,
+    private val keyguardTransitionInteractor: KeyguardTransitionInteractor
 ) : TransitionInteractor(FromPrimaryBouncerTransitionInteractor::class.simpleName!!) {
 
     override fun start() {
@@ -99,47 +93,31 @@
     private fun listenForPrimaryBouncerToGone() {
         scope.launch {
             keyguardInteractor.isKeyguardGoingAway
-                .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
-                .collect { (isKeyguardGoingAway, lastStartedTransitionStep) ->
-                    if (
-                        isKeyguardGoingAway &&
-                            lastStartedTransitionStep.to == KeyguardState.PRIMARY_BOUNCER
-                    ) {
-                        val securityMode =
-                            keyguardSecurityModel.getSecurityMode(
-                                KeyguardUpdateMonitor.getCurrentUser()
-                            )
-                        // IME for password requires a slightly faster animation
-                        val duration =
-                            if (securityMode == Password) {
-                                TO_GONE_SHORT_DURATION
-                            } else {
-                                TO_GONE_DURATION
-                            }
+                .sample(keyguardTransitionInteractor.finishedKeyguardState) { a, b -> Pair(a, b) }
+                .collect { pair ->
+                    val (isKeyguardGoingAway, keyguardState) = pair
+                    if (isKeyguardGoingAway && keyguardState == KeyguardState.PRIMARY_BOUNCER) {
                         keyguardTransitionRepository.startTransition(
                             TransitionInfo(
                                 ownerName = name,
                                 from = KeyguardState.PRIMARY_BOUNCER,
                                 to = KeyguardState.GONE,
-                                animator = getAnimator(duration),
-                            ),
-                            resetIfCanceled = true,
+                                animator = getAnimator(),
+                            )
                         )
                     }
                 }
         }
     }
 
-    private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
+    private fun getAnimator(): ValueAnimator {
         return ValueAnimator().apply {
             setInterpolator(Interpolators.LINEAR)
-            setDuration(duration.inWholeMilliseconds)
+            setDuration(TRANSITION_DURATION_MS)
         }
     }
 
     companion object {
-        private val DEFAULT_DURATION = 300.milliseconds
-        val TO_GONE_DURATION = 250.milliseconds
-        val TO_GONE_SHORT_DURATION = 200.milliseconds
+        private const val TRANSITION_DURATION_MS = 300L
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index ec99049..d25aff0a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -33,9 +33,7 @@
 import com.android.systemui.keyguard.shared.model.DozeTransitionModel
 import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.keyguard.shared.model.WakefulnessModel
-import com.android.systemui.keyguard.shared.model.WakefulnessModel.Companion.isWakingOrStartingToWake
 import com.android.systemui.statusbar.CommandQueue
-import com.android.systemui.util.kotlin.sample
 import javax.inject.Inject
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.delay
@@ -97,9 +95,6 @@
         awaitClose { commandQueue.removeCallback(callback) }
     }
 
-    /** The device wake/sleep state */
-    val wakefulnessModel: Flow<WakefulnessModel> = repository.wakefulness
-
     /**
      * Dozing and dreaming have overlapping events. If the doze state remains in FINISH, it means
      * that doze mode is not running and DREAMING is ok to commence.
@@ -114,12 +109,6 @@
                     isDreaming && isDozeOff(dozeTransitionModel.to)
                 }
             )
-            .sample(
-                wakefulnessModel,
-                { isAbleToDream, wakefulnessModel ->
-                    isAbleToDream && isWakingOrStartingToWake(wakefulnessModel)
-                }
-            )
             .flatMapLatest { isAbleToDream ->
                 flow {
                     delay(50)
@@ -130,8 +119,6 @@
 
     /** Whether the keyguard is showing or not. */
     val isKeyguardShowing: Flow<Boolean> = repository.isKeyguardShowing
-    /** Whether the keyguard is unlocked or not. */
-    val isKeyguardUnlocked: Flow<Boolean> = repository.isKeyguardUnlocked
     /** Whether the keyguard is occluded (covered by an activity). */
     val isKeyguardOccluded: Flow<Boolean> = repository.isKeyguardOccluded
     /** Whether the keyguard is going away. */
@@ -140,6 +127,8 @@
     val primaryBouncerShowing: Flow<Boolean> = bouncerRepository.primaryBouncerVisible
     /** Whether the alternate bouncer is showing or not. */
     val alternateBouncerShowing: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
+    /** The device wake/sleep state */
+    val wakefulnessModel: Flow<WakefulnessModel> = repository.wakefulness
     /** Observable for the [StatusBarState] */
     val statusBarState: Flow<StatusBarState> = repository.statusBarState
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
index e650b9f..51b0277 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -61,15 +61,7 @@
         }
 
         scope.launch {
-            keyguardInteractor.isAbleToDream.collect {
-                logger.log(TAG, VERBOSE, "isAbleToDream", it)
-            }
-        }
-
-        scope.launch {
-            keyguardInteractor.isKeyguardOccluded.collect {
-                logger.log(TAG, VERBOSE, "isOccluded", it)
-            }
+            keyguardInteractor.isDreaming.collect { logger.log(TAG, VERBOSE, "isDreaming", it) }
         }
 
         scope.launch {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 3c0ec35..1b7da5b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -78,10 +78,6 @@
     val occludedToLockscreenTransition: Flow<TransitionStep> =
         repository.transition(OCCLUDED, LOCKSCREEN)
 
-    /** PRIMARY_BOUNCER->GONE transition information. */
-    val primaryBouncerToGoneTransition: Flow<TransitionStep> =
-        repository.transition(PRIMARY_BOUNCER, GONE)
-
     /**
      * AOD<->LOCKSCREEN transition information, mapped to dozeAmount range of AOD (1f) <->
      * Lockscreen (0f).
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index ab009f4..2a9060f6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -342,7 +342,13 @@
         if (viewModel.isClickable) {
             if (viewModel.useLongPress) {
                 view.setOnTouchListener(
-                    OnTouchListener(view, viewModel, messageDisplayer, vibratorHelper)
+                    OnTouchListener(
+                        view,
+                        viewModel,
+                        messageDisplayer,
+                        vibratorHelper,
+                        falsingManager,
+                    )
                 )
             } else {
                 view.setOnClickListener(OnClickListener(viewModel, checkNotNull(falsingManager)))
@@ -371,6 +377,7 @@
         private val viewModel: KeyguardQuickAffordanceViewModel,
         private val messageDisplayer: (Int) -> Unit,
         private val vibratorHelper: VibratorHelper?,
+        private val falsingManager: FalsingManager?,
     ) : View.OnTouchListener {
 
         private val longPressDurationMs = ViewConfiguration.getLongPressTimeout().toLong()
@@ -395,7 +402,14 @@
                                     .scaleY(PRESSED_SCALE)
                                     .setDuration(longPressDurationMs)
                                     .withEndAction {
-                                        dispatchClick(viewModel.configKey)
+                                        if (
+                                            falsingManager
+                                                ?.isFalseLongTap(
+                                                    FalsingManager.MODERATE_PENALTY
+                                                ) == false
+                                        ) {
+                                            dispatchClick(viewModel.configKey)
+                                        }
                                         cancel()
                                     }
                         }
@@ -421,7 +435,8 @@
                         // the pointer performs a click.
                         if (
                             viewModel.configKey != null &&
-                                distanceMoved(event) <= ViewConfiguration.getTouchSlop()
+                                distanceMoved(event) <= ViewConfiguration.getTouchSlop() &&
+                                falsingManager?.isFalseTap(FalsingManager.NO_PENALTY) == false
                         ) {
                             dispatchClick(viewModel.configKey)
                         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
index 2337ffc..7db567b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
@@ -31,7 +31,6 @@
 import com.android.systemui.keyguard.data.BouncerViewDelegate
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
-import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.plugins.ActivityStarter
 import kotlinx.coroutines.awaitCancellation
@@ -45,7 +44,6 @@
     fun bind(
         view: ViewGroup,
         viewModel: KeyguardBouncerViewModel,
-        primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
         componentFactory: KeyguardBouncerComponent.Factory
     ) {
         // Builds the KeyguardSecurityContainerController from bouncer view group.
@@ -147,12 +145,6 @@
                     }
 
                     launch {
-                        primaryBouncerToGoneTransitionViewModel.bouncerAlpha.collect { alpha ->
-                            securityContainerController.setAlpha(alpha)
-                        }
-                    }
-
-                    launch {
                         viewModel.bouncerExpansionAmount
                             .filter { it == EXPANSION_VISIBLE }
                             .collect {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
deleted file mode 100644
index 0890791..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.keyguard.ui.viewmodel
-
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
-import javax.inject.Inject
-import kotlin.time.Duration.Companion.milliseconds
-import kotlinx.coroutines.flow.Flow
-
-/**
- * Breaks down PRIMARY_BOUNCER->GONE transition into discrete steps for corresponding views to
- * consume.
- */
-@SysUISingleton
-class PrimaryBouncerToGoneTransitionViewModel
-@Inject
-constructor(
-    private val interactor: KeyguardTransitionInteractor,
-) {
-    private val transitionAnimation =
-        KeyguardTransitionAnimationFlow(
-            transitionDuration = TO_GONE_DURATION,
-            transitionFlow = interactor.primaryBouncerToGoneTransition,
-        )
-
-    /** Bouncer container alpha */
-    val bouncerAlpha: Flow<Float> =
-        transitionAnimation.createFlow(
-            duration = 200.milliseconds,
-            onStep = { 1f - it },
-        )
-
-    /** Scrim alpha */
-    val scrimAlpha: Flow<Float> =
-        transitionAnimation.createFlow(
-            duration = TO_GONE_DURATION,
-            interpolator = EMPHASIZED_ACCELERATE,
-            onStep = { 1f - it },
-        )
-}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java
index e35575b..b5b1f0f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java
@@ -23,8 +23,6 @@
 
 import com.android.systemui.CoreStartable;
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.statusbar.CommandQueue;
 
 import javax.inject.Inject;
@@ -37,26 +35,19 @@
 
     private final CommandQueue mCommandQueue;
     private final MediaOutputDialogFactory mMediaOutputDialogFactory;
-    private final FeatureFlags mFeatureFlags;
 
     @Inject
     public MediaOutputSwitcherDialogUI(
             Context context,
             CommandQueue commandQueue,
-            MediaOutputDialogFactory mediaOutputDialogFactory,
-            FeatureFlags featureFlags) {
+            MediaOutputDialogFactory mediaOutputDialogFactory) {
         mCommandQueue = commandQueue;
         mMediaOutputDialogFactory = mediaOutputDialogFactory;
-        mFeatureFlags = featureFlags;
     }
 
     @Override
     public void start() {
-        if (mFeatureFlags.isEnabled(Flags.OUTPUT_SWITCHER_SHOW_API_ENABLED)) {
-            mCommandQueue.addCallback(this);
-        } else {
-            Log.w(TAG, "Show media output switcher is not enabled.");
-        }
+        mCommandQueue.addCallback(this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 4db1da3..0dfb9b1 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -1007,7 +1007,11 @@
 
     private void notifyNavigationBarSurface() {
         ViewRootImpl viewRoot = mView.getViewRootImpl();
-        SurfaceControl surface = viewRoot != null ? viewRoot.getSurfaceControl() : null;
+        SurfaceControl surface = viewRoot != null
+                && viewRoot.getSurfaceControl() != null
+                && viewRoot.getSurfaceControl().isValid()
+                        ? viewRoot.getSurfaceControl()
+                        : null;
         mOverviewProxyService.onNavigationBarSurfaceChanged(surface);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 342e0b00..f28c275 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -28,6 +28,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.Insets;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -54,6 +55,7 @@
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.ViewConfiguration;
+import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.window.BackEvent;
 
@@ -776,6 +778,19 @@
         return true;
     }
 
+    private boolean isValidTrackpadBackGesture(boolean isTrackpadEvent) {
+        if (!isTrackpadEvent) {
+            return false;
+        }
+        // for trackpad gestures, unless the whole screen is excluded region, 3-finger swipe
+        // gestures are allowed even if the cursor is in the excluded region.
+        WindowInsets windowInsets = mWindowManager.getCurrentWindowMetrics().getWindowInsets();
+        Insets insets = windowInsets.getInsets(WindowInsets.Type.systemBars());
+        final Rect excludeBounds = mExcludeRegion.getBounds();
+        return !excludeBounds.contains(insets.left, insets.top, mDisplaySize.x - insets.right,
+                mDisplaySize.y - insets.bottom);
+    }
+
     private boolean isWithinTouchRegion(int x, int y) {
         // If the point is inside the PiP or Nav bar overlay excluded bounds, then ignore the back
         // gesture
@@ -896,7 +911,8 @@
                     && (isTrackpadEvent || isWithinInsets)
                     && !mGestureBlockingActivityRunning
                     && !QuickStepContract.isBackGestureDisabled(mSysUiFlags)
-                    && (isTrackpadEvent || isWithinTouchRegion((int) ev.getX(), (int) ev.getY()));
+                    && (isValidTrackpadBackGesture(isTrackpadEvent) || isWithinTouchRegion(
+                    (int) ev.getX(), (int) ev.getY()));
             if (mAllowGesture) {
                 mEdgeBackPlugin.setIsLeftPanel(mIsOnLeftEdge);
                 mEdgeBackPlugin.onMotionEvent(ev);
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/OWNERS b/packages/SystemUI/src/com/android/systemui/notetask/OWNERS
index 7ccb316..0ec996b 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/OWNERS
+++ b/packages/SystemUI/src/com/android/systemui/notetask/OWNERS
@@ -5,4 +5,6 @@
 madym@google.com
 mgalhardo@google.com
 petrcermak@google.com
+stevenckng@google.com
+tkachenkoi@google.com
 vanjan@google.com
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 2522e1c..7a42642 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -154,6 +154,7 @@
     private final Intent mOpenBatterySettings = settings(Intent.ACTION_POWER_USAGE_SUMMARY);
     private final Intent mOpenBatterySaverSettings =
             settings(Settings.ACTION_BATTERY_SAVER_SETTINGS);
+    private final boolean mUseExtraSaverConfirmation;
 
     private int mBatteryLevel;
     private int mBucket;
@@ -197,6 +198,8 @@
         mDialogLaunchAnimator = dialogLaunchAnimator;
         mUiEventLogger = uiEventLogger;
         mUserTracker = userTracker;
+        mUseExtraSaverConfirmation =
+                mContext.getResources().getBoolean(R.bool.config_extra_battery_saver_confirmation);
     }
 
     @Override
@@ -644,7 +647,7 @@
     }
 
     private void showStartSaverConfirmation(Bundle extras) {
-        if (mSaverConfirmation != null) return;
+        if (mSaverConfirmation != null || mUseExtraSaverConfirmation) return;
         final SystemUIDialog d = new SystemUIDialog(mContext);
         final boolean confirmOnly = extras.getBoolean(BatterySaverUtils.EXTRA_CONFIRM_TEXT_ONLY);
         final int batterySaverTriggerMode =
@@ -679,6 +682,10 @@
                                 resolver,
                                 Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
                                 1, mUserTracker.getUserId());
+                        Secure.putIntForUser(
+                                resolver,
+                                Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED,
+                                1, mUserTracker.getUserId());
                     });
         } else {
             d.setTitle(R.string.battery_saver_confirmation_title);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index e86bd7a..9f93e49 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -76,7 +76,8 @@
         this(tileServices, handler, userTracker, new TileLifecycleManager(handler,
                 tileServices.getContext(), tileServices,
                 new PackageManagerAdapter(tileServices.getContext()), broadcastDispatcher,
-                new Intent().setComponent(component), userTracker.getUserHandle()));
+                new Intent(TileService.ACTION_QS_TILE).setComponent(component),
+                userTracker.getUserHandle()));
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index c130b39..87350b46 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -45,7 +45,6 @@
 import com.android.systemui.keyguard.shared.model.TransitionStep;
 import com.android.systemui.keyguard.ui.binder.KeyguardBouncerViewBinder;
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel;
-import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationInsetsController;
@@ -134,8 +133,7 @@
             KeyguardBouncerViewModel keyguardBouncerViewModel,
             KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory,
             AlternateBouncerInteractor alternateBouncerInteractor,
-            KeyguardTransitionInteractor keyguardTransitionInteractor,
-            PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel
+            KeyguardTransitionInteractor keyguardTransitionInteractor
     ) {
         mLockscreenShadeTransitionController = transitionController;
         mFalsingCollector = falsingCollector;
@@ -162,7 +160,6 @@
         KeyguardBouncerViewBinder.bind(
                 mView.findViewById(R.id.keyguard_bouncer_container),
                 keyguardBouncerViewModel,
-                primaryBouncerToGoneTransitionViewModel,
                 keyguardBouncerComponentFactory);
 
         collectFlow(mView, keyguardTransitionInteractor.getLockscreenToDreamingTransition(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index f0d064b..9a9503c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -572,8 +572,7 @@
             entry.setGroupExpansionChanging(true)
             userId = entry.sbn.userId
         }
-        var fullShadeNeedsBouncer = (!lockScreenUserManager.userAllowsPrivateNotificationsInPublic(
-                lockScreenUserManager.getCurrentUserId()) ||
+        var fullShadeNeedsBouncer = (
                 !lockScreenUserManager.shouldShowLockscreenNotifications() ||
                 falsingCollector.shouldEnforceBouncer())
         if (keyguardBypassController.bypassEnabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 664d61a..d6dc671 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -3747,12 +3747,6 @@
     @Override
     public void notifyBiometricAuthModeChanged() {
         mDozeServiceHost.updateDozing();
-        if (mBiometricUnlockController.getMode()
-                == BiometricUnlockController.MODE_DISMISS_BOUNCER) {
-            // Don't update the scrim controller at this time, in favor of the transition repository
-            // updating the scrim
-            return;
-        }
         updateScrimController();
     }
 
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 ce650d5..fb8bf52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
-
 import static java.lang.Float.isNaN;
 
 import android.animation.Animator;
@@ -55,11 +53,7 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
-import com.android.systemui.keyguard.shared.model.TransitionState;
-import com.android.systemui.keyguard.shared.model.TransitionStep;
-import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
 import com.android.systemui.scrim.ScrimView;
 import com.android.systemui.shade.NotificationPanelViewController;
 import com.android.systemui.statusbar.notification.stack.ViewState;
@@ -77,8 +71,6 @@
 
 import javax.inject.Inject;
 
-import kotlinx.coroutines.CoroutineDispatcher;
-
 /**
  * Controls both the scrim behind the notifications and in front of the notifications (when a
  * security method gets shown).
@@ -259,28 +251,6 @@
     private boolean mWakeLockHeld;
     private boolean mKeyguardOccluded;
 
-    private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
-    private CoroutineDispatcher mMainDispatcher;
-    private boolean mIsBouncerToGoneTransitionStarted = false;
-    private boolean mIsBouncerToGoneTransitionRunning = false;
-    private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
-    private final Consumer<Float> mScrimAlphaConsumer =
-            (Float alpha) -> {
-                mScrimInFront.setViewAlpha(0f);
-                mNotificationsScrim.setViewAlpha(0f);
-                mScrimBehind.setViewAlpha(alpha);
-            };
-    final Consumer<TransitionStep> mPrimaryBouncerToGoneTransition =
-            (TransitionStep step) -> {
-                mIsBouncerToGoneTransitionRunning =
-                    step.getTransitionState() == TransitionState.RUNNING;
-                mIsBouncerToGoneTransitionStarted =
-                    step.getTransitionState() == TransitionState.STARTED;
-                if (mIsBouncerToGoneTransitionStarted) {
-                    transitionTo(ScrimState.UNLOCKED);
-                }
-            };
-
     @Inject
     public ScrimController(
             LightBarController lightBarController,
@@ -295,10 +265,7 @@
             @Main Executor mainExecutor,
             ScreenOffAnimationController screenOffAnimationController,
             KeyguardUnlockAnimationController keyguardUnlockAnimationController,
-            StatusBarKeyguardViewManager statusBarKeyguardViewManager,
-            PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel,
-            KeyguardTransitionInteractor keyguardTransitionInteractor,
-            @Main CoroutineDispatcher mainDispatcher) {
+            StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
         mScrimStateListener = lightBarController::setScrimState;
         mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
 
@@ -337,9 +304,6 @@
             }
         });
         mColors = new GradientColors();
-        mPrimaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel;
-        mKeyguardTransitionInteractor = keyguardTransitionInteractor;
-        mMainDispatcher = mainDispatcher;
     }
 
     /**
@@ -379,11 +343,6 @@
         for (ScrimState state : ScrimState.values()) {
             state.prepare(state);
         }
-
-        collectFlow(behindScrim, mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition(),
-                mPrimaryBouncerToGoneTransition, mMainDispatcher);
-        collectFlow(behindScrim, mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha(),
-                mScrimAlphaConsumer, mMainDispatcher);
     }
 
     // TODO(b/270984686) recompute scrim height accurately, based on shade contents.
@@ -413,11 +372,6 @@
     }
 
     public void transitionTo(ScrimState state, Callback callback) {
-        if (mIsBouncerToGoneTransitionRunning) {
-            Log.i(TAG, "Skipping transition to: " + state
-                    + " while mIsBouncerToGoneTransitionRunning");
-            return;
-        }
         if (state == mState) {
             // Call the callback anyway, unless it's already enqueued
             if (callback != null && mCallback != callback) {
@@ -843,11 +797,10 @@
                         mBehindAlpha = 0;
                         mNotificationsAlpha = 0;
                     } else {
+                        // Behind scrim will finish fading in at 30% expansion.
                         float behindFraction = MathUtils
                                 .constrainedMap(0f, 1f, 0f, 0.3f, mPanelExpansionFraction);
-                        if (!mIsBouncerToGoneTransitionStarted) {
-                            mBehindAlpha = behindFraction * mDefaultScrimAlpha;
-                        }
+                        mBehindAlpha = behindFraction * mDefaultScrimAlpha;
                         // Delay fade-in of notification scrim a bit further, to coincide with the
                         // behind scrim finishing fading in.
                         // Also to coincide with the view starting to fade in, otherwise the empty
@@ -1185,9 +1138,7 @@
             Trace.traceCounter(Trace.TRACE_TAG_APP, getScrimName(scrimView) + "_tint",
                     Color.alpha(tint));
             scrimView.setTint(tint);
-            if (!mIsBouncerToGoneTransitionRunning) {
-                scrimView.setViewAlpha(alpha);
-            }
+            scrimView.setViewAlpha(alpha);
         } else {
             scrim.setAlpha(alpha);
         }
@@ -1535,9 +1486,6 @@
     }
 
     public void setKeyguardOccluded(boolean keyguardOccluded) {
-        if (mKeyguardOccluded == keyguardOccluded) {
-            return;
-        }
         mKeyguardOccluded = keyguardOccluded;
         updateScrims();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/OWNERS b/packages/SystemUI/src/com/android/systemui/stylus/OWNERS
index 7ccb316..0ec996b 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/OWNERS
+++ b/packages/SystemUI/src/com/android/systemui/stylus/OWNERS
@@ -5,4 +5,6 @@
 madym@google.com
 mgalhardo@google.com
 petrcermak@google.com
+stevenckng@google.com
+tkachenkoi@google.com
 vanjan@google.com
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
index 4e27ce6..030c54f 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
@@ -22,6 +22,7 @@
 import android.hardware.BatteryState
 import android.hardware.input.InputManager
 import android.hardware.input.InputSettings
+import android.os.Build
 import android.os.Handler
 import android.util.ArrayMap
 import android.util.Log
@@ -398,12 +399,11 @@
 
     companion object {
         val TAG = StylusManager::class.simpleName.orEmpty()
-        const val DEBUG = false
     }
 }
 
 private inline fun logDebug(message: () -> String) {
-    if (StylusManager.DEBUG) {
+    if (Build.IS_DEBUGGABLE) {
         Log.d(StylusManager.TAG, message())
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt b/packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt
index e092f01..8e2b05c 100644
--- a/packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt
@@ -66,7 +66,7 @@
     private fun switchToManagedProfile() {
         try {
             applicationContext.startActivityAsUser(
-                Intent(Intent.ACTION_DIAL, phoneNumber),
+                Intent(Intent.ACTION_CALL, phoneNumber),
                 ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle(),
                 UserHandle.of(managedProfileUserId)
             )
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 1bbc199..531006d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -37,6 +37,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -160,6 +161,29 @@
     }
 
     @Test
+    public void testOnApplyWindowInsets_disappearAnimation_paddingNotSet() {
+        int paddingBottom = getContext().getResources()
+                .getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin);
+        int imeInsetAmount = paddingBottom + 1;
+        int systemBarInsetAmount = 0;
+        initMode(MODE_DEFAULT);
+
+        Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
+        Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);
+
+        WindowInsets insets = new WindowInsets.Builder()
+                .setInsets(ime(), imeInset)
+                .setInsetsIgnoringVisibility(systemBars(), systemBarInset)
+                .build();
+
+        ensureViewFlipperIsMocked();
+        mKeyguardSecurityContainer.startDisappearAnimation(
+                KeyguardSecurityModel.SecurityMode.Password);
+        mKeyguardSecurityContainer.onApplyWindowInsets(insets);
+        assertThat(mKeyguardSecurityContainer.getPaddingBottom()).isNotEqualTo(imeInsetAmount);
+    }
+
+    @Test
     public void testDefaultViewMode() {
         initMode(MODE_ONE_HANDED);
         initMode(MODE_DEFAULT);
@@ -376,6 +400,17 @@
         assertThat(mKeyguardSecurityContainer.getScaleY()).isEqualTo(1);
     }
 
+    @Test
+    public void testDisappearAnimationPassword() {
+        ensureViewFlipperIsMocked();
+        KeyguardPasswordView keyguardPasswordView = mock(KeyguardPasswordView.class);
+        when(mSecurityViewFlipper.getSecurityView()).thenReturn(keyguardPasswordView);
+
+        mKeyguardSecurityContainer
+                .startDisappearAnimation(KeyguardSecurityModel.SecurityMode.Password);
+        verify(keyguardPasswordView).setDisappearAnimationListener(any());
+    }
+
     private BackEvent createBackEvent(float touchX, float progress) {
         return new BackEvent(0, 0, progress, BackEvent.EDGE_LEFT);
     }
@@ -446,4 +481,12 @@
                 mUserSwitcherController, () -> {
                 }, mFalsingA11yDelegate);
     }
+
+    private void ensureViewFlipperIsMocked() {
+        mSecurityViewFlipper = mock(KeyguardSecurityViewFlipper.class);
+        KeyguardPasswordView keyguardPasswordView = mock(KeyguardPasswordView.class);
+        when(mSecurityViewFlipper.getSecurityView()).thenReturn(keyguardPasswordView);
+        mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper;
+    }
+
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 0e6f8d4..0469e77 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -219,29 +219,6 @@
         }
 
     @Test
-    fun isKeyguardUnlocked() =
-        runTest(UnconfinedTestDispatcher()) {
-            whenever(keyguardStateController.isUnlocked).thenReturn(false)
-            var latest: Boolean? = null
-            val job = underTest.isKeyguardUnlocked.onEach { latest = it }.launchIn(this)
-
-            assertThat(latest).isFalse()
-
-            val captor = argumentCaptor<KeyguardStateController.Callback>()
-            verify(keyguardStateController).addCallback(captor.capture())
-
-            whenever(keyguardStateController.isUnlocked).thenReturn(true)
-            captor.value.onUnlockedChanged()
-            assertThat(latest).isTrue()
-
-            whenever(keyguardStateController.isUnlocked).thenReturn(false)
-            captor.value.onUnlockedChanged()
-            assertThat(latest).isFalse()
-
-            job.cancel()
-        }
-
-    @Test
     fun isDozing() =
         runTest(UnconfinedTestDispatcher()) {
             var latest: Boolean? = null
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index fe9098f..ae7a928 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -19,8 +19,6 @@
 import android.animation.ValueAnimator
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.SmallTest
-import com.android.keyguard.KeyguardSecurityModel
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.Interpolators
 import com.android.systemui.flags.FakeFeatureFlags
@@ -42,7 +40,6 @@
 import com.android.systemui.shade.data.repository.FakeShadeRepository
 import com.android.systemui.shade.data.repository.ShadeRepository
 import com.android.systemui.statusbar.CommandQueue
-import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.mockito.withArgCaptor
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.cancelChildren
@@ -54,8 +51,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
-import org.mockito.ArgumentMatchers.anyBoolean
-import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
@@ -82,7 +77,6 @@
     // Used to verify transition requests for test output
     @Mock private lateinit var mockTransitionRepository: KeyguardTransitionRepository
     @Mock private lateinit var commandQueue: CommandQueue
-    @Mock private lateinit var keyguardSecurityModel: KeyguardSecurityModel
 
     private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor
     private lateinit var fromDreamingTransitionInteractor: FromDreamingTransitionInteractor
@@ -108,8 +102,6 @@
         transitionRepository = KeyguardTransitionRepositoryImpl()
         runner = KeyguardTransitionRunner(transitionRepository)
 
-        whenever(keyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(PIN)
-
         val featureFlags = FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, true) }
         fromLockscreenTransitionInteractor =
             FromLockscreenTransitionInteractor(
@@ -181,17 +173,16 @@
                 keyguardInteractor = createKeyguardInteractor(featureFlags),
                 keyguardTransitionRepository = mockTransitionRepository,
                 keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
-                keyguardSecurityModel = keyguardSecurityModel,
             )
         fromPrimaryBouncerTransitionInteractor.start()
     }
 
     @Test
-    fun `DREAMING to LOCKSCREEN`() =
+    fun `DREAMING to LOCKSCREEN - dreaming state changes first`() =
         testScope.runTest {
-            // GIVEN a device is dreaming
+            // GIVEN a device is dreaming and occluded
             keyguardRepository.setDreamingWithOverlay(true)
-            keyguardRepository.setWakefulnessModel(startingToWake())
+            keyguardRepository.setKeyguardOccluded(true)
             runCurrent()
 
             // GIVEN a prior transition has run to DREAMING
@@ -224,7 +215,56 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
+                }
+            // THEN a transition to BOUNCER should occur
+            assertThat(info.ownerName).isEqualTo("FromDreamingTransitionInteractor")
+            assertThat(info.from).isEqualTo(KeyguardState.DREAMING)
+            assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
+            assertThat(info.animator).isNotNull()
+
+            coroutineContext.cancelChildren()
+        }
+
+    @Test
+    fun `DREAMING to LOCKSCREEN - occluded state changes first`() =
+        testScope.runTest {
+            // GIVEN a device is dreaming and occluded
+            keyguardRepository.setDreamingWithOverlay(true)
+            keyguardRepository.setKeyguardOccluded(true)
+            runCurrent()
+
+            // GIVEN a prior transition has run to DREAMING
+            runner.startTransition(
+                testScope,
+                TransitionInfo(
+                    ownerName = "",
+                    from = KeyguardState.LOCKSCREEN,
+                    to = KeyguardState.DREAMING,
+                    animator =
+                        ValueAnimator().apply {
+                            duration = 10
+                            interpolator = Interpolators.LINEAR
+                        },
+                )
+            )
+            runCurrent()
+            reset(mockTransitionRepository)
+
+            // WHEN doze is complete
+            keyguardRepository.setDozeTransitionModel(
+                DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
+            )
+            // AND occluded has stopped
+            keyguardRepository.setKeyguardOccluded(false)
+            advanceUntilIdle()
+            // AND then dreaming has stopped
+            keyguardRepository.setDreamingWithOverlay(false)
+            advanceUntilIdle()
+
+            val info =
+                withArgCaptor<TransitionInfo> {
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to BOUNCER should occur
             assertThat(info.ownerName).isEqualTo("FromDreamingTransitionInteractor")
@@ -264,7 +304,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to PRIMARY_BOUNCER should occur
             assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -305,7 +345,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to DOZING should occur
             assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -346,7 +386,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to DOZING should occur
             assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -387,7 +427,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to DOZING should occur
             assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -428,7 +468,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to DOZING should occur
             assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -465,7 +505,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to DOZING should occur
             assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
@@ -502,7 +542,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to DOZING should occur
             assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
@@ -543,7 +583,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to DOZING should occur
             assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -584,7 +624,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to AOD should occur
             assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -621,7 +661,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to AOD should occur
             assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -637,7 +677,6 @@
         testScope.runTest {
             // GIVEN a device that is not dreaming or dozing
             keyguardRepository.setDreamingWithOverlay(false)
-            keyguardRepository.setWakefulnessModel(startingToWake())
             keyguardRepository.setDozeTransitionModel(
                 DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
             )
@@ -665,7 +704,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to DREAMING should occur
             assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -702,7 +741,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to PRIMARY_BOUNCER should occur
             assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -745,7 +784,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to AOD should occur
             assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -789,7 +828,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to DOZING should occur
             assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -831,7 +870,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to LOCKSCREEN should occur
             assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -873,7 +912,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to AOD should occur
             assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
@@ -915,7 +954,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to DOZING should occur
             assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
@@ -956,7 +995,7 @@
 
             val info =
                 withArgCaptor<TransitionInfo> {
-                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                    verify(mockTransitionRepository).startTransition(capture())
                 }
             // THEN a transition to LOCKSCREEN should occur
             assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/DynamicColorTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/DynamicColorTest.java
index 41ac3213..d364f47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/DynamicColorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/DynamicColorTest.java
@@ -18,13 +18,21 @@
 
 import static com.android.systemui.monet.utils.ArgbSubject.assertThat;
 
+import static org.junit.Assert.assertTrue;
+
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.monet.contrast.Contrast;
 import com.android.systemui.monet.dynamiccolor.DynamicColor;
+import com.android.systemui.monet.dynamiccolor.MaterialDynamicColors;
 import com.android.systemui.monet.dynamiccolor.ToneDeltaConstraint;
 import com.android.systemui.monet.dynamiccolor.TonePolarity;
 import com.android.systemui.monet.hct.Hct;
+import com.android.systemui.monet.scheme.DynamicScheme;
+import com.android.systemui.monet.scheme.SchemeContent;
+import com.android.systemui.monet.scheme.SchemeFidelity;
+import com.android.systemui.monet.scheme.SchemeMonochrome;
 import com.android.systemui.monet.scheme.SchemeTonalSpot;
 
 import org.junit.Test;
@@ -90,4 +98,92 @@
         final SchemeTonalSpot darkScheme = new SchemeTonalSpot(Hct.fromInt(0xff4285f4), true, 0.0);
         assertThat(dynamicColor.getArgb(darkScheme)).isSameColorAs(0x33ffffff);
     }
+
+    @Test
+    public void respectsContrast() {
+        final Hct[] seedColors =
+                new Hct[]{
+                        Hct.fromInt(0xFFFF0000),
+                        Hct.fromInt(0xFFFFFF00),
+                        Hct.fromInt(0xFF00FF00),
+                        Hct.fromInt(0xFF0000FF)
+                };
+
+        final double[] contrastLevels = {-1.0, -0.5, 0.0, 0.5, 1.0};
+
+        for (Hct seedColor : seedColors) {
+            for (double contrastLevel : contrastLevels) {
+                for (boolean isDark : new boolean[]{false, true}) {
+                    final DynamicScheme[] schemes =
+                            new DynamicScheme[]{
+                                    new SchemeContent(seedColor, isDark, contrastLevel),
+                                    new SchemeMonochrome(seedColor, isDark, contrastLevel),
+                                    new SchemeTonalSpot(seedColor, isDark, contrastLevel),
+                                    new SchemeFidelity(seedColor, isDark, contrastLevel)
+                            };
+                    for (final DynamicScheme scheme : schemes) {
+                        assertTrue(
+                                pairSatisfiesContrast(
+                                        scheme, MaterialDynamicColors.onPrimary,
+                                        MaterialDynamicColors.primary));
+                        assertTrue(
+                                pairSatisfiesContrast(
+                                        scheme,
+                                        MaterialDynamicColors.onPrimaryContainer,
+                                        MaterialDynamicColors.primaryContainer));
+                        assertTrue(
+                                pairSatisfiesContrast(
+                                        scheme, MaterialDynamicColors.onSecondary,
+                                        MaterialDynamicColors.secondary));
+                        assertTrue(
+                                pairSatisfiesContrast(
+                                        scheme,
+                                        MaterialDynamicColors.onSecondaryContainer,
+                                        MaterialDynamicColors.secondaryContainer));
+                        assertTrue(
+                                pairSatisfiesContrast(
+                                        scheme, MaterialDynamicColors.onTertiary,
+                                        MaterialDynamicColors.tertiary));
+                        assertTrue(
+                                pairSatisfiesContrast(
+                                        scheme,
+                                        MaterialDynamicColors.onTertiaryContainer,
+                                        MaterialDynamicColors.tertiaryContainer));
+                        assertTrue(
+                                pairSatisfiesContrast(
+                                        scheme, MaterialDynamicColors.onError,
+                                        MaterialDynamicColors.error));
+                        assertTrue(
+                                pairSatisfiesContrast(
+                                        scheme,
+                                        MaterialDynamicColors.onErrorContainer,
+                                        MaterialDynamicColors.errorContainer));
+                        assertTrue(
+                                pairSatisfiesContrast(
+                                        scheme, MaterialDynamicColors.onBackground,
+                                        MaterialDynamicColors.background));
+                        assertTrue(
+                                pairSatisfiesContrast(
+                                        scheme,
+                                        MaterialDynamicColors.onSurfaceVariant,
+                                        MaterialDynamicColors.surfaceVariant));
+                        assertTrue(
+                                pairSatisfiesContrast(
+                                        scheme,
+                                        MaterialDynamicColors.onSurfaceInverse,
+                                        MaterialDynamicColors.surfaceInverse));
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean pairSatisfiesContrast(DynamicScheme scheme, DynamicColor fg, DynamicColor bg) {
+        double fgTone = fg.getHct(scheme).getTone();
+        double bgTone = bg.getHct(scheme).getTone();
+        // TODO(b/270915664) - Fix inconsistencies.
+        // TODO(b/270915664) - Minimum requirement should be 4.5 when not reducing contrast.
+        double minimumRequirement = 3.0;
+        return Contrast.ratioOfTones(fgTone, bgTone) >= minimumRequirement;
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/notetask/OWNERS
index 7ccb316..0ec996b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/OWNERS
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/OWNERS
@@ -5,4 +5,6 @@
 madym@google.com
 mgalhardo@google.com
 petrcermak@google.com
+stevenckng@google.com
+tkachenkoi@google.com
 vanjan@google.com
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 82a5743..0a401b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -33,7 +33,6 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
-import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
 import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
 import com.android.systemui.statusbar.LockscreenShadeTransitionController
 import com.android.systemui.statusbar.NotificationInsetsController
@@ -66,32 +65,48 @@
 @RunWith(AndroidTestingRunner::class)
 @RunWithLooper(setAsMainLooper = true)
 class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
-    @Mock private lateinit var view: NotificationShadeWindowView
-    @Mock private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
-    @Mock private lateinit var centralSurfaces: CentralSurfaces
-    @Mock private lateinit var dockManager: DockManager
-    @Mock private lateinit var notificationPanelViewController: NotificationPanelViewController
-    @Mock private lateinit var notificationShadeDepthController: NotificationShadeDepthController
-    @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
-    @Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
-    @Mock private lateinit var ambientState: AmbientState
-    @Mock private lateinit var keyguardBouncerViewModel: KeyguardBouncerViewModel
-    @Mock private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController
-    @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
-    @Mock private lateinit var statusBarWindowStateController: StatusBarWindowStateController
+    @Mock
+    private lateinit var view: NotificationShadeWindowView
+    @Mock
+    private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
+    @Mock
+    private lateinit var centralSurfaces: CentralSurfaces
+    @Mock
+    private lateinit var dockManager: DockManager
+    @Mock
+    private lateinit var notificationPanelViewController: NotificationPanelViewController
+    @Mock
+    private lateinit var notificationShadeDepthController: NotificationShadeDepthController
+    @Mock
+    private lateinit var notificationShadeWindowController: NotificationShadeWindowController
+    @Mock
+    private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
+    @Mock
+    private lateinit var ambientState: AmbientState
+    @Mock
+    private lateinit var keyguardBouncerViewModel: KeyguardBouncerViewModel
+    @Mock
+    private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController
+    @Mock
+    private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
+    @Mock
+    private lateinit var statusBarWindowStateController: StatusBarWindowStateController
     @Mock
     private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController
-    @Mock private lateinit var lockIconViewController: LockIconViewController
-    @Mock private lateinit var phoneStatusBarViewController: PhoneStatusBarViewController
-    @Mock private lateinit var pulsingGestureListener: PulsingGestureListener
-    @Mock private lateinit var notificationInsetsController: NotificationInsetsController
-    @Mock private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+    @Mock
+    private lateinit var lockIconViewController: LockIconViewController
+    @Mock
+    private lateinit var phoneStatusBarViewController: PhoneStatusBarViewController
+    @Mock
+    private lateinit var pulsingGestureListener: PulsingGestureListener
+    @Mock
+    private lateinit var notificationInsetsController: NotificationInsetsController
+    @Mock
+    private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
     @Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
     @Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
     @Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
     @Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
-    @Mock
-    lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel
 
     private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
     private lateinit var interactionEventHandler: InteractionEventHandler
@@ -103,44 +118,43 @@
         MockitoAnnotations.initMocks(this)
         whenever(view.bottom).thenReturn(VIEW_BOTTOM)
         whenever(view.findViewById<ViewGroup>(R.id.keyguard_bouncer_container))
-            .thenReturn(mock(ViewGroup::class.java))
+                .thenReturn(mock(ViewGroup::class.java))
         whenever(keyguardBouncerComponentFactory.create(any(ViewGroup::class.java)))
-            .thenReturn(keyguardBouncerComponent)
+                .thenReturn(keyguardBouncerComponent)
         whenever(keyguardBouncerComponent.securityContainerController)
-            .thenReturn(keyguardSecurityContainerController)
+                .thenReturn(keyguardSecurityContainerController)
         whenever(keyguardTransitionInteractor.lockscreenToDreamingTransition)
-            .thenReturn(emptyFlow<TransitionStep>())
-        underTest =
-            NotificationShadeWindowViewController(
-                lockscreenShadeTransitionController,
-                FalsingCollectorFake(),
-                sysuiStatusBarStateController,
-                dockManager,
-                notificationShadeDepthController,
-                view,
-                notificationPanelViewController,
-                ShadeExpansionStateManager(),
-                stackScrollLayoutController,
-                statusBarKeyguardViewManager,
-                statusBarWindowStateController,
-                lockIconViewController,
-                centralSurfaces,
-                notificationShadeWindowController,
-                keyguardUnlockAnimationController,
-                notificationInsetsController,
-                ambientState,
-                pulsingGestureListener,
-                keyguardBouncerViewModel,
-                keyguardBouncerComponentFactory,
-                alternateBouncerInteractor,
-                keyguardTransitionInteractor,
-                primaryBouncerToGoneTransitionViewModel,
-            )
+                .thenReturn(emptyFlow<TransitionStep>())
+        underTest = NotificationShadeWindowViewController(
+            lockscreenShadeTransitionController,
+            FalsingCollectorFake(),
+            sysuiStatusBarStateController,
+            dockManager,
+            notificationShadeDepthController,
+            view,
+            notificationPanelViewController,
+            ShadeExpansionStateManager(),
+            stackScrollLayoutController,
+            statusBarKeyguardViewManager,
+            statusBarWindowStateController,
+            lockIconViewController,
+            centralSurfaces,
+            notificationShadeWindowController,
+            keyguardUnlockAnimationController,
+            notificationInsetsController,
+            ambientState,
+            pulsingGestureListener,
+            keyguardBouncerViewModel,
+            keyguardBouncerComponentFactory,
+            alternateBouncerInteractor,
+            keyguardTransitionInteractor,
+        )
         underTest.setupExpandedStatusBar()
 
-        interactionEventHandlerCaptor = ArgumentCaptor.forClass(InteractionEventHandler::class.java)
+        interactionEventHandlerCaptor =
+            ArgumentCaptor.forClass(InteractionEventHandler::class.java)
         verify(view).setInteractionEventHandler(interactionEventHandlerCaptor.capture())
-        interactionEventHandler = interactionEventHandlerCaptor.value
+            interactionEventHandler = interactionEventHandlerCaptor.value
     }
 
     // Note: So far, these tests only cover interactions with the status bar view controller. More
@@ -170,11 +184,14 @@
     @Test
     fun handleDispatchTouchEvent_downTouchBelowViewThenAnotherTouch_sendsTouchToSb() {
         underTest.setStatusBarViewController(phoneStatusBarViewController)
-        val downEvBelow =
-            MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0)
+        val downEvBelow = MotionEvent.obtain(
+            0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0
+        )
         interactionEventHandler.handleDispatchTouchEvent(downEvBelow)
 
-        val nextEvent = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, VIEW_BOTTOM + 5f, 0)
+        val nextEvent = MotionEvent.obtain(
+            0L, 0L, MotionEvent.ACTION_MOVE, 0f, VIEW_BOTTOM + 5f, 0
+        )
         whenever(phoneStatusBarViewController.sendTouchToView(nextEvent)).thenReturn(true)
 
         val returnVal = interactionEventHandler.handleDispatchTouchEvent(nextEvent)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
index faa6221..5d71979 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
@@ -46,7 +46,6 @@
 import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel;
-import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationInsetsController;
@@ -102,7 +101,6 @@
     @Mock private NotificationInsetsController mNotificationInsetsController;
     @Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
     @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
-    @Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
 
     @Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler>
             mInteractionEventHandlerCaptor;
@@ -152,8 +150,7 @@
                 mKeyguardBouncerViewModel,
                 mKeyguardBouncerComponentFactory,
                 mAlternateBouncerInteractor,
-                mKeyguardTransitionInteractor,
-                mPrimaryBouncerToGoneTransitionViewModel
+                mKeyguardTransitionInteractor
         );
         mController.setupExpandedStatusBar();
         mController.setDragDownHelper(mDragDownHelper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java
index 4478039..64e58d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java
@@ -49,6 +49,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.wm.shell.util.TransitionUtil;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -120,7 +121,7 @@
         change.setTaskInfo(createTaskInfo(1 /* taskId */, ACTIVITY_TYPE_HOME));
         change.setEndAbsBounds(endBounds);
         change.setEndRelOffset(0, 0);
-        RemoteAnimationTarget wrapped = RemoteAnimationTargetCompat.newTarget(
+        RemoteAnimationTarget wrapped = TransitionUtil.newTarget(
                 change, 0 /* order */, tinfo, mock(SurfaceControl.Transaction.class), null);
         assertEquals(ACTIVITY_TYPE_HOME, wrapped.windowConfiguration.getActivityType());
         assertEquals(new Rect(0, 0, 100, 140), wrapped.localBounds);
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 d99cdd51..ab615f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -211,16 +211,6 @@
     }
 
     @Test
-    fun testTriggeringBouncerWhenPrivateNotificationsArentAllowed() {
-        whenever(lockScreenUserManager.userAllowsPrivateNotificationsInPublic(anyInt())).thenReturn(
-                false)
-        transitionController.goToLockedShade(null)
-        verify(statusbarStateController, never()).setState(anyInt())
-        verify(statusbarStateController).setLeaveOpenOnKeyguardHide(true)
-        verify(mCentralSurfaces).showBouncerWithDimissAndCancelIfKeyguard(anyObject(), anyObject())
-    }
-
-    @Test
     fun testTriggeringBouncerNoNotificationsOnLockscreen() {
         whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false)
         transitionController.goToLockedShade(null)
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 180d9f8..dc5a047 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
@@ -24,8 +24,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
-
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyFloat;
@@ -60,12 +58,7 @@
 import com.android.systemui.animation.ShadeInterpolation;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
-import com.android.systemui.keyguard.shared.model.KeyguardState;
-import com.android.systemui.keyguard.shared.model.TransitionState;
-import com.android.systemui.keyguard.shared.model.TransitionStep;
-import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
 import com.android.systemui.scrim.ScrimView;
 import com.android.systemui.statusbar.policy.FakeConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -92,10 +85,8 @@
 import java.util.HashSet;
 import java.util.Map;
 
-import kotlinx.coroutines.CoroutineDispatcher;
-
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@TestableLooper.RunWithLooper
 @SmallTest
 public class ScrimControllerTest extends SysuiTestCase {
 
@@ -124,10 +115,6 @@
     @Mock private DockManager mDockManager;
     @Mock private ScreenOffAnimationController mScreenOffAnimationController;
     @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
-    @Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
-    @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
-    @Mock private CoroutineDispatcher mMainDispatcher;
-
     // 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;
@@ -238,20 +225,13 @@
         when(mDelayedWakeLockBuilder.build()).thenReturn(mWakeLock);
         when(mDockManager.isDocked()).thenReturn(false);
 
-        when(mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition())
-                .thenReturn(emptyFlow());
-        when(mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha()).thenReturn(emptyFlow());
-
         mScrimController = new ScrimController(mLightBarController,
                 mDozeParameters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
                 new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
                 mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
                 mScreenOffAnimationController,
                 mKeyguardUnlockAnimationController,
-                mStatusBarKeyguardViewManager,
-                mPrimaryBouncerToGoneTransitionViewModel,
-                mKeyguardTransitionInteractor,
-                mMainDispatcher);
+                mStatusBarKeyguardViewManager);
         mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
         mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
         mScrimController.setAnimatorListener(mAnimatorListener);
@@ -881,10 +861,7 @@
                 mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
                 mScreenOffAnimationController,
                 mKeyguardUnlockAnimationController,
-                mStatusBarKeyguardViewManager,
-                mPrimaryBouncerToGoneTransitionViewModel,
-                mKeyguardTransitionInteractor,
-                mMainDispatcher);
+                mStatusBarKeyguardViewManager);
         mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
         mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
         mScrimController.setAnimatorListener(mAnimatorListener);
@@ -1652,18 +1629,6 @@
         assertScrimAlpha(mScrimBehind, 0);
     }
 
-    @Test
-    public void ignoreTransitionRequestWhileKeyguardTransitionRunning() {
-        mScrimController.transitionTo(ScrimState.UNLOCKED);
-        mScrimController.mPrimaryBouncerToGoneTransition.accept(
-                new TransitionStep(KeyguardState.PRIMARY_BOUNCER, KeyguardState.GONE, 0f,
-                        TransitionState.RUNNING, "ScrimControllerTest"));
-
-        // This request should not happen
-        mScrimController.transitionTo(ScrimState.BOUNCER);
-        assertThat(mScrimController.getState()).isEqualTo(ScrimState.UNLOCKED);
-    }
-
     private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
         mScrimController.setRawPanelExpansionFraction(expansion);
         finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/stylus/OWNERS
index 7ccb316..0ec996b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/OWNERS
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/OWNERS
@@ -5,4 +5,6 @@
 madym@google.com
 mgalhardo@google.com
 petrcermak@google.com
+stevenckng@google.com
+tkachenkoi@google.com
 vanjan@google.com
\ No newline at end of file
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 194ed02..1a371c7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -47,9 +47,6 @@
     private val _isKeyguardShowing = MutableStateFlow(false)
     override val isKeyguardShowing: Flow<Boolean> = _isKeyguardShowing
 
-    private val _isKeyguardUnlocked = MutableStateFlow(false)
-    override val isKeyguardUnlocked: Flow<Boolean> = _isKeyguardUnlocked
-
     private val _isKeyguardOccluded = MutableStateFlow(false)
     override val isKeyguardOccluded: Flow<Boolean> = _isKeyguardOccluded
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
index 16442bb..eac1bd1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
@@ -37,7 +37,7 @@
         _transitions.emit(step)
     }
 
-    override fun startTransition(info: TransitionInfo, resetIfCanceled: Boolean): UUID? {
+    override fun startTransition(info: TransitionInfo): UUID? {
         return null
     }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index a359216..e159f18 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -1635,7 +1635,7 @@
             return false;
         }
 
-        if (event.isAccessibilityDataPrivate()
+        if (event.isAccessibilityDataSensitive()
                 && (mFetchFlags & AccessibilityNodeInfo.FLAG_SERVICE_IS_ACCESSIBILITY_TOOL) == 0) {
             return false;
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java b/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java
index 86b5a12..a94ab34 100644
--- a/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java
+++ b/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java
@@ -53,6 +53,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.util.FeatureFlagUtils;
 import android.util.Log;
 import android.view.Display;
 import android.view.View;
@@ -342,10 +343,12 @@
     private void requestStartFlashNotification(FlashNotification flashNotification) {
         if (DEBUG) Log.d(LOG_TAG, "requestStartFlashNotification");
 
-        mIsCameraFlashNotificationEnabled = Settings.System.getIntForUser(
+        boolean isFeatureOn = FeatureFlagUtils.isEnabled(mContext,
+                FeatureFlagUtils.SETTINGS_FLASH_NOTIFICATIONS);
+        mIsCameraFlashNotificationEnabled = isFeatureOn && Settings.System.getIntForUser(
                 mContext.getContentResolver(), SETTING_KEY_CAMERA_FLASH_NOTIFICATION, 0,
                 UserHandle.USER_CURRENT) != 0;
-        mIsScreenFlashNotificationEnabled = Settings.System.getIntForUser(
+        mIsScreenFlashNotificationEnabled = isFeatureOn && Settings.System.getIntForUser(
                 mContext.getContentResolver(), SETTING_KEY_SCREEN_FLASH_NOTIFICATION, 0,
                 UserHandle.USER_CURRENT) != 0;
 
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 43b816b..61032dc 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -849,6 +849,32 @@
         }
     }
 
+
+    /**
+     * Updates the last fill response when a view was entered.
+     */
+    void logViewEntered(int sessionId, @Nullable Bundle clientState) {
+        synchronized (mLock) {
+            if (!isValidEventLocked("logViewEntered", sessionId)) {
+                return;
+            }
+
+            if (mEventHistory.getEvents() != null) {
+                // Do not log this event more than once
+                for (Event event : mEventHistory.getEvents()) {
+                    if (event.getType() == Event.TYPE_VIEW_REQUESTED_AUTOFILL) {
+                        Slog.v(TAG, "logViewEntered: already logged TYPE_VIEW_REQUESTED_AUTOFILL");
+                        return;
+                    }
+                }
+            }
+
+            mEventHistory.addEvent(
+                    new Event(Event.TYPE_VIEW_REQUESTED_AUTOFILL, null, clientState, null,
+                            null, null, null, null, null, null, null));
+        }
+    }
+
     void logAugmentedAutofillAuthenticationSelected(int sessionId, @Nullable String selectedDataset,
             @Nullable Bundle clientState) {
         synchronized (mLock) {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 598521f..4a12e38 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -442,6 +442,18 @@
     private boolean mPreviouslyFillDialogPotentiallyStarted;
 
     /**
+     * Keeps track of if the user entered view, this is used to
+     * distinguish Fill Request that did not have user interaction
+     * with ones that did.
+     *
+     * This is set to true when entering view - after FillDialog FillRequest
+     * or on plain user tap.
+     */
+    @NonNull
+    @GuardedBy("mLock")
+    private boolean mLogViewEntered;
+
+    /**
      * Keeps the fill dialog trigger ids of the last response. This invalidates
      * the trigger ids of the previous response.
      */
@@ -1289,6 +1301,7 @@
 
         mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
                 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags));
+        mLogViewEntered = false;
     }
 
     /**
@@ -1413,6 +1426,14 @@
 
         mService.setLastResponse(id, response);
 
+        synchronized (mLock) {
+            if (mLogViewEntered) {
+                mLogViewEntered = false;
+                mService.logViewEntered(id, null);
+            }
+        }
+
+
         final long disableDuration = response.getDisableDuration();
         final boolean autofillDisabled = disableDuration > 0;
         if (autofillDisabled) {
@@ -3545,6 +3566,28 @@
                     return;
                 }
 
+                synchronized (mLock) {
+                    if (!mLogViewEntered) {
+                        // If the current request is for FillDialog (preemptive)
+                        // then this is the first time that the view is entered
+                        // (mLogViewEntered == false) in this case, setLastResponse()
+                        // has already been called, so just log here.
+                        // If the current request is not and (mLogViewEntered == false)
+                        // then the last session is being tracked (setLastResponse not called)
+                        // so this calling logViewEntered will be a nop.
+                        // Calling logViewEntered() twice will only log it once
+                        // TODO(271181979): this is broken for multiple partitions
+                        mService.logViewEntered(this.id, null);
+                    }
+
+                    // If this is the first time view is entered for inline, the last
+                    // session is still being tracked, so logViewEntered() needs
+                    // to be delayed until setLastResponse is called.
+                    // For fill dialog requests case logViewEntered is already called above
+                    // so this will do nothing. Assumption: only one fill dialog per session
+                    mLogViewEntered = true;
+                }
+
                 // Previously, fill request will only start whenever a view is entered.
                 // With Fill Dialog, request starts prior to view getting entered. So, we can't end
                 // the event at this moment, otherwise we will be wrongly attributing fill dialog
diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
index 9f27f72..3fffdbe 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
@@ -23,6 +23,7 @@
 import static android.content.ComponentName.createRelative;
 
 import static com.android.server.companion.Utils.prepareForIpc;
+import static com.android.server.companion.transport.Transport.MESSAGE_REQUEST_PERMISSION_RESTORE;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -91,7 +92,8 @@
         mAssociationStore = associationStore;
         mSystemDataTransferRequestStore = systemDataTransferRequestStore;
         mTransportManager = transportManager;
-        mTransportManager.setListener(this::onReceivePermissionRestore);
+        mTransportManager.addListener(MESSAGE_REQUEST_PERMISSION_RESTORE,
+                this::onReceivePermissionRestore);
         mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class);
         mExecutor = Executors.newSingleThreadExecutor();
     }
diff --git a/services/companion/java/com/android/server/companion/securechannel/AttestationVerifier.java b/services/companion/java/com/android/server/companion/securechannel/AttestationVerifier.java
index adaee75..1559a3f 100644
--- a/services/companion/java/com/android/server/companion/securechannel/AttestationVerifier.java
+++ b/services/companion/java/com/android/server/companion/securechannel/AttestationVerifier.java
@@ -35,7 +35,7 @@
 /**
  * Helper class to perform attestation verification synchronously.
  */
-class AttestationVerifier {
+public class AttestationVerifier {
     private static final long ATTESTATION_VERIFICATION_TIMEOUT_SECONDS = 10; // 10 seconds
     private static final String PARAM_OWNED_BY_SYSTEM = "android.key_owned_by_system";
 
diff --git a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
index 13dba84..05b6022 100644
--- a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
+++ b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
@@ -110,7 +110,7 @@
         this(in, out, callback, null, new AttestationVerifier(context));
     }
 
-    private SecureChannel(
+    public SecureChannel(
             final InputStream in,
             final OutputStream out,
             Callback callback,
@@ -381,9 +381,10 @@
 
     private void exchangeAuthentication()
             throws IOException, GeneralSecurityException, BadHandleException, CryptoException {
-        if (mVerifier == null) {
+        if (mPreSharedKey != null) {
             exchangePreSharedKey();
-        } else {
+        }
+        if (mVerifier != null) {
             exchangeAttestation();
         }
     }
diff --git a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
index 6a53adf..8dab231 100644
--- a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
+++ b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
@@ -19,9 +19,9 @@
 import static android.Manifest.permission.DELIVER_COMPANION_MESSAGES;
 
 import static com.android.server.companion.transport.Transport.MESSAGE_REQUEST_PERMISSION_RESTORE;
+import static com.android.server.companion.transport.Transport.MESSAGE_REQUEST_PLATFORM_INFO;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.SuppressLint;
 import android.app.ActivityManagerInternal;
 import android.content.Context;
@@ -30,12 +30,17 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.ParcelFileDescriptor;
+import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.LocalServices;
+import com.android.server.companion.transport.Transport.Listener;
 
 import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Future;
 
@@ -44,6 +49,9 @@
     private static final String TAG = "CDM_CompanionTransportManager";
     private static final boolean DEBUG = false;
 
+    private static final int SECURE_CHANNEL_AVAILABLE_SDK = Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+    private static final int NON_ANDROID = -1;
+
     private boolean mSecureTransportEnabled = true;
 
     private static boolean isRequest(int message) {
@@ -54,24 +62,29 @@
         return (message & 0xFF000000) == 0x33000000;
     }
 
-    public interface Listener {
-        void onRequestPermissionRestore(byte[] data);
-    }
-
     private final Context mContext;
 
     @GuardedBy("mTransports")
     private final SparseArray<Transport> mTransports = new SparseArray<>();
 
-    @Nullable
-    private Listener mListener;
+    @NonNull
+    private final Map<Integer, Listener> mListeners = new HashMap<>();
+
+    private Transport mTempTransport;
 
     public CompanionTransportManager(Context context) {
         mContext = context;
     }
 
-    public void setListener(@NonNull Listener listener) {
-        mListener = listener;
+    /**
+     * Add a message listener when a message is received for the message type
+     */
+    @GuardedBy("mTransports")
+    public void addListener(int message, @NonNull Listener listener) {
+        mListeners.put(message, listener);
+        for (int i = 0; i < mTransports.size(); i++) {
+            mTransports.valueAt(i).addListener(message, listener);
+        }
     }
 
     /**
@@ -105,15 +118,7 @@
                 detachSystemDataTransport(packageName, userId, associationId);
             }
 
-            final Transport transport;
-            if (isSecureTransportEnabled(associationId)) {
-                transport = new SecureTransport(associationId, fd, mContext, mListener);
-            } else {
-                transport = new RawTransport(associationId, fd, mContext, mListener);
-            }
-
-            transport.start();
-            mTransports.put(associationId, transport);
+            initializeTransport(associationId, fd);
         }
     }
 
@@ -128,13 +133,85 @@
         }
     }
 
+    @GuardedBy("mTransports")
+    private void initializeTransport(int associationId, ParcelFileDescriptor fd) {
+        if (!isSecureTransportEnabled()) {
+            Transport transport = new RawTransport(associationId, fd, mContext);
+            for (Map.Entry<Integer, Listener> entry : mListeners.entrySet()) {
+                transport.addListener(entry.getKey(), entry.getValue());
+            }
+            transport.start();
+            mTransports.put(associationId, transport);
+            Slog.i(TAG, "RawTransport is created");
+            return;
+        }
+
+        // Exchange platform info to decide which transport should be created
+        mTempTransport = new RawTransport(associationId, fd, mContext);
+        for (Map.Entry<Integer, Listener> entry : mListeners.entrySet()) {
+            mTempTransport.addListener(entry.getKey(), entry.getValue());
+        }
+        mTempTransport.addListener(MESSAGE_REQUEST_PLATFORM_INFO, this::onPlatformInfoReceived);
+        mTempTransport.start();
+
+        int sdk = Build.VERSION.SDK_INT;
+        String release = Build.VERSION.RELEASE;
+        // data format: | SDK_INT (int) | release length (int) | release |
+        final ByteBuffer data = ByteBuffer.allocate(4 + 4 + release.getBytes().length)
+                .putInt(sdk)
+                .putInt(release.getBytes().length)
+                .put(release.getBytes());
+
+        // TODO: it should check if preSharedKey is given
+        mTempTransport.requestForResponse(MESSAGE_REQUEST_PLATFORM_INFO, data.array());
+    }
+
+    /**
+     * Depending on the remote platform info to decide which transport should be created
+     */
+    @GuardedBy("mTransports")
+    private void onPlatformInfoReceived(byte[] data) {
+        // TODO: it should check if preSharedKey is given
+
+        ByteBuffer buffer = ByteBuffer.wrap(data);
+        int remoteSdk = buffer.getInt();
+        byte[] remoteRelease = new byte[buffer.getInt()];
+        buffer.get(remoteRelease);
+
+        Slog.i(TAG, "Remote device SDK: " + remoteSdk + ", release:" + new String(remoteRelease));
+
+        Transport transport = mTempTransport;
+        mTempTransport = null;
+
+        int sdk = Build.VERSION.SDK_INT;
+        String release = Build.VERSION.RELEASE;
+        if (remoteSdk == NON_ANDROID) {
+            // TODO: pass in a real preSharedKey
+            transport = new SecureTransport(transport.getAssociationId(), transport.getFd(),
+                    mContext, null, null);
+        } else if (sdk < SECURE_CHANNEL_AVAILABLE_SDK
+                || remoteSdk < SECURE_CHANNEL_AVAILABLE_SDK) {
+            // TODO: depending on the release version, either
+            //       1) using a RawTransport for old T versions
+            //       2) or an Ukey2 handshaked transport for UKey2 backported T versions
+        } else {
+            Slog.i(TAG, "Creating a secure channel");
+            transport = new SecureTransport(transport.getAssociationId(), transport.getFd(),
+                    mContext);
+            for (Map.Entry<Integer, Listener> entry : mListeners.entrySet()) {
+                transport.addListener(entry.getKey(), entry.getValue());
+            }
+            transport.start();
+        }
+        mTransports.put(transport.getAssociationId(), transport);
+    }
+
     public Future<?> requestPermissionRestore(int associationId, byte[] data) {
         synchronized (mTransports) {
             final Transport transport = mTransports.get(associationId);
             if (transport == null) {
                 return CompletableFuture.failedFuture(new IOException("Missing transport"));
             }
-
             return transport.requestForResponse(MESSAGE_REQUEST_PERMISSION_RESTORE, data);
         }
     }
@@ -146,10 +223,9 @@
         this.mSecureTransportEnabled = enabled;
     }
 
-    private boolean isSecureTransportEnabled(int associationId) {
+    private boolean isSecureTransportEnabled() {
         boolean enabled = !Build.IS_DEBUGGABLE || mSecureTransportEnabled;
 
-        // TODO: version comparison logic
         return enabled;
     }
 }
diff --git a/services/companion/java/com/android/server/companion/transport/CryptoManager.java b/services/companion/java/com/android/server/companion/transport/CryptoManager.java
index b08354a..a15939e 100644
--- a/services/companion/java/com/android/server/companion/transport/CryptoManager.java
+++ b/services/companion/java/com/android/server/companion/transport/CryptoManager.java
@@ -16,51 +16,51 @@
 
 package com.android.server.companion.transport;
 
-import android.security.keystore.KeyGenParameterSpec;
-import android.security.keystore.KeyProperties;
 import android.util.Slog;
 
-import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableEntryException;
-import java.security.cert.CertificateException;
+import java.util.Arrays;
 
 import javax.crypto.BadPaddingException;
 import javax.crypto.Cipher;
 import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.KeyGenerator;
 import javax.crypto.NoSuchPaddingException;
 import javax.crypto.SecretKey;
 import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
 
 /**
- * This class can be used to encrypt and decrypt bytes using Android Cryptography
+ * This class uses Java Cryptography to encrypt and decrypt messages
  */
 public class CryptoManager {
 
     private static final String TAG = "CDM_CryptoManager";
+    private static final int SECRET_KEY_LENGTH = 32;
+    private static final String ALGORITHM = "AES";
+    private static final String TRANSFORMATION = "AES/CBC/PKCS7Padding";
 
-    private static final String KEY_STORE_ALIAS = "cdm_secret";
-    private static final String ALGORITHM = KeyProperties.KEY_ALGORITHM_AES;
-    private static final String BLOCK_MODE = KeyProperties.BLOCK_MODE_CBC;
-    private static final String PADDING = KeyProperties.ENCRYPTION_PADDING_PKCS7;
-    private static final String TRANSFORMATION = ALGORITHM + "/" + BLOCK_MODE + "/" + PADDING;
+    private final byte[] mPreSharedKey;
+    private Cipher mEncryptCipher;
+    private Cipher mDecryptCipher;
 
-    private final KeyStore mKeyStore;
+    private SecretKey mSecretKey;
 
-    public CryptoManager() {
-        // Initialize KeyStore
+    public CryptoManager(byte[] preSharedKey) {
+        if (preSharedKey == null) {
+            mPreSharedKey = Arrays.copyOf(new byte[0], SECRET_KEY_LENGTH);
+        } else {
+            mPreSharedKey = Arrays.copyOf(preSharedKey, SECRET_KEY_LENGTH);
+        }
+        mSecretKey = new SecretKeySpec(mPreSharedKey, ALGORITHM);
         try {
-            mKeyStore = KeyStore.getInstance("AndroidKeyStore");
-            mKeyStore.load(null);
-        } catch (KeyStoreException | IOException | NoSuchAlgorithmException
-                 | CertificateException e) {
-            throw new RuntimeException(e);
+            mEncryptCipher = Cipher.getInstance(TRANSFORMATION);
+            mEncryptCipher.init(Cipher.ENCRYPT_MODE, mSecretKey);
+            mDecryptCipher = Cipher.getInstance(TRANSFORMATION);
+        } catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
+            Slog.e(TAG, e.getMessage());
         }
     }
 
@@ -69,21 +69,19 @@
      */
     public byte[] encrypt(byte[] input) {
         try {
-            // Encrypt using Cipher
-            Cipher encryptCipher = Cipher.getInstance(TRANSFORMATION);
-            encryptCipher.init(Cipher.ENCRYPT_MODE, getKey());
-            byte[] encryptedBytes = encryptCipher.doFinal(input);
+            if (mEncryptCipher == null) {
+                return null;
+            }
 
-            // Write to bytes
+            byte[] encryptedBytes = mEncryptCipher.doFinal(input);
             ByteBuffer buffer = ByteBuffer.allocate(
-                            4 + encryptCipher.getIV().length + 4 + encryptedBytes.length)
-                    .putInt(encryptCipher.getIV().length)
-                    .put(encryptCipher.getIV())
+                            4 + mEncryptCipher.getIV().length + 4 + encryptedBytes.length)
+                    .putInt(mEncryptCipher.getIV().length)
+                    .put(mEncryptCipher.getIV())
                     .putInt(encryptedBytes.length)
                     .put(encryptedBytes);
             return buffer.array();
-        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
-                 | IllegalBlockSizeException | BadPaddingException e) {
+        } catch (IllegalBlockSizeException | BadPaddingException e) {
             Slog.e(TAG, e.getMessage());
             return null;
         }
@@ -99,45 +97,20 @@
         byte[] encryptedBytes = new byte[buffer.getInt()];
         buffer.get(encryptedBytes);
         try {
-            Cipher decryptCipher = Cipher.getInstance(TRANSFORMATION);
-            decryptCipher.init(Cipher.DECRYPT_MODE, getKey(), new IvParameterSpec(iv));
-            return decryptCipher.doFinal(encryptedBytes);
-        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
-                 | InvalidAlgorithmParameterException | IllegalBlockSizeException
-                 | BadPaddingException e) {
+            mDecryptCipher.init(Cipher.DECRYPT_MODE, getKey(), new IvParameterSpec(iv));
+            return mDecryptCipher.doFinal(encryptedBytes);
+        } catch (InvalidKeyException | InvalidAlgorithmParameterException
+                 | IllegalBlockSizeException | BadPaddingException e) {
             Slog.e(TAG, e.getMessage());
             return null;
         }
     }
 
     private SecretKey getKey() {
-        try {
-            KeyStore.Entry keyEntry = mKeyStore.getEntry(KEY_STORE_ALIAS, null);
-            if (keyEntry instanceof KeyStore.SecretKeyEntry
-                    && ((KeyStore.SecretKeyEntry) keyEntry).getSecretKey() != null) {
-                return ((KeyStore.SecretKeyEntry) keyEntry).getSecretKey();
-            } else {
-                return createKey();
-            }
-        } catch (NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException e) {
-            throw new RuntimeException(e);
+        if (mSecretKey != null) {
+            return mSecretKey;
         }
-    }
-
-    private SecretKey createKey() {
-        try {
-            KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
-            keyGenerator.init(
-                    new KeyGenParameterSpec.Builder(KEY_STORE_ALIAS,
-                            KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
-                            .setBlockModes(BLOCK_MODE)
-                            .setEncryptionPaddings(PADDING)
-                            .setUserAuthenticationRequired(false)
-                            .setRandomizedEncryptionRequired(true)
-                            .build());
-            return keyGenerator.generateKey();
-        } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {
-            throw new RuntimeException(e);
-        }
+        mSecretKey = new SecretKeySpec(mPreSharedKey, ALGORITHM);
+        return mSecretKey;
     }
 }
diff --git a/services/companion/java/com/android/server/companion/transport/RawTransport.java b/services/companion/java/com/android/server/companion/transport/RawTransport.java
index 7c0c7cf..4060f6e 100644
--- a/services/companion/java/com/android/server/companion/transport/RawTransport.java
+++ b/services/companion/java/com/android/server/companion/transport/RawTransport.java
@@ -21,8 +21,6 @@
 import android.os.ParcelFileDescriptor;
 import android.util.Slog;
 
-import com.android.server.companion.transport.CompanionTransportManager.Listener;
-
 import libcore.io.IoUtils;
 import libcore.io.Streams;
 
@@ -32,8 +30,8 @@
 class RawTransport extends Transport {
     private volatile boolean mStopped;
 
-    RawTransport(int associationId, ParcelFileDescriptor fd, Context context, Listener listener) {
-        super(associationId, fd, context, listener);
+    RawTransport(int associationId, ParcelFileDescriptor fd, Context context) {
+        super(associationId, fd, context);
     }
 
     @Override
@@ -64,7 +62,7 @@
     protected void sendMessage(int message, int sequence, @NonNull byte[] data)
             throws IOException {
         if (DEBUG) {
-            Slog.d(TAG, "Sending message 0x" + Integer.toHexString(message)
+            Slog.e(TAG, "Sending message 0x" + Integer.toHexString(message)
                     + " sequence " + sequence + " length " + data.length
                     + " to association " + mAssociationId);
         }
diff --git a/services/companion/java/com/android/server/companion/transport/SecureTransport.java b/services/companion/java/com/android/server/companion/transport/SecureTransport.java
index 4194130..cca0843 100644
--- a/services/companion/java/com/android/server/companion/transport/SecureTransport.java
+++ b/services/companion/java/com/android/server/companion/transport/SecureTransport.java
@@ -21,8 +21,8 @@
 import android.os.ParcelFileDescriptor;
 import android.util.Slog;
 
+import com.android.server.companion.securechannel.AttestationVerifier;
 import com.android.server.companion.securechannel.SecureChannel;
-import com.android.server.companion.transport.CompanionTransportManager.Listener;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
@@ -37,14 +37,17 @@
 
     private final BlockingQueue<byte[]> mRequestQueue = new ArrayBlockingQueue<>(100);
 
-    SecureTransport(int associationId,
-            ParcelFileDescriptor fd,
-            Context context,
-            Listener listener) {
-        super(associationId, fd, context, listener);
+    SecureTransport(int associationId, ParcelFileDescriptor fd, Context context) {
+        super(associationId, fd, context);
         mSecureChannel = new SecureChannel(mRemoteIn, mRemoteOut, this, context);
     }
 
+    SecureTransport(int associationId, ParcelFileDescriptor fd, Context context,
+            byte[] preSharedKey, AttestationVerifier verifier) {
+        super(associationId, fd, context);
+        mSecureChannel = new SecureChannel(mRemoteIn, mRemoteOut, this, preSharedKey, verifier);
+    }
+
     @Override
     public void start() {
         mSecureChannel.start();
diff --git a/services/companion/java/com/android/server/companion/transport/Transport.java b/services/companion/java/com/android/server/companion/transport/Transport.java
index 923d424..e984c63 100644
--- a/services/companion/java/com/android/server/companion/transport/Transport.java
+++ b/services/companion/java/com/android/server/companion/transport/Transport.java
@@ -25,23 +25,28 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.server.companion.transport.CompanionTransportManager.Listener;
 
 import libcore.util.EmptyArray;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Future;
 import java.util.concurrent.atomic.AtomicInteger;
 
-abstract class Transport {
+/**
+ * This class represents the channel established between two devices.
+ */
+public abstract class Transport {
     protected static final String TAG = "CDM_CompanionTransport";
     protected static final boolean DEBUG = Build.IS_DEBUGGABLE;
 
     static final int MESSAGE_REQUEST_PING = 0x63807378; // ?PIN
-    static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 0x63826983; // ?RES
+    public static final int MESSAGE_REQUEST_PLATFORM_INFO = 0x63807086; // ?PFV
+    public static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 0x63826983; // ?RES
 
     static final int MESSAGE_RESPONSE_SUCCESS = 0x33838567; // !SUC
     static final int MESSAGE_RESPONSE_FAILURE = 0x33706573; // !FAI
@@ -49,11 +54,24 @@
     protected static final int HEADER_LENGTH = 12;
 
     protected final int mAssociationId;
+    protected final ParcelFileDescriptor mFd;
     protected final InputStream mRemoteIn;
     protected final OutputStream mRemoteOut;
     protected final Context mContext;
 
-    private final Listener mListener;
+    /** Message type -> Listener */
+    private final Map<Integer, Listener> mListeners;
+
+    /**
+     * Message listener
+     */
+    public interface Listener {
+        /**
+         * Called when a message is received
+         * @param data data content in the message
+         */
+        void onDataReceived(byte[] data);
+    }
 
     private static boolean isRequest(int message) {
         return (message & 0xFF000000) == 0x63000000;
@@ -68,16 +86,36 @@
             new SparseArray<>();
     protected final AtomicInteger mNextSequence = new AtomicInteger();
 
-    Transport(int associationId, ParcelFileDescriptor fd, Context context, Listener listener) {
-        this.mAssociationId = associationId;
-        this.mRemoteIn = new ParcelFileDescriptor.AutoCloseInputStream(fd);
-        this.mRemoteOut = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
-        this.mContext = context;
-        this.mListener = listener;
+    Transport(int associationId, ParcelFileDescriptor fd, Context context) {
+        mAssociationId = associationId;
+        mFd = fd;
+        mRemoteIn = new ParcelFileDescriptor.AutoCloseInputStream(fd);
+        mRemoteOut = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+        mContext = context;
+        mListeners = new HashMap<>();
+    }
+
+    /**
+     * Add a listener when a message is received for the message type
+     * @param message Message type
+     * @param listener Execute when a message with the type is received
+     */
+    public void addListener(int message, Listener listener) {
+        mListeners.put(message, listener);
+    }
+
+    public int getAssociationId() {
+        return mAssociationId;
+    }
+
+    protected ParcelFileDescriptor getFd() {
+        return mFd;
     }
 
     public abstract void start();
     public abstract void stop();
+    protected abstract void sendMessage(int message, int sequence, @NonNull byte[] data)
+            throws IOException;
 
     public Future<byte[]> requestForResponse(int message, byte[] data) {
         if (DEBUG) Slog.d(TAG, "Requesting for response");
@@ -99,9 +137,6 @@
         return pending;
     }
 
-    protected abstract void sendMessage(int message, int sequence, @NonNull byte[] data)
-            throws IOException;
-
     protected final void handleMessage(int message, int sequence, @NonNull byte[] data)
             throws IOException {
         if (DEBUG) {
@@ -130,6 +165,11 @@
                 sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, data);
                 break;
             }
+            case MESSAGE_REQUEST_PLATFORM_INFO: {
+                callback(message, data);
+                sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, EmptyArray.BYTE);
+                break;
+            }
             case MESSAGE_REQUEST_PERMISSION_RESTORE: {
                 if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)
                         && !Build.isDebuggable()) {
@@ -138,7 +178,7 @@
                     break;
                 }
                 try {
-                    mListener.onRequestPermissionRestore(data);
+                    callback(message, data);
                     sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, EmptyArray.BYTE);
                 } catch (Exception e) {
                     Slog.w(TAG, "Failed to restore permissions");
@@ -154,6 +194,12 @@
         }
     }
 
+    private void callback(int message, byte[] data) {
+        if (mListeners.containsKey(message)) {
+            mListeners.get(message).onDataReceived(data);
+        }
+    }
+
     private void processResponse(int message, int sequence, byte[] data) {
         final CompletableFuture<byte[]> future;
         synchronized (mPendingRequests) {
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index e52f1d9..1c46028 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -16,7 +16,6 @@
 
 package com.android.server.companion.virtual;
 
-import static android.companion.virtual.VirtualDeviceParams.RECENTS_POLICY_ALLOW_IN_HOST_DEVICE_RECENTS;
 import static android.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
@@ -29,7 +28,6 @@
 import android.companion.virtual.VirtualDeviceManager.ActivityListener;
 import android.companion.virtual.VirtualDeviceParams;
 import android.companion.virtual.VirtualDeviceParams.ActivityPolicy;
-import android.companion.virtual.VirtualDeviceParams.RecentsPolicy;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
 import android.content.ComponentName;
@@ -137,8 +135,8 @@
             new ArraySet<>();
     @Nullable private final SecureWindowCallback mSecureWindowCallback;
     @Nullable private final List<String> mDisplayCategories;
-    @RecentsPolicy
-    private final int mDefaultRecentsPolicy;
+
+    private final boolean mShowTasksInHostDeviceRecents;
 
     /**
      * Creates a window policy controller that is generic to the different use cases of virtual
@@ -166,7 +164,7 @@
      *   virtual display.
      * @param intentListenerCallback Callback that is called to intercept intents when matching
      *   passed in filters.
-     * @param defaultRecentsPolicy a policy to indicate how to handle activities in recents.
+     * @param showTasksInHostDeviceRecents whether to show activities in recents on the host device.
      */
     public GenericWindowPolicyController(int windowFlags, int systemWindowFlags,
             @NonNull ArraySet<UserHandle> allowedUsers,
@@ -181,7 +179,7 @@
             @NonNull SecureWindowCallback secureWindowCallback,
             @NonNull IntentListenerCallback intentListenerCallback,
             @NonNull List<String> displayCategories,
-            @RecentsPolicy int defaultRecentsPolicy) {
+            boolean showTasksInHostDeviceRecents) {
         super();
         mAllowedUsers = allowedUsers;
         mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations);
@@ -196,7 +194,7 @@
         mSecureWindowCallback = secureWindowCallback;
         mIntentListenerCallback = intentListenerCallback;
         mDisplayCategories = displayCategories;
-        mDefaultRecentsPolicy = defaultRecentsPolicy;
+        mShowTasksInHostDeviceRecents = showTasksInHostDeviceRecents;
     }
 
     /**
@@ -337,7 +335,7 @@
 
     @Override
     public boolean canShowTasksInHostDeviceRecents() {
-        return (mDefaultRecentsPolicy & RECENTS_POLICY_ALLOW_IN_HOST_DEVICE_RECENTS) != 0;
+        return mShowTasksInHostDeviceRecents;
     }
 
     @Override
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index ee1b1fd..2d010cf 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -846,7 +846,9 @@
                         this::onSecureWindowShown,
                         this::shouldInterceptIntent,
                         displayCategories,
-                        mParams.getDefaultRecentsPolicy());
+                        mParams.getDevicePolicy(
+                                VirtualDeviceParams.POLICY_TYPE_RECENTS)
+                                == VirtualDeviceParams.DEVICE_POLICY_DEFAULT);
         gwpc.registerRunningAppsChangedListener(/* listener= */ this);
         return gwpc;
     }
diff --git a/services/core/java/android/os/BatteryStatsInternal.java b/services/core/java/android/os/BatteryStatsInternal.java
index 17ef9a2..c6f63dd 100644
--- a/services/core/java/android/os/BatteryStatsInternal.java
+++ b/services/core/java/android/os/BatteryStatsInternal.java
@@ -38,11 +38,13 @@
 
     public static final int CPU_WAKEUP_SUBSYSTEM_UNKNOWN = -1;
     public static final int CPU_WAKEUP_SUBSYSTEM_ALARM = 1;
+    public static final int CPU_WAKEUP_SUBSYSTEM_WIFI = 2;
 
     /** @hide */
     @IntDef(prefix = {"CPU_WAKEUP_SUBSYSTEM_"}, value = {
             CPU_WAKEUP_SUBSYSTEM_UNKNOWN,
             CPU_WAKEUP_SUBSYSTEM_ALARM,
+            CPU_WAKEUP_SUBSYSTEM_WIFI,
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface CpuWakeupSubsystem {
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 40557f4..3ecf933 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -34,7 +34,6 @@
 import android.content.IntentFilter;
 import android.content.pm.ApexStagedEvent;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.Checksum;
 import android.content.pm.IBackgroundInstallControlService;
 import android.content.pm.IPackageManagerNative;
 import android.content.pm.IStagedApexObserver;
@@ -117,14 +116,17 @@
     @VisibleForTesting
     static final String BINARY_HASH_ERROR = "SHA256HashError";
 
-    static final int MEASURE_APEX_AND_MODULES = 1;
-    static final int MEASURE_PRELOADS = 2;
-    static final int MEASURE_NEW_MBAS = 3;
-
     static final long RECORD_MEASUREMENTS_COOLDOWN_MS = 24 * 60 * 60 * 1000;
 
     static final String APEX_PRELOAD_LOCATION_ERROR = "could-not-be-determined";
 
+    // Copy from the atom. Consistent for both ApexInfoGathered and MobileBundledAppInfoGathered.
+    static final int DIGEST_ALGORITHM_UNKNOWN = 0;
+    static final int DIGEST_ALGORITHM_CHUNKED_SHA256 = 1;
+    static final int DIGEST_ALGORITHM_CHUNKED_SHA512 = 2;
+    static final int DIGEST_ALGORITHM_VERITY_CHUNKED_SHA256 = 3;
+    static final int DIGEST_ALGORITHM_SHA256 = 4;
+
     // used for indicating any type of error during MBA measurement
     static final int MBA_STATUS_ERROR = 0;
     // used for indicating factory condition preloads
@@ -226,9 +228,9 @@
                 appInfo.mbaStatus = mbaStatus;
 
                 // Only digest and split name are different between splits.
-                Checksum checksum = measureApk(split.getPath());
-                appInfo.digest = checksum.getValue();
-                appInfo.digestAlgorithm = checksum.getType();
+                Digest digest = measureApk(split.getPath());
+                appInfo.digest = digest.value;
+                appInfo.digestAlgorithm = digest.algorithm;
 
                 results.add(appInfo);
             }
@@ -260,10 +262,9 @@
          * Perform basic measurement (i.e. content digest) on a given APK.
          *
          * @param apkPath The APK (or APEX, since it's also an APK) file to be measured.
-         * @return a {@link android.content.pm.Checksum} with preferred digest algorithm type and
-         *         the checksum.
+         * @return a {@link #Digest} with preferred digest algorithm type and the value.
          */
-        private @Nullable Checksum measureApk(@NonNull String apkPath) {
+        private @Nullable Digest measureApk(@NonNull String apkPath) {
             // compute content digest
             Map<Integer, byte[]> contentDigests = computeApkContentDigest(apkPath);
             if (contentDigests == null) {
@@ -274,20 +275,20 @@
                 // And only one of them will be available per package.
                 if (contentDigests.containsKey(
                             ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256)) {
-                    return new Checksum(
-                            Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256,
+                    return new Digest(
+                            DIGEST_ALGORITHM_CHUNKED_SHA256,
                             contentDigests.get(ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256));
                 } else if (contentDigests.containsKey(
                         ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512)) {
-                    return new Checksum(
-                            Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512,
+                    return new Digest(
+                            DIGEST_ALGORITHM_CHUNKED_SHA512,
                             contentDigests.get(ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512));
                 }
             }
             // When something went wrong, fall back to simple sha256.
             byte[] digest = PackageUtils.computeSha256DigestForLargeFileAsBytes(apkPath,
                     PackageUtils.createLargeFileBuffer());
-            return new Checksum(Checksum.TYPE_WHOLE_SHA256, digest);
+            return new Digest(DIGEST_ALGORITHM_SHA256, digest);
         }
 
 
@@ -381,7 +382,7 @@
                     Slog.w(TAG, "Skipping the missing APK in " + pkg.getPath());
                     continue;
                 }
-                Checksum apexChecksum = measureApk(pkg.getPath());
+                Digest apexChecksum = measureApk(pkg.getPath());
                 if (apexChecksum == null) {
                     Slog.w(TAG, "Skipping the missing APEX in " + pkg.getPath());
                     continue;
@@ -390,8 +391,8 @@
                 var apexInfo = new IBinaryTransparencyService.ApexInfo();
                 apexInfo.packageName = packageState.getPackageName();
                 apexInfo.longVersion = packageState.getVersionCode();
-                apexInfo.digest = apexChecksum.getValue();
-                apexInfo.digestAlgorithm = apexChecksum.getType();
+                apexInfo.digest = apexChecksum.value;
+                apexInfo.digestAlgorithm = apexChecksum.algorithm;
                 apexInfo.signerDigests =
                         computePackageSignerSha256Digests(packageState.getSigningInfo());
 
@@ -1691,4 +1692,14 @@
         }
         return slice.getList();
     }
+
+    private static class Digest {
+        public int algorithm;
+        public byte[] value;
+
+        Digest(int algorithm, byte[] value) {
+            this.algorithm = algorithm;
+            this.value = value;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index c5b0f05..c3dda71 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -23,6 +23,18 @@
             "file_patterns": ["NotificationManagerService\\.java"]
         },
         {
+            "name": "CtsScopedStorageCoreHostTest",
+            "file_patterns": ["StorageManagerService\\.java"]
+        },
+        {
+            "name": "CtsScopedStorageHostTest",
+            "file_patterns": ["StorageManagerService\\.java"]
+        },
+        {
+            "name": "CtsScopedStorageDeviceOnlyTest",
+            "file_patterns": ["StorageManagerService\\.java"]
+        },
+        {
             "name": "FrameworksMockingServicesTests",
             "options": [
                 {
@@ -63,18 +75,6 @@
     ],
     "presubmit-large": [
         {
-            "name": "CtsScopedStorageCoreHostTest",
-            "file_patterns": ["StorageManagerService\\.java"]
-        },
-        {
-            "name": "CtsScopedStorageHostTest",
-            "file_patterns": ["StorageManagerService\\.java"]
-        },
-        {
-            "name": "CtsScopedStorageDeviceOnlyTest",
-            "file_patterns": ["StorageManagerService\\.java"]
-        },
-        {
             "name": "CtsContentTestCases",
             "options": [
                 {
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 9e95e5f..e3f00ded 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -995,7 +995,7 @@
     private static final String KEY_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION =
             "enable_wait_for_finish_attach_application";
 
-    private static final boolean DEFAULT_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION = false;
+    private static final boolean DEFAULT_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION = true;
 
     /** @see #KEY_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION */
     public volatile boolean mEnableWaitForFinishAttachApplication =
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a1f7445..432c209 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4925,14 +4925,8 @@
         EventLogTags.writeAmProcBound(app.userId, pid, app.processName);
 
         synchronized (mProcLock) {
-            app.mState.setCurAdj(ProcessList.INVALID_ADJ);
-            app.mState.setSetAdj(ProcessList.INVALID_ADJ);
-            app.mState.setVerifiedAdj(ProcessList.INVALID_ADJ);
-            mOomAdjuster.setAttachingSchedGroupLSP(app);
-            app.mState.setForcingToImportant(null);
+            mOomAdjuster.setAttachingProcessStatesLSP(app);
             clearProcessForegroundLocked(app);
-            app.mState.setHasShownUi(false);
-            app.mState.setCached(false);
             app.setDebugging(false);
             app.setKilledByAm(false);
             app.setKilled(false);
@@ -5100,8 +5094,14 @@
                 app.makeActive(thread, mProcessStats);
                 checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
             }
+            app.setPendingFinishAttach(true);
+
             updateLruProcessLocked(app, false, null);
             checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
+
+            updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
+            checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked");
+
             final long now = SystemClock.uptimeMillis();
             synchronized (mAppProfiler.mProfilerLock) {
                 app.mProfile.setLastRequestedGc(now);
@@ -5117,8 +5117,6 @@
 
             if (!mConstants.mEnableWaitForFinishAttachApplication) {
                 finishAttachApplicationInner(startSeq, callingUid, pid);
-            } else {
-                app.setPendingFinishAttach(true);
             }
         } catch (Exception e) {
             // We need kill the process group here. (b/148588589)
@@ -14505,7 +14503,7 @@
             brOptions.setDeferUntilActive(true);
         }
 
-        if (ordered && brOptions != null && brOptions.isDeferUntilActive()) {
+        if (mEnableModernQueue && ordered && brOptions != null && brOptions.isDeferUntilActive()) {
             throw new IllegalArgumentException("Ordered broadcasts can't be deferred until active");
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 4c1835e..02c1b8b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -19,7 +19,7 @@
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
-import static android.app.ActivityManager.PROCESS_CAPABILITY_NETWORK;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
 import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM;
@@ -2014,7 +2014,7 @@
         int mask = PROCESS_CAPABILITY_FOREGROUND_LOCATION
                 | PROCESS_CAPABILITY_FOREGROUND_CAMERA
                 | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
-                | PROCESS_CAPABILITY_NETWORK;
+                | PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
 
         while ((opt=getNextOption()) != null) {
             if (opt.equals("--oom")) {
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index 050ac19..ac2c725 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -1892,15 +1892,11 @@
     }
 
     long getCpuTimeForPid(int pid) {
-        synchronized (mProcessCpuTracker) {
-            return mProcessCpuTracker.getCpuTimeForPid(pid);
-        }
+        return mProcessCpuTracker.getCpuTimeForPid(pid);
     }
 
     long getCpuDelayTimeForPid(int pid) {
-        synchronized (mProcessCpuTracker) {
-            return mProcessCpuTracker.getCpuDelayTimeForPid(pid);
-        }
+        return mProcessCpuTracker.getCpuDelayTimeForPid(pid);
     }
 
     List<ProcessCpuTracker.Stats> getCpuStats(Predicate<ProcessCpuTracker.Stats> predicate) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 1607566..0ee883f 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -23,6 +23,7 @@
 import static android.Manifest.permission.POWER_SAVER;
 import static android.Manifest.permission.UPDATE_DEVICE_STATS;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
 import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
 
@@ -479,9 +480,29 @@
             BatteryStatsService.this.noteJobsDeferred(uid, numDeferred, sinceLast);
         }
 
+        private int transportToSubsystem(NetworkCapabilities nc) {
+            if (nc.hasTransport(TRANSPORT_WIFI)) {
+                return CPU_WAKEUP_SUBSYSTEM_WIFI;
+            }
+            return CPU_WAKEUP_SUBSYSTEM_UNKNOWN;
+        }
+
         @Override
         public void noteCpuWakingNetworkPacket(Network network, long elapsedMillis, int uid) {
-            Slog.d(TAG, "Wakeup due to incoming packet on network " + network + " to uid " + uid);
+            if (uid < 0) {
+                Slog.e(TAG, "Invalid uid for waking network packet: " + uid);
+                return;
+            }
+            final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+            final NetworkCapabilities nc = cm.getNetworkCapabilities(network);
+            final int subsystem = transportToSubsystem(nc);
+
+            if (subsystem == CPU_WAKEUP_SUBSYSTEM_UNKNOWN) {
+                Slog.wtf(TAG, "Could not map transport for network: " + network
+                        + " while attributing wakeup by packet sent to uid: " + uid);
+                return;
+            }
+            noteCpuWakingActivity(subsystem, elapsedMillis, uid);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 679cf0a..7121421 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -22,8 +22,8 @@
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
-import static android.app.ActivityManager.PROCESS_CAPABILITY_NETWORK;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
 import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
 import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
 import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
@@ -117,6 +117,7 @@
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ServiceInfo;
+import android.net.NetworkPolicyManager;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.PowerManagerInternal;
@@ -1259,12 +1260,19 @@
         for (int i = numLru - 1; i >= 0; i--) {
             ProcessRecord app = lruList.get(i);
             final ProcessStateRecord state = app.mState;
-            if (!app.isKilledByAm() && app.getThread() != null && !app.isPendingFinishAttach()) {
+            if (!app.isKilledByAm() && app.getThread() != null) {
                 // We don't need to apply the update for the process which didn't get computed
                 if (state.getCompletedAdjSeq() == mAdjSeq) {
                     applyOomAdjLSP(app, true, now, nowElapsed, oomAdjReason);
                 }
 
+                if (app.isPendingFinishAttach()) {
+                    // Avoid trimming processes that are still initializing. If they aren't
+                    // hosting any components yet because they may be unfairly killed.
+                    // We however apply any computed previously computed oom scores before skipping.
+                    continue;
+                }
+
                 final ProcessServiceRecord psr = app.mServices;
                 // Count the number of process types.
                 switch (state.getCurProcState()) {
@@ -1698,6 +1706,19 @@
             return false;
         }
 
+        if (app.isPendingFinishAttach()) {
+            state.setAdjSeq(mAdjSeq);
+            state.setCompletedAdjSeq(mAdjSeq);
+            // If the process is still initializing, we skip computing any states because we
+            // don't want to override the special states that have been set at
+            // AMS#attachApplication with OomAdjuster#setAttachingProcessStates.
+            // In this limbo state, the app has |PROC_START_TIMEOUT| to finish attach application
+            // and receive updated proc_state based on its importance.
+            // Note that in this state, the oom_score is INVALID_ADJ which is outside the standard
+            // oom score range and the app is safe from lmkd kills.
+            return false;
+        }
+
         state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN);
         state.setAdjSource(null);
         state.setAdjTarget(null);
@@ -2260,14 +2281,15 @@
                         // elevated to a high enough procstate anyway to get network unless they
                         // request otherwise, so don't propagate the network capability by default
                         // in this case unless they explicitly request it.
-                        if ((cstate.getCurCapability() & PROCESS_CAPABILITY_NETWORK) != 0) {
+                        if ((cstate.getCurCapability()
+                                & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0) {
                             if (clientProcState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
                                 // This is used to grant network access to Expedited Jobs.
                                 if (cr.hasFlag(Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS)) {
-                                    capability |= PROCESS_CAPABILITY_NETWORK;
+                                    capability |= PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
                                 }
                             } else {
-                                capability |= PROCESS_CAPABILITY_NETWORK;
+                                capability |= PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
                             }
                         }
 
@@ -2778,27 +2800,33 @@
     }
 
     private int getDefaultCapability(ProcessRecord app, int procState) {
+        final int networkCapabilities =
+                NetworkPolicyManager.getDefaultProcessNetworkCapabilities(procState);
+        final int baseCapabilities;
         switch (procState) {
             case PROCESS_STATE_PERSISTENT:
             case PROCESS_STATE_PERSISTENT_UI:
             case PROCESS_STATE_TOP:
-                return PROCESS_CAPABILITY_ALL; // BFSL allowed
+                baseCapabilities = PROCESS_CAPABILITY_ALL; // BFSL allowed
+                break;
             case PROCESS_STATE_BOUND_TOP:
-                return PROCESS_CAPABILITY_NETWORK | PROCESS_CAPABILITY_BFSL;
+                baseCapabilities = PROCESS_CAPABILITY_BFSL;
+                break;
             case PROCESS_STATE_FOREGROUND_SERVICE:
                 if (app.getActiveInstrumentation() != null) {
-                    return PROCESS_CAPABILITY_ALL_IMPLICIT | PROCESS_CAPABILITY_NETWORK ;
+                    baseCapabilities = PROCESS_CAPABILITY_ALL_IMPLICIT;
                 } else {
                     // Capability from foreground service is conditional depending on
                     // foregroundServiceType in the manifest file and the
                     // mAllowWhileInUsePermissionInFgs flag.
-                    return PROCESS_CAPABILITY_NETWORK;
+                    baseCapabilities = PROCESS_CAPABILITY_NONE;
                 }
-            case PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
-                return PROCESS_CAPABILITY_NETWORK;
+                break;
             default:
-                return PROCESS_CAPABILITY_NONE;
+                baseCapabilities = PROCESS_CAPABILITY_NONE;
+                break;
         }
+        return baseCapabilities | networkCapabilities;
     }
 
     /**
@@ -3211,7 +3239,7 @@
     }
 
     @GuardedBy({"mService", "mProcLock"})
-    void setAttachingSchedGroupLSP(ProcessRecord app) {
+    void setAttachingProcessStatesLSP(ProcessRecord app) {
         int initialSchedGroup = SCHED_GROUP_DEFAULT;
         final ProcessStateRecord state = app.mState;
         // If the process has been marked as foreground, it is starting as the top app (with
@@ -3231,6 +3259,15 @@
 
         state.setSetSchedGroup(initialSchedGroup);
         state.setCurrentSchedulingGroup(initialSchedGroup);
+        state.setCurProcState(PROCESS_STATE_CACHED_EMPTY);
+        state.setCurCapability(PROCESS_CAPABILITY_NONE);
+
+        state.setCurAdj(ProcessList.FOREGROUND_APP_ADJ);
+        state.setSetAdj(ProcessList.FOREGROUND_APP_ADJ);
+        state.setVerifiedAdj(ProcessList.FOREGROUND_APP_ADJ);
+        state.setForcingToImportant(null);
+        state.setHasShownUi(false);
+        state.setCached(true);
     }
 
     // ONLY used for unit testing in OomAdjusterTests.java
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index f4e2b0f..35f71f7 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -3100,9 +3100,10 @@
                 hostingRecord.getDefiningUid(), hostingRecord.getDefiningProcessName());
         final ProcessStateRecord state = r.mState;
 
-        if (!mService.mBooted && !mService.mBooting
+        if (!isolated && !isSdkSandbox
                 && userId == UserHandle.USER_SYSTEM
-                && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
+                && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK
+                && (TextUtils.equals(proc, info.processName))) {
             // The system process is initialized to SCHED_GROUP_DEFAULT in init.rc.
             state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
             state.setSetSchedGroup(ProcessList.SCHED_GROUP_DEFAULT);
diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
index 49279d4..2d6966a 100644
--- a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
+++ b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
@@ -327,9 +327,12 @@
     }
 
     private void commitUidPendingState(int uid) {
-        int pendingUidState = mPendingUidStates.get(uid, MIN_PRIORITY_UID_STATE);
-        int pendingCapability = mPendingCapability.get(uid, PROCESS_CAPABILITY_NONE);
-        boolean pendingVisibleAppWidget = mPendingVisibleAppWidget.get(uid, false);
+        int pendingUidState = mPendingUidStates.get(uid,
+                mUidStates.get(uid, MIN_PRIORITY_UID_STATE));
+        int pendingCapability = mPendingCapability.get(uid,
+                mCapability.get(uid, PROCESS_CAPABILITY_NONE));
+        boolean pendingVisibleAppWidget = mPendingVisibleAppWidget.get(uid,
+                mVisibleAppWidget.get(uid, false));
 
         int uidState = mUidStates.get(uid, MIN_PRIORITY_UID_STATE);
         int capability = mCapability.get(uid, PROCESS_CAPABILITY_NONE);
diff --git a/services/core/java/com/android/server/audio/TEST_MAPPING b/services/core/java/com/android/server/audio/TEST_MAPPING
index 300a2c8..2cea32a 100644
--- a/services/core/java/com/android/server/audio/TEST_MAPPING
+++ b/services/core/java/com/android/server/audio/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-    "presubmit-large": [
+    "presubmit": [
         {
             "name": "CtsMediaAudioTestCases",
             "options": [
@@ -24,9 +24,7 @@
                     "include-annotation": "android.platform.test.annotations.Presubmit"
                 }
             ]
-        }
-    ],
-    "presubmit": [
+        },
         {
             "name": "FrameworksServicesTests",
             "options": [
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
index 7b8f824..f516a49 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
@@ -37,6 +37,7 @@
     private static final String TAG = "BiometricNotificationUtils";
     private static final String RE_ENROLL_NOTIFICATION_TAG = "FaceService";
     private static final String BAD_CALIBRATION_NOTIFICATION_TAG = "FingerprintService";
+    private static final String KEY_RE_ENROLL_FACE = "re_enroll_face_unlock";
     private static final int NOTIFICATION_ID = 1;
     private static final long NOTIFICATION_INTERVAL_MS = 24 * 60 * 60 * 1000;
     private static long sLastAlertTime = 0;
@@ -57,6 +58,7 @@
 
         final Intent intent = new Intent("android.settings.FACE_SETTINGS");
         intent.setPackage("com.android.settings");
+        intent.putExtra(KEY_RE_ENROLL_FACE, true);
 
         final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context,
                 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */,
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 6d7b2cb..c2994a9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -260,9 +260,8 @@
             if (provider == null) {
                 Slog.w(TAG, "Null provider for authenticate");
                 return -1;
-            } else {
-                options.setSensorId(provider.first);
             }
+            options.setSensorId(provider.first);
 
             return provider.second.scheduleAuthenticate(token, operationId,
                     0 /* cookie */, new ClientMonitorCallbackConverter(receiver), options,
@@ -286,6 +285,7 @@
                 Slog.w(TAG, "Null provider for detectFace");
                 return -1;
             }
+            options.setSensorId(provider.first);
 
             return provider.second.scheduleFaceDetect(token,
                     new ClientMonitorCallbackConverter(receiver), options,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index f6c1375..dc00ffc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -261,7 +261,6 @@
             final String opPackageName = options.getOpPackageName();
             final String attributionTag = options.getAttributionTag();
             final int userId = options.getUserId();
-            final int sensorId = options.getSensorId();
 
             if (!canUseFingerprint(
                     opPackageName,
@@ -298,21 +297,22 @@
                     : BiometricsProtoEnums.CLIENT_FINGERPRINT_MANAGER;
 
             final Pair<Integer, ServiceProvider> provider;
-            if (sensorId == FingerprintManager.SENSOR_ID_ANY) {
+            if (options.getSensorId() == FingerprintManager.SENSOR_ID_ANY) {
                 provider = mRegistry.getSingleProvider();
             } else {
                 Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
-                provider = new Pair<>(sensorId, mRegistry.getProviderForSensor(sensorId));
+                provider = new Pair<>(options.getSensorId(),
+                        mRegistry.getProviderForSensor(options.getSensorId()));
             }
+
             if (provider == null) {
                 Slog.w(TAG, "Null provider for authenticate");
                 return -1;
-            } else {
-                options.setSensorId(provider.first);
             }
+            options.setSensorId(provider.first);
 
             final FingerprintSensorPropertiesInternal sensorProps =
-                    provider.second.getSensorProperties(sensorId);
+                    provider.second.getSensorProperties(options.getSensorId());
             if (!isKeyguard && !Utils.isSettings(getContext(), opPackageName)
                     && sensorProps != null && sensorProps.isAnyUdfpsType()) {
                 try {
@@ -431,9 +431,8 @@
             if (provider == null) {
                 Slog.w(TAG, "Null provider for detectFingerprint");
                 return -1;
-            } else {
-                options.setSensorId(provider.first);
             }
+            options.setSensorId(provider.first);
 
             return provider.second.scheduleFingerDetect(token,
                     new ClientMonitorCallbackConverter(receiver), options,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java
index 1630be7..bae84bd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java
@@ -48,6 +48,8 @@
             return BiometricFingerprintConstants.FINGERPRINT_ERROR_VENDOR;
         } else if (aidlError == Error.BAD_CALIBRATION) {
             return BiometricFingerprintConstants.FINGERPRINT_ERROR_BAD_CALIBRATION;
+        } else if (aidlError == Error.POWER_PRESS) {
+            return BiometricFingerprintConstants.BIOMETRIC_ERROR_POWER_PRESSED;
         } else {
             return BiometricFingerprintConstants.FINGERPRINT_ERROR_UNKNOWN;
         }
@@ -84,6 +86,8 @@
         } else if (aidlAcquiredInfo == AcquiredInfo.RETRYING_CAPTURE) {
             // No framework constant available
             return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_UNKNOWN;
+        } else if (aidlAcquiredInfo == AcquiredInfo.POWER_PRESS) {
+            return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED;
         } else {
             return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_UNKNOWN;
         }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index 513b3e3..c2ca78e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -274,8 +274,5 @@
     }
 
     @Override
-    public void onPowerPressed() {
-        onAcquired(BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED,
-                0 /* vendorCode */);
-    }
+    public void onPowerPressed() {}
 }
diff --git a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
index ce29013..63218ee 100644
--- a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
+++ b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
@@ -138,6 +138,8 @@
                         display.setPosition(POSITION_UNKNOWN);
                     }
                     display.setRefreshRateZoneId(d.getRefreshRateZoneId());
+                    display.setRefreshRateThermalThrottlingMapId(
+                            d.getRefreshRateThermalThrottlingMapId());
                 }
             }
         } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 7b560ce..d57dc47 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -22,6 +22,7 @@
 import android.graphics.Rect;
 import android.hardware.display.DisplayViewport;
 import android.os.IBinder;
+import android.util.Slog;
 import android.view.Display;
 import android.view.DisplayAddress;
 import android.view.Surface;
@@ -39,6 +40,7 @@
  * </p>
  */
 abstract class DisplayDevice {
+    private static final String TAG = "DisplayDevice";
     private static final Display.Mode EMPTY_DISPLAY_MODE = new Display.Mode.Builder().build();
 
     private final DisplayAdapter mDisplayAdapter;
@@ -269,10 +271,13 @@
     /**
      * Sets the display layer stack while in a transaction.
      */
-    public final void setLayerStackLocked(SurfaceControl.Transaction t, int layerStack) {
+    public final void setLayerStackLocked(SurfaceControl.Transaction t, int layerStack,
+            int layerStackTag) {
         if (mCurrentLayerStack != layerStack) {
             mCurrentLayerStack = layerStack;
             t.setDisplayLayerStack(mDisplayToken, layerStack);
+            Slog.i(TAG, "[" + layerStackTag + "] Layerstack set to " + layerStack + " for "
+                    + mUniqueId);
         }
     }
 
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 75f8acc..cdab77d 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -31,6 +31,7 @@
 import android.util.MathUtils;
 import android.util.Pair;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.Spline;
 import android.view.DisplayAddress;
 import android.view.SurfaceControl;
@@ -54,6 +55,8 @@
 import com.android.server.display.config.Point;
 import com.android.server.display.config.RefreshRateConfigs;
 import com.android.server.display.config.RefreshRateRange;
+import com.android.server.display.config.RefreshRateThrottlingMap;
+import com.android.server.display.config.RefreshRateThrottlingPoint;
 import com.android.server.display.config.RefreshRateZone;
 import com.android.server.display.config.SdrHdrRatioMap;
 import com.android.server.display.config.SdrHdrRatioPoint;
@@ -88,6 +91,7 @@
  * <pre>
  *  {@code
  *    <displayConfiguration>
+ *      <name>Built-In Display</name>
  *      <densityMapping>
  *        <density>
  *          <height>480</height>
@@ -149,9 +153,26 @@
  *            <brightness>0.005</brightness>
  *          </brightnessThrottlingPoint>
  *        </concurrentDisplaysBrightnessThrottlingMap>
+ *        <refreshRateThrottlingMap>
+ *            <refreshRateThrottlingPoint>
+ *                <thermalStatus>critical</thermalStatus>
+ *                <refreshRateRange>
+ *                     <minimum>0</minimum>
+ *                     <maximum>60</maximum>
+ *                 </refreshRateRange>
+ *            </refreshRateThrottlingPoint>
+ *        </refreshRateThrottlingMap>
  *      </thermalThrottling>
  *
  *      <refreshRate>
+ *       <refreshRateZoneProfiles>
+ *         <refreshRateZoneProfile id="concurrent">
+ *           <refreshRateRange>
+ *             <minimum>60</minimum>
+ *             <maximum>60</maximum>
+ *            </refreshRateRange>
+ *          </refreshRateZoneProfile>
+ *        </refreshRateZoneProfiles>
  *        <defaultRefreshRateInHbmHdr>75</defaultRefreshRateInHbmHdr>
  *        <defaultRefreshRateInHbmSunlight>75</defaultRefreshRateInHbmSunlight>
  *        <lowerBlockingZoneConfigs>
@@ -417,7 +438,7 @@
 
     public static final String QUIRK_CAN_SET_BRIGHTNESS_VIA_HWC = "canSetBrightnessViaHwc";
 
-    static final String DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID = "default";
+    static final String DEFAULT_ID = "default";
 
     private static final float BRIGHTNESS_DEFAULT = 0.5f;
     private static final String ETC_DIR = "etc";
@@ -479,6 +500,10 @@
     private final List<RefreshRateLimitation> mRefreshRateLimitations =
             new ArrayList<>(2 /*initialCapacity*/);
 
+    // Name of the display, if configured.
+    @Nullable
+    private String mName;
+
     // Nits and backlight values that are loaded from either the display device config file, or
     // config.xml. These are the raw values and just used for the dumpsys
     private float[] mRawNits;
@@ -662,7 +687,11 @@
     private int[] mHighDisplayBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS;
     private int[] mHighAmbientBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS;
 
-    private Map<String, BrightnessThrottlingData> mBrightnessThrottlingDataMap = new HashMap();
+    private final Map<String, BrightnessThrottlingData> mBrightnessThrottlingDataMap =
+            new HashMap<>();
+
+    private final Map<String, SparseArray<SurfaceControl.RefreshRateRange>>
+            mRefreshRateThrottlingMap = new HashMap<>();
 
     @Nullable
     private HostUsiVersion mHostUsiVersion;
@@ -808,6 +837,15 @@
         return config;
     }
 
+    /** The name of the display.
+     *
+     * @return The name of the display.
+     */
+    @Nullable
+    public String getName() {
+        return mName;
+    }
+
     /**
      * Return the brightness mapping nits array.
      *
@@ -1315,6 +1353,17 @@
     }
 
     /**
+     * @param id - throttling data id or null for default
+     * @return refresh rate throttling configuration
+     */
+    @Nullable
+    public SparseArray<SurfaceControl.RefreshRateRange> getRefreshRateThrottlingData(
+            @Nullable String id) {
+        String key = id == null ? DEFAULT_ID : id;
+        return mRefreshRateThrottlingMap.get(key);
+    }
+
+    /**
      * @return Auto brightness darkening light debounce
      */
     public long getAutoBrightnessDarkeningLightDebounce() {
@@ -1552,6 +1601,8 @@
                 + ", mRefreshRateZoneProfiles= " + mRefreshRateZoneProfiles
                 + ", mDefaultRefreshRateInHbmHdr= " + mDefaultRefreshRateInHbmHdr
                 + ", mDefaultRefreshRateInHbmSunlight= " + mDefaultRefreshRateInHbmSunlight
+                + ", mRefreshRateThrottlingMap= " + mRefreshRateThrottlingMap
+                + "\n"
                 + ", mLowDisplayBrightnessThresholds= "
                 + Arrays.toString(mLowDisplayBrightnessThresholds)
                 + ", mLowAmbientBrightnessThresholds= "
@@ -1609,11 +1660,12 @@
         try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) {
             final DisplayConfiguration config = XmlParser.read(in);
             if (config != null) {
+                loadName(config);
                 loadDensityMapping(config);
                 loadBrightnessDefaultFromDdcXml(config);
                 loadBrightnessConstraintsFromConfigXml();
                 loadBrightnessMap(config);
-                loadBrightnessThrottlingMaps(config);
+                loadThermalThrottlingConfig(config);
                 loadHighBrightnessModeData(config);
                 loadQuirks(config);
                 loadBrightnessRamps(config);
@@ -1680,6 +1732,10 @@
         }
     }
 
+    private void loadName(DisplayConfiguration config) {
+        mName = config.getName();
+    }
+
     private void loadDensityMapping(DisplayConfiguration config) {
         if (config.getDensityMapping() == null) {
             return;
@@ -1823,13 +1879,17 @@
         return Spline.createSpline(nits, ratios);
     }
 
-    private void loadBrightnessThrottlingMaps(DisplayConfiguration config) {
+    private void loadThermalThrottlingConfig(DisplayConfiguration config) {
         final ThermalThrottling throttlingConfig = config.getThermalThrottling();
         if (throttlingConfig == null) {
             Slog.i(TAG, "No thermal throttling config found");
             return;
         }
+        loadBrightnessThrottlingMaps(throttlingConfig);
+        loadRefreshRateThermalThrottlingMap(throttlingConfig);
+    }
 
+    private void loadBrightnessThrottlingMaps(ThermalThrottling throttlingConfig) {
         final List<BrightnessThrottlingMap> maps = throttlingConfig.getBrightnessThrottlingMap();
         if (maps == null || maps.isEmpty()) {
             Slog.i(TAG, "No brightness throttling map found");
@@ -1855,7 +1915,7 @@
             }
 
             if (!badConfig) {
-                String id = map.getId() == null ? DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID
+                String id = map.getId() == null ? DEFAULT_ID
                         : map.getId();
                 if (mBrightnessThrottlingDataMap.containsKey(id)) {
                     throw new RuntimeException("Brightness throttling data with ID " + id
@@ -1867,6 +1927,57 @@
         }
     }
 
+    private void loadRefreshRateThermalThrottlingMap(ThermalThrottling throttlingConfig) {
+        List<RefreshRateThrottlingMap> maps = throttlingConfig.getRefreshRateThrottlingMap();
+        if (maps == null || maps.isEmpty()) {
+            Slog.w(TAG, "RefreshRateThrottling: map not found");
+            return;
+        }
+
+        for (RefreshRateThrottlingMap map : maps) {
+            List<RefreshRateThrottlingPoint> points = map.getRefreshRateThrottlingPoint();
+            String id = map.getId() == null ? DEFAULT_ID : map.getId();
+
+            if (points == null || points.isEmpty()) {
+                // Expected at lease 1 throttling point for each map
+                Slog.w(TAG, "RefreshRateThrottling: points not found for mapId=" + id);
+                continue;
+            }
+            if (mRefreshRateThrottlingMap.containsKey(id)) {
+                Slog.wtf(TAG, "RefreshRateThrottling: map already exists, mapId=" + id);
+                continue;
+            }
+
+            SparseArray<SurfaceControl.RefreshRateRange> refreshRates = new SparseArray<>();
+            for (RefreshRateThrottlingPoint point : points) {
+                ThermalStatus status = point.getThermalStatus();
+                if (!thermalStatusIsValid(status)) {
+                    Slog.wtf(TAG,
+                            "RefreshRateThrottling: Invalid thermalStatus=" + status.getRawName()
+                                    + ",mapId=" + id);
+                    continue;
+                }
+                int thermalStatusInt = convertThermalStatus(status);
+                if (refreshRates.contains(thermalStatusInt)) {
+                    Slog.wtf(TAG, "RefreshRateThrottling: thermalStatus=" + status.getRawName()
+                            + " is already in the map, mapId=" + id);
+                    continue;
+                }
+
+                refreshRates.put(thermalStatusInt, new SurfaceControl.RefreshRateRange(
+                        point.getRefreshRateRange().getMinimum().floatValue(),
+                        point.getRefreshRateRange().getMaximum().floatValue()
+                ));
+            }
+            if (refreshRates.size() == 0) {
+                Slog.w(TAG, "RefreshRateThrottling: no valid throttling points fond for map, mapId="
+                        + id);
+                continue;
+            }
+            mRefreshRateThrottlingMap.put(id, refreshRates);
+        }
+    }
+
     private void loadRefreshRateSetting(DisplayConfiguration config) {
         final RefreshRateConfigs refreshRateConfigs =
                 (config == null) ? null : config.getRefreshRate();
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 58c5034..8d0689f 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -42,6 +42,7 @@
 import android.view.RoundedCorners;
 import android.view.SurfaceControl;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.display.BrightnessSynchronizer;
 import com.android.internal.util.function.pooled.PooledLambda;
@@ -675,14 +676,13 @@
                 mInfo.flags |= DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY;
 
                 if (mIsFirstDisplay) {
-                    if (res.getBoolean(com.android.internal.R.bool.config_mainBuiltInDisplayIsRound)
+                    if (res.getBoolean(R.bool.config_mainBuiltInDisplayIsRound)
                             || (Build.IS_EMULATOR
                             && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
                         mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
                     }
                 } else {
-                    if (!res.getBoolean(
-                                com.android.internal.R.bool.config_localDisplaysMirrorContent)) {
+                    if (!res.getBoolean(R.bool.config_localDisplaysMirrorContent)) {
                         mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
                     }
 
@@ -711,18 +711,23 @@
                 mInfo.displayShape = DisplayShape.fromResources(
                         res, mInfo.uniqueId, maxWidth, maxHeight, mInfo.width, mInfo.height);
 
+                mInfo.name = getDisplayDeviceConfig().getName();
+
                 if (mStaticDisplayInfo.isInternal) {
                     mInfo.type = Display.TYPE_INTERNAL;
                     mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
                     mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
-                    mInfo.name = res.getString(
-                            com.android.internal.R.string.display_manager_built_in_display_name);
+                    if (mInfo.name == null) {
+                        mInfo.name = res.getString(R.string.display_manager_built_in_display_name);
+                    }
                 } else {
                     mInfo.type = Display.TYPE_EXTERNAL;
                     mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
                     mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
-                    mInfo.name = getContext().getResources().getString(
-                            com.android.internal.R.string.display_manager_hdmi_display_name);
+                    if (mInfo.name == null) {
+                        mInfo.name = getContext().getResources().getString(
+                                R.string.display_manager_hdmi_display_name);
+                    }
                 }
                 mInfo.frameRateOverrides = mFrameRateOverrides;
 
@@ -1255,8 +1260,7 @@
                 return false;
             }
             final Resources res = getOverlayContext().getResources();
-            int[] ports = res.getIntArray(
-                    com.android.internal.R.array.config_localPrivateDisplayPorts);
+            int[] ports = res.getIntArray(R.array.config_localPrivateDisplayPorts);
             if (ports != null) {
                 int port = physicalAddress.getPort();
                 for (int p : ports) {
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 78c597e..dee4cde 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -189,7 +189,7 @@
         mTempFrameRateOverride = new SparseArray<>();
         mIsEnabled = true;
         mIsInTransition = false;
-        mBrightnessThrottlingDataId = DisplayDeviceConfig.DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID;
+        mBrightnessThrottlingDataId = DisplayDeviceConfig.DEFAULT_ID;
     }
 
     public void setDevicePositionLocked(int position) {
@@ -344,6 +344,21 @@
             mInfo.set(null);
         }
     }
+    /**
+     * Updates refreshRateThermalThrottling
+     *
+     * @param refreshRanges new refreshRateThermalThrottling ranges limited by layout or default
+     */
+    public void updateRefreshRateThermalThrottling(
+            @Nullable SparseArray<SurfaceControl.RefreshRateRange> refreshRanges) {
+        if (refreshRanges == null) {
+            refreshRanges = new SparseArray<>();
+        }
+        if (!mBaseDisplayInfo.refreshRateThermalThrottling.contentEquals(refreshRanges)) {
+            mBaseDisplayInfo.refreshRateThermalThrottling = refreshRanges;
+            mInfo.set(null);
+        }
+    }
 
     /**
      * Updates the state of the logical display based on the available display devices.
@@ -572,7 +587,7 @@
             DisplayDevice device,
             boolean isBlanked) {
         // Set the layer stack.
-        device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack);
+        device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack, mDisplayId);
         // Also inform whether the device is the same one sent to inputflinger for its layerstack.
         // Prevent displays that are disabled from receiving input.
         // TODO(b/188914255): Remove once input can dispatch against device vs layerstack.
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 2ac7d9d..e290b7a 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -1013,19 +1013,23 @@
             if (newDisplay != oldDisplay) {
                 newDisplay.swapDisplaysLocked(oldDisplay);
             }
+            DisplayDeviceConfig config = device.getDisplayDeviceConfig();
 
             newDisplay.setDevicePositionLocked(displayLayout.getPosition());
             newDisplay.setLeadDisplayLocked(displayLayout.getLeadDisplayId());
             newDisplay.updateLayoutLimitedRefreshRateLocked(
-                    device.getDisplayDeviceConfig().getRefreshRange(
-                            displayLayout.getRefreshRateZoneId()
+                    config.getRefreshRange(displayLayout.getRefreshRateZoneId())
+            );
+            newDisplay.updateRefreshRateThermalThrottling(
+                    config.getRefreshRateThrottlingData(
+                            displayLayout.getRefreshRateThermalThrottlingMapId()
                     )
             );
 
             setEnabledLocked(newDisplay, displayLayout.isEnabled());
             newDisplay.setBrightnessThrottlingDataIdLocked(
                     displayLayout.getBrightnessThrottlingMapId() == null
-                            ? DisplayDeviceConfig.DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID
+                            ? DisplayDeviceConfig.DEFAULT_ID
                             : displayLayout.getBrightnessThrottlingMapId());
 
             newDisplay.setDisplayGroupNameLocked(displayLayout.getDisplayGroupName());
diff --git a/services/core/java/com/android/server/display/layout/Layout.java b/services/core/java/com/android/server/display/layout/Layout.java
index f1e885e..6a4d23b 100644
--- a/services/core/java/com/android/server/display/layout/Layout.java
+++ b/services/core/java/com/android/server/display/layout/Layout.java
@@ -257,6 +257,9 @@
         @Nullable
         private String mRefreshRateZoneId;
 
+        @Nullable
+        private String mRefreshRateThermalThrottlingMapId;
+
         Display(@NonNull DisplayAddress address, int logicalDisplayId, boolean isEnabled,
                 @NonNull String displayGroupName, String brightnessThrottlingMapId, int position,
                 int leadDisplayId) {
@@ -286,6 +289,7 @@
                     + ", brightnessThrottlingMapId: " + mBrightnessThrottlingMapId
                     + ", mRefreshRateZoneId: " + mRefreshRateZoneId
                     + ", mLeadDisplayId: " + mLeadDisplayId
+                    + ", mRefreshRateThermalThrottlingMapId: " + mRefreshRateThermalThrottlingMapId
                     + "}";
         }
 
@@ -305,7 +309,9 @@
                     && Objects.equals(mBrightnessThrottlingMapId,
                     otherDisplay.mBrightnessThrottlingMapId)
                     && Objects.equals(otherDisplay.mRefreshRateZoneId, this.mRefreshRateZoneId)
-                    && this.mLeadDisplayId == otherDisplay.mLeadDisplayId;
+                    && this.mLeadDisplayId == otherDisplay.mLeadDisplayId
+                    && Objects.equals(mRefreshRateThermalThrottlingMapId,
+                    otherDisplay.mRefreshRateThermalThrottlingMapId);
         }
 
         @Override
@@ -319,6 +325,7 @@
             result = 31 * result + mBrightnessThrottlingMapId.hashCode();
             result = 31 * result + Objects.hashCode(mRefreshRateZoneId);
             result = 31 * result + mLeadDisplayId;
+            result = 31 * result + Objects.hashCode(mRefreshRateThermalThrottlingMapId);
             return result;
         }
 
@@ -388,5 +395,13 @@
         public int getLeadDisplayId() {
             return mLeadDisplayId;
         }
+
+        public void setRefreshRateThermalThrottlingMapId(String refreshRateThermalThrottlingMapId) {
+            mRefreshRateThermalThrottlingMapId = refreshRateThermalThrottlingMapId;
+        }
+
+        public String getRefreshRateThermalThrottlingMapId() {
+            return mRefreshRateThermalThrottlingMapId;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index 24d5ca4..db6944d0 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -224,6 +224,7 @@
         }
         mLoggingEnabled = loggingEnabled;
         mBrightnessObserver.setLoggingEnabled(loggingEnabled);
+        mSkinThermalStatusObserver.setLoggingEnabled(loggingEnabled);
     }
 
     @NonNull
@@ -2669,7 +2670,7 @@
         }
     }
 
-    private static final class SensorObserver implements ProximityActiveListener,
+    protected static final class SensorObserver implements ProximityActiveListener,
             DisplayManager.DisplayListener {
         private final String mProximitySensorName = null;
         private final String mProximitySensorType = Sensor.STRING_TYPE_PROXIMITY;
@@ -2952,52 +2953,6 @@
         }
     }
 
-    private final class SkinThermalStatusObserver extends IThermalEventListener.Stub {
-        private final BallotBox mBallotBox;
-        private final Injector mInjector;
-
-        private @Temperature.ThrottlingStatus int mStatus = -1;
-
-        SkinThermalStatusObserver(Injector injector, BallotBox ballotBox) {
-            mInjector = injector;
-            mBallotBox = ballotBox;
-        }
-
-        @Override
-        public void notifyThrottling(Temperature temp) {
-            mStatus = temp.getStatus();
-            if (mLoggingEnabled) {
-                Slog.d(TAG, "New thermal throttling status "
-                        + ", current thermal status = " + mStatus);
-            }
-            final Vote vote;
-            if (mStatus >= Temperature.THROTTLING_CRITICAL) {
-                vote = Vote.forRenderFrameRates(0f, 60f);
-            } else {
-                vote = null;
-            }
-            mBallotBox.vote(GLOBAL_ID, Vote.PRIORITY_SKIN_TEMPERATURE, vote);
-        }
-
-        public void observe() {
-            IThermalService thermalService = mInjector.getThermalService();
-            if (thermalService == null) {
-                Slog.w(TAG, "Could not observe thermal status. Service not available");
-                return;
-            }
-            try {
-                thermalService.registerThermalEventListenerWithType(this, Temperature.TYPE_SKIN);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to register thermal status listener", e);
-            }
-        }
-
-        void dumpLocked(PrintWriter writer) {
-            writer.println("  SkinThermalStatusObserver:");
-            writer.println("    mStatus: " + mStatus);
-        }
-    }
-
     private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener {
         public void startListening() {
             mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
@@ -3184,11 +3139,15 @@
         void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener,
                 Handler handler, long flags);
 
+        Display[] getDisplays();
+
+        boolean getDisplayInfo(int displayId, DisplayInfo displayInfo);
+
         BrightnessInfo getBrightnessInfo(int displayId);
 
         boolean isDozeState(Display d);
 
-        IThermalService getThermalService();
+        boolean registerThermalServiceListener(IThermalEventListener listener);
 
         boolean supportsFrameRateOverride();
     }
@@ -3222,6 +3181,20 @@
         }
 
         @Override
+        public Display[] getDisplays() {
+            return getDisplayManager().getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
+        }
+
+        @Override
+        public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) {
+            Display display = getDisplayManager().getDisplay(displayId);
+            if (display != null) {
+                return display.getDisplayInfo(displayInfo);
+            }
+            return false;
+        }
+
+        @Override
         public BrightnessInfo getBrightnessInfo(int displayId) {
             final Display display = getDisplayManager().getDisplay(displayId);
             if (display != null) {
@@ -3239,9 +3212,20 @@
         }
 
         @Override
-        public IThermalService getThermalService() {
-            return IThermalService.Stub.asInterface(
-                    ServiceManager.getService(Context.THERMAL_SERVICE));
+        public boolean registerThermalServiceListener(IThermalEventListener listener) {
+            IThermalService thermalService = getThermalService();
+            if (thermalService == null) {
+                Slog.w(TAG, "Could not observe thermal status. Service not available");
+                return false;
+            }
+            try {
+                thermalService.registerThermalEventListenerWithType(listener,
+                        Temperature.TYPE_SKIN);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to register thermal status listener", e);
+                return false;
+            }
+            return true;
         }
 
         @Override
@@ -3255,6 +3239,11 @@
             }
             return mDisplayManager;
         }
+
+        private IThermalService getThermalService() {
+            return IThermalService.Stub.asInterface(
+                    ServiceManager.getService(Context.THERMAL_SERVICE));
+        }
     }
 
     interface BallotBox {
diff --git a/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java b/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java
new file mode 100644
index 0000000..1bb34ab
--- /dev/null
+++ b/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode;
+
+import android.annotation.Nullable;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.IThermalEventListener;
+import android.os.Temperature;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.SurfaceControl;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+
+import java.io.PrintWriter;
+
+final class SkinThermalStatusObserver extends IThermalEventListener.Stub implements
+        DisplayManager.DisplayListener {
+    private static final String TAG = "SkinThermalStatusObserver";
+
+    private final DisplayModeDirector.BallotBox mBallotBox;
+    private final DisplayModeDirector.Injector mInjector;
+
+    private boolean mLoggingEnabled;
+
+    private final Handler mHandler;
+    private final Object mThermalObserverLock = new Object();
+    @GuardedBy("mThermalObserverLock")
+    @Temperature.ThrottlingStatus
+    private int mStatus = -1;
+    @GuardedBy("mThermalObserverLock")
+    private final SparseArray<SparseArray<SurfaceControl.RefreshRateRange>>
+            mThermalThrottlingByDisplay = new SparseArray<>();
+
+    SkinThermalStatusObserver(DisplayModeDirector.Injector injector,
+            DisplayModeDirector.BallotBox ballotBox) {
+        this(injector, ballotBox, BackgroundThread.getHandler());
+    }
+
+    @VisibleForTesting
+    SkinThermalStatusObserver(DisplayModeDirector.Injector injector,
+            DisplayModeDirector.BallotBox ballotBox, Handler handler) {
+        mInjector = injector;
+        mBallotBox = ballotBox;
+        mHandler = handler;
+    }
+
+    void observe() {
+        // if failed to register thermal service listener, don't register display listener
+        if (!mInjector.registerThermalServiceListener(this)) {
+            return;
+        }
+
+        mInjector.registerDisplayListener(this, mHandler,
+                DisplayManager.EVENT_FLAG_DISPLAY_ADDED | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+                        | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
+
+        populateInitialDisplayInfo();
+    }
+
+    void setLoggingEnabled(boolean enabled) {
+        mLoggingEnabled = enabled;
+    }
+
+    @Override
+    public void notifyThrottling(Temperature temp) {
+        @Temperature.ThrottlingStatus int currentStatus = temp.getStatus();
+        synchronized (mThermalObserverLock) {
+            mStatus = currentStatus;
+            mHandler.post(this::updateVotes);
+        }
+
+        if (mLoggingEnabled) {
+            Slog.d(TAG, "New thermal throttling status " + ", current thermal status = "
+                    + currentStatus);
+        }
+    }
+
+    //region DisplayManager.DisplayListener
+    @Override
+    public void onDisplayAdded(int displayId) {
+        updateRefreshRateThermalThrottling(displayId);
+        if (mLoggingEnabled) {
+            Slog.d(TAG, "Display added:" + displayId);
+        }
+    }
+
+    @Override
+    public void onDisplayRemoved(int displayId) {
+        synchronized (mThermalObserverLock) {
+            mThermalThrottlingByDisplay.remove(displayId);
+            mHandler.post(() -> mBallotBox.vote(displayId,
+                    DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE, null));
+        }
+        if (mLoggingEnabled) {
+            Slog.d(TAG, "Display removed and voted: displayId=" + displayId);
+        }
+    }
+
+    @Override
+    public void onDisplayChanged(int displayId) {
+        updateRefreshRateThermalThrottling(displayId);
+        if (mLoggingEnabled) {
+            Slog.d(TAG, "Display changed:" + displayId);
+        }
+    }
+    //endregion
+
+    private void populateInitialDisplayInfo() {
+        DisplayInfo info = new DisplayInfo();
+        Display[] displays = mInjector.getDisplays();
+        int size = displays.length;
+        SparseArray<SparseArray<SurfaceControl.RefreshRateRange>> localMap = new SparseArray<>(
+                size);
+        for (Display d : displays) {
+            final int displayId = d.getDisplayId();
+            d.getDisplayInfo(info);
+            localMap.put(displayId, info.refreshRateThermalThrottling);
+        }
+        synchronized (mThermalObserverLock) {
+            for (int i = 0; i < size; i++) {
+                mThermalThrottlingByDisplay.put(localMap.keyAt(i), localMap.valueAt(i));
+            }
+        }
+        if (mLoggingEnabled) {
+            Slog.d(TAG, "Display initial info:" + localMap);
+        }
+    }
+
+    private void updateRefreshRateThermalThrottling(int displayId) {
+        DisplayInfo displayInfo = new DisplayInfo();
+        mInjector.getDisplayInfo(displayId, displayInfo);
+        SparseArray<SurfaceControl.RefreshRateRange> throttlingMap =
+                displayInfo.refreshRateThermalThrottling;
+
+        synchronized (mThermalObserverLock) {
+            mThermalThrottlingByDisplay.put(displayId, throttlingMap);
+            mHandler.post(() -> updateVoteForDisplay(displayId));
+        }
+        if (mLoggingEnabled) {
+            Slog.d(TAG,
+                    "Thermal throttling updated: display=" + displayId + ", map=" + throttlingMap);
+        }
+    }
+
+    //region in mHandler thread
+    private void updateVotes() {
+        @Temperature.ThrottlingStatus int localStatus;
+        SparseArray<SparseArray<SurfaceControl.RefreshRateRange>> localMap;
+
+        synchronized (mThermalObserverLock) {
+            localStatus = mStatus;
+            localMap = mThermalThrottlingByDisplay.clone();
+        }
+        if (mLoggingEnabled) {
+            Slog.d(TAG, "Updating votes for status=" + localStatus + ", map=" + localMap);
+        }
+        int size = localMap.size();
+        for (int i = 0; i < size; i++) {
+            reportThrottlingIfNeeded(localMap.keyAt(i), localStatus, localMap.valueAt(i));
+        }
+    }
+
+    private void updateVoteForDisplay(int displayId) {
+        @Temperature.ThrottlingStatus int localStatus;
+        SparseArray<SurfaceControl.RefreshRateRange> localMap;
+
+        synchronized (mThermalObserverLock) {
+            localStatus = mStatus;
+            localMap = mThermalThrottlingByDisplay.get(displayId);
+        }
+        if (mLoggingEnabled) {
+            Slog.d(TAG, "Updating votes for status=" + localStatus + ", display =" + displayId
+                    + ", map=" + localMap);
+        }
+        reportThrottlingIfNeeded(displayId, localStatus, localMap);
+    }
+
+    private void reportThrottlingIfNeeded(int displayId,
+            @Temperature.ThrottlingStatus int currentStatus,
+            SparseArray<SurfaceControl.RefreshRateRange> throttlingMap) {
+        if (currentStatus == -1) { // no throttling status reported from thermal sensor yet
+            return;
+        }
+
+        if (throttlingMap.size() == 0) { // map is not configured, using default behaviour
+            fallbackReportThrottlingIfNeeded(displayId, currentStatus);
+            return;
+        }
+
+        SurfaceControl.RefreshRateRange foundRange = findBestMatchingRefreshRateRange(currentStatus,
+                throttlingMap);
+        // if status <= currentStatus not found in the map reset vote
+        DisplayModeDirector.Vote vote = null;
+        if (foundRange != null) { // otherwise vote with found range
+            vote = DisplayModeDirector.Vote.forRenderFrameRates(foundRange.min, foundRange.max);
+        }
+        mBallotBox.vote(displayId, DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE, vote);
+        if (mLoggingEnabled) {
+            Slog.d(TAG, "Voted: vote=" + vote + ", display =" + displayId);
+        }
+    }
+
+    @Nullable
+    private SurfaceControl.RefreshRateRange findBestMatchingRefreshRateRange(
+            @Temperature.ThrottlingStatus int currentStatus,
+            SparseArray<SurfaceControl.RefreshRateRange> throttlingMap) {
+        SurfaceControl.RefreshRateRange foundRange = null;
+        for (int status = currentStatus; status >= 0; status--) {
+            foundRange = throttlingMap.get(status);
+            if (foundRange != null) {
+                break;
+            }
+        }
+        return foundRange;
+    }
+
+    private void fallbackReportThrottlingIfNeeded(int displayId,
+            @Temperature.ThrottlingStatus int currentStatus) {
+        DisplayModeDirector.Vote vote = null;
+        if (currentStatus >= Temperature.THROTTLING_CRITICAL) {
+            vote = DisplayModeDirector.Vote.forRenderFrameRates(0f, 60f);
+        }
+        mBallotBox.vote(displayId, DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE, vote);
+        if (mLoggingEnabled) {
+            Slog.d(TAG, "Voted(fallback): vote=" + vote + ", display =" + displayId);
+        }
+    }
+    //endregion
+
+    void dumpLocked(PrintWriter writer) {
+        @Temperature.ThrottlingStatus int localStatus;
+        SparseArray<SparseArray<SurfaceControl.RefreshRateRange>> localMap;
+
+        synchronized (mThermalObserverLock) {
+            localStatus = mStatus;
+            localMap = mThermalThrottlingByDisplay.clone();
+        }
+
+        writer.println("  SkinThermalStatusObserver:");
+        writer.println("    mStatus: " + localStatus);
+        writer.println("    mThermalThrottlingByDisplay: " + localMap);
+    }
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index d397a0c..91f91f8 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -3325,6 +3325,7 @@
             if (!canInteractWithImeLocked(uid, client, "showSoftInput", statsToken)) {
                 ImeTracker.forLogging().onFailed(
                         statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
+                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                 return false;
             }
             final long ident = Binder.clearCallingIdentity();
@@ -6458,19 +6459,21 @@
                                 0 /* flags */, null /* resultReceiver */,
                                 SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND);
                         mBindingController.unbindCurrentMethod();
-                        // Reset the current IME
-                        resetSelectedInputMethodAndSubtypeLocked(null);
-                        // Also reset the settings of the current IME
-                        mSettings.putSelectedInputMethod(null);
-                        // Disable all enabled IMEs.
-                        for (InputMethodInfo inputMethodInfo :
-                                mSettings.getEnabledInputMethodListLocked()) {
-                            setInputMethodEnabledLocked(inputMethodInfo.getId(), false);
+
+                        // Enable default IMEs, disable others
+                        var toDisable = mSettings.getEnabledInputMethodListLocked();
+                        var defaultEnabled = InputMethodInfoUtils.getDefaultEnabledImes(
+                                mContext, mMethodList);
+                        toDisable.removeAll(defaultEnabled);
+                        for (InputMethodInfo info : toDisable) {
+                            setInputMethodEnabledLocked(info.getId(), false);
                         }
-                        // Re-enable with default enabled IMEs.
-                        for (InputMethodInfo imi : InputMethodInfoUtils.getDefaultEnabledImes(
-                                mContext, mMethodList)) {
-                            setInputMethodEnabledLocked(imi.getId(), true);
+                        for (InputMethodInfo info : defaultEnabled) {
+                            setInputMethodEnabledLocked(info.getId(), true);
+                        }
+                        // Choose new default IME, reset to none if no IME available.
+                        if (!chooseNewDefaultIMELocked()) {
+                            resetSelectedInputMethodAndSubtypeLocked(null);
                         }
                         updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
                         InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index ca184ee..1e32ad6 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -18,6 +18,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.hardware.contexthub.HostEndpointInfo;
+import android.hardware.contexthub.NanSessionRequest;
 import android.hardware.contexthub.V1_0.ContextHub;
 import android.hardware.contexthub.V1_0.ContextHubMsg;
 import android.hardware.contexthub.V1_0.TransactionResult;
@@ -456,8 +457,8 @@
                 });
             }
 
-            public void handleNanSessionRequest(boolean enable) {
-                // TODO(229888878): Implement
+            public void handleNanSessionRequest(NanSessionRequest request) {
+                // TODO(271471342): Implement
             }
 
             @Override
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 5a832b7..4f28432 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -33,7 +33,6 @@
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN;
-import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
 import static com.android.internal.widget.LockPatternUtils.CURRENT_LSKF_BASED_PROTECTOR_ID_KEY;
 import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
@@ -82,7 +81,6 @@
 import android.hardware.fingerprint.FingerprintManager;
 import android.net.Uri;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -117,7 +115,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.EventLog;
-import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -201,7 +198,6 @@
     private static final String TAG = "LockSettingsService";
     private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
     private static final String BIOMETRIC_PERMISSION = MANAGE_BIOMETRIC;
-    private static final boolean DEBUG = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.DEBUG);
 
     private static final int PROFILE_KEY_IV_SIZE = 12;
     private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
@@ -381,7 +377,6 @@
      */
     private void tieProfileLockIfNecessary(int profileUserId,
             LockscreenCredential profileUserPassword) {
-        if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + profileUserId);
         // Only for profiles that shares credential with parent
         if (!isCredentialSharableWithParent(profileUserId)) {
             return;
@@ -399,8 +394,7 @@
         // as its parent.
         final int parentId = mUserManager.getProfileParent(profileUserId).id;
         if (!isUserSecure(parentId) && !profileUserPassword.isNone()) {
-            if (DEBUG) Slog.v(TAG, "Parent does not have a screen lock but profile has one");
-
+            Slogf.i(TAG, "Clearing password for profile user %d to match parent", profileUserId);
             setLockCredentialInternal(LockscreenCredential.createNone(), profileUserPassword,
                     profileUserId, /* isLockTiedToParent= */ true);
             return;
@@ -416,7 +410,6 @@
             Slog.e(TAG, "Failed to talk to GateKeeper service", e);
             return;
         }
-        if (DEBUG) Slog.v(TAG, "Tie profile to parent now!");
         try (LockscreenCredential unifiedProfilePassword = generateRandomProfilePassword()) {
             setLockCredentialInternal(unifiedProfilePassword, profileUserPassword, profileUserId,
                     /* isLockTiedToParent= */ true);
@@ -690,8 +683,8 @@
         PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
                 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
-        Slog.d(TAG, TextUtils.formatSimple("showing encryption notification, user: %d; reason: %s",
-                user.getIdentifier(), reason));
+        Slogf.d(TAG, "Showing encryption notification for user %d; reason: %s",
+                user.getIdentifier(), reason);
 
         showEncryptionNotification(user, title, message, detail, intent);
     }
@@ -735,7 +728,7 @@
     }
 
     private void hideEncryptionNotification(UserHandle userHandle) {
-        Slog.d(TAG, "hide encryption notification, user: " + userHandle.getIdentifier());
+        Slogf.d(TAG, "Hiding encryption notification for user %d", userHandle.getIdentifier());
         mNotificationManager.cancelAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION,
             userHandle);
     }
@@ -888,7 +881,6 @@
                 && !getBoolean("migrated_frp", false, 0)) {
             migrateFrpCredential();
             setBoolean("migrated_frp", true, 0);
-            Slog.i(TAG, "Migrated migrated_frp.");
         }
     }
 
@@ -1034,7 +1026,7 @@
     private void enforceFrpResolved() {
         final int mainUserId = mInjector.getUserManagerInternal().getMainUserId();
         if (mainUserId < 0) {
-            Slog.i(TAG, "No Main user on device; skip enforceFrpResolved");
+            Slog.d(TAG, "No Main user on device; skipping enforceFrpResolved");
             return;
         }
         final ContentResolver cr = mContext.getContentResolver();
@@ -1269,7 +1261,6 @@
     }
 
     private void unlockKeystore(byte[] password, int userHandle) {
-        if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
         Authorization.onLockScreenEvent(false, userHandle, password, null);
     }
 
@@ -1279,7 +1270,7 @@
             NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
             InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
             CertificateException, IOException {
-        if (DEBUG) Slog.v(TAG, "Get child profile decrypted key");
+        Slogf.d(TAG, "Decrypting password for tied profile %d", userId);
         byte[] storedData = mStorage.readChildProfileLock(userId);
         if (storedData == null) {
             throw new FileNotFoundException("Child profile lock file not found");
@@ -1328,7 +1319,6 @@
      * {@link com.android.server.SystemServiceManager#unlockUser} </em>
      */
     private void unlockUser(@UserIdInt int userId) {
-        Slogf.i(TAG, "Unlocking user %d", userId);
         // TODO: make this method fully async so we can update UI with progress strings
         final boolean alreadyUnlocked = mUserManager.isUserUnlockingOrUnlocked(userId);
         final CountDownLatch latch = new CountDownLatch(1);
@@ -1638,7 +1628,6 @@
             LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent) {
         Objects.requireNonNull(credential);
         Objects.requireNonNull(savedCredential);
-        if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId);
         synchronized (mSpManager) {
             if (savedCredential.isNone() && isProfileWithUnifiedLock(userId)) {
                 // get credential from keystore when profile has unified lock
@@ -1720,6 +1709,7 @@
         if (passwordHistoryLength == 0) {
             passwordHistory = "";
         } else {
+            Slogf.d(TAG, "Adding new password to password history for user %d", userHandle);
             final byte[] hashFactor = getHashFactor(password, userHandle);
             final byte[] salt = getSalt(userHandle).getBytes();
             String hash = password.passwordToHistoryHash(salt, hashFactor);
@@ -1751,7 +1741,6 @@
         if (salt == 0) {
             salt = SecureRandomUtils.randomLong();
             setLong(LockPatternUtils.LOCK_PASSWORD_SALT_KEY, salt, userId);
-            Slog.v(TAG, "Initialized lock password salt for user: " + userId);
         }
         return Long.toHexString(salt);
     }
@@ -1875,7 +1864,8 @@
     @VisibleForTesting /** Note: this method is overridden in unit tests */
     protected void tieProfileLockToParent(int profileUserId, int parentUserId,
             LockscreenCredential password) {
-        if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + profileUserId);
+        Slogf.i(TAG, "Tying lock for profile user %d to parent user %d", profileUserId,
+                parentUserId);
         final byte[] iv;
         final byte[] ciphertext;
         final long parentSid;
@@ -2002,7 +1992,7 @@
     @Override
     public void resetKeyStore(int userId) {
         checkWritePermission();
-        if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
+        Slogf.d(TAG, "Resetting keystore for user %d", userId);
         List<Integer> profileUserIds = new ArrayList<>();
         List<LockscreenCredential> profileUserDecryptedPasswords = new ArrayList<>();
         final List<UserInfo> profiles = mUserManager.getProfiles(userId);
@@ -2039,7 +2029,6 @@
                 int piUserId = profileUserIds.get(i);
                 LockscreenCredential piUserDecryptedPassword = profileUserDecryptedPasswords.get(i);
                 if (piUserId != -1 && piUserDecryptedPassword != null) {
-                    if (DEBUG) Slog.v(TAG, "Restore tied profile lock");
                     tieProfileLockToParent(piUserId, userId, piUserDecryptedPassword);
                 }
                 if (piUserDecryptedPassword != null) {
@@ -2132,7 +2121,7 @@
             Slog.e(TAG, "FRP credential can only be verified prior to provisioning.");
             return VerifyCredentialResponse.ERROR;
         }
-        Slog.d(TAG, "doVerifyCredential: user=" + userId);
+        Slogf.i(TAG, "Verifying lockscreen credential for user %d", userId);
 
         final AuthenticationResult authResult;
         VerifyCredentialResponse response;
@@ -2166,6 +2155,7 @@
             }
         }
         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
+            Slogf.i(TAG, "Successfully verified lockscreen credential for user %d", userId);
             onCredentialVerified(authResult.syntheticPassword,
                     PasswordMetrics.computeForCredential(credential), userId);
             if ((flags & VERIFY_FLAG_REQUEST_GK_PW_HANDLE) != 0) {
@@ -2324,13 +2314,18 @@
     }
 
     private void removeKeystoreProfileKey(int targetUserId) {
-        Slog.i(TAG, "Remove keystore profile key for user: " + targetUserId);
+        final String encryptAlias = PROFILE_KEY_NAME_ENCRYPT + targetUserId;
+        final String decryptAlias = PROFILE_KEY_NAME_DECRYPT + targetUserId;
         try {
-            mJavaKeyStore.deleteEntry(PROFILE_KEY_NAME_ENCRYPT + targetUserId);
-            mJavaKeyStore.deleteEntry(PROFILE_KEY_NAME_DECRYPT + targetUserId);
+            if (mJavaKeyStore.containsAlias(encryptAlias) ||
+                    mJavaKeyStore.containsAlias(decryptAlias)) {
+                Slogf.i(TAG, "Removing keystore profile key for user %d", targetUserId);
+                mJavaKeyStore.deleteEntry(encryptAlias);
+                mJavaKeyStore.deleteEntry(decryptAlias);
+            }
         } catch (KeyStoreException e) {
-            // We have tried our best to remove all keys
-            Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e);
+            // We have tried our best to remove the key.
+            Slogf.e(TAG, e, "Error removing keystore profile key for user %d", targetUserId);
         }
     }
 
@@ -2678,7 +2673,7 @@
     @VisibleForTesting
     SyntheticPassword initializeSyntheticPassword(int userId) {
         synchronized (mSpManager) {
-            Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId);
+            Slogf.i(TAG, "Initializing synthetic password for user %d", userId);
             Preconditions.checkState(getCurrentLskfBasedProtectorId(userId) ==
                     SyntheticPasswordManager.NULL_PROTECTOR_ID,
                     "Cannot reinitialize SP");
@@ -2689,6 +2684,7 @@
             setCurrentLskfBasedProtectorId(protectorId, userId);
             setUserKeyProtection(userId, sp.deriveFileBasedEncryptionKey());
             onSyntheticPasswordCreated(userId, sp);
+            Slogf.i(TAG, "Successfully initialized synthetic password for user %d", userId);
             return sp;
         }
     }
@@ -2725,8 +2721,11 @@
         final long finalHandle = handle;
         mHandler.postDelayed(() -> {
             synchronized (mGatekeeperPasswords) {
-                Slog.d(TAG, "Removing handle: " + finalHandle);
-                mGatekeeperPasswords.remove(finalHandle);
+                if (mGatekeeperPasswords.get(finalHandle) != null) {
+                    Slogf.d(TAG, "Cached Gatekeeper password with handle %016x has expired",
+                            finalHandle);
+                    mGatekeeperPasswords.remove(finalHandle);
+                }
             }
         }, GK_PW_HANDLE_STORE_DURATION_MS);
 
@@ -2775,7 +2774,8 @@
     @GuardedBy("mSpManager")
     private long setLockCredentialWithSpLocked(LockscreenCredential credential,
             SyntheticPassword sp, int userId) {
-        if (DEBUG) Slog.d(TAG, "setLockCredentialWithSpLocked: user=" + userId);
+        Slogf.i(TAG, "Changing lockscreen credential of user %d; newCredentialType=%s\n",
+                userId, LockPatternUtils.credentialTypeToString(credential.getType()));
         final int savedCredentialType = getCredentialTypeInternal(userId);
         final long oldProtectorId = getCurrentLskfBasedProtectorId(userId);
         final long newProtectorId = mSpManager.createLskfBasedProtector(getGateKeeperService(),
@@ -2820,6 +2820,7 @@
             }
         }
         mSpManager.destroyLskfBasedProtector(oldProtectorId, userId);
+        Slogf.i(TAG, "Successfully changed lockscreen credential of user %d", userId);
         return newProtectorId;
     }
 
@@ -2904,6 +2905,7 @@
     public byte[] getHashFactor(LockscreenCredential currentCredential, int userId) {
         checkPasswordReadPermission();
         try {
+            Slogf.d(TAG, "Getting password history hash factor for user %d", userId);
             if (isProfileWithUnifiedLock(userId)) {
                 try {
                     currentCredential = getDecryptedPasswordForTiedProfile(userId);
@@ -2929,7 +2931,7 @@
 
     private long addEscrowToken(@NonNull byte[] token, @TokenType int type, int userId,
             @NonNull EscrowTokenStateChangeCallback callback) {
-        if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId + ", type=" + type);
+        Slogf.i(TAG, "Adding escrow token for user %d", userId);
         synchronized (mSpManager) {
             // If the user has no LSKF, then the token can be activated immediately.  Otherwise, the
             // token can't be activated until the SP is unlocked by another protector (normally the
@@ -2947,18 +2949,20 @@
             long handle = mSpManager.addPendingToken(token, type, userId, callback);
             if (sp != null) {
                 // Activate the token immediately
+                Slogf.i(TAG, "Immediately activating escrow token %016x", handle);
                 mSpManager.createTokenBasedProtector(handle, sp, userId);
+            } else {
+                Slogf.i(TAG, "Escrow token %016x will be activated when user is unlocked", handle);
             }
             return handle;
         }
     }
 
     private void activateEscrowTokens(SyntheticPassword sp, int userId) {
-        if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId);
         synchronized (mSpManager) {
             disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
             for (long handle : mSpManager.getPendingTokensForUser(userId)) {
-                Slog.i(TAG, TextUtils.formatSimple("activateEscrowTokens: %x %d ", handle, userId));
+                Slogf.i(TAG, "Activating escrow token %016x for user %d", handle, userId);
                 mSpManager.createTokenBasedProtector(handle, sp, userId);
             }
         }
@@ -3029,6 +3033,8 @@
     @GuardedBy("mSpManager")
     private boolean setLockCredentialWithTokenInternalLocked(LockscreenCredential credential,
             long tokenHandle, byte[] token, int userId) {
+        Slogf.i(TAG, "Resetting lockscreen credential of user %d using escrow token %016x",
+                userId, tokenHandle);
         final AuthenticationResult result;
         result = mSpManager.unlockTokenBasedProtector(getGateKeeperService(), tokenHandle, token,
                     userId);
@@ -3051,8 +3057,9 @@
     private boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
         AuthenticationResult authResult;
         synchronized (mSpManager) {
+            Slogf.i(TAG, "Unlocking user %d using escrow token %016x", userId, tokenHandle);
             if (!mSpManager.hasEscrowData(userId)) {
-                Slog.w(TAG, "Escrow token is disabled on the current user");
+                Slogf.w(TAG, "Escrow token support is disabled on user %d", userId);
                 return false;
             }
             authResult = mSpManager.unlockTokenBasedProtector(getGateKeeperService(), tokenHandle,
@@ -3063,6 +3070,7 @@
             }
         }
 
+        Slogf.i(TAG, "Unlocked synthetic password for user %d using escrow token", userId);
         onCredentialVerified(authResult.syntheticPassword,
                 loadPasswordMetrics(authResult.syntheticPassword, userId), userId);
         return true;
@@ -3090,21 +3098,6 @@
         return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(timestamp));
     }
 
-    private static String credentialTypeToString(int credentialType) {
-        switch (credentialType) {
-            case CREDENTIAL_TYPE_NONE:
-                return "None";
-            case CREDENTIAL_TYPE_PATTERN:
-                return "Pattern";
-            case CREDENTIAL_TYPE_PIN:
-                return "Pin";
-            case CREDENTIAL_TYPE_PASSWORD:
-                return "Password";
-            default:
-                return "Unknown " + credentialType;
-        }
-    }
-
     @Override
     protected void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, printWriter)) return;
@@ -3121,22 +3114,23 @@
             pw.println("User " + userId);
             pw.increaseIndent();
             synchronized (mSpManager) {
-                pw.println(TextUtils.formatSimple("LSKF-based SP protector ID: %x",
+                pw.println(TextUtils.formatSimple("LSKF-based SP protector ID: %016x",
                         getCurrentLskfBasedProtectorId(userId)));
-                pw.println(TextUtils.formatSimple("LSKF last changed: %s (previous protector: %x)",
-                        timestampToString(getLong(LSKF_LAST_CHANGED_TIME_KEY, 0, userId)),
-                        getLong(PREV_LSKF_BASED_PROTECTOR_ID_KEY, 0, userId)));
+                pw.println(TextUtils.formatSimple(
+                            "LSKF last changed: %s (previous protector: %016x)",
+                            timestampToString(getLong(LSKF_LAST_CHANGED_TIME_KEY, 0, userId)),
+                            getLong(PREV_LSKF_BASED_PROTECTOR_ID_KEY, 0, userId)));
             }
             try {
-                pw.println(TextUtils.formatSimple("SID: %x",
+                pw.println(TextUtils.formatSimple("SID: %016x",
                         getGateKeeperService().getSecureUserId(userId)));
             } catch (RemoteException e) {
                 // ignore.
             }
-            // It's OK to dump the password type since anyone with physical access can just
+            // It's OK to dump the credential type since anyone with physical access can just
             // observe it from the keyguard directly.
             pw.println("Quality: " + getKeyguardStoredQuality(userId));
-            pw.println("CredentialType: " + credentialTypeToString(
+            pw.println("CredentialType: " + LockPatternUtils.credentialTypeToString(
                     getCredentialTypeInternal(userId)));
             pw.println("SeparateChallenge: " + getSeparateProfileChallengeEnabledInternal(userId));
             pw.println(TextUtils.formatSimple("Metrics: %s",
@@ -3194,6 +3188,11 @@
      * if we are running an automotive build.
      */
     private void disableEscrowTokenOnNonManagedDevicesIfNeeded(int userId) {
+
+        if (!mSpManager.hasAnyEscrowData(userId)) {
+            return;
+        }
+
         // TODO(b/258213147): Remove
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -3238,7 +3237,7 @@
         }
 
         // Disable escrow token permanently on all other device/user types.
-        Slog.i(TAG, "Disabling escrow token on user " + userId);
+        Slogf.i(TAG, "Permanently disabling support for escrow tokens on user %d", userId);
         mSpManager.destroyEscrowData(userId);
     }
 
@@ -3470,6 +3469,7 @@
             synchronized (mSpManager) {
                 mSpManager.verifyChallenge(getGateKeeperService(), sp, 0L, userId);
             }
+            Slogf.i(TAG, "Restored synthetic password for user %d using reboot escrow", userId);
             onCredentialVerified(sp, loadPasswordMetrics(sp, userId), userId);
         }
     }
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index d070b41..1663b01 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -744,6 +744,11 @@
                 && hasState(SP_P1_NAME, NULL_PROTECTOR_ID, userId);
     }
 
+    public boolean hasAnyEscrowData(int userId) {
+        return hasState(SP_E0_NAME, NULL_PROTECTOR_ID, userId)
+                || hasState(SP_P1_NAME, NULL_PROTECTOR_ID, userId);
+    }
+
     public void destroyEscrowData(int userId) {
         destroyState(SP_E0_NAME, NULL_PROTECTOR_ID, userId);
         destroyState(SP_P1_NAME, NULL_PROTECTOR_ID, userId);
@@ -786,11 +791,11 @@
             }
             Set<Integer> usedSlots = getUsedWeaverSlots();
             if (!usedSlots.contains(slot)) {
-                Slog.i(TAG, "Destroy weaver slot " + slot + " for user " + userId);
+                Slogf.i(TAG, "Erasing Weaver slot %d", slot);
                 weaverEnroll(slot, null, null);
                 mPasswordSlotManager.markSlotDeleted(slot);
             } else {
-                Slog.w(TAG, "Skip destroying reused weaver slot " + slot + " for user " + userId);
+                Slogf.i(TAG, "Weaver slot %d was already reused; not erasing it", slot);
             }
         }
     }
@@ -858,11 +863,13 @@
         long sid = GateKeeper.INVALID_SECURE_USER_ID;
         final byte[] protectorSecret;
 
+        Slogf.i(TAG, "Creating LSKF-based protector %016x for user %d", protectorId, userId);
+
         if (isWeaverAvailable()) {
             // Weaver is available, so make the protector use it to verify the LSKF.  Do this even
             // if the LSKF is empty, as that gives us support for securely deleting the protector.
             int weaverSlot = getNextAvailableWeaverSlot();
-            Slog.i(TAG, "Weaver enroll password to slot " + weaverSlot + " for user " + userId);
+            Slogf.i(TAG, "Enrolling LSKF for user %d into Weaver slot %d", userId, weaverSlot);
             byte[] weaverSecret = weaverEnroll(weaverSlot, stretchedLskfToWeaverKey(stretchedLskf),
                     null);
             if (weaverSecret == null) {
@@ -892,6 +899,7 @@
                 } catch (RemoteException ignore) {
                     Slog.w(TAG, "Failed to clear SID from gatekeeper");
                 }
+                Slogf.i(TAG, "Enrolling LSKF for user %d into Gatekeeper", userId);
                 GateKeeperResponse response;
                 try {
                     response = gatekeeper.enroll(fakeUserId(userId), null, null,
@@ -964,6 +972,7 @@
                 && LockPatternUtils.userOwnsFrpCredential(mContext, userInfo)
                 && getCredentialType(protectorId, userInfo.id) !=
                         LockPatternUtils.CREDENTIAL_TYPE_NONE) {
+            Slog.i(TAG, "Migrating FRP credential to persistent data block");
             PasswordData pwd = PasswordData.fromBytes(loadState(PASSWORD_DATA_NAME, protectorId,
                     userInfo.id));
             int weaverSlot = loadWeaverSlot(protectorId, userInfo.id);
@@ -1092,9 +1101,10 @@
             Slog.w(TAG, "User is not escrowable");
             return false;
         }
+        Slogf.i(TAG, "Creating token-based protector %016x for user %d", tokenHandle, userId);
         if (isWeaverAvailable()) {
             int slot = getNextAvailableWeaverSlot();
-            Slog.i(TAG, "Weaver enroll token to slot " + slot + " for user " + userId);
+            Slogf.i(TAG, "Using Weaver slot %d for new token-based protector", slot);
             if (weaverEnroll(slot, null, tokenData.weaverSecret) == null) {
                 Slog.e(TAG, "Failed to enroll weaver secret when activating token");
                 return false;
@@ -1170,8 +1180,9 @@
             storedType = pwd.credentialType;
         }
         if (!credential.checkAgainstStoredType(storedType)) {
-            Slog.e(TAG, TextUtils.formatSimple("Credential type mismatch: expected %d actual %d",
-                    storedType, credential.getType()));
+            Slogf.e(TAG, "Credential type mismatch: stored type is %s but provided type is %s",
+                    LockPatternUtils.credentialTypeToString(storedType),
+                    LockPatternUtils.credentialTypeToString(credential.getType()));
             result.gkResponse = VerifyCredentialResponse.ERROR;
             return result;
         }
@@ -1473,6 +1484,7 @@
 
     /** Destroy a token-based SP protector. */
     public void destroyTokenBasedProtector(long protectorId, int userId) {
+        Slogf.i(TAG, "Destroying token-based protector %016x for user %d", protectorId, userId);
         SyntheticPasswordBlob blob = SyntheticPasswordBlob.fromBytes(loadState(SP_BLOB_NAME,
                     protectorId, userId));
         destroyProtectorCommon(protectorId, userId);
@@ -1498,6 +1510,7 @@
      * Destroy an LSKF-based SP protector.  This is used when the user's LSKF is changed.
      */
     public void destroyLskfBasedProtector(long protectorId, int userId) {
+        Slogf.i(TAG, "Destroying LSKF-based protector %016x for user %d", protectorId, userId);
         destroyProtectorCommon(protectorId, userId);
         destroyState(PASSWORD_DATA_NAME, protectorId, userId);
         destroyState(PASSWORD_METRICS_NAME, protectorId, userId);
@@ -1658,6 +1671,9 @@
     }
 
     private String getProtectorKeyAlias(long protectorId) {
+        // Note, this arguably has a bug: %x should be %016x so that the protector ID is left-padded
+        // with zeroes, like how the synthetic password state files are named.  It's too late to fix
+        // this, though, and it doesn't actually matter.
         return TextUtils.formatSimple("%s%x", PROTECTOR_KEY_ALIAS_PREFIX, protectorId);
     }
 
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 638e81a..6619e6c 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -60,7 +60,7 @@
     private final UserHandle mUser;
 
     private final DeviceRouteController mDeviceRouteController;
-    private final BluetoothRouteController mBtRouteProvider;
+    private final BluetoothRouteController mBluetoothRouteController;
 
     private String mSelectedRouteId;
     // For apps without MODIFYING_AUDIO_ROUTING permission.
@@ -84,7 +84,7 @@
 
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
 
-        mBtRouteProvider = BluetoothRouteController.createInstance(context, (routes) -> {
+        mBluetoothRouteController = BluetoothRouteController.createInstance(context, (routes) -> {
             publishProviderState();
             if (updateSessionInfosIfNeeded()) {
                 notifySessionInfoUpdated();
@@ -113,7 +113,7 @@
                 intentFilter, null, null);
 
         mHandler.post(() -> {
-            mBtRouteProvider.start(mUser);
+            mBluetoothRouteController.start(mUser);
             notifyProviderState();
         });
         updateVolume();
@@ -122,7 +122,7 @@
     public void stop() {
         mContext.unregisterReceiver(mAudioReceiver);
         mHandler.post(() -> {
-            mBtRouteProvider.stop();
+            mBluetoothRouteController.stop();
             notifyProviderState();
         });
     }
@@ -189,9 +189,9 @@
 
         MediaRoute2Info deviceRoute = mDeviceRouteController.getDeviceRoute();
         if (TextUtils.equals(routeId, deviceRoute.getId())) {
-            mBtRouteProvider.transferTo(null);
+            mBluetoothRouteController.transferTo(null);
         } else {
-            mBtRouteProvider.transferTo(routeId);
+            mBluetoothRouteController.transferTo(routeId);
         }
     }
 
@@ -232,7 +232,7 @@
             RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder(
                     SYSTEM_SESSION_ID, packageName).setSystemSession(true);
             builder.addSelectedRoute(deviceRoute.getId());
-            for (MediaRoute2Info route : mBtRouteProvider.getAllBluetoothRoutes()) {
+            for (MediaRoute2Info route : mBluetoothRouteController.getAllBluetoothRoutes()) {
                 builder.addTransferableRoute(route.getId());
             }
             return builder.setProviderId(mUniqueId).build();
@@ -245,7 +245,7 @@
         // We must have a device route in the provider info.
         builder.addRoute(mDeviceRouteController.getDeviceRoute());
 
-        for (MediaRoute2Info route : mBtRouteProvider.getAllBluetoothRoutes()) {
+        for (MediaRoute2Info route : mBluetoothRouteController.getAllBluetoothRoutes()) {
             builder.addRoute(route);
         }
         MediaRoute2ProviderInfo providerInfo = builder.build();
@@ -269,7 +269,7 @@
 
             MediaRoute2Info deviceRoute = mDeviceRouteController.getDeviceRoute();
             MediaRoute2Info selectedRoute = deviceRoute;
-            MediaRoute2Info selectedBtRoute = mBtRouteProvider.getSelectedRoute();
+            MediaRoute2Info selectedBtRoute = mBluetoothRouteController.getSelectedRoute();
             if (selectedBtRoute != null) {
                 selectedRoute = selectedBtRoute;
                 builder.addTransferableRoute(deviceRoute.getId());
@@ -281,7 +281,7 @@
                     .build();
             builder.addSelectedRoute(mSelectedRouteId);
 
-            for (MediaRoute2Info route : mBtRouteProvider.getTransferableRoutes()) {
+            for (MediaRoute2Info route : mBluetoothRouteController.getTransferableRoutes()) {
                 builder.addTransferableRoute(route.getId());
             }
 
@@ -361,7 +361,7 @@
                     .build();
         }
 
-        if (mBtRouteProvider.updateVolumeForDevices(devices, volume)) {
+        if (mBluetoothRouteController.updateVolumeForDevices(devices, volume)) {
             return;
         }
 
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index c63cddd..59af58f 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -862,11 +862,11 @@
             if (r == null) {
                 throw new IllegalArgumentException("Invalid package");
             }
+            if (r.groups.size() >= NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT) {
+                throw new IllegalStateException("Limit exceed; cannot create more groups");
+            }
             if (fromTargetApp) {
                 group.setBlocked(false);
-                if (r.groups.size() >= NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT) {
-                    throw new IllegalStateException("Limit exceed; cannot create more groups");
-                }
             }
             final NotificationChannelGroup oldGroup = r.groups.get(group.getId());
             if (oldGroup != null) {
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index a868470..7fe6c7d 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -164,6 +164,7 @@
 import com.android.server.EventLogTags;
 import com.android.server.LocalManagerRegistry;
 import com.android.server.art.model.DexoptParams;
+import com.android.server.art.model.DexoptResult;
 import com.android.server.pm.Installer.LegacyDexoptDisabledException;
 import com.android.server.pm.dex.ArtManagerService;
 import com.android.server.pm.dex.DexManager;
@@ -2534,8 +2535,9 @@
                                     packageManagerLocal.withFilteredSnapshot()) {
                         DexoptParams params =
                                 dexoptOptions.convertToDexoptParams(0 /* extraFlags */);
-                        DexOptHelper.getArtManagerLocal().dexoptPackage(
+                        DexoptResult dexOptResult = DexOptHelper.getArtManagerLocal().dexoptPackage(
                                 snapshot, packageName, params);
+                        installRequest.onDexoptFinished(dexOptResult);
                     }
                 } else {
                     try {
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 46ea010..95e7904 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -43,6 +43,7 @@
 import android.util.ExceptionUtils;
 import android.util.Slog;
 
+import com.android.server.art.model.DexoptResult;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageState;
@@ -127,6 +128,8 @@
     private final int mSessionId;
     private final int mRequireUserAction;
 
+    private int mDexoptStatus;
+
     // New install
     InstallRequest(InstallingSession params) {
         mUserId = params.getUser().getIdentifier();
@@ -609,6 +612,10 @@
         return mRequireUserAction;
     }
 
+    public int getDexoptStatus() {
+        return mDexoptStatus;
+    }
+
     public void setScanFlags(int scanFlags) {
         mScanFlags = scanFlags;
     }
@@ -799,6 +806,25 @@
         }
     }
 
+    public void onDexoptFinished(DexoptResult dexoptResult) {
+        if (mPackageMetrics == null) {
+            return;
+        }
+        mDexoptStatus = dexoptResult.getFinalStatus();
+        if (mDexoptStatus != DexoptResult.DEXOPT_PERFORMED) {
+            return;
+        }
+        long durationMillis = 0;
+        for (DexoptResult.PackageDexoptResult packageResult :
+                dexoptResult.getPackageDexoptResults()) {
+            for (DexoptResult.DexContainerFileDexoptResult fileResult :
+                    packageResult.getDexContainerFileDexoptResults()) {
+                durationMillis += fileResult.getDex2oatWallTimeMillis();
+            }
+        }
+        mPackageMetrics.onStepFinished(PackageMetrics.STEP_DEXOPT, durationMillis);
+    }
+
     public void onInstallCompleted() {
         if (getReturnCode() == INSTALL_SUCCEEDED) {
             if (mPackageMetrics != null) {
diff --git a/services/core/java/com/android/server/pm/PackageMetrics.java b/services/core/java/com/android/server/pm/PackageMetrics.java
index fe014a4..80d6ebb 100644
--- a/services/core/java/com/android/server/pm/PackageMetrics.java
+++ b/services/core/java/com/android/server/pm/PackageMetrics.java
@@ -48,12 +48,14 @@
     public static final int STEP_SCAN = 2;
     public static final int STEP_RECONCILE = 3;
     public static final int STEP_COMMIT = 4;
+    public static final int STEP_DEXOPT = 5;
 
     @IntDef(prefix = {"STEP_"}, value = {
             STEP_PREPARE,
             STEP_SCAN,
             STEP_RECONCILE,
             STEP_COMMIT,
+            STEP_DEXOPT
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface StepInt {
@@ -175,6 +177,10 @@
         }
     }
 
+    public void onStepFinished(@StepInt int step, long durationMillis) {
+        mInstallSteps.put(step, new InstallStep(durationMillis));
+    }
+
     // List of steps (e.g., 1, 2, 3) and corresponding list of durations (e.g., 200ms, 100ms, 150ms)
     private Pair<int[], long[]> getInstallStepDurations() {
         ArrayList<Integer> steps = new ArrayList<>();
@@ -203,6 +209,11 @@
             mStartTimestampMillis = System.currentTimeMillis();
         }
 
+        InstallStep(long durationMillis) {
+            mStartTimestampMillis = -1;
+            mDurationMillis = durationMillis;
+        }
+
         void finish() {
             mDurationMillis = System.currentTimeMillis() - mStartTimestampMillis;
         }
diff --git a/services/core/java/com/android/server/pm/ResilientAtomicFile.java b/services/core/java/com/android/server/pm/ResilientAtomicFile.java
new file mode 100644
index 0000000..19aa4f8
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ResilientAtomicFile.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.server.security.FileIntegrity;
+
+import libcore.io.IoUtils;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+final class ResilientAtomicFile implements Closeable {
+    private static final String LOG_TAG = "ResilientAtomicFile";
+
+    private final File mFile;
+
+    private final File mTemporaryBackup;
+
+    private final File mReserveCopy;
+
+    private final int mFileMode;
+
+    private final String mDebugName;
+
+    private final ReadEventLogger mReadEventLogger;
+
+    // Write state.
+    private FileOutputStream mMainOutStream = null;
+    private FileInputStream mMainInStream = null;
+    private FileOutputStream mReserveOutStream = null;
+    private FileInputStream mReserveInStream = null;
+
+    // Read state.
+    private File mCurrentFile = null;
+    private FileInputStream mCurrentInStream = null;
+
+    private void finalizeOutStream(FileOutputStream str) throws IOException {
+        // Flash/sync + set permissions.
+        str.flush();
+        FileUtils.sync(str);
+        FileUtils.setPermissions(str.getFD(), mFileMode, -1, -1);
+    }
+
+    ResilientAtomicFile(@NonNull File file, @NonNull File temporaryBackup,
+            @NonNull File reserveCopy, int fileMode, String debugName,
+            @Nullable ReadEventLogger readEventLogger) {
+        mFile = file;
+        mTemporaryBackup = temporaryBackup;
+        mReserveCopy = reserveCopy;
+        mFileMode = fileMode;
+        mDebugName = debugName;
+        mReadEventLogger = readEventLogger;
+    }
+
+    public File getBaseFile() {
+        return mFile;
+    }
+
+    public FileOutputStream startWrite() throws IOException {
+        if (mMainOutStream != null) {
+            throw new IllegalStateException("Duplicate startWrite call?");
+        }
+
+        new File(mFile.getParent()).mkdirs();
+
+        if (mFile.exists()) {
+            // Presence of backup settings file indicates that we failed
+            // to persist packages earlier. So preserve the older
+            // backup for future reference since the current packages
+            // might have been corrupted.
+            if (!mTemporaryBackup.exists()) {
+                if (!mFile.renameTo(mTemporaryBackup)) {
+                    throw new IOException("Unable to backup " + mDebugName
+                            + " file, current changes will be lost at reboot");
+                }
+            } else {
+                mFile.delete();
+                Slog.w(LOG_TAG, "Preserving older " + mDebugName + " backup");
+            }
+        }
+        // Reserve copy is not valid anymore.
+        mReserveCopy.delete();
+
+        // In case of MT access, it's possible the files get overwritten during write.
+        // Let's open all FDs we need now.
+        mMainOutStream = new FileOutputStream(mFile);
+        mMainInStream = new FileInputStream(mFile);
+        mReserveOutStream = new FileOutputStream(mReserveCopy);
+        mReserveInStream = new FileInputStream(mReserveCopy);
+
+        return mMainOutStream;
+    }
+
+    public void finishWrite(FileOutputStream str) throws IOException {
+        if (mMainOutStream != str) {
+            throw new IllegalStateException("Invalid incoming stream.");
+        }
+
+        // Flush and set permissions.
+        try (FileOutputStream mainOutStream = mMainOutStream) {
+            mMainOutStream = null;
+            finalizeOutStream(mainOutStream);
+        }
+        // New file successfully written, old one are no longer needed.
+        mTemporaryBackup.delete();
+
+        try (FileInputStream mainInStream = mMainInStream;
+             FileInputStream reserveInStream = mReserveInStream) {
+            mMainInStream = null;
+            mReserveInStream = null;
+
+            // Copy main file to reserve.
+            try (FileOutputStream reserveOutStream = mReserveOutStream) {
+                mReserveOutStream = null;
+                FileUtils.copy(mainInStream, reserveOutStream);
+                finalizeOutStream(reserveOutStream);
+            }
+
+            // Protect both main and reserve using fs-verity.
+            try (ParcelFileDescriptor mainPfd = ParcelFileDescriptor.dup(mainInStream.getFD());
+                 ParcelFileDescriptor copyPfd = ParcelFileDescriptor.dup(reserveInStream.getFD())) {
+                FileIntegrity.setUpFsVerity(mainPfd);
+                FileIntegrity.setUpFsVerity(copyPfd);
+            } catch (IOException e) {
+                Slog.e(LOG_TAG, "Failed to verity-protect " + mDebugName, e);
+            }
+        } catch (IOException e) {
+            Slog.e(LOG_TAG, "Failed to write reserve copy " + mDebugName + ": " + mReserveCopy, e);
+        }
+    }
+
+    public void failWrite(FileOutputStream str) {
+        if (mMainOutStream != str) {
+            throw new IllegalStateException("Invalid incoming stream.");
+        }
+
+        // Close all FDs.
+        close();
+
+        // Clean up partially written files
+        if (mFile.exists()) {
+            if (!mFile.delete()) {
+                Slog.i(LOG_TAG, "Failed to clean up mangled file: " + mFile);
+            }
+        }
+    }
+
+    public FileInputStream openRead() throws IOException {
+        if (mTemporaryBackup.exists()) {
+            try {
+                mCurrentFile = mTemporaryBackup;
+                mCurrentInStream = new FileInputStream(mCurrentFile);
+                if (mReadEventLogger != null) {
+                    mReadEventLogger.logEvent(Log.INFO,
+                            "Need to read from backup " + mDebugName + " file");
+                }
+                if (mFile.exists()) {
+                    // If both the backup and normal file exist, we
+                    // ignore the normal one since it might have been
+                    // corrupted.
+                    Slog.w(LOG_TAG, "Cleaning up " + mDebugName + " file " + mFile);
+                    mFile.delete();
+                }
+                // Ignore reserve copy as well.
+                mReserveCopy.delete();
+            } catch (java.io.IOException e) {
+                // We'll try for the normal settings file.
+            }
+        }
+
+        if (mCurrentInStream != null) {
+            return mCurrentInStream;
+        }
+
+        if (mFile.exists()) {
+            mCurrentFile = mFile;
+            mCurrentInStream = new FileInputStream(mCurrentFile);
+        } else if (mReserveCopy.exists()) {
+            mCurrentFile = mReserveCopy;
+            mCurrentInStream = new FileInputStream(mCurrentFile);
+            if (mReadEventLogger != null) {
+                mReadEventLogger.logEvent(Log.INFO,
+                        "Need to read from reserve copy " + mDebugName + " file");
+            }
+        }
+
+        if (mCurrentInStream == null) {
+            if (mReadEventLogger != null) {
+                mReadEventLogger.logEvent(Log.INFO, "No " + mDebugName + " file");
+            }
+        }
+
+        return mCurrentInStream;
+    }
+
+    public void failRead(FileInputStream str, Exception e) {
+        if (mCurrentInStream != str) {
+            throw new IllegalStateException("Invalid incoming stream.");
+        }
+        mCurrentInStream = null;
+        IoUtils.closeQuietly(str);
+
+        if (mReadEventLogger != null) {
+            mReadEventLogger.logEvent(Log.ERROR,
+                    "Error reading " + mDebugName + ", removing " + mCurrentFile + '\n'
+                            + Log.getStackTraceString(e));
+        }
+
+        mCurrentFile.delete();
+        mCurrentFile = null;
+    }
+
+    public void delete() {
+        mFile.delete();
+        mTemporaryBackup.delete();
+        mReserveCopy.delete();
+    }
+
+    @Override
+    public void close() {
+        IoUtils.closeQuietly(mMainOutStream);
+        IoUtils.closeQuietly(mMainInStream);
+        IoUtils.closeQuietly(mReserveOutStream);
+        IoUtils.closeQuietly(mReserveInStream);
+        IoUtils.closeQuietly(mCurrentInStream);
+        mMainOutStream = null;
+        mMainInStream = null;
+        mReserveOutStream = null;
+        mReserveInStream = null;
+        mCurrentInStream = null;
+        mCurrentFile = null;
+    }
+
+    public String toString() {
+        return mFile.getPath();
+    }
+
+    interface ReadEventLogger {
+        void logEvent(int priority, String msg);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 2658d31..b6557d0 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -119,7 +119,6 @@
 import com.android.server.pm.verify.domain.DomainVerificationLegacySettings;
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
 import com.android.server.pm.verify.domain.DomainVerificationPersistence;
-import com.android.server.security.FileIntegrity;
 import com.android.server.utils.Slogf;
 import com.android.server.utils.Snappable;
 import com.android.server.utils.SnapshotCache;
@@ -172,7 +171,7 @@
 /**
  * Holds information about dynamic settings.
  */
-public final class Settings implements Watchable, Snappable {
+public final class Settings implements Watchable, Snappable, ResilientAtomicFile.ReadEventLogger {
     private static final String TAG = "PackageSettings";
 
     /**
@@ -344,7 +343,7 @@
     private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall";
     private static final String ATTR_ENABLED = "enabled";
     private static final String ATTR_ENABLED_CALLER = "enabledCaller";
-    private static final String ATTR_DOMAIN_VERIFICATON_STATE = "domainVerificationStatus";
+    private static final String ATTR_DOMAIN_VERIFICATION_STATE = "domainVerificationStatus";
     private static final String ATTR_APP_LINK_GENERATION = "app-link-generation";
     private static final String ATTR_INSTALL_REASON = "install-reason";
     private static final String ATTR_UNINSTALL_REASON = "uninstall-reason";
@@ -1511,16 +1510,22 @@
         return new File(new File(mSystemDir, "users"), Integer.toString(userId));
     }
 
-    // The method itself does not have to be guarded, but the file does.
-    @GuardedBy("mPackageRestrictionsLock")
-    private File getUserPackagesStateFile(int userId) {
-        return new File(getUserSystemDirectory(userId), "package-restrictions.xml");
+    private ResilientAtomicFile getUserPackagesStateFile(int userId) {
+        File mainFile = new File(getUserSystemDirectory(userId), "package-restrictions.xml");
+        File temporaryBackup = new File(getUserSystemDirectory(userId),
+                "package-restrictions-backup.xml");
+        File reserveCopy = new File(getUserSystemDirectory(userId),
+                "package-restrictions.xml.reservecopy");
+        return new ResilientAtomicFile(mainFile, temporaryBackup, reserveCopy,
+                FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
+                "package restrictions", this);
     }
 
-    // The method itself does not have to be guarded, but the file does.
-    @GuardedBy("mPackageRestrictionsLock")
-    private File getUserPackagesStateBackupFile(int userId) {
-        return new File(getUserSystemDirectory(userId), "package-restrictions-backup.xml");
+    private ResilientAtomicFile getSettingsFile() {
+        return new ResilientAtomicFile(mSettingsFilename, mPreviousSettingsFilename,
+                mSettingsReserveCopyFilename,
+                FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
+                "package manager settings", this);
     }
 
     private File getUserRuntimePermissionsFile(int userId) {
@@ -1730,272 +1735,243 @@
         }
     }
 
+    @Override
+    public void logEvent(int priority, String msg) {
+        mReadMessages.append(msg + "\n");
+        PackageManagerService.reportSettingsProblem(priority, msg);
+    }
+
+
     void readPackageRestrictionsLPr(int userId,
             @NonNull ArrayMap<String, Long> origFirstInstallTimes) {
         if (DEBUG_MU) {
             Log.i(TAG, "Reading package restrictions for user=" + userId);
         }
-        FileInputStream str = null;
 
-        synchronized (mPackageRestrictionsLock) {
-            File userPackagesStateFile = getUserPackagesStateFile(userId);
-            File backupFile = getUserPackagesStateBackupFile(userId);
-            if (backupFile.exists()) {
-                try {
-                    str = new FileInputStream(backupFile);
-                    mReadMessages.append("Reading from backup stopped packages file\n");
-                    PackageManagerService.reportSettingsProblem(Log.INFO,
-                            "Need to read from backup stopped packages file");
-                    if (userPackagesStateFile.exists()) {
-                        // If both the backup and normal file exist, we
-                        // ignore the normal one since it might have been
-                        // corrupted.
-                        Slog.w(PackageManagerService.TAG, "Cleaning up stopped packages file "
-                                + userPackagesStateFile);
-                        userPackagesStateFile.delete();
+        try (ResilientAtomicFile atomicFile = getUserPackagesStateFile(userId)) {
+            FileInputStream str = null;
+            try {
+                synchronized (mPackageRestrictionsLock) {
+                    str = atomicFile.openRead();
+                    if (str == null) {
+                        // At first boot, make sure no packages are stopped.
+                        // We usually want to have third party apps initialize
+                        // in the stopped state, but not at first boot.  Also
+                        // consider all applications to be installed.
+                        for (PackageSetting pkg : mPackages.values()) {
+                            pkg.setUserState(userId, 0, COMPONENT_ENABLED_STATE_DEFAULT,
+                                    true  /*installed*/,
+                                    false /*stopped*/,
+                                    false /*notLaunched*/,
+                                    false /*hidden*/,
+                                    0 /*distractionFlags*/,
+                                    null /*suspendParams*/,
+                                    false /*instantApp*/,
+                                    false /*virtualPreload*/,
+                                    null /*lastDisableAppCaller*/,
+                                    null /*enabledComponents*/,
+                                    null /*disabledComponents*/,
+                                    PackageManager.INSTALL_REASON_UNKNOWN,
+                                    PackageManager.UNINSTALL_REASON_UNKNOWN,
+                                    null /*harmfulAppWarning*/,
+                                    null /* splashScreenTheme*/,
+                                    0 /*firstInstallTime*/
+                            );
+                        }
+                        return;
                     }
-                } catch (java.io.IOException e) {
-                    // We'll try for the normal settings file.
-                }
-            }
-
-            if (str == null && userPackagesStateFile.exists()) {
-                try {
-                    str = new FileInputStream(userPackagesStateFile);
-                    if (DEBUG_MU) Log.i(TAG, "Reading " + userPackagesStateFile);
-                } catch (java.io.IOException e) {
-                    mReadMessages.append("Error reading: " + e.toString());
-                    PackageManagerService.reportSettingsProblem(Log.ERROR,
-                            "Error reading settings: " + e);
-                    Slog.wtf(TAG, "Error reading package manager stopped packages", e);
-                }
-            }
-        }
-
-        if (str == null) {
-            mReadMessages.append("No stopped packages file found\n");
-            PackageManagerService.reportSettingsProblem(Log.INFO,
-                    "No stopped packages file; "
-                            + "assuming all started");
-            // At first boot, make sure no packages are stopped.
-            // We usually want to have third party apps initialize
-            // in the stopped state, but not at first boot.  Also
-            // consider all applications to be installed.
-            for (PackageSetting pkg : mPackages.values()) {
-                pkg.setUserState(userId, 0, COMPONENT_ENABLED_STATE_DEFAULT,
-                        true  /*installed*/,
-                        false /*stopped*/,
-                        false /*notLaunched*/,
-                        false /*hidden*/,
-                        0 /*distractionFlags*/,
-                        null /*suspendParams*/,
-                        false /*instantApp*/,
-                        false /*virtualPreload*/,
-                        null /*lastDisableAppCaller*/,
-                        null /*enabledComponents*/,
-                        null /*disabledComponents*/,
-                        PackageManager.INSTALL_REASON_UNKNOWN,
-                        PackageManager.UNINSTALL_REASON_UNKNOWN,
-                        null /*harmfulAppWarning*/,
-                        null /* splashScreenTheme*/,
-                        0 /*firstInstallTime*/
-                );
-            }
-            return;
-        }
-
-        try {
-            final TypedXmlPullParser parser = Xml.resolvePullParser(str);
-
-            int type;
-            while ((type=parser.next()) != XmlPullParser.START_TAG
-                       && type != XmlPullParser.END_DOCUMENT) {
-                ;
-            }
-
-            if (type != XmlPullParser.START_TAG) {
-                mReadMessages.append("No start tag found in package restrictions file\n");
-                PackageManagerService.reportSettingsProblem(Log.WARN,
-                        "No start tag found in package manager stopped packages");
-                return;
-            }
-
-            int outerDepth = parser.getDepth();
-            PackageSetting ps = null;
-            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
-                   && (type != XmlPullParser.END_TAG
-                           || parser.getDepth() > outerDepth)) {
-                if (type == XmlPullParser.END_TAG
-                        || type == XmlPullParser.TEXT) {
-                    continue;
                 }
 
-                String tagName = parser.getName();
-                if (tagName.equals(TAG_PACKAGE)) {
-                    String name = parser.getAttributeValue(null, ATTR_NAME);
-                    ps = mPackages.get(name);
-                    if (ps == null) {
-                        Slog.w(PackageManagerService.TAG, "No package known for stopped package "
-                                + name);
-                        XmlUtils.skipCurrentTag(parser);
+                final TypedXmlPullParser parser = Xml.resolvePullParser(str);
+
+                int type;
+                while ((type = parser.next()) != XmlPullParser.START_TAG
+                        && type != XmlPullParser.END_DOCUMENT) {
+                    // nothing
+                }
+
+                if (type != XmlPullParser.START_TAG) {
+                    mReadMessages.append("No start tag found in package restrictions file\n");
+                    PackageManagerService.reportSettingsProblem(Log.WARN,
+                            "No start tag found in package manager package restrictions file");
+                    return;
+                }
+
+                int outerDepth = parser.getDepth();
+                PackageSetting ps = null;
+                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                        && (type != XmlPullParser.END_TAG
+                        || parser.getDepth() > outerDepth)) {
+                    if (type == XmlPullParser.END_TAG
+                            || type == XmlPullParser.TEXT) {
                         continue;
                     }
 
-                    final long ceDataInode =
-                            parser.getAttributeLong(null, ATTR_CE_DATA_INODE, 0);
-                    final boolean installed =
-                            parser.getAttributeBoolean(null, ATTR_INSTALLED, true);
-                    final boolean stopped =
-                            parser.getAttributeBoolean(null, ATTR_STOPPED, false);
-                    final boolean notLaunched =
-                            parser.getAttributeBoolean(null, ATTR_NOT_LAUNCHED, false);
-
-                    // For backwards compatibility with the previous name of "blocked", which
-                    // now means hidden, read the old attribute as well.
-                    boolean hidden = parser.getAttributeBoolean(null, ATTR_HIDDEN, false);
-                    if (!hidden) {
-                        hidden = parser.getAttributeBoolean(null, ATTR_BLOCKED, false);
-                    }
-
-                    final int distractionFlags = parser.getAttributeInt(null, ATTR_DISTRACTION_FLAGS, 0);
-                    final boolean suspended = parser.getAttributeBoolean(null, ATTR_SUSPENDED, false);
-                    String oldSuspendingPackage = parser.getAttributeValue(null,
-                            ATTR_SUSPENDING_PACKAGE);
-                    final String dialogMessage = parser.getAttributeValue(null,
-                            ATTR_SUSPEND_DIALOG_MESSAGE);
-                    if (suspended && oldSuspendingPackage == null) {
-                        oldSuspendingPackage = PLATFORM_PACKAGE_NAME;
-                    }
-
-                    final boolean blockUninstall =
-                            parser.getAttributeBoolean(null, ATTR_BLOCK_UNINSTALL, false);
-                    final boolean instantApp =
-                            parser.getAttributeBoolean(null, ATTR_INSTANT_APP, false);
-                    final boolean virtualPreload =
-                            parser.getAttributeBoolean(null, ATTR_VIRTUAL_PRELOAD, false);
-                    final int enabled = parser.getAttributeInt(null, ATTR_ENABLED,
-                            COMPONENT_ENABLED_STATE_DEFAULT);
-                    final String enabledCaller = parser.getAttributeValue(null,
-                            ATTR_ENABLED_CALLER);
-                    final String harmfulAppWarning =
-                            parser.getAttributeValue(null, ATTR_HARMFUL_APP_WARNING);
-                    final int verifState = parser.getAttributeInt(null,
-                            ATTR_DOMAIN_VERIFICATON_STATE,
-                            PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
-                    final int installReason = parser.getAttributeInt(null, ATTR_INSTALL_REASON,
-                            PackageManager.INSTALL_REASON_UNKNOWN);
-                    final int uninstallReason = parser.getAttributeInt(null, ATTR_UNINSTALL_REASON,
-                            PackageManager.UNINSTALL_REASON_UNKNOWN);
-                    final String splashScreenTheme = parser.getAttributeValue(null,
-                            ATTR_SPLASH_SCREEN_THEME);
-                    final long firstInstallTime = parser.getAttributeLongHex(null,
-                            ATTR_FIRST_INSTALL_TIME, 0);
-
-                    ArraySet<String> enabledComponents = null;
-                    ArraySet<String> disabledComponents = null;
-                    PersistableBundle suspendedAppExtras = null;
-                    PersistableBundle suspendedLauncherExtras = null;
-                    SuspendDialogInfo oldSuspendDialogInfo = null;
-
-                    int packageDepth = parser.getDepth();
-                    ArrayMap<String, SuspendParams> suspendParamsMap = null;
-                    while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
-                            && (type != XmlPullParser.END_TAG
-                            || parser.getDepth() > packageDepth)) {
-                        if (type == XmlPullParser.END_TAG
-                                || type == XmlPullParser.TEXT) {
+                    String tagName = parser.getName();
+                    if (tagName.equals(TAG_PACKAGE)) {
+                        String name = parser.getAttributeValue(null, ATTR_NAME);
+                        ps = mPackages.get(name);
+                        if (ps == null) {
+                            Slog.w(PackageManagerService.TAG,
+                                    "No package known for package restrictions " + name);
+                            XmlUtils.skipCurrentTag(parser);
                             continue;
                         }
-                        switch (parser.getName()) {
-                            case TAG_ENABLED_COMPONENTS:
-                                enabledComponents = readComponentsLPr(parser);
-                                break;
-                            case TAG_DISABLED_COMPONENTS:
-                                disabledComponents = readComponentsLPr(parser);
-                                break;
-                            case TAG_SUSPENDED_APP_EXTRAS:
-                                suspendedAppExtras = PersistableBundle.restoreFromXml(parser);
-                                break;
-                            case TAG_SUSPENDED_LAUNCHER_EXTRAS:
-                                suspendedLauncherExtras = PersistableBundle.restoreFromXml(parser);
-                                break;
-                            case TAG_SUSPENDED_DIALOG_INFO:
-                                oldSuspendDialogInfo = SuspendDialogInfo.restoreFromXml(parser);
-                                break;
-                            case TAG_SUSPEND_PARAMS:
-                                final String suspendingPackage = parser.getAttributeValue(null,
-                                        ATTR_SUSPENDING_PACKAGE);
-                                if (suspendingPackage == null) {
-                                    Slog.wtf(TAG, "No suspendingPackage found inside tag "
-                                            + TAG_SUSPEND_PARAMS);
-                                    continue;
-                                }
-                                if (suspendParamsMap == null) {
-                                    suspendParamsMap = new ArrayMap<>();
-                                }
-                                suspendParamsMap.put(suspendingPackage,
-                                        SuspendParams.restoreFromXml(parser));
-                                break;
-                            default:
-                                Slog.wtf(TAG, "Unknown tag " + parser.getName() + " under tag "
-                                        + TAG_PACKAGE);
+
+                        final long ceDataInode =
+                                parser.getAttributeLong(null, ATTR_CE_DATA_INODE, 0);
+                        final boolean installed =
+                                parser.getAttributeBoolean(null, ATTR_INSTALLED, true);
+                        final boolean stopped =
+                                parser.getAttributeBoolean(null, ATTR_STOPPED, false);
+                        final boolean notLaunched =
+                                parser.getAttributeBoolean(null, ATTR_NOT_LAUNCHED, false);
+
+                        // For backwards compatibility with the previous name of "blocked", which
+                        // now means hidden, read the old attribute as well.
+                        boolean hidden = parser.getAttributeBoolean(null, ATTR_HIDDEN, false);
+                        if (!hidden) {
+                            hidden = parser.getAttributeBoolean(null, ATTR_BLOCKED, false);
                         }
-                    }
-                    if (oldSuspendDialogInfo == null && !TextUtils.isEmpty(dialogMessage)) {
-                        oldSuspendDialogInfo = new SuspendDialogInfo.Builder()
-                                .setMessage(dialogMessage)
-                                .build();
-                    }
-                    if (suspended && suspendParamsMap == null) {
-                        final SuspendParams suspendParams = new SuspendParams(
-                                        oldSuspendDialogInfo,
-                                        suspendedAppExtras,
-                                        suspendedLauncherExtras);
-                        suspendParamsMap = new ArrayMap<>();
-                        suspendParamsMap.put(oldSuspendingPackage, suspendParams);
-                    }
 
-                    if (blockUninstall) {
-                        setBlockUninstallLPw(userId, name, true);
-                    }
-                    ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
-                            hidden, distractionFlags, suspendParamsMap, instantApp, virtualPreload,
-                            enabledCaller, enabledComponents, disabledComponents, installReason,
-                            uninstallReason, harmfulAppWarning, splashScreenTheme,
-                            firstInstallTime != 0 ? firstInstallTime :
-                                    origFirstInstallTimes.getOrDefault(name, 0L));
+                        final int distractionFlags = parser.getAttributeInt(null,
+                                ATTR_DISTRACTION_FLAGS, 0);
+                        final boolean suspended = parser.getAttributeBoolean(null, ATTR_SUSPENDED,
+                                false);
+                        String oldSuspendingPackage = parser.getAttributeValue(null,
+                                ATTR_SUSPENDING_PACKAGE);
+                        final String dialogMessage = parser.getAttributeValue(null,
+                                ATTR_SUSPEND_DIALOG_MESSAGE);
+                        if (suspended && oldSuspendingPackage == null) {
+                            oldSuspendingPackage = PLATFORM_PACKAGE_NAME;
+                        }
 
-                    mDomainVerificationManager.setLegacyUserState(name, userId, verifState);
-                } else if (tagName.equals("preferred-activities")) {
-                    readPreferredActivitiesLPw(parser, userId);
-                } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
-                    readPersistentPreferredActivitiesLPw(parser, userId);
-                } else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) {
-                    readCrossProfileIntentFiltersLPw(parser, userId);
-                } else if (tagName.equals(TAG_DEFAULT_APPS)) {
-                    readDefaultAppsLPw(parser, userId);
-                } else if (tagName.equals(TAG_BLOCK_UNINSTALL_PACKAGES)) {
-                    readBlockUninstallPackagesLPw(parser, userId);
-                } else {
-                    Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
-                          + parser.getName());
-                    XmlUtils.skipCurrentTag(parser);
+                        final boolean blockUninstall =
+                                parser.getAttributeBoolean(null, ATTR_BLOCK_UNINSTALL, false);
+                        final boolean instantApp =
+                                parser.getAttributeBoolean(null, ATTR_INSTANT_APP, false);
+                        final boolean virtualPreload =
+                                parser.getAttributeBoolean(null, ATTR_VIRTUAL_PRELOAD, false);
+                        final int enabled = parser.getAttributeInt(null, ATTR_ENABLED,
+                                COMPONENT_ENABLED_STATE_DEFAULT);
+                        final String enabledCaller = parser.getAttributeValue(null,
+                                ATTR_ENABLED_CALLER);
+                        final String harmfulAppWarning =
+                                parser.getAttributeValue(null, ATTR_HARMFUL_APP_WARNING);
+                        final int verifState = parser.getAttributeInt(null,
+                                ATTR_DOMAIN_VERIFICATION_STATE,
+                                PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
+                        final int installReason = parser.getAttributeInt(null, ATTR_INSTALL_REASON,
+                                PackageManager.INSTALL_REASON_UNKNOWN);
+                        final int uninstallReason = parser.getAttributeInt(null,
+                                ATTR_UNINSTALL_REASON,
+                                PackageManager.UNINSTALL_REASON_UNKNOWN);
+                        final String splashScreenTheme = parser.getAttributeValue(null,
+                                ATTR_SPLASH_SCREEN_THEME);
+                        final long firstInstallTime = parser.getAttributeLongHex(null,
+                                ATTR_FIRST_INSTALL_TIME, 0);
+
+                        ArraySet<String> enabledComponents = null;
+                        ArraySet<String> disabledComponents = null;
+                        PersistableBundle suspendedAppExtras = null;
+                        PersistableBundle suspendedLauncherExtras = null;
+                        SuspendDialogInfo oldSuspendDialogInfo = null;
+
+                        int packageDepth = parser.getDepth();
+                        ArrayMap<String, SuspendParams> suspendParamsMap = null;
+                        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                                && (type != XmlPullParser.END_TAG
+                                || parser.getDepth() > packageDepth)) {
+                            if (type == XmlPullParser.END_TAG
+                                    || type == XmlPullParser.TEXT) {
+                                continue;
+                            }
+                            switch (parser.getName()) {
+                                case TAG_ENABLED_COMPONENTS:
+                                    enabledComponents = readComponentsLPr(parser);
+                                    break;
+                                case TAG_DISABLED_COMPONENTS:
+                                    disabledComponents = readComponentsLPr(parser);
+                                    break;
+                                case TAG_SUSPENDED_APP_EXTRAS:
+                                    suspendedAppExtras = PersistableBundle.restoreFromXml(parser);
+                                    break;
+                                case TAG_SUSPENDED_LAUNCHER_EXTRAS:
+                                    suspendedLauncherExtras = PersistableBundle.restoreFromXml(
+                                            parser);
+                                    break;
+                                case TAG_SUSPENDED_DIALOG_INFO:
+                                    oldSuspendDialogInfo = SuspendDialogInfo.restoreFromXml(parser);
+                                    break;
+                                case TAG_SUSPEND_PARAMS:
+                                    final String suspendingPackage = parser.getAttributeValue(null,
+                                            ATTR_SUSPENDING_PACKAGE);
+                                    if (suspendingPackage == null) {
+                                        Slog.wtf(TAG, "No suspendingPackage found inside tag "
+                                                + TAG_SUSPEND_PARAMS);
+                                        continue;
+                                    }
+                                    if (suspendParamsMap == null) {
+                                        suspendParamsMap = new ArrayMap<>();
+                                    }
+                                    suspendParamsMap.put(suspendingPackage,
+                                            SuspendParams.restoreFromXml(parser));
+                                    break;
+                                default:
+                                    Slog.wtf(TAG, "Unknown tag " + parser.getName() + " under tag "
+                                            + TAG_PACKAGE);
+                            }
+                        }
+                        if (oldSuspendDialogInfo == null && !TextUtils.isEmpty(dialogMessage)) {
+                            oldSuspendDialogInfo = new SuspendDialogInfo.Builder()
+                                    .setMessage(dialogMessage)
+                                    .build();
+                        }
+                        if (suspended && suspendParamsMap == null) {
+                            final SuspendParams suspendParams = new SuspendParams(
+                                    oldSuspendDialogInfo,
+                                    suspendedAppExtras,
+                                    suspendedLauncherExtras);
+                            suspendParamsMap = new ArrayMap<>();
+                            suspendParamsMap.put(oldSuspendingPackage, suspendParams);
+                        }
+
+                        if (blockUninstall) {
+                            setBlockUninstallLPw(userId, name, true);
+                        }
+                        ps.setUserState(userId, ceDataInode, enabled, installed, stopped,
+                                notLaunched,
+                                hidden, distractionFlags, suspendParamsMap, instantApp,
+                                virtualPreload,
+                                enabledCaller, enabledComponents, disabledComponents, installReason,
+                                uninstallReason, harmfulAppWarning, splashScreenTheme,
+                                firstInstallTime != 0 ? firstInstallTime :
+                                        origFirstInstallTimes.getOrDefault(name, 0L));
+
+                        mDomainVerificationManager.setLegacyUserState(name, userId, verifState);
+                    } else if (tagName.equals("preferred-activities")) {
+                        readPreferredActivitiesLPw(parser, userId);
+                    } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
+                        readPersistentPreferredActivitiesLPw(parser, userId);
+                    } else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) {
+                        readCrossProfileIntentFiltersLPw(parser, userId);
+                    } else if (tagName.equals(TAG_DEFAULT_APPS)) {
+                        readDefaultAppsLPw(parser, userId);
+                    } else if (tagName.equals(TAG_BLOCK_UNINSTALL_PACKAGES)) {
+                        readBlockUninstallPackagesLPw(parser, userId);
+                    } else {
+                        Slog.w(PackageManagerService.TAG,
+                                "Unknown element under <stopped-packages>: "
+                                        + parser.getName());
+                        XmlUtils.skipCurrentTag(parser);
+                    }
                 }
+            } catch (IOException | XmlPullParserException e) {
+                // Remove corrupted file and retry.
+                atomicFile.failRead(str, e);
+
+                readPackageRestrictionsLPr(userId, origFirstInstallTimes);
             }
-
-            str.close();
-        } catch (XmlPullParserException e) {
-            mReadMessages.append("Error reading: " + e.toString());
-            PackageManagerService.reportSettingsProblem(Log.ERROR,
-                    "Error reading stopped packages: " + e);
-            Slog.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages",
-                    e);
-
-        } catch (java.io.IOException e) {
-            mReadMessages.append("Error reading: " + e.toString());
-            PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
-            Slog.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages",
-                    e);
         }
     }
 
@@ -2165,219 +2141,176 @@
             Log.i(TAG, "Writing package restrictions for user=" + userId);
         }
 
-        final File userPackagesStateFile;
-        final File backupFile;
-        final FileOutputStream fstr;
+        FileOutputStream str = null;
+        try (ResilientAtomicFile atomicFile = getUserPackagesStateFile(userId)) {
+            try {
+                synchronized (mPackageRestrictionsLock) {
+                    if (!sync) {
+                        int pending = mPendingAsyncPackageRestrictionsWrites.get(userId, 0) - 1;
+                        if (pending < 0) {
+                            Log.i(TAG, "Cancel writing package restrictions for user=" + userId);
+                            return;
+                        }
+                        mPendingAsyncPackageRestrictionsWrites.put(userId, pending);
+                    }
 
-        synchronized (mPackageRestrictionsLock) {
-            if (!sync) {
-                int pending = mPendingAsyncPackageRestrictionsWrites.get(userId, 0) - 1;
-                if (pending < 0) {
-                    Log.i(TAG, "Cancel writing package restrictions for user=" + userId);
-                    return;
-                }
-                mPendingAsyncPackageRestrictionsWrites.put(userId, pending);
-            }
-
-            // Keep the old stopped packages around until we know the new ones have
-            // been successfully written.
-            userPackagesStateFile = getUserPackagesStateFile(userId);
-            backupFile = getUserPackagesStateBackupFile(userId);
-            new File(userPackagesStateFile.getParent()).mkdirs();
-            if (userPackagesStateFile.exists()) {
-                // Presence of backup settings file indicates that we failed
-                // to persist packages earlier. So preserve the older
-                // backup for future reference since the current packages
-                // might have been corrupted.
-                if (!backupFile.exists()) {
-                    if (!userPackagesStateFile.renameTo(backupFile)) {
+                    try {
+                        str = atomicFile.startWrite();
+                    } catch (java.io.IOException e) {
                         Slog.wtf(PackageManagerService.TAG,
-                                "Unable to backup user packages state file, "
-                                        + "current changes will be lost at reboot");
+                                "Unable to write package manager package restrictions, "
+                                        + " current changes will be lost at reboot", e);
                         return;
                     }
-                } else {
-                    userPackagesStateFile.delete();
-                    Slog.w(PackageManagerService.TAG, "Preserving older stopped packages backup");
                 }
-            }
 
-            try {
-                fstr = new FileOutputStream(userPackagesStateFile);
-                // File is created, set permissions.
-                FileUtils.setPermissions(userPackagesStateFile.toString(),
-                        FileUtils.S_IRUSR | FileUtils.S_IWUSR
-                                | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
-                        -1, -1);
-            } catch (java.io.IOException e) {
-                Slog.wtf(PackageManagerService.TAG,
-                        "Unable to write package manager user packages state, "
-                                + " current changes will be lost at reboot", e);
-                return;
-            }
-        }
+                synchronized (mLock) {
+                    final TypedXmlSerializer serializer = Xml.resolveSerializer(str);
+                    serializer.startDocument(null, true);
+                    serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
+                            true);
 
-        try {
-            synchronized (mLock) {
-                final TypedXmlSerializer serializer = Xml.resolveSerializer(fstr);
-                serializer.startDocument(null, true);
-                serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
-                        true);
+                    serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS);
 
-                serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS);
+                    if (DEBUG_MU) {
+                        Slogf.i(TAG, "Writing %s (%d packages)", atomicFile,
+                                mPackages.values().size());
+                    }
+                    for (final PackageSetting pkg : mPackages.values()) {
+                        final PackageUserStateInternal ustate = pkg.readUserState(userId);
+                        if (DEBUG_MU) {
+                            Log.v(TAG, "  pkg=" + pkg.getPackageName()
+                                    + ", installed=" + ustate.isInstalled()
+                                    + ", state=" + ustate.getEnabledState());
+                        }
+
+                        serializer.startTag(null, TAG_PACKAGE);
+                        serializer.attribute(null, ATTR_NAME, pkg.getPackageName());
+                        if (ustate.getCeDataInode() != 0) {
+                            serializer.attributeLong(null, ATTR_CE_DATA_INODE,
+                                    ustate.getCeDataInode());
+                        }
+                        if (!ustate.isInstalled()) {
+                            serializer.attributeBoolean(null, ATTR_INSTALLED, false);
+                        }
+                        if (ustate.isStopped()) {
+                            serializer.attributeBoolean(null, ATTR_STOPPED, true);
+                        }
+                        if (ustate.isNotLaunched()) {
+                            serializer.attributeBoolean(null, ATTR_NOT_LAUNCHED, true);
+                        }
+                        if (ustate.isHidden()) {
+                            serializer.attributeBoolean(null, ATTR_HIDDEN, true);
+                        }
+                        if (ustate.getDistractionFlags() != 0) {
+                            serializer.attributeInt(null, ATTR_DISTRACTION_FLAGS,
+                                    ustate.getDistractionFlags());
+                        }
+                        if (ustate.isSuspended()) {
+                            serializer.attributeBoolean(null, ATTR_SUSPENDED, true);
+                        }
+                        if (ustate.isInstantApp()) {
+                            serializer.attributeBoolean(null, ATTR_INSTANT_APP, true);
+                        }
+                        if (ustate.isVirtualPreload()) {
+                            serializer.attributeBoolean(null, ATTR_VIRTUAL_PRELOAD, true);
+                        }
+                        if (ustate.getEnabledState() != COMPONENT_ENABLED_STATE_DEFAULT) {
+                            serializer.attributeInt(null, ATTR_ENABLED, ustate.getEnabledState());
+                            if (ustate.getLastDisableAppCaller() != null) {
+                                serializer.attribute(null, ATTR_ENABLED_CALLER,
+                                        ustate.getLastDisableAppCaller());
+                            }
+                        }
+                        if (ustate.getInstallReason() != PackageManager.INSTALL_REASON_UNKNOWN) {
+                            serializer.attributeInt(null, ATTR_INSTALL_REASON,
+                                    ustate.getInstallReason());
+                        }
+                        serializer.attributeLongHex(null, ATTR_FIRST_INSTALL_TIME,
+                                ustate.getFirstInstallTimeMillis());
+                        if (ustate.getUninstallReason()
+                                != PackageManager.UNINSTALL_REASON_UNKNOWN) {
+                            serializer.attributeInt(null, ATTR_UNINSTALL_REASON,
+                                    ustate.getUninstallReason());
+                        }
+                        if (ustate.getHarmfulAppWarning() != null) {
+                            serializer.attribute(null, ATTR_HARMFUL_APP_WARNING,
+                                    ustate.getHarmfulAppWarning());
+                        }
+                        if (ustate.getSplashScreenTheme() != null) {
+                            serializer.attribute(null, ATTR_SPLASH_SCREEN_THEME,
+                                    ustate.getSplashScreenTheme());
+                        }
+                        if (ustate.isSuspended()) {
+                            for (int i = 0; i < ustate.getSuspendParams().size(); i++) {
+                                final String suspendingPackage = ustate.getSuspendParams().keyAt(i);
+                                serializer.startTag(null, TAG_SUSPEND_PARAMS);
+                                serializer.attribute(null, ATTR_SUSPENDING_PACKAGE,
+                                        suspendingPackage);
+                                final SuspendParams params =
+                                        ustate.getSuspendParams().valueAt(i);
+                                if (params != null) {
+                                    params.saveToXml(serializer);
+                                }
+                                serializer.endTag(null, TAG_SUSPEND_PARAMS);
+                            }
+                        }
+                        final ArraySet<String> enabledComponents = ustate.getEnabledComponents();
+                        if (enabledComponents != null && enabledComponents.size() > 0) {
+                            serializer.startTag(null, TAG_ENABLED_COMPONENTS);
+                            for (int i = 0; i < enabledComponents.size(); i++) {
+                                serializer.startTag(null, TAG_ITEM);
+                                serializer.attribute(null, ATTR_NAME,
+                                        enabledComponents.valueAt(i));
+                                serializer.endTag(null, TAG_ITEM);
+                            }
+                            serializer.endTag(null, TAG_ENABLED_COMPONENTS);
+                        }
+                        final ArraySet<String> disabledComponents = ustate.getDisabledComponents();
+                        if (disabledComponents != null && disabledComponents.size() > 0) {
+                            serializer.startTag(null, TAG_DISABLED_COMPONENTS);
+                            for (int i = 0; i < disabledComponents.size(); i++) {
+                                serializer.startTag(null, TAG_ITEM);
+                                serializer.attribute(null, ATTR_NAME,
+                                        disabledComponents.valueAt(i));
+                                serializer.endTag(null, TAG_ITEM);
+                            }
+                            serializer.endTag(null, TAG_DISABLED_COMPONENTS);
+                        }
+
+                        serializer.endTag(null, TAG_PACKAGE);
+                    }
+
+                    writePreferredActivitiesLPr(serializer, userId, true);
+                    writePersistentPreferredActivitiesLPr(serializer, userId);
+                    writeCrossProfileIntentFiltersLPr(serializer, userId);
+                    writeDefaultAppsLPr(serializer, userId);
+                    writeBlockUninstallPackagesLPr(serializer, userId);
+
+                    serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
+
+                    serializer.endDocument();
+                }
+
+                atomicFile.finishWrite(str);
 
                 if (DEBUG_MU) {
-                    Slogf.i(TAG, "Writing %s (%d packages)", userPackagesStateFile,
-                            mPackages.values().size());
-                }
-                for (final PackageSetting pkg : mPackages.values()) {
-                    final PackageUserStateInternal ustate = pkg.readUserState(userId);
-                    if (DEBUG_MU) {
-                        Log.v(TAG, "  pkg=" + pkg.getPackageName()
-                                + ", installed=" + ustate.isInstalled()
-                                + ", state=" + ustate.getEnabledState());
-                    }
-
-                    serializer.startTag(null, TAG_PACKAGE);
-                    serializer.attribute(null, ATTR_NAME, pkg.getPackageName());
-                    if (ustate.getCeDataInode() != 0) {
-                        serializer.attributeLong(null, ATTR_CE_DATA_INODE, ustate.getCeDataInode());
-                    }
-                    if (!ustate.isInstalled()) {
-                        serializer.attributeBoolean(null, ATTR_INSTALLED, false);
-                    }
-                    if (ustate.isStopped()) {
-                        serializer.attributeBoolean(null, ATTR_STOPPED, true);
-                    }
-                    if (ustate.isNotLaunched()) {
-                        serializer.attributeBoolean(null, ATTR_NOT_LAUNCHED, true);
-                    }
-                    if (ustate.isHidden()) {
-                        serializer.attributeBoolean(null, ATTR_HIDDEN, true);
-                    }
-                    if (ustate.getDistractionFlags() != 0) {
-                        serializer.attributeInt(null, ATTR_DISTRACTION_FLAGS,
-                                ustate.getDistractionFlags());
-                    }
-                    if (ustate.isSuspended()) {
-                        serializer.attributeBoolean(null, ATTR_SUSPENDED, true);
-                    }
-                    if (ustate.isInstantApp()) {
-                        serializer.attributeBoolean(null, ATTR_INSTANT_APP, true);
-                    }
-                    if (ustate.isVirtualPreload()) {
-                        serializer.attributeBoolean(null, ATTR_VIRTUAL_PRELOAD, true);
-                    }
-                    if (ustate.getEnabledState() != COMPONENT_ENABLED_STATE_DEFAULT) {
-                        serializer.attributeInt(null, ATTR_ENABLED, ustate.getEnabledState());
-                        if (ustate.getLastDisableAppCaller() != null) {
-                            serializer.attribute(null, ATTR_ENABLED_CALLER,
-                                    ustate.getLastDisableAppCaller());
-                        }
-                    }
-                    if (ustate.getInstallReason() != PackageManager.INSTALL_REASON_UNKNOWN) {
-                        serializer.attributeInt(null, ATTR_INSTALL_REASON,
-                                ustate.getInstallReason());
-                    }
-                    serializer.attributeLongHex(null, ATTR_FIRST_INSTALL_TIME,
-                            ustate.getFirstInstallTimeMillis());
-                    if (ustate.getUninstallReason() != PackageManager.UNINSTALL_REASON_UNKNOWN) {
-                        serializer.attributeInt(null, ATTR_UNINSTALL_REASON,
-                                ustate.getUninstallReason());
-                    }
-                    if (ustate.getHarmfulAppWarning() != null) {
-                        serializer.attribute(null, ATTR_HARMFUL_APP_WARNING,
-                                ustate.getHarmfulAppWarning());
-                    }
-                    if (ustate.getSplashScreenTheme() != null) {
-                        serializer.attribute(null, ATTR_SPLASH_SCREEN_THEME,
-                                ustate.getSplashScreenTheme());
-                    }
-                    if (ustate.isSuspended()) {
-                        for (int i = 0; i < ustate.getSuspendParams().size(); i++) {
-                            final String suspendingPackage = ustate.getSuspendParams().keyAt(i);
-                            serializer.startTag(null, TAG_SUSPEND_PARAMS);
-                            serializer.attribute(null, ATTR_SUSPENDING_PACKAGE, suspendingPackage);
-                            final SuspendParams params =
-                                    ustate.getSuspendParams().valueAt(i);
-                            if (params != null) {
-                                params.saveToXml(serializer);
-                            }
-                            serializer.endTag(null, TAG_SUSPEND_PARAMS);
-                        }
-                    }
-                    final ArraySet<String> enabledComponents = ustate.getEnabledComponents();
-                    if (enabledComponents != null && enabledComponents.size() > 0) {
-                        serializer.startTag(null, TAG_ENABLED_COMPONENTS);
-                        for (int i = 0; i < enabledComponents.size(); i++) {
-                            serializer.startTag(null, TAG_ITEM);
-                            serializer.attribute(null, ATTR_NAME,
-                                    enabledComponents.valueAt(i));
-                            serializer.endTag(null, TAG_ITEM);
-                        }
-                        serializer.endTag(null, TAG_ENABLED_COMPONENTS);
-                    }
-                    final ArraySet<String> disabledComponents = ustate.getDisabledComponents();
-                    if (disabledComponents != null && disabledComponents.size() > 0) {
-                        serializer.startTag(null, TAG_DISABLED_COMPONENTS);
-                        for (int i = 0; i < disabledComponents.size(); i++) {
-                            serializer.startTag(null, TAG_ITEM);
-                            serializer.attribute(null, ATTR_NAME,
-                                    disabledComponents.valueAt(i));
-                            serializer.endTag(null, TAG_ITEM);
-                        }
-                        serializer.endTag(null, TAG_DISABLED_COMPONENTS);
-                    }
-
-                    serializer.endTag(null, TAG_PACKAGE);
+                    Log.i(TAG, "New package restrictions successfully written for user=" + userId
+                            + ": " + atomicFile);
                 }
 
-                writePreferredActivitiesLPr(serializer, userId, true);
-                writePersistentPreferredActivitiesLPr(serializer, userId);
-                writeCrossProfileIntentFiltersLPr(serializer, userId);
-                writeDefaultAppsLPr(serializer, userId);
-                writeBlockUninstallPackagesLPr(serializer, userId);
+                com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
+                        "package-user-" + userId, SystemClock.uptimeMillis() - startTime);
 
-                serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
-
-                serializer.endDocument();
-            }
-
-            fstr.flush();
-            FileUtils.sync(fstr);
-            IoUtils.closeQuietly(fstr);
-
-            synchronized (mPackageRestrictionsLock) {
-                // File is created, set permissions.
-                FileUtils.setPermissions(userPackagesStateFile.toString(),
-                        FileUtils.S_IRUSR | FileUtils.S_IWUSR
-                                | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
-                        -1, -1);
-                // New settings successfully written, old ones are no longer needed.
-                backupFile.delete();
-            }
-
-            if (DEBUG_MU) {
-                Log.i(TAG, "New settings successfully written for user=" + userId + ": "
-                        + userPackagesStateFile);
-            }
-
-            com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
-                    "package-user-" + userId, SystemClock.uptimeMillis() - startTime);
-
-            // Done, all is good!
-            return;
-        } catch (java.io.IOException e) {
-            Slog.wtf(PackageManagerService.TAG,
-                    "Unable to write package manager user packages state, "
-                    + " current changes will be lost at reboot", e);
-        }
-
-        // Clean up partially written files
-        if (userPackagesStateFile.exists()) {
-            if (!userPackagesStateFile.delete()) {
-                Log.i(PackageManagerService.TAG, "Failed to clean up mangled file: "
-                        + mStoppedPackagesFilename);
+                // Done, all is good!
+                return;
+            } catch (java.io.IOException e) {
+                Slog.wtf(PackageManagerService.TAG,
+                        "Unable to write package manager package restrictions, "
+                                + " current changes will be lost at reboot", e);
+                if (str != null) {
+                    atomicFile.failWrite(str);
+                }
             }
         }
     }
@@ -2589,153 +2522,108 @@
         // right time.
         invalidatePackageCache();
 
-        // Keep the old settings around until we know the new ones have
-        // been successfully written.
-        if (mSettingsFilename.exists()) {
-            // Presence of backup settings file indicates that we failed
-            // to persist settings earlier. So preserve the older
-            // backup for future reference since the current settings
-            // might have been corrupted.
-            if (!mPreviousSettingsFilename.exists()) {
-                if (!mSettingsFilename.renameTo(mPreviousSettingsFilename)) {
-                    Slog.wtf(PackageManagerService.TAG,
-                            "Unable to store older package manager settings, "
-                            + " current changes will be lost at reboot");
-                    return;
-                }
-            } else {
-                mSettingsFilename.delete();
-                Slog.w(PackageManagerService.TAG, "Preserving older settings backup");
-            }
-        }
-
         mPastSignatures.clear();
 
-        try {
-            final FileOutputStream fstr = new FileOutputStream(mSettingsFilename);
-            final TypedXmlSerializer serializer = Xml.resolveSerializer(fstr);
-            serializer.startDocument(null, true);
-            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-
-            serializer.startTag(null, "packages");
-
-            for (int i = 0; i < mVersion.size(); i++) {
-                final String volumeUuid = mVersion.keyAt(i);
-                final VersionInfo ver = mVersion.valueAt(i);
-
-                serializer.startTag(null, TAG_VERSION);
-                XmlUtils.writeStringAttribute(serializer, ATTR_VOLUME_UUID, volumeUuid);
-                serializer.attributeInt(null, ATTR_SDK_VERSION, ver.sdkVersion);
-                serializer.attributeInt(null, ATTR_DATABASE_VERSION, ver.databaseVersion);
-                XmlUtils.writeStringAttribute(serializer, ATTR_BUILD_FINGERPRINT,
-                        ver.buildFingerprint);
-                XmlUtils.writeStringAttribute(serializer, ATTR_FINGERPRINT, ver.fingerprint);
-                serializer.endTag(null, TAG_VERSION);
-            }
-
-            if (mVerifierDeviceIdentity != null) {
-                serializer.startTag(null, "verifier");
-                serializer.attribute(null, "device", mVerifierDeviceIdentity.toString());
-                serializer.endTag(null, "verifier");
-            }
-
-            serializer.startTag(null, "permission-trees");
-            mPermissions.writePermissionTrees(serializer);
-            serializer.endTag(null, "permission-trees");
-
-            serializer.startTag(null, "permissions");
-            mPermissions.writePermissions(serializer);
-            serializer.endTag(null, "permissions");
-
-            for (final PackageSetting pkg : mPackages.values()) {
-                if (pkg.getPkg() != null && pkg.getPkg().isApex()) {
-                    // Don't persist APEX which doesn't have a valid app id and will fail to load
-                    continue;
-                }
-                writePackageLPr(serializer, pkg);
-            }
-
-            for (final PackageSetting pkg : mDisabledSysPackages.values()) {
-                if (pkg.getPkg() != null && pkg.getPkg().isApex()) {
-                    // Don't persist APEX which doesn't have a valid app id and will fail to load
-                    continue;
-                }
-                writeDisabledSysPackageLPr(serializer, pkg);
-            }
-
-            for (final SharedUserSetting usr : mSharedUsers.values()) {
-                serializer.startTag(null, "shared-user");
-                serializer.attribute(null, ATTR_NAME, usr.name);
-                serializer.attributeInt(null, "userId", usr.mAppId);
-                usr.signatures.writeXml(serializer, "sigs", mPastSignatures.untrackedStorage());
-                serializer.endTag(null, "shared-user");
-            }
-
-            if (mRenamedPackages.size() > 0) {
-                for (Map.Entry<String, String> e : mRenamedPackages.entrySet()) {
-                    serializer.startTag(null, "renamed-package");
-                    serializer.attribute(null, "new", e.getKey());
-                    serializer.attribute(null, "old", e.getValue());
-                    serializer.endTag(null, "renamed-package");
-                }
-            }
-
-            mDomainVerificationManager.writeSettings(computer, serializer,
-                    false /* includeSignatures */, UserHandle.USER_ALL);
-
-            mKeySetManagerService.writeKeySetManagerServiceLPr(serializer);
-
-            serializer.endTag(null, "packages");
-
-            serializer.endDocument();
-
-            fstr.flush();
-            FileUtils.sync(fstr);
-            fstr.close();
-
-            // New settings successfully written, old ones are no longer needed.
-            mPreviousSettingsFilename.delete();
-            mSettingsReserveCopyFilename.delete();
-
-            FileUtils.setPermissions(mSettingsFilename.toString(),
-                    FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
-                    -1, -1);
-
-            try (FileInputStream in = new FileInputStream(mSettingsFilename);
-                 FileOutputStream out = new FileOutputStream(mSettingsReserveCopyFilename)) {
-                FileUtils.copy(in, out);
-                out.flush();
-                FileUtils.sync(out);
-            } catch (IOException e) {
-                Slog.e(TAG,
-                        "Failed to write reserve copy of settings: " + mSettingsReserveCopyFilename,
-                        e);
-            }
-
+        try (ResilientAtomicFile atomicFile = getSettingsFile()) {
+            FileOutputStream str = null;
             try {
-                FileIntegrity.setUpFsVerity(mSettingsFilename);
-                FileIntegrity.setUpFsVerity(mSettingsReserveCopyFilename);
-            } catch (IOException e) {
-                Slog.e(TAG, "Failed to verity-protect settings", e);
-            }
+                str = atomicFile.startWrite();
 
-            writeKernelMappingLPr();
-            writePackageListLPr();
-            writeAllUsersPackageRestrictionsLPr(sync);
-            writeAllRuntimePermissionsLPr();
-            com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
-                    "package", SystemClock.uptimeMillis() - startTime);
-            return;
+                final TypedXmlSerializer serializer = Xml.resolveSerializer(str);
+                serializer.startDocument(null, true);
+                serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
+                        true);
 
-        } catch(java.io.IOException e) {
-            Slog.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
-                    + "current changes will be lost at reboot", e);
-        }
-        // Clean up partially written files
-        if (mSettingsFilename.exists()) {
-            if (!mSettingsFilename.delete()) {
-                Slog.wtf(PackageManagerService.TAG, "Failed to clean up mangled file: "
-                        + mSettingsFilename);
+                serializer.startTag(null, "packages");
+
+                for (int i = 0; i < mVersion.size(); i++) {
+                    final String volumeUuid = mVersion.keyAt(i);
+                    final VersionInfo ver = mVersion.valueAt(i);
+
+                    serializer.startTag(null, TAG_VERSION);
+                    XmlUtils.writeStringAttribute(serializer, ATTR_VOLUME_UUID, volumeUuid);
+                    serializer.attributeInt(null, ATTR_SDK_VERSION, ver.sdkVersion);
+                    serializer.attributeInt(null, ATTR_DATABASE_VERSION, ver.databaseVersion);
+                    XmlUtils.writeStringAttribute(serializer, ATTR_BUILD_FINGERPRINT,
+                            ver.buildFingerprint);
+                    XmlUtils.writeStringAttribute(serializer, ATTR_FINGERPRINT, ver.fingerprint);
+                    serializer.endTag(null, TAG_VERSION);
+                }
+
+                if (mVerifierDeviceIdentity != null) {
+                    serializer.startTag(null, "verifier");
+                    serializer.attribute(null, "device", mVerifierDeviceIdentity.toString());
+                    serializer.endTag(null, "verifier");
+                }
+
+                serializer.startTag(null, "permission-trees");
+                mPermissions.writePermissionTrees(serializer);
+                serializer.endTag(null, "permission-trees");
+
+                serializer.startTag(null, "permissions");
+                mPermissions.writePermissions(serializer);
+                serializer.endTag(null, "permissions");
+
+                for (final PackageSetting pkg : mPackages.values()) {
+                    if (pkg.getPkg() != null && pkg.getPkg().isApex()) {
+                        // Don't persist APEX which doesn't have a valid app id and will fail to
+                        // load
+                        continue;
+                    }
+                    writePackageLPr(serializer, pkg);
+                }
+
+                for (final PackageSetting pkg : mDisabledSysPackages.values()) {
+                    if (pkg.getPkg() != null && pkg.getPkg().isApex()) {
+                        // Don't persist APEX which doesn't have a valid app id and will fail to
+                        // load
+                        continue;
+                    }
+                    writeDisabledSysPackageLPr(serializer, pkg);
+                }
+
+                for (final SharedUserSetting usr : mSharedUsers.values()) {
+                    serializer.startTag(null, "shared-user");
+                    serializer.attribute(null, ATTR_NAME, usr.name);
+                    serializer.attributeInt(null, "userId", usr.mAppId);
+                    usr.signatures.writeXml(serializer, "sigs", mPastSignatures.untrackedStorage());
+                    serializer.endTag(null, "shared-user");
+                }
+
+                if (mRenamedPackages.size() > 0) {
+                    for (Map.Entry<String, String> e : mRenamedPackages.entrySet()) {
+                        serializer.startTag(null, "renamed-package");
+                        serializer.attribute(null, "new", e.getKey());
+                        serializer.attribute(null, "old", e.getValue());
+                        serializer.endTag(null, "renamed-package");
+                    }
+                }
+
+                mDomainVerificationManager.writeSettings(computer, serializer,
+                        false /* includeSignatures */, UserHandle.USER_ALL);
+
+                mKeySetManagerService.writeKeySetManagerServiceLPr(serializer);
+
+                serializer.endTag(null, "packages");
+
+                serializer.endDocument();
+
+                atomicFile.finishWrite(str);
+
+                writeKernelMappingLPr();
+                writePackageListLPr();
+                writeAllUsersPackageRestrictionsLPr(sync);
+                writeAllRuntimePermissionsLPr();
+                com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
+                        "package", SystemClock.uptimeMillis() - startTime);
+                return;
+
+            } catch (java.io.IOException e) {
+                Slog.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
+                        + "current changes will be lost at reboot", e);
+                if (str != null) {
+                    atomicFile.failWrite(str);
+                }
             }
         }
         //Debug.stopMethodTracing();
@@ -3160,183 +3048,140 @@
         mInstallerPackages.clear();
         originalFirstInstallTimes.clear();
 
-        File file = null;
-        FileInputStream str = null;
+        try (ResilientAtomicFile atomicFile = getSettingsFile()) {
+            FileInputStream str = null;
+            try {
+                str = atomicFile.openRead();
+                if (str == null) {
+                    // Not necessary, but will avoid wtf-s in the "finally" section.
+                    findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent();
+                    findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent();
+                    return false;
+                }
+                final TypedXmlPullParser parser = Xml.resolvePullParser(str);
 
-        try {
-            // Check if the previous write was incomplete.
-            if (mPreviousSettingsFilename.exists()) {
-                try {
-                    file = mPreviousSettingsFilename;
-                    str = new FileInputStream(file);
-                    mReadMessages.append("Reading from backup settings file\n");
-                    PackageManagerService.reportSettingsProblem(Log.INFO,
-                            "Need to read from backup settings file");
-                    if (mSettingsFilename.exists()) {
-                        // If both the previous and current settings files exist,
-                        // we ignore the current since it might have been corrupted.
-                        Slog.w(PackageManagerService.TAG, "Cleaning up settings file "
-                                + mSettingsFilename);
-                        mSettingsFilename.delete();
+                int type;
+                while ((type = parser.next()) != XmlPullParser.START_TAG
+                        && type != XmlPullParser.END_DOCUMENT) {
+                    // nothing
+                }
+
+                if (type != XmlPullParser.START_TAG) {
+                    mReadMessages.append("No start tag found in settings file\n");
+                    PackageManagerService.reportSettingsProblem(Log.WARN,
+                            "No start tag found in package manager settings");
+                    Slog.wtf(PackageManagerService.TAG,
+                            "No start tag found in package manager settings");
+                    return false;
+                }
+
+                int outerDepth = parser.getDepth();
+                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                        && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                    if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                        continue;
                     }
-                    // Ignore reserve copy as well.
-                    mSettingsReserveCopyFilename.delete();
-                } catch (java.io.IOException e) {
-                    // We'll try for the normal settings file.
-                }
-            }
-            if (str == null) {
-                if (mSettingsFilename.exists()) {
-                    // Using packages.xml.
-                    file = mSettingsFilename;
-                    str = new FileInputStream(file);
-                } else if (mSettingsReserveCopyFilename.exists()) {
-                    // Using reserve copy.
-                    file = mSettingsReserveCopyFilename;
-                    str = new FileInputStream(file);
-                    mReadMessages.append("Reading from reserve copy settings file\n");
-                    PackageManagerService.reportSettingsProblem(Log.INFO,
-                            "Need to read from reserve copy settings file");
-                }
-            }
-            if (str == null) {
-                // No available data sources.
-                mReadMessages.append("No settings file found\n");
-                PackageManagerService.reportSettingsProblem(Log.INFO,
-                        "No settings file; creating initial state");
-                // Not necessary, but will avoid wtf-s in the "finally" section.
-                findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent();
-                findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent();
-                return false;
-            }
-            final TypedXmlPullParser parser = Xml.resolvePullParser(str);
 
-            int type;
-            while ((type = parser.next()) != XmlPullParser.START_TAG
-                    && type != XmlPullParser.END_DOCUMENT) {
-                ;
-            }
+                    String tagName = parser.getName();
+                    if (tagName.equals("package")) {
+                        readPackageLPw(parser, users, originalFirstInstallTimes);
+                    } else if (tagName.equals("permissions")) {
+                        mPermissions.readPermissions(parser);
+                    } else if (tagName.equals("permission-trees")) {
+                        mPermissions.readPermissionTrees(parser);
+                    } else if (tagName.equals("shared-user")) {
+                        readSharedUserLPw(parser, users);
+                    } else if (tagName.equals("preferred-packages")) {
+                        // no longer used.
+                    } else if (tagName.equals("preferred-activities")) {
+                        // Upgrading from old single-user implementation;
+                        // these are the preferred activities for user 0.
+                        readPreferredActivitiesLPw(parser, 0);
+                    } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
+                        // TODO: check whether this is okay! as it is very
+                        // similar to how preferred-activities are treated
+                        readPersistentPreferredActivitiesLPw(parser, 0);
+                    } else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) {
+                        // TODO: check whether this is okay! as it is very
+                        // similar to how preferred-activities are treated
+                        readCrossProfileIntentFiltersLPw(parser, 0);
+                    } else if (tagName.equals(TAG_DEFAULT_BROWSER)) {
+                        readDefaultAppsLPw(parser, 0);
+                    } else if (tagName.equals("updated-package")) {
+                        readDisabledSysPackageLPw(parser, users);
+                    } else if (tagName.equals("renamed-package")) {
+                        String nname = parser.getAttributeValue(null, "new");
+                        String oname = parser.getAttributeValue(null, "old");
+                        if (nname != null && oname != null) {
+                            mRenamedPackages.put(nname, oname);
+                        }
+                    } else if (tagName.equals("last-platform-version")) {
+                        // Upgrade from older XML schema
+                        final VersionInfo internal = findOrCreateVersion(
+                                StorageManager.UUID_PRIVATE_INTERNAL);
+                        final VersionInfo external = findOrCreateVersion(
+                                StorageManager.UUID_PRIMARY_PHYSICAL);
 
-            if (type != XmlPullParser.START_TAG) {
-                mReadMessages.append("No start tag found in settings file\n");
-                PackageManagerService.reportSettingsProblem(Log.WARN,
-                        "No start tag found in package manager settings");
-                Slog.wtf(PackageManagerService.TAG,
-                        "No start tag found in package manager settings");
-                return false;
-            }
+                        internal.sdkVersion = parser.getAttributeInt(null, "internal", 0);
+                        external.sdkVersion = parser.getAttributeInt(null, "external", 0);
+                        internal.buildFingerprint = external.buildFingerprint =
+                                XmlUtils.readStringAttribute(parser, "buildFingerprint");
+                        internal.fingerprint = external.fingerprint =
+                                XmlUtils.readStringAttribute(parser, "fingerprint");
 
-            int outerDepth = parser.getDepth();
-            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                    continue;
-                }
+                    } else if (tagName.equals("database-version")) {
+                        // Upgrade from older XML schema
+                        final VersionInfo internal = findOrCreateVersion(
+                                StorageManager.UUID_PRIVATE_INTERNAL);
+                        final VersionInfo external = findOrCreateVersion(
+                                StorageManager.UUID_PRIMARY_PHYSICAL);
 
-                String tagName = parser.getName();
-                if (tagName.equals("package")) {
-                    readPackageLPw(parser, users, originalFirstInstallTimes);
-                } else if (tagName.equals("permissions")) {
-                    mPermissions.readPermissions(parser);
-                } else if (tagName.equals("permission-trees")) {
-                    mPermissions.readPermissionTrees(parser);
-                } else if (tagName.equals("shared-user")) {
-                    readSharedUserLPw(parser, users);
-                } else if (tagName.equals("preferred-packages")) {
-                    // no longer used.
-                } else if (tagName.equals("preferred-activities")) {
-                    // Upgrading from old single-user implementation;
-                    // these are the preferred activities for user 0.
-                    readPreferredActivitiesLPw(parser, 0);
-                } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
-                    // TODO: check whether this is okay! as it is very
-                    // similar to how preferred-activities are treated
-                    readPersistentPreferredActivitiesLPw(parser, 0);
-                } else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) {
-                    // TODO: check whether this is okay! as it is very
-                    // similar to how preferred-activities are treated
-                    readCrossProfileIntentFiltersLPw(parser, 0);
-                } else if (tagName.equals(TAG_DEFAULT_BROWSER)) {
-                    readDefaultAppsLPw(parser, 0);
-                } else if (tagName.equals("updated-package")) {
-                    readDisabledSysPackageLPw(parser, users);
-                } else if (tagName.equals("renamed-package")) {
-                    String nname = parser.getAttributeValue(null, "new");
-                    String oname = parser.getAttributeValue(null, "old");
-                    if (nname != null && oname != null) {
-                        mRenamedPackages.put(nname, oname);
+                        internal.databaseVersion = parser.getAttributeInt(null, "internal", 0);
+                        external.databaseVersion = parser.getAttributeInt(null, "external", 0);
+
+                    } else if (tagName.equals("verifier")) {
+                        final String deviceIdentity = parser.getAttributeValue(null, "device");
+                        try {
+                            mVerifierDeviceIdentity = VerifierDeviceIdentity.parse(deviceIdentity);
+                        } catch (IllegalArgumentException e) {
+                            Slog.w(PackageManagerService.TAG, "Discard invalid verifier device id: "
+                                    + e.getMessage());
+                        }
+                    } else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) {
+                        // No longer used.
+                    } else if (tagName.equals("keyset-settings")) {
+                        mKeySetManagerService.readKeySetsLPw(parser,
+                                mKeySetRefs.untrackedStorage());
+                    } else if (TAG_VERSION.equals(tagName)) {
+                        final String volumeUuid = XmlUtils.readStringAttribute(parser,
+                                ATTR_VOLUME_UUID);
+                        final VersionInfo ver = findOrCreateVersion(volumeUuid);
+                        ver.sdkVersion = parser.getAttributeInt(null, ATTR_SDK_VERSION);
+                        ver.databaseVersion = parser.getAttributeInt(null, ATTR_DATABASE_VERSION);
+                        ver.buildFingerprint = XmlUtils.readStringAttribute(parser,
+                                ATTR_BUILD_FINGERPRINT);
+                        ver.fingerprint = XmlUtils.readStringAttribute(parser, ATTR_FINGERPRINT);
+                    } else if (tagName.equals(
+                            DomainVerificationPersistence.TAG_DOMAIN_VERIFICATIONS)) {
+                        mDomainVerificationManager.readSettings(computer, parser);
+                    } else if (tagName.equals(
+                            DomainVerificationLegacySettings.TAG_DOMAIN_VERIFICATIONS_LEGACY)) {
+                        mDomainVerificationManager.readLegacySettings(parser);
+                    } else {
+                        Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
+                                + parser.getName());
+                        XmlUtils.skipCurrentTag(parser);
                     }
-                } else if (tagName.equals("last-platform-version")) {
-                    // Upgrade from older XML schema
-                    final VersionInfo internal = findOrCreateVersion(
-                            StorageManager.UUID_PRIVATE_INTERNAL);
-                    final VersionInfo external = findOrCreateVersion(
-                            StorageManager.UUID_PRIMARY_PHYSICAL);
-
-                    internal.sdkVersion = parser.getAttributeInt(null, "internal", 0);
-                    external.sdkVersion = parser.getAttributeInt(null, "external", 0);
-                    internal.buildFingerprint = external.buildFingerprint =
-                            XmlUtils.readStringAttribute(parser, "buildFingerprint");
-                    internal.fingerprint = external.fingerprint =
-                            XmlUtils.readStringAttribute(parser, "fingerprint");
-
-                } else if (tagName.equals("database-version")) {
-                    // Upgrade from older XML schema
-                    final VersionInfo internal = findOrCreateVersion(
-                            StorageManager.UUID_PRIVATE_INTERNAL);
-                    final VersionInfo external = findOrCreateVersion(
-                            StorageManager.UUID_PRIMARY_PHYSICAL);
-
-                    internal.databaseVersion = parser.getAttributeInt(null, "internal", 0);
-                    external.databaseVersion = parser.getAttributeInt(null, "external", 0);
-
-                } else if (tagName.equals("verifier")) {
-                    final String deviceIdentity = parser.getAttributeValue(null, "device");
-                    try {
-                        mVerifierDeviceIdentity = VerifierDeviceIdentity.parse(deviceIdentity);
-                    } catch (IllegalArgumentException e) {
-                        Slog.w(PackageManagerService.TAG, "Discard invalid verifier device id: "
-                                + e.getMessage());
-                    }
-                } else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) {
-                    // No longer used.
-                } else if (tagName.equals("keyset-settings")) {
-                    mKeySetManagerService.readKeySetsLPw(parser, mKeySetRefs.untrackedStorage());
-                } else if (TAG_VERSION.equals(tagName)) {
-                    final String volumeUuid = XmlUtils.readStringAttribute(parser,
-                            ATTR_VOLUME_UUID);
-                    final VersionInfo ver = findOrCreateVersion(volumeUuid);
-                    ver.sdkVersion = parser.getAttributeInt(null, ATTR_SDK_VERSION);
-                    ver.databaseVersion = parser.getAttributeInt(null, ATTR_DATABASE_VERSION);
-                    ver.buildFingerprint = XmlUtils.readStringAttribute(parser,
-                            ATTR_BUILD_FINGERPRINT);
-                    ver.fingerprint = XmlUtils.readStringAttribute(parser, ATTR_FINGERPRINT);
-                } else if (tagName.equals(DomainVerificationPersistence.TAG_DOMAIN_VERIFICATIONS)) {
-                    mDomainVerificationManager.readSettings(computer, parser);
-                } else if (tagName.equals(
-                        DomainVerificationLegacySettings.TAG_DOMAIN_VERIFICATIONS_LEGACY)) {
-                    mDomainVerificationManager.readLegacySettings(parser);
-                } else {
-                    Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
-                            + parser.getName());
-                    XmlUtils.skipCurrentTag(parser);
                 }
+
+                str.close();
+            } catch (IOException | XmlPullParserException e) {
+                // Remove corrupted file and retry.
+                atomicFile.failRead(str, e);
+
+                // Ignore the result to not mark this as a "first boot".
+                readSettingsLPw(computer, users, originalFirstInstallTimes);
             }
-
-            str.close();
-        } catch (IOException | XmlPullParserException e) {
-            mReadMessages.append("Error reading: " + e.toString());
-            PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
-            Slog.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);
-
-            // Remove corrupted file and retry.
-            Slog.e(TAG,
-                    "Error reading package manager settings, removing " + file + " and retrying.",
-                    e);
-            file.delete();
-
-            // Ignore the result to not mark this as a "first boot".
-            readSettingsLPw(computer, users, originalFirstInstallTimes);
         }
 
         return true;
@@ -4488,10 +4333,7 @@
         mPreferredActivities.remove(userId);
 
         synchronized (mPackageRestrictionsLock) {
-            File file = getUserPackagesStateFile(userId);
-            file.delete();
-            file = getUserPackagesStateBackupFile(userId);
-            file.delete();
+            getUserPackagesStateFile(userId).delete();
             mPendingAsyncPackageRestrictionsWrites.delete(userId);
         }
 
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 67639fb..28cb7f0 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -2048,6 +2048,9 @@
                                         shortcutUser.getUserId(), fromBackup);
                                 // Don't use addShortcut(), we don't need to save the icon.
                                 ret.mShortcuts.put(si.getId(), si);
+                            } catch (IOException e) {
+                                // Don't ignore IO exceptions.
+                                throw e;
                             } catch (Exception e) {
                                 // b/246540168 malformed shortcuts should be ignored
                                 Slog.e(TAG, "Failed parsing shortcut.", e);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index e20330d..8b118da 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -27,6 +27,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 import com.android.modules.utils.TypedXmlSerializer;
+import com.android.server.security.FileIntegrity;
 
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -180,6 +181,12 @@
 
             os.flush();
             file.finishWrite(os);
+
+            try {
+                FileIntegrity.setUpFsVerity(path);
+            } catch (IOException e) {
+                Slog.e(TAG, "Failed to verity-protect " + path, e);
+            }
         } catch (XmlPullParserException | IOException e) {
             Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
             file.failWrite(os);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 372b3bb..20cb485 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -119,7 +119,6 @@
 import com.android.modules.utils.TypedXmlSerializer;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
-import com.android.server.security.FileIntegrity;
 import com.android.server.uri.UriGrantsManagerInternal;
 
 import org.json.JSONArray;
@@ -1070,57 +1069,38 @@
     }
 
     @VisibleForTesting
-    final File getUserFile(@UserIdInt int userId) {
-        return new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES);
-    }
-
-    @VisibleForTesting
-    final File getReserveCopyUserFile(@UserIdInt int userId) {
-        return new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES_RESERVE_COPY);
+    final ResilientAtomicFile getUserFile(@UserIdInt int userId) {
+        File mainFile = new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES);
+        File temporaryBackup = new File(injectUserDataPath(userId),
+                FILENAME_USER_PACKAGES + ".backup");
+        File reserveCopy = new File(injectUserDataPath(userId),
+                FILENAME_USER_PACKAGES_RESERVE_COPY);
+        int fileMode = FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH;
+        return new ResilientAtomicFile(mainFile, temporaryBackup, reserveCopy, fileMode,
+                "user shortcut", null);
     }
 
     @GuardedBy("mLock")
     private void saveUserLocked(@UserIdInt int userId) {
-        final File path = getUserFile(userId);
-        if (DEBUG || DEBUG_REBOOT) {
-            Slog.d(TAG, "Saving to " + path);
-        }
+        try (ResilientAtomicFile file = getUserFile(userId)) {
+            FileOutputStream os = null;
+            try {
+                if (DEBUG || DEBUG_REBOOT) {
+                    Slog.d(TAG, "Saving to " + file);
+                }
 
-        final File reservePath = getReserveCopyUserFile(userId);
-        reservePath.delete();
+                os = file.startWrite();
 
-        path.getParentFile().mkdirs();
-        final AtomicFile file = new AtomicFile(path);
-        FileOutputStream os = null;
-        try {
-            os = file.startWrite();
+                saveUserInternalLocked(userId, os, /* forBackup= */ false);
 
-            saveUserInternalLocked(userId, os, /* forBackup= */ false);
+                file.finishWrite(os);
 
-            file.finishWrite(os);
-
-            // Remove all dangling bitmap files.
-            cleanupDanglingBitmapDirectoriesLocked(userId);
-        } catch (XmlPullParserException | IOException e) {
-            Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
-            file.failWrite(os);
-        }
-
-        // Store the reserve copy of the file.
-        try (FileInputStream in = new FileInputStream(path);
-             FileOutputStream out = new FileOutputStream(reservePath)) {
-            FileUtils.copy(in, out);
-            FileUtils.sync(out);
-        } catch (IOException e) {
-            Slog.e(TAG, "Failed to write reserve copy: " + path, e);
-        }
-
-        // Protect both primary and reserve copy with fs-verity.
-        try {
-            FileIntegrity.setUpFsVerity(path);
-            FileIntegrity.setUpFsVerity(reservePath);
-        } catch (IOException e) {
-            Slog.e(TAG, "Failed to verity-protect", e);
+                // Remove all dangling bitmap files.
+                cleanupDanglingBitmapDirectoriesLocked(userId);
+            } catch (XmlPullParserException | IOException e) {
+                Slog.e(TAG, "Failed to write to file " + file, e);
+                file.failWrite(os);
+            }
         }
 
         getUserShortcutsLocked(userId).logSharingShortcutStats(mMetricsLogger);
@@ -1157,29 +1137,26 @@
 
     @Nullable
     private ShortcutUser loadUserLocked(@UserIdInt int userId) {
-        final File path = getUserFile(userId);
-        if (DEBUG || DEBUG_REBOOT) {
-            Slog.d(TAG, "Loading from " + path);
-        }
-
-        try (FileInputStream in = new AtomicFile(path).openRead()) {
-            return loadUserInternal(userId, in, /* forBackup= */ false);
-        } catch (FileNotFoundException e) {
-            if (DEBUG || DEBUG_REBOOT) {
-                Slog.d(TAG, "Not found " + path);
-            }
-        } catch (Exception e) {
-            final File reservePath = getReserveCopyUserFile(userId);
-            Slog.e(TAG, "Reading from reserve copy: " + reservePath, e);
-            try (FileInputStream in = new AtomicFile(reservePath).openRead()) {
+        try (ResilientAtomicFile file = getUserFile(userId)) {
+            FileInputStream in = null;
+            try {
+                if (DEBUG || DEBUG_REBOOT) {
+                    Slog.d(TAG, "Loading from " + file);
+                }
+                in = file.openRead();
+                if (in == null) {
+                    if (DEBUG || DEBUG_REBOOT) {
+                        Slog.d(TAG, "Not found " + file);
+                    }
+                    return null;
+                }
                 return loadUserInternal(userId, in, /* forBackup= */ false);
-            } catch (Exception exceptionReadingReserveFile) {
-                Slog.e(TAG, "Failed to read reserve copy: " + reservePath,
-                        exceptionReadingReserveFile);
+            } catch (Exception e) {
+                // Remove corrupted file and retry.
+                file.failRead(in, e);
+                return loadUserLocked(userId);
             }
-            Slog.e(TAG, "Failed to read file " + path, e);
         }
-        return null;
     }
 
     private ShortcutUser loadUserInternal(@UserIdInt int userId, InputStream is,
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index 9ef1bba..b4d467f 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -64,12 +64,11 @@
     })
     public @interface UserAssignmentResult {}
 
-    // TODO(b/248408342): Move keep annotation to the method referencing these fields reflectively.
-    @Keep public static final int USER_START_MODE_FOREGROUND = 1;
-    @Keep public static final int USER_START_MODE_BACKGROUND = 2;
-    @Keep public static final int USER_START_MODE_BACKGROUND_VISIBLE = 3;
-
     private static final String PREFIX_USER_START_MODE = "USER_START_MODE_";
+
+    /**
+     * Type used to indicate how a user started.
+     */
     @IntDef(flag = false, prefix = {PREFIX_USER_START_MODE}, value = {
             USER_START_MODE_FOREGROUND,
             USER_START_MODE_BACKGROUND,
@@ -77,6 +76,32 @@
     })
     public @interface UserStartMode {}
 
+    // TODO(b/248408342): Move keep annotations below to the method referencing these fields
+    // reflectively.
+
+    /** (Full) user started on foreground (a.k.a. "current user"). */
+    @Keep public static final int USER_START_MODE_FOREGROUND = 1;
+
+    /**
+     * User (full or profile) started on background and is
+     * {@link UserManager#isUserVisible() invisible}.
+     *
+     * <p>This is the "traditional" way of starting a background user, and can be used to start
+     * profiles as well, although starting an invisible profile is not common from the System UI
+     * (it could be done through APIs or adb, though).
+     */
+    @Keep public static final int USER_START_MODE_BACKGROUND = 2;
+
+    /**
+     * User (full or profile) started on background and is
+     * {@link UserManager#isUserVisible() visible}.
+     *
+     * <p>This is the "traditional" way of starting a profile (i.e., when the profile of the current
+     * user is the current foreground user), but it can also be used to start a full user associated
+     * with a display (which is the case on automotives with passenger displays).
+     */
+    @Keep public static final int USER_START_MODE_BACKGROUND_VISIBLE = 3;
+
     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 2b08a2c..2f98d34 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2049,6 +2049,27 @@
                 + "permission to: check " + name);
     }
 
+    /**
+     * Enforces that the calling user is in the same profile group as {@code userId} or that only
+     * the system UID or root's UID or apps that have the
+     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
+     * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS} or
+     * {@link android.Manifest.permission#QUERY_USERS QUERY_USERS}
+     * can make certain calls to the UserManager.
+     *
+     * @param userId the user's id
+     * @param name used as message if SecurityException is thrown
+     * @throws SecurityException if the caller lacks the required permissions.
+     */
+    private void checkQueryOrCreateUsersPermissionIfCallerInOtherProfileGroup(
+            @UserIdInt int userId, String name) {
+        final int callingUserId = UserHandle.getCallingUserId();
+        if (callingUserId == userId || isSameProfileGroupNoChecks(callingUserId, userId)) {
+            return;
+        }
+        checkQueryOrCreateUsersPermission(name);
+    }
+
     @Override
     public boolean isDemoUser(@UserIdInt int userId) {
         final int callingUserId = UserHandle.getCallingUserId();
@@ -2063,6 +2084,15 @@
     }
 
     @Override
+    public boolean isAdminUser(@UserIdInt int userId) {
+        checkQueryOrCreateUsersPermissionIfCallerInOtherProfileGroup(userId, "isAdminUser");
+        synchronized (mUsersLock) {
+            final UserInfo userInfo = getUserInfoLU(userId);
+            return userInfo != null && userInfo.isAdmin();
+        }
+    }
+
+    @Override
     public boolean isPreCreated(@UserIdInt int userId) {
         checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "isPreCreated");
         synchronized (mUsersLock) {
@@ -3605,6 +3635,13 @@
         } finally {
             IoUtils.closeQuietly(fis);
         }
+
+        synchronized (mUsersLock) {
+            if (mUsers.size() == 0) {
+                Slog.e(LOG_TAG, "mUsers is empty, fallback to single user");
+                fallbackToSingleUserLP();
+            }
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/UserVisibilityMediator.java b/services/core/java/com/android/server/pm/UserVisibilityMediator.java
index 3f7502b..f87f50a 100644
--- a/services/core/java/com/android/server/pm/UserVisibilityMediator.java
+++ b/services/core/java/com/android/server/pm/UserVisibilityMediator.java
@@ -42,6 +42,7 @@
 import android.util.EventLog;
 import android.util.IndentingPrintWriter;
 import android.util.IntArray;
+import android.util.Log;
 import android.util.SparseIntArray;
 import android.view.Display;
 
@@ -55,6 +56,8 @@
 import com.android.server.utils.Slogf;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
@@ -77,11 +80,11 @@
  */
 public final class UserVisibilityMediator implements Dumpable {
 
-    private static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
-    private static final boolean VERBOSE = false; // DO NOT SUBMIT WITH TRUE
-
     private static final String TAG = UserVisibilityMediator.class.getSimpleName();
 
+    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final boolean VERBOSE = false; // DO NOT SUBMIT WITH TRUE
+
     private static final String PREFIX_SECONDARY_DISPLAY_MAPPING = "SECONDARY_DISPLAY_MAPPING_";
     public static final int SECONDARY_DISPLAY_MAPPING_NEEDED = 1;
     public static final int SECONDARY_DISPLAY_MAPPING_NOT_NEEDED = 2;
@@ -98,7 +101,7 @@
     })
     public @interface SecondaryDisplayMappingStatus {}
 
-    // TODO(b/242195409): might need to change this if boot logic is refactored for HSUM devices
+    // TODO(b/266158156): might need to change this if boot logic is refactored for HSUM devices
     @VisibleForTesting
     static final int INITIAL_CURRENT_USER_ID = USER_SYSTEM;
 
@@ -132,10 +135,23 @@
     private final SparseIntArray mExtraDisplaysAssignedToUsers;
 
     /**
-     * Mapping from each started user to its profile group.
+     * Mapping of each user that started visible (key) to its profile group id (value).
+     *
+     * <p>It's used to determine not just if the user is visible, but also
+     * {@link #isProfile(int, int) if it's a profile}.
      */
     @GuardedBy("mLock")
-    private final SparseIntArray mStartedProfileGroupIds = new SparseIntArray();
+    private final SparseIntArray mStartedVisibleProfileGroupIds = new SparseIntArray();
+
+    /**
+     * List of profiles that have explicitly started invisible.
+     *
+     * <p>Only used for debugging purposes (and set when {@link #DBG} is {@code true}), hence we
+     * don't care about autoboxing.
+     */
+    @GuardedBy("mLock")
+    @Nullable
+    private final List<Integer> mStartedInvisibleProfileUserIds;
 
     /**
      * Handler user to call listeners
@@ -164,9 +180,14 @@
             mUsersAssignedToDisplayOnStart = null;
             mExtraDisplaysAssignedToUsers = null;
         }
+        mStartedInvisibleProfileUserIds = DBG ? new ArrayList<>(4) : null;
         mHandler = handler;
-        // TODO(b/242195409): might need to change this if boot logic is refactored for HSUM devices
-        mStartedProfileGroupIds.put(INITIAL_CURRENT_USER_ID, INITIAL_CURRENT_USER_ID);
+        // TODO(b/266158156): might need to change this if boot logic is refactored for HSUM devices
+        mStartedVisibleProfileGroupIds.put(INITIAL_CURRENT_USER_ID, INITIAL_CURRENT_USER_ID);
+
+        if (DBG) {
+            Slogf.i(TAG, "UserVisibilityMediator created with DBG on");
+        }
     }
 
     /**
@@ -177,6 +198,8 @@
             int displayId) {
         Preconditions.checkArgument(!isSpecialUserId(userId), "user id cannot be generic: %d",
                 userId);
+        validateUserStartMode(userStartMode);
+
         // This method needs to perform 4 actions:
         //
         // 1. Check if the user can be started given the provided arguments
@@ -224,14 +247,29 @@
 
             visibleUsersBefore = getVisibleUsers();
 
-            // Set current user / profiles state
-            if (userStartMode == USER_START_MODE_FOREGROUND) {
-                mCurrentUserId = userId;
+            // Set current user / started users state
+            switch (userStartMode) {
+                case USER_START_MODE_FOREGROUND:
+                    mCurrentUserId = userId;
+                    // Fallthrough
+                case USER_START_MODE_BACKGROUND_VISIBLE:
+                    if (DBG) {
+                        Slogf.d(TAG, "adding visible user / profile group id mapping (%d -> %d)",
+                                userId, profileGroupId);
+                    }
+                    mStartedVisibleProfileGroupIds.put(userId, profileGroupId);
+                    break;
+                case USER_START_MODE_BACKGROUND:
+                    if (mStartedInvisibleProfileUserIds != null
+                            && isProfile(userId, profileGroupId)) {
+                        Slogf.d(TAG, "adding user %d to list of invisible profiles", userId);
+                        mStartedInvisibleProfileUserIds.add(userId);
+                    }
+                    break;
+                default:
+                    Slogf.wtf(TAG,  "invalid userStartMode passed to assignUserToDisplayOnStart: "
+                            + "%d", userStartMode);
             }
-            if (DBG) {
-                Slogf.d(TAG, "adding user / profile mapping (%d -> %d)", userId, profileGroupId);
-            }
-            mStartedProfileGroupIds.put(userId, profileGroupId);
 
             //  Set user / display state
             switch (mappingResult) {
@@ -297,38 +335,44 @@
         boolean foreground = userStartMode == USER_START_MODE_FOREGROUND;
         if (displayId != DEFAULT_DISPLAY) {
             if (foreground) {
-                Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %b, %d) failed: cannot start "
+                Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: cannot start "
                         + "foreground user on secondary display", userId, profileGroupId,
-                        foreground, displayId);
+                        userStartModeToString(userStartMode), displayId);
                 return USER_ASSIGNMENT_RESULT_FAILURE;
             }
             if (!mVisibleBackgroundUsersEnabled) {
-                Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %b, %d) failed: called on "
+                Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: called on "
                         + "device that doesn't support multiple users on multiple displays",
-                        userId, profileGroupId, foreground, displayId);
+                        userId, profileGroupId, userStartModeToString(userStartMode), displayId);
                 return USER_ASSIGNMENT_RESULT_FAILURE;
             }
         }
 
         if (isProfile(userId, profileGroupId)) {
             if (displayId != DEFAULT_DISPLAY) {
-                Slogf.w(TAG, "canStartUserLocked(%d, %d, %b, %d) failed: cannot start profile user "
-                        + "on secondary display", userId, profileGroupId, foreground,
-                        displayId);
+                Slogf.w(TAG, "canStartUserLocked(%d, %d, %s, %d) failed: cannot start profile user "
+                        + "on secondary display", userId, profileGroupId,
+                        userStartModeToString(userStartMode), displayId);
                 return USER_ASSIGNMENT_RESULT_FAILURE;
             }
-            if (foreground) {
-                Slogf.w(TAG, "startUser(%d, %d, %b, %d) failed: cannot start profile user in "
-                        + "foreground", userId, profileGroupId, foreground, displayId);
-                return USER_ASSIGNMENT_RESULT_FAILURE;
-            } else {
-                boolean isParentVisibleOnDisplay = isUserVisible(profileGroupId, displayId);
-                if (DBG) {
-                    Slogf.d(TAG, "parent visible on display: %b", isParentVisibleOnDisplay);
-                }
-                return isParentVisibleOnDisplay
-                        ? USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE
-                        : USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
+            switch (userStartMode) {
+                case USER_START_MODE_FOREGROUND:
+                    Slogf.w(TAG, "startUser(%d, %d, %s, %d) failed: cannot start profile user in "
+                            + "foreground", userId, profileGroupId,
+                            userStartModeToString(userStartMode), displayId);
+                    return USER_ASSIGNMENT_RESULT_FAILURE;
+                case USER_START_MODE_BACKGROUND_VISIBLE:
+                    boolean isParentVisibleOnDisplay = isUserVisible(profileGroupId, displayId);
+                    if (!isParentVisibleOnDisplay) {
+                        Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: cannot"
+                                + " start profile user visible when its parent is not visible in "
+                                + "that display", userId, profileGroupId,
+                                userStartModeToString(userStartMode), displayId);
+                        return USER_ASSIGNMENT_RESULT_FAILURE;
+                    }
+                    return USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE;
+                case USER_START_MODE_BACKGROUND:
+                    return USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
             }
         } else if (mUsersAssignedToDisplayOnStart != null
                 && isUserAssignedToDisplayOnStartLocked(userId, displayId)) {
@@ -353,8 +397,9 @@
             if (mVisibleBackgroundUserOnDefaultDisplayAllowed
                     && userStartMode == USER_START_MODE_BACKGROUND_VISIBLE) {
                 int userStartedOnDefaultDisplay = getUserStartedOnDisplay(DEFAULT_DISPLAY);
-                if (userStartedOnDefaultDisplay != USER_NULL) {
-                    Slogf.w(TAG, "getUserVisibilityOnStartLocked(): cannot start user %d visible on"
+                if (userStartedOnDefaultDisplay != USER_NULL
+                        && userStartedOnDefaultDisplay != profileGroupId) {
+                    Slogf.w(TAG, "canAssignUserToDisplayLocked(): cannot start user %d visible on"
                             + " default display because user %d already did so", userId,
                             userStartedOnDefaultDisplay);
                     return SECONDARY_DISPLAY_MAPPING_FAILED;
@@ -468,7 +513,7 @@
                         userId, displayId);
                 return false;
             }
-            if (isStartedProfile(userId)) {
+            if (isStartedVisibleProfileLocked(userId)) {
                 Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user is a profile",
                         userId, displayId);
                 return false;
@@ -556,10 +601,14 @@
     @GuardedBy("mLock")
     private void unassignUserFromAllDisplaysOnStopLocked(@UserIdInt int userId) {
         if (DBG) {
-            Slogf.d(TAG, "Removing %d from mStartedProfileGroupIds (%s)", userId,
-                    mStartedProfileGroupIds);
+            Slogf.d(TAG, "Removing %d from mStartedVisibleProfileGroupIds (%s)", userId,
+                    mStartedVisibleProfileGroupIds);
         }
-        mStartedProfileGroupIds.delete(userId);
+        mStartedVisibleProfileGroupIds.delete(userId);
+        if (mStartedInvisibleProfileUserIds != null) {
+            Slogf.d(TAG, "Removing %d from list of invisible profiles", userId);
+            mStartedInvisibleProfileUserIds.remove(Integer.valueOf(userId));
+        }
 
         if (!mVisibleBackgroundUsersEnabled) {
             // Don't need to update mUsersAssignedToDisplayOnStart because methods (such as
@@ -589,7 +638,8 @@
      * See {@link UserManagerInternal#isUserVisible(int)}.
      */
     public boolean isUserVisible(@UserIdInt int userId) {
-        // First check current foreground user and their profiles (on main display)
+        // For optimization (as most devices don't support visible background users), check for
+        // current foreground user and their profiles first
         if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
             if (VERBOSE) {
                 Slogf.v(TAG, "isUserVisible(%d): true to current user or profile", userId);
@@ -598,19 +648,31 @@
         }
 
         if (!mVisibleBackgroundUsersEnabled) {
-            if (DBG) {
-                Slogf.d(TAG, "isUserVisible(%d): false for non-current user (or its profiles) when"
+            if (VERBOSE) {
+                Slogf.v(TAG, "isUserVisible(%d): false for non-current user (or its profiles) when"
                         + " device doesn't support visible background users", userId);
             }
             return false;
         }
 
-        boolean visible;
+
         synchronized (mLock) {
-            visible = mUsersAssignedToDisplayOnStart.indexOfKey(userId) >= 0;
+            int profileGroupId;
+            synchronized (mLock) {
+                profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
+            }
+            if (isProfile(userId, profileGroupId)) {
+                return isUserAssignedToDisplayOnStartLocked(profileGroupId);
+            }
+            return isUserAssignedToDisplayOnStartLocked(userId);
         }
-        if (DBG) {
-            Slogf.d(TAG, "isUserVisible(%d): %b from mapping", userId, visible);
+    }
+
+    @GuardedBy("mLock")
+    private boolean isUserAssignedToDisplayOnStartLocked(@UserIdInt int userId) {
+        boolean visible = mUsersAssignedToDisplayOnStart.indexOfKey(userId) >= 0;
+        if (VERBOSE) {
+            Slogf.v(TAG, "isUserAssignedToDisplayOnStartLocked(%d): %b", userId, visible);
         }
         return visible;
     }
@@ -640,7 +702,8 @@
             return false;
         }
 
-        // Current user is always visible on:
+        // For optimization (as most devices don't support visible background users), check for
+        // current user and profile first. Current user is always visible on:
         // - Default display
         // - Secondary displays when device doesn't support visible bg users
         //   - Or when explicitly added (which is checked below)
@@ -662,16 +725,28 @@
         }
 
         synchronized (mLock) {
-            if (mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY) == displayId) {
-                // User assigned to display on start
-                return true;
+            int profileGroupId;
+            synchronized (mLock) {
+                profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
             }
-
-            // Check for extra display assignment
-            return mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId;
+            if (isProfile(userId, profileGroupId)) {
+                return isFullUserVisibleOnBackgroundLocked(profileGroupId, displayId);
+            }
+            return isFullUserVisibleOnBackgroundLocked(userId, displayId);
         }
     }
 
+    // NOTE: it doesn't check if the userId is a full user, it's up to the caller to check that
+    @GuardedBy("mLock")
+    private boolean isFullUserVisibleOnBackgroundLocked(@UserIdInt int userId, int displayId) {
+        if (mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY) == displayId) {
+            // User assigned to display on start
+            return true;
+        }
+        // Check for extra display assignment
+        return mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId;
+    }
+
     /**
      * See {@link UserManagerInternal#getDisplayAssignedToUser(int)}.
      */
@@ -737,7 +812,7 @@
                     continue;
                 }
                 int userId = mUsersAssignedToDisplayOnStart.keyAt(i);
-                if (!isStartedProfile(userId)) {
+                if (!isStartedVisibleProfileLocked(userId)) {
                     return userId;
                 } else if (DBG) {
                     Slogf.d(TAG, "getUserAssignedToDisplay(%d): skipping user %d because it's "
@@ -770,8 +845,8 @@
         // number of users is too small, the gain is probably not worth the increase on complexity.
         IntArray visibleUsers = new IntArray();
         synchronized (mLock) {
-            for (int i = 0; i < mStartedProfileGroupIds.size(); i++) {
-                int userId = mStartedProfileGroupIds.keyAt(i);
+            for (int i = 0; i < mStartedVisibleProfileGroupIds.size(); i++) {
+                int userId = mStartedVisibleProfileGroupIds.keyAt(i);
                 if (isUserVisible(userId)) {
                     visibleUsers.add(userId);
                 }
@@ -804,7 +879,7 @@
         }
     }
 
-    // TODO(b/242195409): remove this method if not needed anymore
+    // TODO(b/266158156): remove this method if not needed anymore
     /**
      * Nofify all listeners that the system user visibility changed.
      */
@@ -866,6 +941,9 @@
         ipw.println("UserVisibilityMediator");
         ipw.increaseIndent();
 
+        ipw.print("DBG: ");
+        ipw.println(DBG);
+
         synchronized (mLock) {
             ipw.print("Current user id: ");
             ipw.println(mCurrentUserId);
@@ -873,8 +951,12 @@
             ipw.print("Visible users: ");
             ipw.println(getVisibleUsers());
 
-            dumpSparseIntArray(ipw, mStartedProfileGroupIds, "started user / profile group",
-                    "u", "pg");
+            dumpSparseIntArray(ipw, mStartedVisibleProfileGroupIds,
+                    "started visible user / profile group", "u", "pg");
+            if (mStartedInvisibleProfileUserIds != null) {
+                ipw.print("Profiles started invisible: ");
+                ipw.println(mStartedInvisibleProfileUserIds);
+            }
 
             ipw.print("Supports visible background users on displays: ");
             ipw.println(mVisibleBackgroundUsersEnabled);
@@ -982,22 +1064,25 @@
             if (mCurrentUserId == userId) {
                 return true;
             }
-            return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID) == mCurrentUserId;
+            return mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID)
+                    == mCurrentUserId;
         }
     }
 
-    private boolean isStartedProfile(@UserIdInt int userId) {
-        int profileGroupId;
-        synchronized (mLock) {
-            profileGroupId = mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
-        }
+    @GuardedBy("mLock")
+    private boolean isStartedVisibleProfileLocked(@UserIdInt int userId) {
+        int profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
         return isProfile(userId, profileGroupId);
     }
 
-    private @UserIdInt int getStartedProfileGroupId(@UserIdInt int userId) {
-        synchronized (mLock) {
-            return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
+    private void validateUserStartMode(@UserStartMode int userStartMode) {
+        switch (userStartMode) {
+            case USER_START_MODE_FOREGROUND:
+            case USER_START_MODE_BACKGROUND:
+            case USER_START_MODE_BACKGROUND_VISIBLE:
+                return;
         }
+        throw new IllegalArgumentException("Invalid user start mode: " + userStartMode);
     }
 
     private static String secondaryDisplayMappingStatusToString(
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index bf8cbea..2e8a150 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -5693,6 +5693,7 @@
             }
 
             if (eventTime > now) {
+                Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now);
                 throw new IllegalArgumentException("event time must not be in the future");
             }
 
@@ -5708,7 +5709,9 @@
         @Override // Binder call
         public void wakeUp(long eventTime, @WakeReason int reason, String details,
                 String opPackageName) {
-            if (eventTime > mClock.uptimeMillis()) {
+            final long now = mClock.uptimeMillis();
+            if (eventTime > now) {
+                Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now);
                 throw new IllegalArgumentException("event time must not be in the future");
             }
 
@@ -5760,7 +5763,9 @@
 
         @Override // Binder call
         public void nap(long eventTime) {
-            if (eventTime > mClock.uptimeMillis()) {
+            final long now = mClock.uptimeMillis();
+            if (eventTime > now) {
+                Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now);
                 throw new IllegalArgumentException("event time must not be in the future");
             }
 
@@ -6525,7 +6530,9 @@
 
         @Override // Binder call
         public void boostScreenBrightness(long eventTime) {
+            final long now = mClock.uptimeMillis();
             if (eventTime > mClock.uptimeMillis()) {
+                Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now);
                 throw new IllegalArgumentException("event time must not be in the future");
             }
 
@@ -6684,7 +6691,9 @@
 
     @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
     private void goToSleepInternal(IntArray groupIds, long eventTime, int reason, int flags) {
-        if (eventTime > mClock.uptimeMillis()) {
+        final long now = mClock.uptimeMillis();
+        if (eventTime > now) {
+            Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now);
             throw new IllegalArgumentException("event time must not be in the future");
         }
 
diff --git a/services/core/java/com/android/server/power/stats/CpuWakeupStats.java b/services/core/java/com/android/server/power/stats/CpuWakeupStats.java
index 54f3476..e8c0e59 100644
--- a/services/core/java/com/android/server/power/stats/CpuWakeupStats.java
+++ b/services/core/java/com/android/server/power/stats/CpuWakeupStats.java
@@ -18,6 +18,7 @@
 
 import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_ALARM;
 import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_UNKNOWN;
+import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_WIFI;
 
 import android.content.Context;
 import android.os.Handler;
@@ -49,6 +50,7 @@
     private static final String TAG = "CpuWakeupStats";
 
     private static final String SUBSYSTEM_ALARM_STRING = "Alarm";
+    private static final String SUBSYSTEM_ALARM_WIFI = "Wifi";
     @VisibleForTesting
     static final long WAKEUP_RETENTION_MS = 3 * 24 * 60 * 60_000; // 3 days.
     @VisibleForTesting
@@ -74,6 +76,8 @@
         switch (subsystem) {
             case CPU_WAKEUP_SUBSYSTEM_ALARM:
                 return FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED__REASON__ALARM;
+            case CPU_WAKEUP_SUBSYSTEM_WIFI:
+                return FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED__REASON__WIFI;
         }
         return FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED__REASON__UNKNOWN;
     }
@@ -425,6 +429,8 @@
         switch (rawSubsystem) {
             case SUBSYSTEM_ALARM_STRING:
                 return CPU_WAKEUP_SUBSYSTEM_ALARM;
+            case SUBSYSTEM_ALARM_WIFI:
+                return CPU_WAKEUP_SUBSYSTEM_WIFI;
         }
         return CPU_WAKEUP_SUBSYSTEM_UNKNOWN;
     }
@@ -433,6 +439,8 @@
         switch (subsystem) {
             case CPU_WAKEUP_SUBSYSTEM_ALARM:
                 return SUBSYSTEM_ALARM_STRING;
+            case CPU_WAKEUP_SUBSYSTEM_WIFI:
+                return SUBSYSTEM_ALARM_WIFI;
             case CPU_WAKEUP_SUBSYSTEM_UNKNOWN:
                 return "Unknown";
         }
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index ac03808..7a73359 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -945,7 +945,9 @@
             mWindowManagerInternal.removeWindowToken(mToken, false/* removeWindows */,
                     mDisplayId);
             try {
-                connection.mService.detach(mToken);
+                if (connection.mService != null) {
+                    connection.mService.detach(mToken);
+                }
             } catch (RemoteException e) {
                 Slog.w(TAG, "connection.mService.destroy() threw a RemoteException");
             }
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 01e9522..d108f0d 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -1714,4 +1714,20 @@
             }
         }
     }
+
+    /**
+     * Returns {@code true} if the activity was explicitly requested to be launched in its
+     * current TaskFragment.
+     *
+     * @see ActivityRecord#mRequestedLaunchingTaskFragmentToken
+     */
+    public boolean isRequestedToLaunchInTaskFragment(IBinder activityToken,
+            IBinder taskFragmentToken) {
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.isInRootTaskLocked(activityToken);
+            if (r == null) return false;
+
+            return r.mRequestedLaunchingTaskFragmentToken == taskFragmentToken;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index e62d305..9def87c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -565,6 +565,8 @@
     volatile boolean inHistory;
     final ActivityTaskSupervisor mTaskSupervisor;
     final RootWindowContainer mRootWindowContainer;
+    // The token of the TaskFragment that this activity was requested to be launched into.
+    IBinder mRequestedLaunchingTaskFragmentToken;
 
     // Tracking splash screen status from previous activity
     boolean mSplashScreenStyleSolidColor = false;
@@ -1605,6 +1607,8 @@
 
         if (oldParent != null) {
             oldParent.cleanUpActivityReferences(this);
+            // Clear the state as this activity is removed from its old parent.
+            mRequestedLaunchingTaskFragmentToken = null;
         }
 
         if (newParent != null) {
@@ -7933,7 +7937,7 @@
         }
 
         return getTask().getConfiguration().smallestScreenWidthDp
-                >= mAtmService.mLargeScreenSmallestScreenWidthDp;
+                >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP;
     }
 
     /**
@@ -8080,11 +8084,7 @@
                 return false;
             }
         }
-        // Activity should be resizable if the task is.
-        final boolean isResizeable = task != null
-                ? task.isResizeable() || isResizeable()
-                : isResizeable();
-        return !isResizeable && (info.isFixedOrientation() || hasFixedAspectRatio())
+        return !isResizeable() && (info.isFixedOrientation() || hasFixedAspectRatio())
                 // The configuration of non-standard type should be enforced by system.
                 // {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} is set when this activity is
                 // added to a task, but this function is called when resolving the launch params, at
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index ac07248..88d1086 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -3036,6 +3036,8 @@
             int embeddingCheckResult = canEmbedActivity(mInTaskFragment, mStartActivity, task);
             if (embeddingCheckResult == EMBEDDING_ALLOWED) {
                 newParent = mInTaskFragment;
+                mStartActivity.mRequestedLaunchingTaskFragmentToken =
+                        mInTaskFragment.getFragmentToken();
             } else {
                 // Start mStartActivity to task instead if it can't be embedded to mInTaskFragment.
                 sendCanNotEmbedActivityError(mInTaskFragment, embeddingCheckResult);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 7d478b3..923ca79 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -609,7 +609,7 @@
      * Whether the device supports non-resizable in multi windowing modes.
      * -1: The device doesn't support non-resizable in multi windowing modes.
      *  0: The device supports non-resizable in multi windowing modes only if this is a large
-     *     screen (smallest width >= {@link #mLargeScreenSmallestScreenWidthDp}).
+     *     screen (smallest width >= {@link WindowManager#LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP}).
      *  1: The device always supports non-resizable in multi windowing modes.
      */
     int mSupportsNonResizableMultiWindow;
@@ -619,7 +619,8 @@
      * windowing modes.
      * -1: The device ignores activity min width/height when determining if it can be shown in multi
      *     windowing modes.
-     *  0: If it is a small screen (smallest width < {@link #mLargeScreenSmallestScreenWidthDp}),
+     *  0: If it is a small screen (smallest width <
+     *     {@link WindowManager#LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP}),
      *     the device compares the activity min width/height with the min multi windowing modes
      *     dimensions {@link #mMinPercentageMultiWindowSupportHeight} the device supports to
      *     determine whether the activity can be shown in multi windowing modes
@@ -647,13 +648,6 @@
      */
     float mMinPercentageMultiWindowSupportWidth;
 
-    /**
-     * If the display {@link Configuration#smallestScreenWidthDp} is greater or equal to this value,
-     * we will treat it as a large screen device, which will have some multi window features enabled
-     * by default.
-     */
-    int mLargeScreenSmallestScreenWidthDp;
-
     final List<ActivityTaskManagerInternal.ScreenObserver> mScreenObservers = new ArrayList<>();
 
     // VR Vr2d Display Id.
@@ -914,8 +908,6 @@
                 com.android.internal.R.dimen.config_minPercentageMultiWindowSupportHeight);
         final float minPercentageMultiWindowSupportWidth = mContext.getResources().getFloat(
                 com.android.internal.R.dimen.config_minPercentageMultiWindowSupportWidth);
-        final int largeScreenSmallestScreenWidthDp = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_largeScreenSmallestScreenWidthDp);
 
         // Transfer any global setting for forcing RTL layout, into a System Property
         DisplayProperties.debug_force_rtl(forceRtl);
@@ -934,7 +926,6 @@
             mRespectsActivityMinWidthHeightMultiWindow = respectsActivityMinWidthHeightMultiWindow;
             mMinPercentageMultiWindowSupportHeight = minPercentageMultiWindowSupportHeight;
             mMinPercentageMultiWindowSupportWidth = minPercentageMultiWindowSupportWidth;
-            mLargeScreenSmallestScreenWidthDp = largeScreenSmallestScreenWidthDp;
             final boolean multiWindowFormEnabled = freeformWindowManagement
                     || supportsSplitScreenMultiWindow
                     || supportsPictureInPicture
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index a229fc5..2d45dc2 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -75,6 +75,11 @@
     private final ArrayList<WindowContainer> mTmpOpenApps = new ArrayList<>();
     private final ArrayList<WindowContainer> mTmpCloseApps = new ArrayList<>();
 
+    // This will be set if the back navigation is in progress and the current transition is still
+    // running. The pending animation builder will do the animation stuff includes creating leashes,
+    // re-parenting leashes and set launch behind, etc. Will be handled when transition finished.
+    private AnimationHandler.ScheduleAnimationBuilder mPendingAnimationBuilder;
+
     /**
      * true if the back predictability feature is enabled
      */
@@ -305,25 +310,26 @@
                             || backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY)
                     && adapter != null;
 
-            // Only prepare animation if no leash has been created (no animation is running).
-            // TODO(b/241808055): Cancel animation when preparing back animation.
-            if (prepareAnimation
-                    && (removedWindowContainer.hasCommittedReparentToAnimationLeash()
-                            || removedWindowContainer.mTransitionController.inTransition())) {
-                Slog.w(TAG, "Can't prepare back animation due to another animation is running.");
-                prepareAnimation = false;
-            }
-
             if (prepareAnimation) {
-                mPendingAnimation = mAnimationHandler.scheduleAnimation(backType, adapter,
-                        currentTask, prevTask, currentActivity, prevActivity);
-                prepareAnimation = mPendingAnimation != null;
-                mBackAnimationInProgress = prepareAnimation;
-                if (prepareAnimation) {
-                    mWindowManagerService.mWindowPlacerLocked.requestTraversal();
-                    if (mShowWallpaper) {
-                        currentTask.getDisplayContent().mWallpaperController
-                                .adjustWallpaperWindows();
+                final AnimationHandler.ScheduleAnimationBuilder builder =
+                        mAnimationHandler.prepareAnimation(backType, adapter,
+                                currentTask, prevTask, currentActivity, prevActivity);
+                mBackAnimationInProgress = builder != null;
+                if (mBackAnimationInProgress) {
+                    if (removedWindowContainer.hasCommittedReparentToAnimationLeash()
+                            || removedWindowContainer.mTransitionController.inTransition()
+                            || mWindowManagerService.mSyncEngine.hasPendingSyncSets()) {
+                        ProtoLog.w(WM_DEBUG_BACK_PREVIEW,
+                                "Pending back animation due to another animation is running");
+                        mPendingAnimationBuilder = builder;
+                        // Current transition is still running, we have to defer the hiding to the
+                        // client process to prevent the unexpected relayout when handling the back
+                        // animation.
+                        if (prevActivity != null) {
+                            prevActivity.setDeferHidingClient(true);
+                        }
+                    } else {
+                        scheduleAnimation(builder);
                     }
                 }
             }
@@ -345,6 +351,15 @@
         return isWaitBackTransition() || mNavigationMonitor.isMonitoring();
     }
 
+    private void scheduleAnimation(@NonNull AnimationHandler.ScheduleAnimationBuilder builder) {
+        mPendingAnimation = builder.build();
+        mWindowManagerService.mWindowPlacerLocked.requestTraversal();
+        if (mShowWallpaper) {
+            mWindowManagerService.getDefaultDisplayContentLocked().mWallpaperController
+                    .adjustWallpaperWindows();
+        }
+    }
+
     private boolean isWaitBackTransition() {
         return mAnimationHandler.mComposed && mAnimationHandler.mWaitTransition;
     }
@@ -526,6 +541,57 @@
         mAnimationHandler.clearBackAnimateTarget(cleanupTransaction);
     }
 
+     /**
+     * Handle the pending animation when the running transition finished.
+     * @param targets The final animation targets derived in transition.
+     */
+    boolean handleDeferredBackAnimation(@NonNull ArrayList<Transition.ChangeInfo> targets) {
+        if (!mBackAnimationInProgress || mPendingAnimationBuilder == null) {
+            return false;
+        }
+
+        ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
+                "Handling the deferred animation after transition finished");
+
+        // Show the target surface and its parents to prevent it or its parents hidden when
+        // the transition finished.
+        // The target could be affected by transition when :
+        // Open transition -> the open target in back navigation
+        // Close transition -> the close target in back navigation.
+        boolean hasTarget = false;
+        final SurfaceControl.Transaction t =
+                mPendingAnimationBuilder.mCloseTarget.getPendingTransaction();
+        for (int i = 0; i < targets.size(); i++) {
+            final WindowContainer wc = targets.get(i).mContainer;
+            if (wc.asActivityRecord() == null && wc.asTask() == null) {
+                continue;
+            } else if (!mPendingAnimationBuilder.containTarget(wc)) {
+                continue;
+            }
+
+            hasTarget = true;
+            t.show(wc.getSurfaceControl());
+        }
+
+        if (!hasTarget) {
+            // Skip if no target participated in current finished transition.
+            Slog.w(TAG, "Finished transition didn't include the targets"
+                    + " open: " + mPendingAnimationBuilder.mOpenTarget
+                    + " close: " + mPendingAnimationBuilder.mCloseTarget);
+            try {
+                mPendingAnimationBuilder.mBackAnimationAdapter.getRunner().onAnimationCancelled();
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+            mPendingAnimationBuilder = null;
+            return false;
+        }
+
+        scheduleAnimation(mPendingAnimationBuilder);
+        mPendingAnimationBuilder = null;
+        return true;
+    }
+
     /**
      * Create and handling animations status for an open/close animation targets.
      */
@@ -638,6 +704,7 @@
             if (open) {
                 return wc == mOpenAdaptor.mTarget || mOpenAdaptor.mTarget.hasChild(wc);
             }
+
             if (mSwitchType == TASK_SWITCH) {
                 return  wc == mCloseAdaptor.mTarget
                         || (wc.asTask() != null && wc.hasChild(mCloseAdaptor.mTarget));
@@ -841,23 +908,22 @@
             }
         }
 
-        Runnable scheduleAnimation(int backType, BackAnimationAdapter adapter,
+        ScheduleAnimationBuilder prepareAnimation(int backType, BackAnimationAdapter adapter,
                 Task currentTask, Task previousTask, ActivityRecord currentActivity,
                 ActivityRecord previousActivity) {
             switch (backType) {
                 case BackNavigationInfo.TYPE_RETURN_TO_HOME:
                     return new ScheduleAnimationBuilder(backType, adapter)
                             .setIsLaunchBehind(true)
-                            .setComposeTarget(currentTask, previousTask)
-                            .build();
+                            .setComposeTarget(currentTask, previousTask);
                 case BackNavigationInfo.TYPE_CROSS_ACTIVITY:
                     return new ScheduleAnimationBuilder(backType, adapter)
                             .setComposeTarget(currentActivity, previousActivity)
-                            .setOpeningSnapshot(getActivitySnapshot(previousActivity)).build();
+                            .setOpeningSnapshot(getActivitySnapshot(previousActivity));
                 case BackNavigationInfo.TYPE_CROSS_TASK:
                     return new ScheduleAnimationBuilder(backType, adapter)
                             .setComposeTarget(currentTask, previousTask)
-                            .setOpeningSnapshot(getTaskSnapshot(previousTask)).build();
+                            .setOpeningSnapshot(getTaskSnapshot(previousTask));
             }
             return null;
         }
@@ -891,6 +957,11 @@
                 return this;
             }
 
+            boolean containTarget(@NonNull WindowContainer wc) {
+                return wc == mOpenTarget || wc == mCloseTarget
+                        || wc.hasChild(mOpenTarget) || wc.hasChild(mCloseTarget);
+            }
+
             Runnable build() {
                 if (mOpenTarget == null || mCloseTarget == null) {
                     return null;
@@ -967,49 +1038,43 @@
                     }
                 };
             }
-
-            private void setLaunchBehind(ActivityRecord activity) {
-                if (activity == null) {
-                    return;
-                }
-                if (!activity.isVisibleRequested()) {
-                    activity.setVisibility(true);
-                }
-                activity.mLaunchTaskBehind = true;
-
-                // Handle fixed rotation launching app.
-                final DisplayContent dc = activity.mDisplayContent;
-                dc.rotateInDifferentOrientationIfNeeded(activity);
-                if (activity.hasFixedRotationTransform()) {
-                    // Set the record so we can recognize it to continue to update display
-                    // orientation if the previous activity becomes the top later.
-                    dc.setFixedRotationLaunchingApp(activity,
-                            activity.getWindowConfiguration().getRotation());
-                }
-
-                ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
-                        "Setting Activity.mLauncherTaskBehind to true. Activity=%s", activity);
-                activity.mTaskSupervisor.mStoppingActivities.remove(activity);
-                activity.getDisplayContent().ensureActivitiesVisible(null /* starting */,
-                        0 /* configChanges */, false /* preserveWindows */, true);
-            }
-            private void restoreLaunchBehind(ActivityRecord activity) {
-                if (activity == null) {
-                    return;
-                }
-
-                activity.mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp();
-
-                // Restore the launch-behind state.
-                activity.mTaskSupervisor.scheduleLaunchTaskBehindComplete(activity.token);
-                activity.mLaunchTaskBehind = false;
-                ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
-                        "Setting Activity.mLauncherTaskBehind to false. Activity=%s",
-                        activity);
-            }
         }
     }
 
+    private static void setLaunchBehind(@NonNull ActivityRecord activity) {
+        if (!activity.isVisibleRequested()) {
+            activity.setVisibility(true);
+        }
+        activity.mLaunchTaskBehind = true;
+
+        // Handle fixed rotation launching app.
+        final DisplayContent dc = activity.mDisplayContent;
+        dc.rotateInDifferentOrientationIfNeeded(activity);
+        if (activity.hasFixedRotationTransform()) {
+            // Set the record so we can recognize it to continue to update display
+            // orientation if the previous activity becomes the top later.
+            dc.setFixedRotationLaunchingApp(activity,
+                    activity.getWindowConfiguration().getRotation());
+        }
+
+        ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
+                "Setting Activity.mLauncherTaskBehind to true. Activity=%s", activity);
+        activity.mTaskSupervisor.mStoppingActivities.remove(activity);
+        activity.getDisplayContent().ensureActivitiesVisible(null /* starting */,
+                0 /* configChanges */, false /* preserveWindows */, true);
+    }
+
+    private static void restoreLaunchBehind(@NonNull ActivityRecord activity) {
+        activity.mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp();
+
+        // Restore the launch-behind state.
+        activity.mTaskSupervisor.scheduleLaunchTaskBehindComplete(activity.token);
+        activity.mLaunchTaskBehind = false;
+        ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
+                "Setting Activity.mLauncherTaskBehind to false. Activity=%s",
+                activity);
+    }
+
     void checkAnimationReady(WallpaperController wallpaperController) {
         if (!mBackAnimationInProgress) {
             return;
@@ -1039,6 +1104,7 @@
         mNavigationMonitor.stopMonitor();
         mBackAnimationInProgress = false;
         mShowWallpaper = false;
+        mPendingAnimationBuilder = null;
     }
 
     private static TaskSnapshot getActivitySnapshot(@NonNull ActivityRecord r) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 86c4e0f..947edde 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -38,6 +38,9 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.util.DisplayMetrics.DENSITY_DEFAULT;
 import static android.util.RotationUtils.deltaRotation;
+import static android.util.TypedValue.COMPLEX_UNIT_DIP;
+import static android.util.TypedValue.COMPLEX_UNIT_MASK;
+import static android.util.TypedValue.COMPLEX_UNIT_SHIFT;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
 import static android.view.Display.FLAG_PRIVATE;
@@ -170,6 +173,7 @@
 import android.content.pm.ActivityInfo.ScreenOrientation;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.ColorSpace;
 import android.graphics.Insets;
@@ -206,6 +210,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.util.TypedValue;
 import android.util.proto.ProtoOutputStream;
 import android.view.ContentRecordingSession;
 import android.view.Display;
@@ -1684,14 +1689,16 @@
     private int getMinimalTaskSizeDp() {
         final Context displayConfigurationContext =
                 mAtmService.mContext.createConfigurationContext(getConfiguration());
-        final float minimalSize =
-                displayConfigurationContext.getResources().getDimension(
-                        R.dimen.default_minimal_size_resizable_task);
-        if (Double.compare(mDisplayMetrics.density, 0.0) == 0) {
-            throw new IllegalArgumentException("Display with ID=" + getDisplayId() + "has invalid "
-                + "DisplayMetrics.density= 0.0");
+        final Resources res = displayConfigurationContext.getResources();
+        final TypedValue value = new TypedValue();
+        res.getValue(R.dimen.default_minimal_size_resizable_task, value, true /* resolveRefs */);
+        final int valueUnit = ((value.data >> COMPLEX_UNIT_SHIFT) & COMPLEX_UNIT_MASK);
+        if (value.type != TypedValue.TYPE_DIMENSION || valueUnit != COMPLEX_UNIT_DIP) {
+            throw new IllegalArgumentException(
+                "Resource ID #0x" + Integer.toHexString(R.dimen.default_minimal_size_resizable_task)
+                    + " is not in valid type or unit");
         }
-        return (int) (minimalSize / mDisplayMetrics.density);
+        return (int) TypedValue.complexToFloat(value.data);
     }
 
     private boolean updateOrientation(boolean forceUpdate) {
diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
index 47bdba3..41eb2c9 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
@@ -359,12 +359,6 @@
                 CAMERA_OPENED_ROTATION_UPDATE_DELAY_MS);
     }
 
-    private void updateOrientationWithWmLock() {
-        synchronized (mWmService.mGlobalLock) {
-            mDisplayContent.updateOrientation();
-        }
-    }
-
     private void delayedUpdateOrientationWithWmLock(
             @NonNull String cameraId, @NonNull String packageName) {
         synchronized (this) {
@@ -375,25 +369,28 @@
             }
             mCameraIdPackageBiMap.put(packageName, cameraId);
         }
-        ActivityRecord topActivity = mDisplayContent.topRunningActivity(
-                    /* considerKeyguardState= */ true);
-        if (topActivity == null || topActivity.getTask() == null) {
-            return;
-        }
-        // Checking whether an activity in fullscreen rather than the task as this camera compat
-        // treatment doesn't cover activity embedding.
-        if (topActivity.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
-            if (topActivity.mLetterboxUiController.isOverrideOrientationOnlyForCameraEnabled()) {
-                topActivity.recomputeConfiguration();
+        synchronized (mWmService.mGlobalLock) {
+            ActivityRecord topActivity = mDisplayContent.topRunningActivity(
+                        /* considerKeyguardState= */ true);
+            if (topActivity == null || topActivity.getTask() == null) {
+                return;
             }
-            updateOrientationWithWmLock();
-            return;
-        }
-        // Checking that the whole app is in multi-window mode as we shouldn't show toast
-        // for the activity embedding case.
-        if (topActivity.getTask().getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW
-                && isTreatmentEnabledForActivity(topActivity, /* mustBeFullscreen */ false)) {
-            showToast(R.string.display_rotation_camera_compat_toast_in_split_screen);
+            // Checking whether an activity in fullscreen rather than the task as this camera
+            // compat treatment doesn't cover activity embedding.
+            if (topActivity.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
+                if (topActivity.mLetterboxUiController
+                        .isOverrideOrientationOnlyForCameraEnabled()) {
+                    topActivity.recomputeConfiguration();
+                }
+                mDisplayContent.updateOrientation();
+                return;
+            }
+            // Checking that the whole app is in multi-window mode as we shouldn't show toast
+            // for the activity embedding case.
+            if (topActivity.getTask().getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW
+                    && isTreatmentEnabledForActivity(topActivity, /* mustBeFullscreen */ false)) {
+                showToast(R.string.display_rotation_camera_compat_toast_in_split_screen);
+            }
         }
     }
 
@@ -441,18 +438,20 @@
         ProtoLog.v(WM_DEBUG_ORIENTATION,
                 "Display id=%d is notified that Camera %s is closed, updating rotation.",
                 mDisplayContent.mDisplayId, cameraId);
-        ActivityRecord topActivity = mDisplayContent.topRunningActivity(
-                /* considerKeyguardState= */ true);
-        if (topActivity == null
-                // Checking whether an activity in fullscreen rather than the task as this camera
-                // compat treatment doesn't cover activity embedding.
-                || topActivity.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
-            return;
+        synchronized (mWmService.mGlobalLock) {
+            ActivityRecord topActivity = mDisplayContent.topRunningActivity(
+                    /* considerKeyguardState= */ true);
+            if (topActivity == null
+                    // Checking whether an activity in fullscreen rather than the task as this
+                    // camera compat treatment doesn't cover activity embedding.
+                    || topActivity.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
+                return;
+            }
+            if (topActivity.mLetterboxUiController.isOverrideOrientationOnlyForCameraEnabled()) {
+                topActivity.recomputeConfiguration();
+            }
+            mDisplayContent.updateOrientation();
         }
-        if (topActivity.mLetterboxUiController.isOverrideOrientationOnlyForCameraEnabled()) {
-            topActivity.recomputeConfiguration();
-        }
-        updateOrientationWithWmLock();
     }
 
     private boolean isActivityForCameraIdRefreshing(String cameraId) {
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index dc674c2..44b1cc8 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -862,10 +862,9 @@
         return mActivityRecord.mWmService.mContext.getResources();
     }
 
-    private void handleHorizontalDoubleTap(int x) {
-        // TODO(b/260857308): Investigate if enabling reachability for translucent activity
-        if (hasInheritedLetterboxBehavior() || !isHorizontalReachabilityEnabled()
-                || mActivityRecord.isInTransition()) {
+    @VisibleForTesting
+    void handleHorizontalDoubleTap(int x) {
+        if (!isHorizontalReachabilityEnabled() || mActivityRecord.isInTransition()) {
             return;
         }
 
@@ -903,10 +902,9 @@
         mActivityRecord.recomputeConfiguration();
     }
 
-    private void handleVerticalDoubleTap(int y) {
-        // TODO(b/260857308): Investigate if enabling reachability for translucent activity
-        if (hasInheritedLetterboxBehavior() || !isVerticalReachabilityEnabled()
-                || mActivityRecord.isInTransition()) {
+    @VisibleForTesting
+    void handleVerticalDoubleTap(int y) {
+        if (!isVerticalReachabilityEnabled() || mActivityRecord.isInTransition()) {
             return;
         }
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 0a833f4..7433c7e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2035,6 +2035,10 @@
         Rect outOverrideBounds = getResolvedOverrideConfiguration().windowConfiguration.getBounds();
 
         if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
+            if (!mCreatedByOrganizer) {
+                // Use empty bounds to indicate "fill parent".
+                outOverrideBounds.setEmpty();
+            }
             // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if
             // the parent or display is smaller than the size, the content may be cropped.
             return;
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 3cec3aa..76759ba 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -49,6 +49,7 @@
 import android.util.Slog;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
+import android.view.WindowManager;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
@@ -1486,7 +1487,7 @@
      */
     private boolean isLargeEnoughForMultiWindow() {
         return getConfiguration().smallestScreenWidthDp
-                >= mAtmService.mLargeScreenSmallestScreenWidthDp;
+                >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP;
     }
 
     boolean isTopRootTask(Task rootTask) {
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 808e79d..035859e 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -2574,6 +2574,7 @@
      */
     TaskFragmentInfo getTaskFragmentInfo() {
         List<IBinder> childActivities = new ArrayList<>();
+        List<IBinder> inRequestedTaskFragmentActivities = new ArrayList<>();
         for (int i = 0; i < getChildCount(); i++) {
             final WindowContainer<?> wc = getChildAt(i);
             final ActivityRecord ar = wc.asActivityRecord();
@@ -2582,6 +2583,9 @@
                     && ar.getUid() == mTaskFragmentOrganizerUid && !ar.finishing) {
                 // Only includes Activities that belong to the organizer process for security.
                 childActivities.add(ar.token);
+                if (ar.mRequestedLaunchingTaskFragmentToken == mFragmentToken) {
+                    inRequestedTaskFragmentActivities.add(ar.token);
+                }
             }
         }
         final Point positionInParent = new Point();
@@ -2593,6 +2597,7 @@
                 getNonFinishingActivityCount(),
                 shouldBeVisible(null /* starting */),
                 childActivities,
+                inRequestedTaskFragmentActivities,
                 positionInParent,
                 mClearedTaskForReuse,
                 mClearedTaskFragmentForPip,
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index a68b3cb..a30ab11 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -813,7 +813,7 @@
         }
 
         boolean hasParticipatedDisplay = false;
-        boolean reportTaskStackChanged = false;
+        boolean hasVisibleTransientLaunch = false;
         // Commit all going-invisible containers
         for (int i = 0; i < mParticipants.size(); ++i) {
             final WindowContainer<?> participant = mParticipants.valueAt(i);
@@ -856,7 +856,7 @@
                         && ar.isVisible()) {
                     // Transient launch was committed, so report enteringAnimation
                     ar.mEnteringAnimation = true;
-                    reportTaskStackChanged = true;
+                    hasVisibleTransientLaunch = true;
 
                     // Since transient launches don't automatically take focus, make sure we
                     // synchronize focus since we committed to the launch.
@@ -900,8 +900,14 @@
             }
         }
 
-        if (reportTaskStackChanged) {
+        if (hasVisibleTransientLaunch) {
+            // Notify the change about the transient-below task that becomes invisible.
             mController.mAtm.getTaskChangeNotificationController().notifyTaskStackChanged();
+            // Prevent spurious background app switches.
+            mController.mAtm.stopAppSwitches();
+            // The end of transient launch may not reorder task, so make sure to compute the latest
+            // task rank according to the current visibility.
+            mController.mAtm.mRootWindowContainer.rankTaskLayers();
         }
 
         // dispatch legacy callback in a different loop. This is because multiple legacy handlers
@@ -983,6 +989,9 @@
         cleanUpInternal();
         mController.updateAnimatingState(mTmpTransaction);
         mTmpTransaction.apply();
+
+        // Handle back animation if it's already started.
+        mController.mAtm.mBackNavigationController.handleDeferredBackAnimation(mTargets);
     }
 
     void abort() {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 8e22821..b9cb59a 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -74,7 +74,9 @@
 import android.graphics.Rect;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.Parcel;
 import android.os.RemoteException;
 import android.util.AndroidRuntimeException;
@@ -998,11 +1000,14 @@
                     activityOptions.setCallerDisplayId(DEFAULT_DISPLAY);
                 }
                 final Bundle options = activityOptions != null ? activityOptions.toBundle() : null;
-                waitAsyncStart(() -> mService.mAmInternal.sendIntentSender(
+                int res = waitAsyncStart(() -> mService.mAmInternal.sendIntentSender(
                         hop.getPendingIntent().getTarget(),
                         hop.getPendingIntent().getWhitelistToken(), 0 /* code */,
                         hop.getActivityIntent(), resolvedType, null /* finishReceiver */,
                         null /* requiredPermission */, options));
+                if (ActivityManager.isStartResultSuccessful(res)) {
+                    effects |= TRANSACT_EFFECTS_LIFECYCLE;
+                }
                 break;
             }
             case HIERARCHY_OP_TYPE_START_SHORTCUT: {
@@ -1353,9 +1358,16 @@
      * Post and wait for the result of the activity start to prevent potential deadlock against
      * {@link WindowManagerGlobalLock}.
      */
-    private void waitAsyncStart(IntSupplier startActivity) {
+    private int waitAsyncStart(IntSupplier startActivity) {
         final Integer[] starterResult = {null};
-        mService.mH.post(() -> {
+        final Handler handler = (Looper.myLooper() == mService.mH.getLooper())
+                // uncommon case where a queued transaction is trying to start an activity. We can't
+                // post to our own thread and wait (otherwise we deadlock), so use anim thread
+                // instead (which is 1 higher priority).
+                ? mService.mWindowManager.mAnimationHandler
+                // Otherwise just put it on main handler
+                : mService.mH;
+        handler.post(() -> {
             try {
                 starterResult[0] = startActivity.getAsInt();
             } catch (Throwable t) {
@@ -1372,6 +1384,7 @@
             } catch (InterruptedException ignored) {
             }
         }
+        return starterResult[0];
     }
 
     private int sanitizeAndApplyHierarchyOp(WindowContainer container,
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index aa10291..694f1be 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -1826,6 +1826,9 @@
                     pw.print("F|");
                 }
             }
+            if ((stateFlags & ACTIVITY_STATE_FLAG_HAS_ACTIVITY_IN_VISIBLE_TASK) != 0) {
+                pw.print("VT|");
+            }
             final int taskLayer = stateFlags & ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
             if (taskLayer != ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER) {
                 pw.print("taskLayer=" + taskLayer);
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 9260d2b..981844c 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -26,6 +26,10 @@
     <xs:element name="displayConfiguration">
         <xs:complexType>
             <xs:sequence>
+                <xs:element type ="xs:string" name="name">
+                    <xs:annotation name="nullable"/>
+                    <xs:annotation name="final"/>
+                </xs:element>
                 <xs:element type="densityMapping" name="densityMapping" minOccurs="0" maxOccurs="1">
                     <xs:annotation name="nullable"/>
                     <xs:annotation name="final"/>
@@ -211,6 +215,32 @@
             <xs:element type="brightnessThrottlingMap" name="brightnessThrottlingMap" maxOccurs="unbounded">
                 <xs:annotation name="final"/>
             </xs:element>
+            <xs:element type="refreshRateThrottlingMap" name="refreshRateThrottlingMap" maxOccurs="unbounded">
+                <xs:annotation name="final"/>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="refreshRateThrottlingMap">
+        <xs:attribute name="id" type="xs:string" />
+        <xs:sequence>
+            <xs:element name="refreshRateThrottlingPoint" type="refreshRateThrottlingPoint" maxOccurs="unbounded">
+                <xs:annotation name="nonnull"/>
+                <xs:annotation name="final"/>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="refreshRateThrottlingPoint">
+        <xs:sequence>
+            <xs:element type="thermalStatus" name="thermalStatus">
+                <xs:annotation name="nonnull"/>
+                <xs:annotation name="final"/>
+            </xs:element>
+            <xs:element type="refreshRateRange" name="refreshRateRange">
+                <xs:annotation name="nonnull"/>
+                <xs:annotation name="final"/>
+            </xs:element>
         </xs:sequence>
     </xs:complexType>
 
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index e81c27d..8cb4837 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -89,6 +89,7 @@
     method public final com.android.server.display.config.Thresholds getDisplayBrightnessChangeThresholdsIdle();
     method public com.android.server.display.config.HighBrightnessMode getHighBrightnessMode();
     method public final com.android.server.display.config.SensorDetails getLightSensor();
+    method @Nullable public final String getName();
     method public final com.android.server.display.config.SensorDetails getProxSensor();
     method public com.android.server.display.config.DisplayQuirks getQuirks();
     method public com.android.server.display.config.RefreshRateConfigs getRefreshRate();
@@ -114,6 +115,7 @@
     method public final void setDisplayBrightnessChangeThresholdsIdle(com.android.server.display.config.Thresholds);
     method public void setHighBrightnessMode(com.android.server.display.config.HighBrightnessMode);
     method public final void setLightSensor(com.android.server.display.config.SensorDetails);
+    method public final void setName(@Nullable String);
     method public final void setProxSensor(com.android.server.display.config.SensorDetails);
     method public void setQuirks(com.android.server.display.config.DisplayQuirks);
     method public void setRefreshRate(com.android.server.display.config.RefreshRateConfigs);
@@ -214,6 +216,21 @@
     method public final void setMinimum(java.math.BigInteger);
   }
 
+  public class RefreshRateThrottlingMap {
+    ctor public RefreshRateThrottlingMap();
+    method public String getId();
+    method @NonNull public final java.util.List<com.android.server.display.config.RefreshRateThrottlingPoint> getRefreshRateThrottlingPoint();
+    method public void setId(String);
+  }
+
+  public class RefreshRateThrottlingPoint {
+    ctor public RefreshRateThrottlingPoint();
+    method @NonNull public final com.android.server.display.config.RefreshRateRange getRefreshRateRange();
+    method @NonNull public final com.android.server.display.config.ThermalStatus getThermalStatus();
+    method public final void setRefreshRateRange(@NonNull com.android.server.display.config.RefreshRateRange);
+    method public final void setThermalStatus(@NonNull com.android.server.display.config.ThermalStatus);
+  }
+
   public class RefreshRateZone {
     ctor public RefreshRateZone();
     method public String getId();
@@ -264,6 +281,7 @@
   public class ThermalThrottling {
     ctor public ThermalThrottling();
     method public final java.util.List<com.android.server.display.config.BrightnessThrottlingMap> getBrightnessThrottlingMap();
+    method public final java.util.List<com.android.server.display.config.RefreshRateThrottlingMap> getRefreshRateThrottlingMap();
   }
 
   public class ThresholdPoint {
diff --git a/services/core/xsd/display-layout-config/display-layout-config.xsd b/services/core/xsd/display-layout-config/display-layout-config.xsd
index d4556d7..ce022e9 100644
--- a/services/core/xsd/display-layout-config/display-layout-config.xsd
+++ b/services/core/xsd/display-layout-config/display-layout-config.xsd
@@ -52,6 +52,7 @@
             <xs:element name="address" type="xs:nonNegativeInteger"/>
             <xs:element name="position" type="xs:string" minOccurs="0" maxOccurs="1" />
             <xs:element name="brightnessThrottlingMapId" type="xs:string" minOccurs="0" maxOccurs="1" />
+            <xs:element name="refreshRateThermalThrottlingMapId" type="xs:string" minOccurs="0" />
         </xs:sequence>
         <xs:attribute name="enabled" type="xs:boolean" use="optional" />
         <xs:attribute name="defaultDisplay" type="xs:boolean" use="optional" />
diff --git a/services/core/xsd/display-layout-config/schema/current.txt b/services/core/xsd/display-layout-config/schema/current.txt
index 52133ab..42a800d 100644
--- a/services/core/xsd/display-layout-config/schema/current.txt
+++ b/services/core/xsd/display-layout-config/schema/current.txt
@@ -7,6 +7,7 @@
     method public String getBrightnessThrottlingMapId();
     method public String getDisplayGroup();
     method public String getPosition();
+    method public String getRefreshRateThermalThrottlingMapId();
     method public String getRefreshRateZoneId();
     method public boolean isDefaultDisplay();
     method public boolean isEnabled();
@@ -16,6 +17,7 @@
     method public void setDisplayGroup(String);
     method public void setEnabled(boolean);
     method public void setPosition(String);
+    method public void setRefreshRateThermalThrottlingMapId(String);
     method public void setRefreshRateZoneId(String);
   }
 
diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
index 3245c91..97b7811 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
@@ -35,6 +35,7 @@
 import android.service.credentials.CreateEntry;
 import android.service.credentials.CredentialProviderInfo;
 import android.service.credentials.CredentialProviderService;
+import android.service.credentials.RemoteEntry;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
@@ -301,14 +302,14 @@
         @NonNull
         private final Map<String, Pair<CreateEntry, Entry>> mUiCreateEntries = new HashMap<>();
 
-        @Nullable private Pair<String, Pair<CreateEntry, Entry>> mUiRemoteEntry = null;
+        @Nullable private Pair<String, Pair<RemoteEntry, Entry>> mUiRemoteEntry = null;
 
         ProviderResponseDataHandler(String hybridService) {
             mExpectedRemoteEntryProviderService = ComponentName.unflattenFromString(hybridService);
         }
 
         public void addResponseContent(List<CreateEntry> createEntries,
-                CreateEntry remoteEntry) {
+                RemoteEntry remoteEntry) {
             createEntries.forEach(this::addCreateEntry);
             setRemoteEntry(remoteEntry);
         }
@@ -319,7 +320,7 @@
             mUiCreateEntries.put(id, new Pair<>(createEntry, entry));
         }
 
-        public void setRemoteEntry(@Nullable CreateEntry remoteEntry) {
+        public void setRemoteEntry(@Nullable RemoteEntry remoteEntry) {
             if (remoteEntry == null) {
                 mUiRemoteEntry = null;
                 return;
@@ -363,7 +364,7 @@
             return mUiCreateEntries.isEmpty() && mUiRemoteEntry == null;
         }
         @Nullable
-        public CreateEntry getRemoteEntry(String entryKey) {
+        public RemoteEntry getRemoteEntry(String entryKey) {
             return mUiRemoteEntry == null || mUiRemoteEntry
                     .first == null || !mUiRemoteEntry.first.equals(entryKey)
                     || mUiRemoteEntry.second == null
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index 6498b6a..ee813e9 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -38,6 +38,7 @@
 import android.service.credentials.CredentialProviderInfo;
 import android.service.credentials.CredentialProviderService;
 import android.service.credentials.GetCredentialRequest;
+import android.service.credentials.RemoteEntry;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
@@ -299,7 +300,7 @@
         }
         return new Intent().putExtra(CredentialProviderService.EXTRA_GET_CREDENTIAL_REQUEST,
                 new GetCredentialRequest(
-                        mCallingAppInfo, mBeginGetOptionToCredentialOptionMap.get(id)));
+                        mCallingAppInfo, List.of(mBeginGetOptionToCredentialOptionMap.get(id))));
     }
 
     private Intent setUpFillInIntentWithQueryRequest() {
@@ -472,7 +473,7 @@
         private final Map<String, Pair<Action, AuthenticationEntry>> mUiAuthenticationEntries =
                 new HashMap<>();
 
-        @Nullable private Pair<String, Pair<CredentialEntry, Entry>> mUiRemoteEntry = null;
+        @Nullable private Pair<String, Pair<RemoteEntry, Entry>> mUiRemoteEntry = null;
 
         ProviderResponseDataHandler(ComponentName expectedRemoteEntryProviderService) {
             mExpectedRemoteEntryProviderService = expectedRemoteEntryProviderService;
@@ -480,7 +481,7 @@
 
         public void addResponseContent(List<CredentialEntry> credentialEntries,
                 List<Action> actions, List<Action> authenticationActions,
-                CredentialEntry remoteEntry) {
+                RemoteEntry remoteEntry) {
             credentialEntries.forEach(this::addCredentialEntry);
             actions.forEach(this::addAction);
             authenticationActions.forEach(
@@ -522,7 +523,7 @@
             mUiAuthenticationEntries.remove(id);
         }
 
-        public void setRemoteEntry(@Nullable CredentialEntry remoteEntry) {
+        public void setRemoteEntry(@Nullable RemoteEntry remoteEntry) {
             if (remoteEntry == null) {
                 return;
             }
@@ -533,8 +534,7 @@
             }
             String id = generateUniqueId();
             Entry entry = new Entry(REMOTE_ENTRY_KEY,
-                    id, remoteEntry.getSlice(), setUpFillInIntent(
-                            remoteEntry.getBeginGetCredentialOption().getId()));
+                    id, remoteEntry.getSlice(), setUpFillInIntentForRemoteEntry());
             mUiRemoteEntry = new Pair<>(generateUniqueId(), new Pair<>(remoteEntry, entry));
         }
 
@@ -604,7 +604,7 @@
         }
 
         @Nullable
-        public CredentialEntry getRemoteEntry(String entryKey) {
+        public RemoteEntry getRemoteEntry(String entryKey) {
             return mUiRemoteEntry.first.equals(entryKey) && mUiRemoteEntry.second != null
                     ? mUiRemoteEntry.second.first : null;
         }
@@ -662,4 +662,10 @@
                     from.getFrameworkExtrasIntent());
         }
     }
+
+    private Intent setUpFillInIntentForRemoteEntry() {
+        return new Intent().putExtra(CredentialProviderService.EXTRA_GET_CREDENTIAL_REQUEST,
+                new GetCredentialRequest(
+                        mCallingAppInfo, mCompleteRequest.getCredentialOptions()));
+    }
 }
diff --git a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
index a57cb5f..36d6b3d 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
@@ -121,7 +121,7 @@
                 CredentialProviderService
                         .EXTRA_GET_CREDENTIAL_REQUEST,
                 new android.service.credentials.GetCredentialRequest(
-                        mCallingAppInfo, mProviderRequest));
+                        mCallingAppInfo, List.of(mProviderRequest)));
         return intent;
     }
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index bfcb4c7..e9c23a0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -11337,7 +11337,7 @@
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_APPLICATION_RESTRICTIONS)
                 .setAdmin(caller.getPackageName())
-                .setBoolean(/* isDelegate */ who == null)
+                .setBoolean(/* isDelegate */ isCallerDelegate(caller))
                 .setStrings(packageName)
                 .write();
     }
@@ -13378,7 +13378,7 @@
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_APPLICATION_HIDDEN)
                 .setAdmin(caller.getPackageName())
-                .setBoolean(/* isDelegate */ who == null)
+                .setBoolean(/* isDelegate */ isCallerDelegate(caller))
                 .setStrings(packageName, hidden ? "hidden" : "not_hidden",
                         parent ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT)
                 .write();
@@ -13730,7 +13730,7 @@
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_UNINSTALL_BLOCKED)
                 .setAdmin(caller.getPackageName())
-                .setBoolean(/* isDelegate */ who == null)
+                .setBoolean(/* isDelegate */ isCallerDelegate(caller))
                 .setStrings(packageName)
                 .write();
     }
@@ -16280,7 +16280,8 @@
                                                 .setAdmin(caller.getPackageName())
                                                 .setStrings(permission)
                                                 .setInt(grantState)
-                                                .setBoolean(/* isDelegate */ admin == null)
+                                                .setBoolean(
+                                                        /* isDelegate */ isCallerDelegate(caller))
                                                 .write();
 
                                         callback.sendResult(Bundle.EMPTY);
@@ -16405,12 +16406,12 @@
                     mInjector.getPackageManager().getPackagesForUid(caller.getUid()));
             Preconditions.checkArgument(callerUidPackageNames.contains(packageName),
                     "Caller uid doesn't match the one for the provided package.");
+
+            return checkProvisioningPreconditionSkipPermission(action, packageName, caller.getUserId())
+                    == STATUS_OK;
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
         }
-
-        return checkProvisioningPreconditionSkipPermission(action, packageName, caller.getUserId())
-                == STATUS_OK;
     }
 
     @Override
@@ -22183,6 +22184,10 @@
     private static final HashMap<String, String> DELEGATE_SCOPES = new HashMap<>();
     {
         DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS, DELEGATION_PERMISSION_GRANT);
+        DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_APP_RESTRICTIONS, DELEGATION_APP_RESTRICTIONS);
+        DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_APPS_CONTROL, DELEGATION_BLOCK_UNINSTALL);
+        DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, DELEGATION_SECURITY_LOGGING);
+        DELEGATE_SCOPES.put(MANAGE_DEVICE_POLICY_PACKAGE_STATE, DELEGATION_PACKAGE_ACCESS);
     }
 
     private static final HashMap<String, String> CROSS_USER_PERMISSIONS =
@@ -22371,6 +22376,7 @@
                     + permission
                     + ", "
                     + CROSS_USER_PERMISSIONS.get(permission)
+                    + "(if calling cross-user)"
                     + "}");
         }
     }
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 17e1744..0ca4dfc 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -113,7 +113,6 @@
     private static final long USAGE_STATS_QUERY_INTERVAL_SEC = 120L;
     @VisibleForTesting
     static final int MAX_CACHED_RECENT_SHORTCUTS = 30;
-    private static final int DEBOUNCE_LENGTH_MS = 500;
 
     private final Context mContext;
     private final Injector mInjector;
@@ -130,7 +129,6 @@
     private final List<PeopleService.ConversationsListener> mConversationsListeners =
             new ArrayList<>(1);
     private final Handler mHandler;
-    private final PerPackageThrottler mShortcutsThrottler;
 
     private ContentObserver mCallLogContentObserver;
     private ContentObserver mMmsSmsContentObserver;
@@ -142,17 +140,14 @@
     private ConversationStatusExpirationBroadcastReceiver mStatusExpReceiver;
 
     public DataManager(Context context) {
-        this(context, new Injector(), BackgroundThread.get().getLooper(),
-                new PerPackageThrottlerImpl(BackgroundThread.getHandler(), DEBOUNCE_LENGTH_MS));
+        this(context, new Injector(), BackgroundThread.get().getLooper());
     }
 
-    DataManager(Context context, Injector injector, Looper looper,
-            PerPackageThrottler shortcutsThrottler) {
+    DataManager(Context context, Injector injector, Looper looper) {
         mContext = context;
         mInjector = injector;
         mScheduledExecutor = mInjector.createScheduledExecutor();
         mHandler = new Handler(looper);
-        mShortcutsThrottler = shortcutsThrottler;
     }
 
     /** Initialization. Called when the system services are up running. */
@@ -856,12 +851,12 @@
         // pair of <package name, conversation info>
         List<Pair<String, ConversationInfo>> cachedConvos = new ArrayList<>();
         userData.forAllPackages(packageData -> {
-            packageData.forAllConversations(conversationInfo -> {
-                if (isEligibleForCleanUp(conversationInfo)) {
-                    cachedConvos.add(
-                            Pair.create(packageData.getPackageName(), conversationInfo));
-                }
-            });
+                packageData.forAllConversations(conversationInfo -> {
+                    if (isEligibleForCleanUp(conversationInfo)) {
+                        cachedConvos.add(
+                                Pair.create(packageData.getPackageName(), conversationInfo));
+                    }
+                });
         });
         if (cachedConvos.size() <= targetCachedCount) {
             return;
@@ -872,8 +867,8 @@
                 numToUncache + 1,
                 Comparator.comparingLong((Pair<String, ConversationInfo> pair) ->
                         Math.max(
-                                pair.second.getLastEventTimestamp(),
-                                pair.second.getCreationTimestamp())).reversed());
+                            pair.second.getLastEventTimestamp(),
+                            pair.second.getCreationTimestamp())).reversed());
         for (Pair<String, ConversationInfo> cached : cachedConvos) {
             if (hasActiveNotifications(cached.first, userId, cached.second.getShortcutId())) {
                 continue;
@@ -1109,35 +1104,26 @@
         @Override
         public void onShortcutsAddedOrUpdated(@NonNull String packageName,
                 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
-            mShortcutsThrottler.scheduleDebounced(
-                    new Pair<>(packageName, user.getIdentifier()),
-                    () -> {
-                        PackageData packageData = getPackage(packageName, user.getIdentifier());
-                        List<ShortcutInfo> queriedShortcuts = getShortcuts(packageName,
-                                user.getIdentifier(), null);
-                        boolean hasCachedShortcut = false;
-                        for (ShortcutInfo shortcut : queriedShortcuts) {
-                            if (ShortcutHelper.isConversationShortcut(
-                                    shortcut, mShortcutServiceInternal, user.getIdentifier())) {
-                                if (shortcut.isCached()) {
-                                    ConversationInfo info = packageData != null
-                                            ? packageData.getConversationInfo(shortcut.getId())
-                                            : null;
-                                    if (info == null
-                                            || !info.isShortcutCachedForNotification()) {
-                                        hasCachedShortcut = true;
-                                    }
-                                }
-                                addOrUpdateConversationInfo(shortcut);
+            mInjector.getBackgroundExecutor().execute(() -> {
+                PackageData packageData = getPackage(packageName, user.getIdentifier());
+                for (ShortcutInfo shortcut : shortcuts) {
+                    if (ShortcutHelper.isConversationShortcut(
+                            shortcut, mShortcutServiceInternal, user.getIdentifier())) {
+                        if (shortcut.isCached()) {
+                            ConversationInfo conversationInfo = packageData != null
+                                    ? packageData.getConversationInfo(shortcut.getId()) : null;
+                            if (conversationInfo == null
+                                    || !conversationInfo.isShortcutCachedForNotification()) {
+                                // This is a newly cached shortcut. Clean up the existing cached
+                                // shortcuts to ensure the cache size is under the limit.
+                                cleanupCachedShortcuts(user.getIdentifier(),
+                                        MAX_CACHED_RECENT_SHORTCUTS - 1);
                             }
                         }
-                        // Added at least one new conversation. Uncache older existing cached
-                        // shortcuts to ensure the cache size is under the limit.
-                        if (hasCachedShortcut) {
-                            cleanupCachedShortcuts(user.getIdentifier(),
-                                    MAX_CACHED_RECENT_SHORTCUTS);
-                        }
-                    });
+                        addOrUpdateConversationInfo(shortcut);
+                    }
+                }
+            });
         }
 
         @Override
diff --git a/services/people/java/com/android/server/people/data/PerPackageThrottler.java b/services/people/java/com/android/server/people/data/PerPackageThrottler.java
deleted file mode 100644
index 3d6cd84..0000000
--- a/services/people/java/com/android/server/people/data/PerPackageThrottler.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.people.data;
-
-import android.util.Pair;
-
-/** The interface for throttling expensive runnables per package. */
-interface PerPackageThrottler {
-    /**
-     * Schedule a runnable to run in the future, and debounce runnables for same {@code pkgUserId}
-     * that occur until that future has run.
-     */
-    void scheduleDebounced(Pair<String, Integer> pkgUserId, Runnable runnable);
-}
diff --git a/services/people/java/com/android/server/people/data/PerPackageThrottlerImpl.java b/services/people/java/com/android/server/people/data/PerPackageThrottlerImpl.java
deleted file mode 100644
index fa5a67b..0000000
--- a/services/people/java/com/android/server/people/data/PerPackageThrottlerImpl.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.people.data;
-
-import android.os.Handler;
-import android.util.Pair;
-
-import java.util.HashSet;
-
-/**
- * A class that implements a per-package throttler that prevents a runnable from executing more than
- * once every {@code debounceTime}.
- */
-public class PerPackageThrottlerImpl implements PerPackageThrottler {
-    private final Handler mBackgroundHandler;
-    private final int mDebounceTime;
-    private final HashSet<Pair<String, Integer>> mPkgScheduledTasks = new HashSet<>();
-
-    PerPackageThrottlerImpl(Handler backgroundHandler, int debounceTime) {
-        mBackgroundHandler = backgroundHandler;
-        mDebounceTime = debounceTime;
-    }
-
-    @Override
-    public synchronized void scheduleDebounced(
-            Pair<String, Integer> pkgUserId, Runnable runnable) {
-        if (mPkgScheduledTasks.contains(pkgUserId)) {
-            return;
-        }
-        mPkgScheduledTasks.add(pkgUserId);
-        mBackgroundHandler.postDelayed(() -> {
-            synchronized (this) {
-                mPkgScheduledTasks.remove(pkgUserId);
-                runnable.run();
-            }
-        }, mDebounceTime);
-    }
-}
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
index a39e021..836f858 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -566,6 +566,22 @@
     }
 
     @Test
+    public void testWriteCorruptReadPackageRestrictions() {
+        final Settings settingsUnderTest = makeSettings();
+
+        populateDistractionFlags(settingsUnderTest);
+        settingsUnderTest.writePackageRestrictionsLPr(0, /*sync=*/true);
+
+        // Corrupt primary file.
+        writeCorruptedPackageRestrictions(0);
+
+        // now read and verify
+        populateDefaultSettings(settingsUnderTest);
+        settingsUnderTest.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
+        verifyDistractionFlags(settingsUnderTest);
+    }
+
+    @Test
     public void testReadWritePackageRestrictionsAsync() {
         final Settings settingsWrite = makeSettings();
         final Settings settingsRead = makeSettings();
@@ -1811,6 +1827,14 @@
                         .getBytes());
     }
 
+    private void writeCorruptedPackageRestrictions(final int userId) {
+        writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/users/"
+                        + userId + "/package-restrictions.xml"),
+                ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+                        + "<package-restrictions>\n"
+                        + "    <pkg name=\"" + PACKAGE_NAME_1 + "\" ").getBytes());
+    }
+
     private static void writeStoppedPackagesXml() {
         writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/packages-stopped.xml"),
                 ( "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index bcd69fda..8582012 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -86,6 +86,9 @@
 import android.os.PowerSaveState;
 import android.os.SystemClock;
 import android.provider.DeviceConfig;
+import android.telephony.TelephonyCallback;
+import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -119,6 +122,8 @@
     private AnyMotionDetectorForTest mAnyMotionDetector;
     private AppStateTrackerForTest mAppStateTracker;
     private DeviceIdleController.Constants mConstants;
+    private TelephonyCallback.OutgoingEmergencyCallListener mEmergencyCallListener;
+    private TelephonyCallback.CallStateListener mCallStateListener;
     private InjectorForTest mInjector;
 
     private MockitoSession mMockingSession;
@@ -140,6 +145,8 @@
     private Sensor mMotionSensor;
     @Mock
     private SensorManager mSensorManager;
+    @Mock
+    private TelephonyManager mTelephonyManager;
 
     class InjectorForTest extends DeviceIdleController.Injector {
         ConnectivityManager connectivityManager;
@@ -232,6 +239,11 @@
         }
 
         @Override
+        TelephonyManager getTelephonyManager() {
+            return mTelephonyManager;
+        }
+
+        @Override
         boolean useMotionSensor() {
             return true;
         }
@@ -343,6 +355,15 @@
 
         // Get the same Constants object that mDeviceIdleController got.
         mConstants = mInjector.getConstants(mDeviceIdleController);
+
+        final ArgumentCaptor<TelephonyCallback> telephonyCallbackCaptor =
+                ArgumentCaptor.forClass(TelephonyCallback.class);
+        verify(mTelephonyManager)
+                .registerTelephonyCallback(any(), telephonyCallbackCaptor.capture());
+        mEmergencyCallListener = (TelephonyCallback.OutgoingEmergencyCallListener)
+                telephonyCallbackCaptor.getValue();
+        mCallStateListener =
+                (TelephonyCallback.CallStateListener) telephonyCallbackCaptor.getValue();
     }
 
     @After
@@ -531,6 +552,16 @@
 
         mDeviceIdleController.becomeInactiveIfAppropriateLocked();
         verifyStateConditions(STATE_ACTIVE);
+
+        // All other conditions allow for going INACTIVE...
+        setAlarmSoon(false);
+        setChargingOn(false);
+        setScreenOn(false);
+        // ...except the emergency call.
+        setEmergencyCallActive(true);
+
+        mDeviceIdleController.becomeInactiveIfAppropriateLocked();
+        verifyStateConditions(STATE_ACTIVE);
     }
 
     @Test
@@ -559,6 +590,15 @@
 
         mDeviceIdleController.becomeInactiveIfAppropriateLocked();
         verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+
+        // All other conditions allow for going INACTIVE...
+        setChargingOn(false);
+        setScreenOn(false);
+        // ...except the emergency call.
+        setEmergencyCallActive(true);
+
+        mDeviceIdleController.becomeInactiveIfAppropriateLocked();
+        verifyLightStateConditions(LIGHT_STATE_ACTIVE);
     }
 
     @Test
@@ -569,6 +609,7 @@
         setAlarmSoon(false);
         setChargingOn(false);
         setScreenOn(false);
+        setEmergencyCallActive(false);
 
         mDeviceIdleController.becomeInactiveIfAppropriateLocked();
         verifyStateConditions(STATE_INACTIVE);
@@ -613,6 +654,7 @@
 
         setChargingOn(false);
         setScreenOn(false);
+        setEmergencyCallActive(false);
 
         mDeviceIdleController.becomeInactiveIfAppropriateLocked();
         verifyLightStateConditions(LIGHT_STATE_INACTIVE);
@@ -1147,6 +1189,22 @@
                 eq(true));
     }
 
+    @Test
+    public void testEmergencyCallEndTriggersInactive() {
+        setAlarmSoon(false);
+        setChargingOn(false);
+        setScreenOn(false);
+        setEmergencyCallActive(true);
+
+        verifyStateConditions(STATE_ACTIVE);
+        verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+
+        setEmergencyCallActive(false);
+
+        verifyStateConditions(STATE_INACTIVE);
+        verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+    }
+
     ///////////////// EXIT conditions ///////////////////
 
     @Test
@@ -2096,6 +2154,75 @@
                 .onDeviceStationaryChanged(eq(true));
     }
 
+    @Test
+    public void testEmergencyEndsIdle() {
+        enterDeepState(STATE_ACTIVE);
+        setEmergencyCallActive(true);
+        verifyStateConditions(STATE_ACTIVE);
+
+        enterDeepState(STATE_INACTIVE);
+        setEmergencyCallActive(true);
+        verifyStateConditions(STATE_ACTIVE);
+
+        enterDeepState(STATE_IDLE_PENDING);
+        setEmergencyCallActive(true);
+        verifyStateConditions(STATE_ACTIVE);
+
+        enterDeepState(STATE_SENSING);
+        setEmergencyCallActive(true);
+        verifyStateConditions(STATE_ACTIVE);
+
+        enterDeepState(STATE_LOCATING);
+        setEmergencyCallActive(true);
+        verifyStateConditions(STATE_ACTIVE);
+
+        // Quick doze enabled or not shouldn't affect the end state.
+        enterDeepState(STATE_QUICK_DOZE_DELAY);
+        setQuickDozeEnabled(true);
+        setEmergencyCallActive(true);
+        verifyStateConditions(STATE_ACTIVE);
+
+        enterDeepState(STATE_QUICK_DOZE_DELAY);
+        setQuickDozeEnabled(false);
+        setEmergencyCallActive(true);
+        verifyStateConditions(STATE_ACTIVE);
+
+        enterDeepState(STATE_IDLE);
+        setEmergencyCallActive(true);
+        verifyStateConditions(STATE_ACTIVE);
+
+        enterDeepState(STATE_IDLE_MAINTENANCE);
+        setEmergencyCallActive(true);
+        verifyStateConditions(STATE_ACTIVE);
+    }
+
+    @Test
+    public void testEmergencyEndsLightIdle() {
+        enterLightState(LIGHT_STATE_ACTIVE);
+        setEmergencyCallActive(true);
+        verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+
+        enterLightState(LIGHT_STATE_INACTIVE);
+        setEmergencyCallActive(true);
+        verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+
+        enterLightState(LIGHT_STATE_WAITING_FOR_NETWORK);
+        setEmergencyCallActive(true);
+        verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+
+        enterLightState(LIGHT_STATE_IDLE);
+        setEmergencyCallActive(true);
+        verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+
+        enterLightState(LIGHT_STATE_IDLE_MAINTENANCE);
+        setEmergencyCallActive(true);
+        verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+
+        enterLightState(LIGHT_STATE_OVERRIDE);
+        setEmergencyCallActive(true);
+        verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+    }
+
     private void enterDeepState(int state) {
         switch (state) {
             case STATE_ACTIVE:
@@ -2108,6 +2235,7 @@
                 setQuickDozeEnabled(true);
                 setScreenOn(false);
                 setChargingOn(false);
+                setEmergencyCallActive(false);
                 mDeviceIdleController.becomeInactiveIfAppropriateLocked();
                 break;
             case STATE_LOCATING:
@@ -2128,6 +2256,7 @@
                 setQuickDozeEnabled(false);
                 setScreenOn(false);
                 setChargingOn(false);
+                setEmergencyCallActive(false);
                 mDeviceIdleController.becomeInactiveIfAppropriateLocked();
                 int count = 0;
                 while (mDeviceIdleController.getState() != state) {
@@ -2159,6 +2288,7 @@
                 enterLightState(LIGHT_STATE_ACTIVE);
                 setScreenOn(false);
                 setChargingOn(false);
+                setEmergencyCallActive(false);
                 int count = 0;
                 mDeviceIdleController.becomeInactiveIfAppropriateLocked();
                 while (mDeviceIdleController.getLightState() != lightState) {
@@ -2177,6 +2307,7 @@
             case LIGHT_STATE_OVERRIDE:
                 setScreenOn(false);
                 setChargingOn(false);
+                setEmergencyCallActive(false);
                 mDeviceIdleController.setLightStateForTest(lightState);
                 break;
             default:
@@ -2188,6 +2319,14 @@
         mDeviceIdleController.updateChargingLocked(on);
     }
 
+    private void setEmergencyCallActive(boolean active) {
+        if (active) {
+            mEmergencyCallListener.onOutgoingEmergencyCall(mock(EmergencyNumber.class), 0);
+        } else {
+            mCallStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_IDLE);
+        }
+    }
+
     private void setScreenLocked(boolean locked) {
         mDeviceIdleController.keyguardShowingLocked(locked);
     }
@@ -2235,6 +2374,7 @@
                 assertFalse(mDeviceIdleController.isCharging());
                 assertFalse(mDeviceIdleController.isScreenOn()
                         && !mDeviceIdleController.isKeyguardShowing());
+                assertFalse(mDeviceIdleController.isEmergencyCallActive());
                 break;
             case STATE_IDLE_PENDING:
                 assertEquals(
@@ -2244,6 +2384,7 @@
                 assertFalse(mDeviceIdleController.isCharging());
                 assertFalse(mDeviceIdleController.isScreenOn()
                         && !mDeviceIdleController.isKeyguardShowing());
+                assertFalse(mDeviceIdleController.isEmergencyCallActive());
                 break;
             case STATE_SENSING:
                 assertEquals(
@@ -2255,6 +2396,7 @@
                 assertFalse(mDeviceIdleController.isCharging());
                 assertFalse(mDeviceIdleController.isScreenOn()
                         && !mDeviceIdleController.isKeyguardShowing());
+                assertFalse(mDeviceIdleController.isEmergencyCallActive());
                 break;
             case STATE_LOCATING:
                 assertEquals(
@@ -2263,6 +2405,7 @@
                 assertFalse(mDeviceIdleController.isCharging());
                 assertFalse(mDeviceIdleController.isScreenOn()
                         && !mDeviceIdleController.isKeyguardShowing());
+                assertFalse(mDeviceIdleController.isEmergencyCallActive());
                 break;
             case STATE_IDLE:
                 if (mDeviceIdleController.hasMotionSensor()) {
@@ -2276,6 +2419,7 @@
                         && !mDeviceIdleController.isKeyguardShowing());
                 // Light state should be OVERRIDE at this point.
                 verifyLightStateConditions(LIGHT_STATE_OVERRIDE);
+                assertFalse(mDeviceIdleController.isEmergencyCallActive());
                 break;
             case STATE_IDLE_MAINTENANCE:
                 if (mDeviceIdleController.hasMotionSensor()) {
@@ -2287,6 +2431,7 @@
                 assertFalse(mDeviceIdleController.isCharging());
                 assertFalse(mDeviceIdleController.isScreenOn()
                         && !mDeviceIdleController.isKeyguardShowing());
+                assertFalse(mDeviceIdleController.isEmergencyCallActive());
                 break;
             case STATE_QUICK_DOZE_DELAY:
                 // If quick doze is enabled, the motion listener should NOT be active.
@@ -2295,6 +2440,7 @@
                 assertFalse(mDeviceIdleController.isCharging());
                 assertFalse(mDeviceIdleController.isScreenOn()
                         && !mDeviceIdleController.isKeyguardShowing());
+                assertFalse(mDeviceIdleController.isEmergencyCallActive());
                 break;
             default:
                 fail("Conditions for " + stateToString(expectedState) + " unknown.");
@@ -2312,6 +2458,7 @@
             case LIGHT_STATE_ACTIVE:
                 assertTrue(
                         mDeviceIdleController.isCharging() || mDeviceIdleController.isScreenOn()
+                                || mDeviceIdleController.isEmergencyCallActive()
                                 // Or there's an alarm coming up soon.
                                 || SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM
                                 > mAlarmManager.getNextWakeFromIdleTime());
@@ -2324,6 +2471,7 @@
                 assertFalse(mDeviceIdleController.isCharging());
                 assertFalse(mDeviceIdleController.isScreenOn()
                         && !mDeviceIdleController.isKeyguardShowing());
+                assertFalse(mDeviceIdleController.isEmergencyCallActive());
                 break;
             default:
                 fail("Conditions for " + lightStateToString(expectedLightState) + " unknown.");
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 485ce33..0b4c70c2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -1968,6 +1968,36 @@
 
     @SuppressWarnings("GuardedBy")
     @Test
+    public void testUpdateOomAdj_DoOne_PendingFinishAttach() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        app.setPendingFinishAttach(true);
+        app.mState.setHasForegroundActivities(false);
+
+        sService.mOomAdjuster.setAttachingProcessStatesLSP(app);
+        updateOomAdj(app);
+
+        assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, FOREGROUND_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoOne_TopApp_PendingFinishAttach() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        app.setPendingFinishAttach(true);
+        app.mState.setHasForegroundActivities(true);
+
+        sService.mOomAdjuster.setAttachingProcessStatesLSP(app);
+        updateOomAdj(app);
+
+        assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, FOREGROUND_APP_ADJ,
+                SCHED_GROUP_TOP_APP);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
     public void testUpdateOomAdj_UidIdle_StopService() {
         final ProcessRecord app1 = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
index 3e0e5a8..7942e24 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -249,7 +249,7 @@
         when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled);
         when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false);
         when(logicalDisplayMock.getBrightnessThrottlingDataIdLocked()).thenReturn(
-                DisplayDeviceConfig.DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID);
+                DisplayDeviceConfig.DEFAULT_ID);
         when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo);
         when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId);
         when(displayDeviceMock.getDisplayDeviceConfig()).thenReturn(displayDeviceConfigMock);
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
index 6c4afd3..16bf2a22 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -252,7 +252,7 @@
         when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled);
         when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false);
         when(logicalDisplayMock.getBrightnessThrottlingDataIdLocked()).thenReturn(
-                DisplayDeviceConfig.DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID);
+                DisplayDeviceConfig.DEFAULT_ID);
         when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo);
         when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId);
         when(displayDeviceMock.getDisplayDeviceConfig()).thenReturn(displayDeviceConfigMock);
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java
index 9aa53db..8979585 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java
@@ -20,6 +20,8 @@
 import static android.view.Display.INVALID_DISPLAY;
 
 import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE;
+import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_ALREADY_VISIBLE;
+import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
 import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE;
 import static com.android.server.pm.UserVisibilityChangedEvent.onInvisible;
 import static com.android.server.pm.UserVisibilityChangedEvent.onVisible;
@@ -73,8 +75,8 @@
         assertUserCanBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID);
 
         // Make sure another user cannot be started on default display
-        int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, visibleBgUserId,
-                BG_VISIBLE, DEFAULT_DISPLAY);
+        int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, otherUserId, BG_VISIBLE,
+                DEFAULT_DISPLAY);
         assertStartUserResult(result2, USER_ASSIGNMENT_RESULT_FAILURE,
                 "when user (%d) is starting on default display after it was started by user %d",
                 otherUserId, visibleBgUserId);
@@ -117,8 +119,8 @@
         assertUserCanBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID);
 
         // Make sure another user cannot be started on default display
-        int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, visibleBgUserId,
-                BG_VISIBLE, DEFAULT_DISPLAY);
+        int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, otherUserId, BG_VISIBLE,
+                DEFAULT_DISPLAY);
         assertStartUserResult(result2, USER_ASSIGNMENT_RESULT_FAILURE,
                 "when user (%d) is starting on default display after it was started by user %d",
                 otherUserId, visibleBgUserId);
@@ -127,8 +129,6 @@
         listener.verify();
     }
 
-  /* TODO(b/261538337): re-add after the reverted CL is merged again
-
     @Test
     public void
        testStartVisibleBgProfile_onDefaultDisplay_whenParentIsStartedVisibleOnBgOnSecondaryDisplay()
@@ -226,5 +226,4 @@
 
         listener.verify();
     }
-  */
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java
index 1bf921c..2774803 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java
@@ -44,7 +44,6 @@
 import android.util.IntArray;
 import android.util.Log;
 
-import com.android.internal.util.Preconditions;
 import com.android.server.DumpableDumperRule;
 import com.android.server.ExpectableTestCase;
 
@@ -152,6 +151,12 @@
     }
 
     @Test
+    public final void testAssignUserToDisplayOnStart_invalidUserStartMode() {
+        assertThrows(IllegalArgumentException.class, () -> mMediator
+                .assignUserToDisplayOnStart(USER_ID, USER_ID, 666, DEFAULT_DISPLAY));
+    }
+
+    @Test
     public final void testStartFgUser_onSecondaryDisplay() throws Exception {
         AsyncUserVisibilityListener listener = addListenerForNoEvents();
 
@@ -286,7 +291,7 @@
 
         int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
                 BG_VISIBLE, DEFAULT_DISPLAY);
-        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
+        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
 
         expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
         expectNoDisplayAssignedToUser(PROFILE_USER_ID);
@@ -302,14 +307,14 @@
 
         int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
                 BG_VISIBLE, DEFAULT_DISPLAY);
-        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
+        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
 
         expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
 
         expectNoDisplayAssignedToUser(PROFILE_USER_ID);
         expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
 
-        assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+        assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
 
         listener.verify();
     }
@@ -335,6 +340,41 @@
     }
 
     @Test
+    public final void testStartBgProfile_onDefaultDisplay_whenParentIsNotStarted()
+            throws Exception {
+        AsyncUserVisibilityListener listener = addListenerForNoEvents();
+
+        int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
+                DEFAULT_DISPLAY);
+        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
+
+        expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
+        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
+
+        listener.verify();
+    }
+
+    @Test
+    public final void testStartBgProfile_onDefaultDisplay_whenParentIsStartedOnBg()
+            throws Exception {
+        AsyncUserVisibilityListener listener = addListenerForNoEvents();
+        startBackgroundUser(PARENT_USER_ID);
+
+        int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
+                DEFAULT_DISPLAY);
+        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
+
+        expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
+
+        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
+        expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
+
+        assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+
+        listener.verify();
+    }
+
+    @Test
     public final void testStartBgProfile_onSecondaryDisplay() throws Exception {
         AsyncUserVisibilityListener listener = addListenerForNoEvents();
 
@@ -488,8 +528,6 @@
      * se.
      */
     protected final void startUserInSecondaryDisplay(@UserIdInt int userId, int displayId) {
-        Preconditions.checkArgument(displayId != INVALID_DISPLAY && displayId != DEFAULT_DISPLAY,
-                "must pass a secondary display, not %d", displayId);
         Log.d(TAG, "startUserInSecondaryDisplay(" + userId + ", " + displayId + ")");
         int result = mMediator.assignUserToDisplayOnStart(userId, userId, BG_VISIBLE, displayId);
         if (result != USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java
index af85ef4..e82910f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java
@@ -109,34 +109,6 @@
     }
 
     @Test
-    public final void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsCurrentUser()
-            throws Exception {
-        AsyncUserVisibilityListener listener = addListenerForEvents(
-                onInvisible(INITIAL_CURRENT_USER_ID),
-                onVisible(PARENT_USER_ID),
-                onVisible(PROFILE_USER_ID));
-        startForegroundUser(PARENT_USER_ID);
-
-        int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
-                BG_VISIBLE, DEFAULT_DISPLAY);
-        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
-        expectUserCannotBeUnassignedFromDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
-
-        expectUserIsVisible(PROFILE_USER_ID);
-        expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY);
-        expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
-        expectUserIsVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
-        expectVisibleUsers(PARENT_USER_ID, PROFILE_USER_ID);
-
-        expectDisplayAssignedToUser(PROFILE_USER_ID, DEFAULT_DISPLAY);
-        expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
-
-        assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
-
-        listener.verify();
-    }
-
-    @Test
     public final void testStartFgUser_onInvalidDisplay() throws Exception {
         AsyncUserVisibilityListener listener = addListenerForNoEvents();
 
@@ -301,14 +273,83 @@
     }
 
     @Test
+    public final void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsCurrentUser()
+            throws Exception {
+        AsyncUserVisibilityListener listener = addListenerForEvents(
+                onInvisible(INITIAL_CURRENT_USER_ID),
+                onVisible(PARENT_USER_ID),
+                onVisible(PROFILE_USER_ID));
+        startForegroundUser(PARENT_USER_ID);
+
+        int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
+                BG_VISIBLE, DEFAULT_DISPLAY);
+        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
+        expectUserCannotBeUnassignedFromDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
+
+        expectUserIsVisible(PROFILE_USER_ID);
+        expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY);
+        expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+        expectUserIsVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
+        expectVisibleUsers(PARENT_USER_ID, PROFILE_USER_ID);
+
+        expectDisplayAssignedToUser(PROFILE_USER_ID, DEFAULT_DISPLAY);
+        expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
+
+        assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+
+        listener.verify();
+    }
+
+    @Test
     public final void
-            testStartVisibleBgProfile_onDefaultDisplay_whenParentVisibleOnSecondaryDisplay()
-                    throws Exception {
+            testStartVisibleBgProfile_onDefaultDisplay_whenParentIsStartedVisibleOnAnotherDisplay()
+            throws Exception {
         AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID));
         startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
 
         int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
                 BG_VISIBLE, DEFAULT_DISPLAY);
+        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
+
+        expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
+        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
+        expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, PARENT_USER_ID);
+
+        assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+
+        listener.verify();
+    }
+
+    // Not supported - profiles can only be started on default display
+    @Test
+    public final void
+            testStartVisibleBgProfile_onSecondaryDisplay_whenParentIsStartedVisibleOnThatDisplay()
+            throws Exception {
+        AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID));
+        startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
+
+        int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
+                BG_VISIBLE, DEFAULT_DISPLAY);
+        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
+
+        expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
+        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
+        expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, PARENT_USER_ID);
+
+        assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+
+        listener.verify();
+    }
+
+    @Test
+    public final void
+            testStartProfile_onDefaultDisplay_whenParentIsStartedVisibleOnSecondaryDisplay()
+            throws Exception {
+        AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID));
+        startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
+
+        int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
+                DEFAULT_DISPLAY);
         assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
 
         expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 3a7b9a4..90dbd53 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -115,6 +115,7 @@
         ":StubTestApp",
         ":SuspendTestApp",
         ":MediaButtonReceiverHolderTestHelperApp",
+        "data/broken_shortcut.xml",
     ],
 
     java_resources: [
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index d967647..b304968 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -21,6 +21,8 @@
         <option name="cleanup" value="true" />
         <option name="push-file" key="SimpleServiceTestApp3.apk"
                 value="/data/local/tmp/cts/content/SimpleServiceTestApp3.apk" />
+        <option name="push-file" key="broken_shortcut.xml"
+                value="/data/local/tmp/cts/content/broken_shortcut.xml" />
     </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/services/tests/servicestests/data/broken_shortcut.xml b/services/tests/servicestests/data/broken_shortcut.xml
new file mode 100644
index 0000000..f2b083d
--- /dev/null
+++ b/services/tests/servicestests/data/broken_shortcut.xml
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 93dfee6..8c7b0c5 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -528,7 +528,7 @@
             ActivityManager.PROCESS_CAPABILITY_NONE,
             ActivityManager.PROCESS_CAPABILITY_NONE,
             ActivityManager.PROCESS_CAPABILITY_NONE,
-            ActivityManager.PROCESS_CAPABILITY_NETWORK,
+            ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK,
         };
         final Map<Integer, ChangeRecord> changeItems = new HashMap<>();
         for (int i = 0; i < changesForPendingUidRecords.length; ++i) {
diff --git a/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
index 8a3f246..f788c92 100644
--- a/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
@@ -18,8 +18,8 @@
 
 import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
-import static android.app.ActivityManager.PROCESS_CAPABILITY_NETWORK;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
 import static android.app.ActivityManager.PROCESS_STATE_CACHED_RECENT;
 import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
 import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
@@ -185,10 +185,10 @@
         verifyNoMoreInteractions(observer2);
 
         addPendingChange(TEST_UID1, UidRecord.CHANGE_PROCSTATE | UidRecord.CHANGE_CAPABILITY,
-                PROCESS_STATE_RECEIVER, 111, PROCESS_CAPABILITY_NETWORK, false);
+                PROCESS_STATE_RECEIVER, 111, PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK, false);
         mUidObserverController.dispatchUidsChanged();
         verify(observer2).onUidStateChanged(TEST_UID1, PROCESS_STATE_RECEIVER,
-                111, PROCESS_CAPABILITY_NETWORK);
+                111, PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK);
         verifyNoMoreInteractions(observer1);
         verifyNoMoreInteractions(observer2);
 
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index 26524d7..7646c40 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -273,16 +273,6 @@
         showHideOverlay(c -> c.onEnrollResult(new Fingerprint("", 1, 1), 0));
     }
 
-    @Test
-    public void testPowerPressForwardsAcquireMessage() throws RemoteException {
-        final FingerprintEnrollClient client = createClient();
-        client.start(mCallback);
-        client.onPowerPressed();
-
-        verify(mClientMonitorCallbackConverter).onAcquired(anyInt(),
-                eq(FINGERPRINT_ACQUIRED_POWER_PRESSED), anyInt());
-    }
-
     private void showHideOverlay(Consumer<FingerprintEnrollClient> block)
             throws RemoteException {
         final FingerprintEnrollClient client = createClient();
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 09a84da..2967c5c 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -18,6 +18,7 @@
 
 import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
 import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_RECENTS;
 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
 import static android.content.Context.DEVICE_ID_DEFAULT;
 import static android.content.Context.DEVICE_ID_INVALID;
@@ -117,6 +118,7 @@
 
 import com.google.android.collect.Sets;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -372,6 +374,11 @@
         mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1);
     }
 
+    @After
+    public void tearDown() {
+        mDeviceImpl.close();
+    }
+
     @Test
     public void getDeviceIdForDisplayId_invalidDisplayId_returnsDefault() {
         assertThat(mVdm.getDeviceIdForDisplayId(Display.INVALID_DISPLAY))
@@ -444,6 +451,7 @@
                 .setBlockedActivities(getBlockedActivities())
                 .setDevicePolicy(POLICY_TYPE_SENSORS, DEVICE_POLICY_CUSTOM)
                 .build();
+        mDeviceImpl.close();
         mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
 
         assertThat(mVdm.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
@@ -451,6 +459,35 @@
     }
 
     @Test
+    public void getDevicePolicy_defaultRecentsPolicy_gwpcCanShowRecentsOnHostDevice() {
+        VirtualDeviceParams params = new VirtualDeviceParams
+                .Builder()
+                .build();
+        mDeviceImpl.close();
+        mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+
+        GenericWindowPolicyController gwpc =
+                mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1);
+        assertThat(gwpc.canShowTasksInHostDeviceRecents()).isTrue();
+    }
+
+    @Test
+    public void getDevicePolicy_customRecentsPolicy_gwpcCannotShowRecentsOnHostDevice() {
+        VirtualDeviceParams params = new VirtualDeviceParams
+                .Builder()
+                .setDevicePolicy(POLICY_TYPE_RECENTS, DEVICE_POLICY_CUSTOM)
+                .build();
+        mDeviceImpl.close();
+        mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+
+        GenericWindowPolicyController gwpc =
+                mDeviceImpl.getDisplayWindowPolicyControllerForTest(DISPLAY_ID_1);
+        assertThat(gwpc.canShowTasksInHostDeviceRecents()).isFalse();
+    }
+
+    @Test
     public void getDeviceOwnerUid_oneDevice_returnsCorrectId() {
         int ownerUid = mLocalService.getDeviceOwnerUid(mDeviceImpl.getDeviceId());
         assertThat(ownerUid).isEqualTo(mDeviceImpl.getOwnerUid());
@@ -501,6 +538,7 @@
 
         doReturn(SENSOR_HANDLE).when(mSensorManagerInternalMock).createRuntimeSensor(
                 anyInt(), anyInt(), anyString(), anyString(), anyInt(), any());
+        mDeviceImpl.close();
         mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
 
         VirtualSensor sensor = mLocalService.getVirtualSensor(VIRTUAL_DEVICE_ID_1, SENSOR_HANDLE);
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
index 7b5af1e..d9e4da7 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -90,8 +90,7 @@
                         /* secureWindowCallback= */ null,
                         /* intentListenerCallback= */ null,
                         /* displayCategories= */ new ArrayList<>(),
-                        /* recentsPolicy= */
-                        VirtualDeviceParams.RECENTS_POLICY_ALLOW_IN_HOST_DEVICE_RECENTS);
+                        /* showTasksInHostDeviceRecents= */ true);
     }
 
 
diff --git a/services/tests/servicestests/src/com/android/server/display/DeviceStateToLayoutMapTest.java b/services/tests/servicestests/src/com/android/server/display/DeviceStateToLayoutMapTest.java
index a380eff..e74b278 100644
--- a/services/tests/servicestests/src/com/android/server/display/DeviceStateToLayoutMapTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DeviceStateToLayoutMapTest.java
@@ -157,6 +157,26 @@
         assertEquals(testLayout, configLayout);
     }
 
+    @Test
+    public void testRefreshRateThermalThrottlingMapId() {
+        Layout configLayout = mDeviceStateToLayoutMap.get(4);
+
+        Layout testLayout = new Layout();
+        Layout.Display display1 = testLayout.createDisplayLocked(
+                DisplayAddress.fromPhysicalDisplayId(345L), /* isDefault= */ true,
+                /* isEnabled= */ true, /* displayGroup= */ null, mDisplayIdProducerMock,
+                /* brightnessThrottlingMapId= */ null,
+                /* leadDisplayId= */ Display.DEFAULT_DISPLAY);
+        display1.setRefreshRateThermalThrottlingMapId("test2");
+        testLayout.createDisplayLocked(
+                DisplayAddress.fromPhysicalDisplayId(678L), /* isDefault= */ false,
+                /* isEnabled= */ true, /* displayGroup= */ null, mDisplayIdProducerMock,
+                /* brightnessThrottlingMapId= */ null,
+                /* leadDisplayId= */ Display.DEFAULT_DISPLAY);
+
+        assertEquals(testLayout, configLayout);
+    }
+
     ////////////////////
     // Helper Methods //
     ////////////////////
@@ -221,6 +241,19 @@
                 +        "<address>678</address>\n"
                 +      "</display>\n"
                 +    "</layout>\n"
+
+                +    "<layout>\n"
+                +      "<state>4</state> \n"
+                +      "<display enabled=\"true\" defaultDisplay=\"true\" >\n"
+                +        "<address>345</address>\n"
+                +        "<refreshRateThermalThrottlingMapId>"
+                +          "test2"
+                +        "</refreshRateThermalThrottlingMapId>"
+                +      "</display>\n"
+                +      "<display enabled=\"true\">\n"
+                +        "<address>678</address>\n"
+                +      "</display>\n"
+                +    "</layout>\n"
                 +  "</layouts>\n";
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
index fdfcd81..45f1037 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.mock;
@@ -28,6 +29,9 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.os.Temperature;
+import android.util.SparseArray;
+import android.view.SurfaceControl;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -82,6 +86,7 @@
     public void testConfigValuesFromDisplayConfig() throws IOException {
         setupDisplayDeviceConfigFromDisplayConfigFile();
 
+        assertEquals(mDisplayDeviceConfig.getName(), "Example Display");
         assertEquals(mDisplayDeviceConfig.getAmbientHorizonLong(), 5000);
         assertEquals(mDisplayDeviceConfig.getAmbientHorizonShort(), 50);
         assertEquals(mDisplayDeviceConfig.getBrightnessRampDecreaseMaxMillis(), 3000);
@@ -237,6 +242,7 @@
     @Test
     public void testConfigValuesFromConfigResource() {
         setupDisplayDeviceConfigFromConfigResourceFile();
+        assertNull(mDisplayDeviceConfig.getName());
         assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(), new
                 float[]{2.0f, 200.0f, 600.0f}, ZERO_DELTA);
         assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(), new
@@ -315,9 +321,59 @@
         // HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
     }
 
+    @Test
+    public void testRefreshRateThermalThrottlingFromDisplayConfig() throws IOException {
+        setupDisplayDeviceConfigFromDisplayConfigFile();
+
+        SparseArray<SurfaceControl.RefreshRateRange> defaultMap =
+                mDisplayDeviceConfig.getRefreshRateThrottlingData(null);
+        assertNotNull(defaultMap);
+        assertEquals(2, defaultMap.size());
+        assertEquals(30, defaultMap.get(Temperature.THROTTLING_CRITICAL).min, SMALL_DELTA);
+        assertEquals(60, defaultMap.get(Temperature.THROTTLING_CRITICAL).max, SMALL_DELTA);
+        assertEquals(0, defaultMap.get(Temperature.THROTTLING_SHUTDOWN).min, SMALL_DELTA);
+        assertEquals(30, defaultMap.get(Temperature.THROTTLING_SHUTDOWN).max, SMALL_DELTA);
+
+        SparseArray<SurfaceControl.RefreshRateRange> testMap =
+                mDisplayDeviceConfig.getRefreshRateThrottlingData("test");
+        assertNotNull(testMap);
+        assertEquals(1, testMap.size());
+        assertEquals(60, testMap.get(Temperature.THROTTLING_EMERGENCY).min, SMALL_DELTA);
+        assertEquals(90, testMap.get(Temperature.THROTTLING_EMERGENCY).max, SMALL_DELTA);
+    }
+
+    private String getRefreshThermalThrottlingMaps() {
+        return "<refreshRateThrottlingMap>\n"
+               + "    <refreshRateThrottlingPoint>\n"
+               + "        <thermalStatus>critical</thermalStatus>\n"
+               + "        <refreshRateRange>\n"
+               + "            <minimum>30</minimum>\n"
+               + "            <maximum>60</maximum>\n"
+               + "        </refreshRateRange>\n"
+               + "    </refreshRateThrottlingPoint>\n"
+               + "    <refreshRateThrottlingPoint>\n"
+               + "        <thermalStatus>shutdown</thermalStatus>\n"
+               + "        <refreshRateRange>\n"
+               + "            <minimum>0</minimum>\n"
+               + "            <maximum>30</maximum>\n"
+               + "        </refreshRateRange>\n"
+               + "    </refreshRateThrottlingPoint>\n"
+               + "</refreshRateThrottlingMap>\n"
+               + "<refreshRateThrottlingMap id=\"test\">\n"
+               + "    <refreshRateThrottlingPoint>\n"
+               + "        <thermalStatus>emergency</thermalStatus>\n"
+               + "        <refreshRateRange>\n"
+               + "            <minimum>60</minimum>\n"
+               + "            <maximum>90</maximum>\n"
+               + "        </refreshRateRange>\n"
+               + "    </refreshRateThrottlingPoint>\n"
+               + "</refreshRateThrottlingMap>\n";
+    }
+
     private String getContent() {
         return "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
                 + "<displayConfiguration>\n"
+                +   "<name>Example Display</name>"
                 +   "<screenBrightnessMap>\n"
                 +       "<point>\n"
                 +           "<value>0.0</value>\n"
@@ -557,6 +613,7 @@
                 +               "<brightness>0.0125</brightness>\n"
                 +           "</brightnessThrottlingPoint>\n"
                 +       "</brightnessThrottlingMap>\n"
+                +  getRefreshThermalThrottlingMaps()
                 +   "</thermalThrottling>\n"
                 +   "<refreshRate>\n"
                 +       "<defaultRefreshRate>45</defaultRefreshRate>\n"
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
index b698cdf..9eb6003 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -687,10 +687,10 @@
         assertTrue(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked());
         assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isInTransitionLocked());
         assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked());
-        assertEquals(DisplayDeviceConfig.DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID,
+        assertEquals(DisplayDeviceConfig.DEFAULT_ID,
                 mLogicalDisplayMapper.getDisplayLocked(device1)
                         .getBrightnessThrottlingDataIdLocked());
-        assertEquals(DisplayDeviceConfig.DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID,
+        assertEquals(DisplayDeviceConfig.DEFAULT_ID,
                 mLogicalDisplayMapper.getDisplayLocked(device2)
                         .getBrightnessThrottlingDataIdLocked());
 
@@ -700,10 +700,10 @@
         assertTrue(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked());
         assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isInTransitionLocked());
         assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked());
-        assertEquals(DisplayDeviceConfig.DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID,
+        assertEquals(DisplayDeviceConfig.DEFAULT_ID,
                 mLogicalDisplayMapper.getDisplayLocked(device1)
                         .getBrightnessThrottlingDataIdLocked());
-        assertEquals(DisplayDeviceConfig.DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID,
+        assertEquals(DisplayDeviceConfig.DEFAULT_ID,
                 mLogicalDisplayMapper.getDisplayLocked(device2)
                         .getBrightnessThrottlingDataIdLocked());
     }
diff --git a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
index bbed1b6..618ab1b 100644
--- a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
@@ -34,6 +34,7 @@
 import android.content.ContextWrapper;
 import android.content.res.Resources;
 import android.hardware.display.ColorDisplayManager;
+import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.Time;
 import android.os.Handler;
 import android.os.UserHandle;
@@ -77,6 +78,7 @@
 
     private MockTwilightManager mTwilightManager;
     private DisplayTransformManager mDisplayTransformManager;
+    private DisplayManagerInternal mDisplayManagerInternal;
 
     private ColorDisplayService mCds;
     private ColorDisplayService.BinderService mBinderService;
@@ -116,6 +118,10 @@
         doReturn(true).when(mDisplayTransformManager).needsLinearColorMatrix();
         LocalServices.addService(DisplayTransformManager.class, mDisplayTransformManager);
 
+        mDisplayManagerInternal = Mockito.mock(DisplayManagerInternal.class);
+        LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+        LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternal);
+
         mCds = new ColorDisplayService(mContext);
         mBinderService = mCds.new BinderService();
         LocalServices.addService(ColorDisplayService.ColorDisplayServiceInternal.class,
@@ -142,6 +148,7 @@
         FakeSettingsProvider.clearSettingsProvider();
 
         LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class);
+        LocalServices.removeServiceForTest(DisplayManagerInternal.class);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
index f256c8a..1b02799 100644
--- a/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
@@ -59,12 +59,12 @@
 import android.hardware.display.BrightnessInfo;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
+import android.hardware.display.DisplayManagerGlobal;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
 import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
 import android.os.Handler;
 import android.os.IThermalEventListener;
-import android.os.IThermalService;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.Temperature;
@@ -75,6 +75,7 @@
 import android.util.SparseArray;
 import android.util.TypedValue;
 import android.view.Display;
+import android.view.DisplayInfo;
 import android.view.SurfaceControl.RefreshRateRange;
 import android.view.SurfaceControl.RefreshRateRanges;
 
@@ -83,6 +84,7 @@
 
 import com.android.internal.R;
 import com.android.internal.display.BrightnessSynchronizer;
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.internal.util.test.FakeSettingsProviderRule;
@@ -140,8 +142,6 @@
     public SensorManagerInternal mSensorManagerInternalMock;
     @Mock
     public DisplayManagerInternal mDisplayManagerInternalMock;
-    @Mock
-    public IThermalService mThermalServiceMock;
 
     @Before
     public void setUp() throws Exception {
@@ -150,7 +150,6 @@
         final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext);
         when(mContext.getContentResolver()).thenReturn(resolver);
         mInjector = spy(new FakesInjector());
-        when(mInjector.getThermalService()).thenReturn(mThermalServiceMock);
         mHandler = new Handler(Looper.getMainLooper());
 
         LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
@@ -1773,11 +1772,12 @@
 
         ArgumentCaptor<DisplayListener> DisplayCaptor =
                 ArgumentCaptor.forClass(DisplayListener.class);
-        verify(mInjector).registerDisplayListener(DisplayCaptor.capture(), any(Handler.class),
+        verify(mInjector, times(2)).registerDisplayListener(DisplayCaptor.capture(),
+                any(Handler.class),
                 eq(DisplayManager.EVENT_FLAG_DISPLAY_ADDED
                         | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
                         | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
-        DisplayListener displayListener = DisplayCaptor.getValue();
+        DisplayListener displayListener = DisplayCaptor.getAllValues().get(0);
 
         // Verify that there is no proximity vote initially
         Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
@@ -2236,8 +2236,7 @@
         ArgumentCaptor<IThermalEventListener> thermalEventListener =
                 ArgumentCaptor.forClass(IThermalEventListener.class);
 
-        verify(mThermalServiceMock).registerThermalEventListenerWithType(
-                thermalEventListener.capture(), eq(Temperature.TYPE_SKIN));
+        verify(mInjector).registerThermalServiceListener(thermalEventListener.capture());
         final IThermalEventListener listener = thermalEventListener.getValue();
 
         // Verify that there is no skin temperature vote initially.
@@ -2246,11 +2245,13 @@
 
         // Set the skin temperature to critical and verify that we added a vote.
         listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_CRITICAL));
+        BackgroundThread.getHandler().runWithScissors(() -> { }, 500 /*timeout*/);
         vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE);
         assertVoteForRenderFrameRateRange(vote, 0f, 60.f);
 
         // Set the skin temperature to severe and verify that the vote is gone.
         listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_SEVERE));
+        BackgroundThread.getHandler().runWithScissors(() -> { }, 500 /*timeout*/);
         vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE);
         assertNull(vote);
     }
@@ -2709,6 +2710,16 @@
         public void registerDisplayListener(DisplayListener listener, Handler handler, long flag) {}
 
         @Override
+        public Display[] getDisplays() {
+            return new Display[] { createDisplay(DISPLAY_ID) };
+        }
+
+        @Override
+        public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) {
+            return false;
+        }
+
+        @Override
         public BrightnessInfo getBrightnessInfo(int displayId) {
             return null;
         }
@@ -2719,8 +2730,8 @@
         }
 
         @Override
-        public IThermalService getThermalService() {
-            return null;
+        public boolean registerThermalServiceListener(IThermalEventListener listener) {
+            return true;
         }
 
         @Override
@@ -2728,6 +2739,11 @@
             return true;
         }
 
+        protected Display createDisplay(int id) {
+            return new Display(DisplayManagerGlobal.getInstance(), id, new DisplayInfo(),
+                    ApplicationProvider.getApplicationContext().getResources());
+        }
+
         void notifyPeakRefreshRateChanged() {
             if (mPeakRefreshRateObserver != null) {
                 mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
diff --git a/services/tests/servicestests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java b/services/tests/servicestests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java
new file mode 100644
index 0000000..dd0cd96
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.mode;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.IThermalEventListener;
+import android.os.Temperature;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.SurfaceControl;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.server.testutils.TestHandler;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Tests for DisplayModeDirector.SkinThermalStatusObserver. Comply with changes described in
+ * b/266789924
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SkinThermalStatusObserverTest {
+    private static final float FLOAT_TOLERANCE = 0.01f;
+    private static final int DISPLAY_ID = 1;
+    private static final int DISPLAY_ID_OTHER = 2;
+
+    SkinThermalStatusObserver mObserver;
+
+    private RegisteringFakesInjector mInjector = new RegisteringFakesInjector();
+
+    private final TestHandler mHandler = new TestHandler(null);
+    private final FakeVoteStorage mStorage = new FakeVoteStorage();
+
+    @Before
+    public void setUp() {
+        mObserver = new SkinThermalStatusObserver(mInjector, mStorage, mHandler);
+    }
+
+    @Test
+    public void testRegisterListenersOnObserve() {
+        // GIVEN thermal sensor is available
+        assertNull(mInjector.mThermalEventListener);
+        assertNull(mInjector.mDisplayListener);
+        // WHEN observe is called
+        mObserver.observe();
+        // THEN thermal and display listeners are registered
+        assertEquals(mObserver, mInjector.mThermalEventListener);
+        assertEquals(mObserver, mInjector.mDisplayListener);
+    }
+
+    @Test
+    public void testFailToRegisterThermalListenerOnObserve() {
+        // GIVEN thermal sensor is not available
+        mInjector = new RegisteringFakesInjector(false);
+        mObserver = new SkinThermalStatusObserver(mInjector, mStorage, mHandler);
+        // WHEN observe is called
+        mObserver.observe();
+        // THEN nothing is registered
+        assertNull(mInjector.mThermalEventListener);
+        assertNull(mInjector.mDisplayListener);
+    }
+
+    @Test
+    public void testNotifyWithDefaultVotesForCritical() {
+        // GIVEN 2 displays with no thermalThrottling config
+        mObserver.observe();
+        assertEquals(0, mStorage.mVoteRegistry.size());
+
+        // WHEN thermal sensor notifies CRITICAL
+        mObserver.notifyThrottling(createTemperature(Temperature.THROTTLING_CRITICAL));
+        mHandler.flush();
+
+        // THEN 2 votes are added to storage with (0,60) render refresh rate(default behaviour)
+        assertEquals(2, mStorage.mVoteRegistry.size());
+
+        SparseArray<DisplayModeDirector.Vote> displayVotes = mStorage.mVoteRegistry.get(DISPLAY_ID);
+        assertEquals(1, displayVotes.size());
+
+        DisplayModeDirector.Vote vote = displayVotes.get(
+                DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE);
+        assertEquals(0, vote.refreshRateRanges.render.min, FLOAT_TOLERANCE);
+        assertEquals(60, vote.refreshRateRanges.render.max, FLOAT_TOLERANCE);
+
+        SparseArray<DisplayModeDirector.Vote> otherDisplayVotes = mStorage.mVoteRegistry.get(
+                DISPLAY_ID_OTHER);
+        assertEquals(1, otherDisplayVotes.size());
+
+        vote = otherDisplayVotes.get(DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE);
+        assertEquals(0, vote.refreshRateRanges.render.min, FLOAT_TOLERANCE);
+        assertEquals(60, vote.refreshRateRanges.render.max, FLOAT_TOLERANCE);
+    }
+
+    @Test
+    public void testNotifyWithDefaultVotesChangeFromCriticalToSevere() {
+        // GIVEN 2 displays with no thermalThrottling config AND temperature level CRITICAL
+        mObserver.observe();
+        assertEquals(0, mStorage.mVoteRegistry.size());
+        mObserver.notifyThrottling(createTemperature(Temperature.THROTTLING_CRITICAL));
+        // WHEN thermal sensor notifies SEVERE
+        mObserver.notifyThrottling(createTemperature(Temperature.THROTTLING_SEVERE));
+        mHandler.flush();
+        // THEN all votes with PRIORITY_SKIN_TEMPERATURE are removed from the storage
+        assertEquals(0, mStorage.mVoteRegistry.size());
+    }
+
+    @Test
+    public void testNotifyWithDefaultVotesForSevere() {
+        // GIVEN 2 displays with no thermalThrottling config
+        mObserver.observe();
+        assertEquals(0, mStorage.mVoteRegistry.size());
+        // WHEN thermal sensor notifies CRITICAL
+        mObserver.notifyThrottling(createTemperature(Temperature.THROTTLING_SEVERE));
+        mHandler.flush();
+        // THEN nothing is added to the storage
+        assertEquals(0, mStorage.mVoteRegistry.size());
+    }
+
+    @Test
+    public void testNotifiesWithConfigVotes() {
+        // GIVEN 2 displays AND one has thermalThrottling config defined
+        SparseArray<SurfaceControl.RefreshRateRange> displayConfig = new SparseArray<>();
+        displayConfig.put(Temperature.THROTTLING_MODERATE,
+                new SurfaceControl.RefreshRateRange(90.0f, 120.0f));
+        SparseArray<SparseArray<SurfaceControl.RefreshRateRange>> config = new SparseArray<>();
+        config.put(DISPLAY_ID, displayConfig);
+        mInjector = new RegisteringFakesInjector(true, config);
+        mObserver = new SkinThermalStatusObserver(mInjector, mStorage, mHandler);
+        mObserver.observe();
+        mObserver.onDisplayChanged(DISPLAY_ID);
+        assertEquals(0, mStorage.mVoteRegistry.size());
+        // WHEN thermal sensor notifies temperature above configured
+        mObserver.notifyThrottling(createTemperature(Temperature.THROTTLING_SEVERE));
+        mHandler.flush();
+        // THEN vote with refreshRate from config is added to the storage
+        assertEquals(1, mStorage.mVoteRegistry.size());
+        SparseArray<DisplayModeDirector.Vote> displayVotes = mStorage.mVoteRegistry.get(DISPLAY_ID);
+        assertEquals(1, displayVotes.size());
+        DisplayModeDirector.Vote vote = displayVotes.get(
+                DisplayModeDirector.Vote.PRIORITY_SKIN_TEMPERATURE);
+        assertEquals(90, vote.refreshRateRanges.render.min, FLOAT_TOLERANCE);
+        assertEquals(120, vote.refreshRateRanges.render.max, FLOAT_TOLERANCE);
+    }
+
+    private static Temperature createTemperature(@Temperature.ThrottlingStatus int status) {
+        return new Temperature(40.0f, Temperature.TYPE_SKIN, "test_temp", status);
+    }
+
+
+    private static class RegisteringFakesInjector extends DisplayModeDirectorTest.FakesInjector {
+        private IThermalEventListener mThermalEventListener;
+        private DisplayManager.DisplayListener mDisplayListener;
+
+        private final boolean mRegisterThermalListener;
+        private final SparseArray<SparseArray<SurfaceControl.RefreshRateRange>> mOverriddenConfig;
+
+
+        private RegisteringFakesInjector() {
+            this(true);
+        }
+
+        private RegisteringFakesInjector(boolean registerThermalListener) {
+            this(registerThermalListener, new SparseArray<>());
+        }
+
+        private RegisteringFakesInjector(boolean registerThermalListener,
+                SparseArray<SparseArray<SurfaceControl.RefreshRateRange>> overriddenConfig) {
+            mRegisterThermalListener = registerThermalListener;
+            mOverriddenConfig = overriddenConfig;
+        }
+
+        @Override
+        public boolean registerThermalServiceListener(IThermalEventListener listener) {
+            mThermalEventListener = (mRegisterThermalListener ? listener : null);
+            return mRegisterThermalListener;
+        }
+
+        @Override
+        public void registerDisplayListener(DisplayManager.DisplayListener listener,
+                Handler handler, long flag) {
+            mDisplayListener = listener;
+        }
+
+        @Override
+        public Display[] getDisplays() {
+            return new Display[] {createDisplay(DISPLAY_ID), createDisplay(DISPLAY_ID_OTHER)};
+        }
+
+        @Override
+        public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) {
+            SparseArray<SurfaceControl.RefreshRateRange> config = mOverriddenConfig.get(displayId);
+            if (config != null) {
+                displayInfo.refreshRateThermalThrottling = config;
+                return true;
+            }
+            return false;
+        }
+    }
+
+
+    private static class FakeVoteStorage implements DisplayModeDirector.BallotBox {
+        private final SparseArray<SparseArray<DisplayModeDirector.Vote>> mVoteRegistry =
+                new SparseArray<>();
+
+        @Override
+        public void vote(int displayId, int priority, DisplayModeDirector.Vote vote) {
+            SparseArray<DisplayModeDirector.Vote> votesPerDisplay = mVoteRegistry.get(displayId);
+            if (votesPerDisplay == null) {
+                votesPerDisplay = new SparseArray<>();
+                mVoteRegistry.put(displayId, votesPerDisplay);
+            }
+            if (vote == null) {
+                votesPerDisplay.remove(priority);
+            } else {
+                votesPerDisplay.put(priority, vote);
+            }
+            if (votesPerDisplay.size() == 0) {
+                mVoteRegistry.remove(displayId);
+            }
+        }
+    }
+}
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 4a2e5d7..9fc46c5 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
@@ -86,7 +86,6 @@
 import android.telecom.TelecomManager;
 import android.telephony.TelephonyManager;
 import android.text.format.DateUtils;
-import android.util.Pair;
 import android.util.Range;
 
 import com.android.internal.app.ChooserActivity;
@@ -187,7 +186,6 @@
     private ShortcutInfo mShortcutInfo;
     private TestInjector mInjector;
     private TestLooper mLooper;
-    private TestPerPackageThrottler mShortcutThrottler;
 
     @Before
     public void setUp() throws PackageManager.NameNotFoundException {
@@ -277,9 +275,7 @@
 
         mInjector = new TestInjector();
         mLooper = new TestLooper();
-        mShortcutThrottler = new TestPerPackageThrottler();
-        mDataManager = new DataManager(mContext, mInjector, mLooper.getLooper(),
-                mShortcutThrottler);
+        mDataManager = new DataManager(mContext, mInjector, mLooper.getLooper());
         mDataManager.initialize();
 
         when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
@@ -287,7 +283,10 @@
 
         mShortcutInfo = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
                 buildPerson());
-        mockGetShortcuts(Collections.singletonList(mShortcutInfo));
+        when(mShortcutServiceInternal.getShortcuts(
+                anyInt(), anyString(), anyLong(), anyString(), anyList(), any(), any(),
+                anyInt(), anyInt(), anyInt(), anyInt()))
+                .thenReturn(Collections.singletonList(mShortcutInfo));
         verify(mShortcutServiceInternal).addShortcutChangeCallback(
                 mShortcutChangeCallbackCaptor.capture());
         mShortcutChangeCallback = mShortcutChangeCallbackCaptor.getValue();
@@ -973,7 +972,6 @@
                 buildPerson());
         ShortcutInfo shortcut3 = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, "sc3",
                 buildPerson());
-        mockGetShortcuts(List.of(shortcut1, shortcut2, shortcut3));
         mShortcutChangeCallback.onShortcutsAddedOrUpdated(TEST_PKG_NAME,
                 Arrays.asList(shortcut1, shortcut2, shortcut3), UserHandle.of(USER_ID_PRIMARY));
         mShortcutChangeCallback.onShortcutsRemoved(TEST_PKG_NAME,
@@ -1225,6 +1223,7 @@
                     eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
         }
     }
+
     @Test
     public void testUncacheOldestCachedShortcut_missingNotificationEvents() {
         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
@@ -1234,7 +1233,6 @@
             ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId,
                     buildPerson());
             shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
-            mockGetShortcuts(Collections.singletonList(shortcut));
             mShortcutChangeCallback.onShortcutsAddedOrUpdated(
                     TEST_PKG_NAME,
                     Collections.singletonList(shortcut),
@@ -1254,6 +1252,7 @@
                     eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
         }
     }
+
     @Test
     public void testUncacheOldestCachedShortcut_legacyConversation() {
         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
@@ -1275,7 +1274,6 @@
             ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId,
                     buildPerson());
             shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
-            mockGetShortcuts(Collections.singletonList(shortcut));
             mShortcutChangeCallback.onShortcutsAddedOrUpdated(
                     TEST_PKG_NAME,
                     Collections.singletonList(shortcut),
@@ -1313,8 +1311,7 @@
         mDataManager.reportShareTargetEvent(appTargetEvent, intentFilter);
         byte[] payload = mDataManager.getBackupPayload(USER_ID_PRIMARY);
 
-        DataManager dataManager = new DataManager(
-                mContext, mInjector, mLooper.getLooper(), mShortcutThrottler);
+        DataManager dataManager = new DataManager(mContext, mInjector, mLooper.getLooper());
         dataManager.onUserUnlocked(USER_ID_PRIMARY);
         dataManager.restore(USER_ID_PRIMARY, payload);
         ConversationInfo conversationInfo = dataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
@@ -1726,13 +1723,6 @@
         return (queryFlags & flag) != 0;
     }
 
-    private void mockGetShortcuts(List<ShortcutInfo> shortcutInfoList) {
-        when(mShortcutServiceInternal.getShortcuts(
-                anyInt(), anyString(), anyLong(), anyString(), any(), any(), any(),
-                anyInt(), anyInt(), anyInt(), anyInt()))
-                .thenReturn(shortcutInfoList);
-    }
-
     // "Sends" a notification to a non-customized notification channel - the notification channel
     // is something generic like "messages" and the notification has a  shortcut id
     private void sendGenericNotification() {
@@ -1994,11 +1984,4 @@
             return mUsageStatsQueryHelper;
         }
     }
-
-    private static class TestPerPackageThrottler implements PerPackageThrottler {
-        @Override
-        public void scheduleDebounced(Pair<String, Integer> pkgUserId, Runnable runnable) {
-            runnable.run();
-        }
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/people/data/PerPackageThrottlerImplTest.java b/services/tests/servicestests/src/com/android/server/people/data/PerPackageThrottlerImplTest.java
deleted file mode 100644
index 672cbb9..0000000
--- a/services/tests/servicestests/src/com/android/server/people/data/PerPackageThrottlerImplTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.people.data;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.util.Pair;
-
-import com.android.server.testutils.OffsettableClock;
-import com.android.server.testutils.TestHandler;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-@RunWith(JUnit4.class)
-public class PerPackageThrottlerImplTest {
-    private static final int DEBOUNCE_INTERVAL = 500;
-    private static final String PKG_ONE = "pkg_one";
-    private static final String PKG_TWO = "pkg_two";
-    private static final int USER_ID = 10;
-
-    private final OffsettableClock mClock = new OffsettableClock.Stopped();
-    private final TestHandler mTestHandler = new TestHandler(null, mClock);
-    private PerPackageThrottlerImpl mThrottler;
-
-    @Before
-    public void setUp() {
-        mThrottler = new PerPackageThrottlerImpl(mTestHandler, DEBOUNCE_INTERVAL);
-    }
-
-    @Test
-    public void scheduleDebounced() {
-        AtomicBoolean pkgOneRan = new AtomicBoolean();
-        AtomicBoolean pkgTwoRan = new AtomicBoolean();
-
-        mThrottler.scheduleDebounced(new Pair<>(PKG_ONE, USER_ID), () -> pkgOneRan.set(true));
-        mThrottler.scheduleDebounced(new Pair<>(PKG_ONE, USER_ID), () -> pkgOneRan.set(true));
-        mThrottler.scheduleDebounced(new Pair<>(PKG_TWO, USER_ID), () -> pkgTwoRan.set(true));
-        mThrottler.scheduleDebounced(new Pair<>(PKG_TWO, USER_ID), () -> pkgTwoRan.set(true));
-
-        assertFalse(pkgOneRan.get());
-        assertFalse(pkgTwoRan.get());
-        mClock.fastForward(DEBOUNCE_INTERVAL);
-        mTestHandler.timeAdvance();
-        assertTrue(pkgOneRan.get());
-        assertTrue(pkgTwoRan.get());
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 0a718e3..e65f8cf 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -4007,6 +4007,18 @@
         // TODO Check all other fields
     }
 
+    public void testLoadCorruptedShortcuts() throws Exception {
+        initService();
+
+        addPackage("com.android.chrome", 0, 0);
+
+        ShortcutUser user = new ShortcutUser(mService, 0);
+
+        File corruptedShortcutPackage = new File("/data/local/tmp/cts/content/",
+                "broken_shortcut.xml");
+        assertNull(ShortcutPackage.loadFromFile(mService, user, corruptedShortcutPackage, false));
+    }
+
     public void testSaveCorruptAndLoadUser() throws Exception {
         // First, create some shortcuts and save.
         runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
@@ -4096,11 +4108,12 @@
 
         // Save and corrupt the primary files.
         mService.saveDirtyInfo();
-        try (Writer os = new FileWriter(mService.getUserFile(UserHandle.USER_SYSTEM))) {
+        try (Writer os = new FileWriter(
+                mService.getUserFile(UserHandle.USER_SYSTEM).getBaseFile())) {
             os.write("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
                     + "<user locales=\"en\" last-app-scan-time2=\"14400000");
         }
-        try (Writer os = new FileWriter(mService.getUserFile(USER_10))) {
+        try (Writer os = new FileWriter(mService.getUserFile(USER_10).getBaseFile())) {
             os.write("<?xml version='1.0' encoding='utf");
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 15fd73c..01e56a0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -2349,7 +2349,7 @@
      * can still be read.
      */
     public void testLoadLegacySavedFile() throws Exception {
-        final File path = mService.getUserFile(USER_0);
+        final File path = mService.getUserFile(USER_0).getBaseFile();
         path.getParentFile().mkdirs();
         try (Writer w = new FileWriter(path)) {
             w.write(readTestAsset("shortcut/shortcut_legacy_file.xml"));
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 1ecd4a1..79f69ee 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -4131,17 +4131,26 @@
     }
 
     @Test
-    public void testTooManyGroups() {
+    public void testTooManyGroups_fromTargetApp() {
+        testTooManyGroups(/* fromTargetApp= */ true);
+    }
+
+    @Test
+    public void testTooManyGroups_fromListener() {
+        testTooManyGroups(/* fromTargetApp= */ false);
+    }
+
+    private void testTooManyGroups(boolean fromTargetApp) {
         for (int i = 0; i < NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT; i++) {
             NotificationChannelGroup group = new NotificationChannelGroup(String.valueOf(i),
                     String.valueOf(i));
-            mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true);
+            mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, fromTargetApp);
         }
         try {
             NotificationChannelGroup group = new NotificationChannelGroup(
                     String.valueOf(NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT),
                     String.valueOf(NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT));
-            mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true);
+            mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, fromTargetApp);
             fail("Allowed to create too many notification channel groups");
         } catch (IllegalStateException e) {
             // great
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 3dcae91..0044e2e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -66,6 +66,7 @@
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.IDisplayWindowListener;
+import android.view.WindowManager;
 
 import androidx.test.filters.MediumTest;
 
@@ -456,13 +457,15 @@
         mAtm.mSupportsNonResizableMultiWindow = 0;
 
         // Supports on large screen.
-        tda.getConfiguration().smallestScreenWidthDp = mAtm.mLargeScreenSmallestScreenWidthDp;
+        tda.getConfiguration().smallestScreenWidthDp =
+                WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP;
 
         assertTrue(activity.supportsMultiWindow());
         assertTrue(task.supportsMultiWindow());
 
         // Not supports on small screen.
-        tda.getConfiguration().smallestScreenWidthDp = mAtm.mLargeScreenSmallestScreenWidthDp - 1;
+        tda.getConfiguration().smallestScreenWidthDp =
+                WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1;
 
         assertFalse(activity.supportsMultiWindow());
         assertFalse(task.supportsMultiWindow());
@@ -475,8 +478,10 @@
                 new ActivityInfo.WindowLayout(0, 0, 0, 0, 0,
                         // This is larger than the min dimensions device support in multi window,
                         // the activity will not be supported in multi window if the device respects
-                        /* minWidth= */(int) (mAtm.mLargeScreenSmallestScreenWidthDp * density),
-                        /* minHeight= */(int) (mAtm.mLargeScreenSmallestScreenWidthDp * density));
+                        /* minWidth= */
+                        (int) (WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP * density),
+                        /* minHeight= */
+                        (int) (WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP * density));
         final ActivityRecord activity = new ActivityBuilder(mAtm)
                 .setCreateTask(true)
                 .setWindowLayout(windowLayout)
@@ -501,13 +506,15 @@
         mAtm.mRespectsActivityMinWidthHeightMultiWindow = 0;
 
         // Ignore on large screen.
-        tda.getConfiguration().smallestScreenWidthDp = mAtm.mLargeScreenSmallestScreenWidthDp;
+        tda.getConfiguration().smallestScreenWidthDp =
+                WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP;
 
         assertTrue(activity.supportsMultiWindow());
         assertTrue(task.supportsMultiWindow());
 
         // Check on small screen.
-        tda.getConfiguration().smallestScreenWidthDp = mAtm.mLargeScreenSmallestScreenWidthDp - 1;
+        tda.getConfiguration().smallestScreenWidthDp =
+                WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1;
 
         assertFalse(activity.supportsMultiWindow());
         assertFalse(task.supportsMultiWindow());
@@ -518,7 +525,7 @@
         // This is smaller than the min dimensions device support in multi window,
         // the activity will be supported in multi window
         final float density = mContext.getResources().getDisplayMetrics().density;
-        final int supportedWidth = (int) (mAtm.mLargeScreenSmallestScreenWidthDp
+        final int supportedWidth = (int) (WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP
                 * mAtm.mMinPercentageMultiWindowSupportWidth * density);
         final ActivityInfo.WindowLayout windowLayout =
                 new ActivityInfo.WindowLayout(0, 0, 0, 0, 0,
@@ -531,15 +538,17 @@
                 .build();
         final Task task = activity.getTask();
         final TaskDisplayArea tda = task.getDisplayArea();
-        tda.getConfiguration().smallestScreenWidthDp = mAtm.mLargeScreenSmallestScreenWidthDp - 1;
-        tda.getConfiguration().screenWidthDp = mAtm.mLargeScreenSmallestScreenWidthDp - 1;
+        tda.getConfiguration().smallestScreenWidthDp =
+                WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1;
+        tda.getConfiguration().screenWidthDp =
+                WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1;
         tda.getConfiguration().orientation = ORIENTATION_LANDSCAPE;
 
         assertFalse(activity.supportsMultiWindow());
         assertFalse(task.supportsMultiWindow());
 
         tda.getConfiguration().screenWidthDp = (int) Math.ceil(
-                mAtm.mLargeScreenSmallestScreenWidthDp
+                WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP
                         / mAtm.mMinPercentageMultiWindowSupportWidth);
 
         assertTrue(activity.supportsMultiWindow());
@@ -551,7 +560,7 @@
         // This is smaller than the min dimensions device support in multi window,
         // the activity will be supported in multi window
         final float density = mContext.getResources().getDisplayMetrics().density;
-        final int supportedHeight = (int) (mAtm.mLargeScreenSmallestScreenWidthDp
+        final int supportedHeight = (int) (WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP
                 * mAtm.mMinPercentageMultiWindowSupportHeight * density);
         final ActivityInfo.WindowLayout windowLayout =
                 new ActivityInfo.WindowLayout(0, 0, 0, 0, 0,
@@ -564,15 +573,17 @@
                 .build();
         final Task task = activity.getTask();
         final TaskDisplayArea tda = task.getDisplayArea();
-        tda.getConfiguration().smallestScreenWidthDp = mAtm.mLargeScreenSmallestScreenWidthDp - 1;
-        tda.getConfiguration().screenHeightDp = mAtm.mLargeScreenSmallestScreenWidthDp - 1;
+        tda.getConfiguration().smallestScreenWidthDp =
+                WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1;
+        tda.getConfiguration().screenHeightDp =
+                WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1;
         tda.getConfiguration().orientation = ORIENTATION_PORTRAIT;
 
         assertFalse(activity.supportsMultiWindow());
         assertFalse(task.supportsMultiWindow());
 
         tda.getConfiguration().screenHeightDp = (int) Math.ceil(
-                mAtm.mLargeScreenSmallestScreenWidthDp
+                WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP
                         / mAtm.mMinPercentageMultiWindowSupportHeight);
 
         assertTrue(activity.supportsMultiWindow());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index 8cc362c..17f6d51a7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -35,6 +35,8 @@
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.never;
 
+import android.app.WindowConfiguration;
+import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -45,6 +47,7 @@
 import android.provider.DeviceConfig;
 import android.util.DisplayMetrics;
 import android.view.ContentRecordingSession;
+import android.view.Gravity;
 import android.view.Surface;
 import android.view.SurfaceControl;
 
@@ -258,8 +261,17 @@
 
     @Test
     public void testOnTaskBoundsConfigurationChanged_notifiesCallback() {
+        mTask.getRootTask().setWindowingMode(WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW);
+
         final int recordedWidth = 333;
         final int recordedHeight = 999;
+
+        final ActivityInfo info = new ActivityInfo();
+        info.windowLayout = new ActivityInfo.WindowLayout(-1 /* width */,
+                        -1 /* widthFraction */, -1 /* height */, -1 /* heightFraction */,
+                        Gravity.NO_GRAVITY, recordedWidth, recordedHeight);
+        mTask.setMinDimensions(info);
+
         // WHEN a recording is ongoing.
         mContentRecorder.setContentRecordingSession(mTaskSession);
         mContentRecorder.updateRecording();
@@ -267,7 +279,6 @@
 
         // WHEN a configuration change arrives, and the recorded content is a different size.
         mTask.setBounds(new Rect(0, 0, recordedWidth, recordedHeight));
-        mContentRecorder.onConfigurationChanged(mDefaultDisplay.getLastOrientation());
         assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
 
         // THEN content in the captured DisplayArea is scaled to fit the surface size.
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index d242a5f..abbd397 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -117,6 +117,8 @@
 import org.mockito.ArgumentCaptor;
 
 import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
 
 /**
  * Tests for Size Compatibility mode.
@@ -172,6 +174,156 @@
     }
 
     @Test
+    public void testHorizontalReachabilityEnabledForTranslucentActivities() {
+        setUpDisplaySizeWithApp(2500, 1000);
+        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        final LetterboxConfiguration config = mWm.mLetterboxConfiguration;
+        config.setTranslucentLetterboxingOverrideEnabled(true);
+        config.setLetterboxHorizontalPositionMultiplier(0.5f);
+        config.setIsHorizontalReachabilityEnabled(true);
+
+        // Opaque activity
+        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+        addWindowToActivity(mActivity);
+        mActivity.mRootWindowContainer.performSurfacePlacement();
+
+        // Translucent Activity
+        final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
+                .setLaunchedFromUid(mActivity.getUid())
+                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
+                .build();
+        doReturn(false).when(translucentActivity).fillsParent();
+        mTask.addChild(translucentActivity);
+
+        spyOn(translucentActivity.mLetterboxUiController);
+        doReturn(true).when(translucentActivity.mLetterboxUiController)
+                .shouldShowLetterboxUi(any());
+
+        addWindowToActivity(translucentActivity);
+        translucentActivity.mRootWindowContainer.performSurfacePlacement();
+
+        final Function<ActivityRecord, Rect> innerBoundsOf =
+                (ActivityRecord a) -> {
+                    final Rect bounds = new Rect();
+                    a.mLetterboxUiController.getLetterboxInnerBounds(bounds);
+                    return bounds;
+                };
+        final Runnable checkLetterboxPositions = () -> assertEquals(innerBoundsOf.apply(mActivity),
+                innerBoundsOf.apply(translucentActivity));
+        final Runnable checkIsLeft = () -> assertThat(
+                innerBoundsOf.apply(translucentActivity).left).isEqualTo(0);
+        final Runnable checkIsRight = () -> assertThat(
+                innerBoundsOf.apply(translucentActivity).right).isEqualTo(2500);
+        final Runnable checkIsCentered = () -> assertThat(
+                innerBoundsOf.apply(translucentActivity).left > 0
+                        && innerBoundsOf.apply(translucentActivity).right < 2500).isTrue();
+
+        final Consumer<Integer> doubleClick =
+                (Integer x) -> {
+                    mActivity.mLetterboxUiController.handleHorizontalDoubleTap(x);
+                    mActivity.mRootWindowContainer.performSurfacePlacement();
+                };
+
+        // Initial state
+        checkIsCentered.run();
+
+        // Double-click left
+        doubleClick.accept(/* x */ 10);
+        checkLetterboxPositions.run();
+        checkIsLeft.run();
+
+        // Double-click right
+        doubleClick.accept(/* x */ 1990);
+        checkLetterboxPositions.run();
+        checkIsCentered.run();
+
+        // Double-click right
+        doubleClick.accept(/* x */ 1990);
+        checkLetterboxPositions.run();
+        checkIsRight.run();
+
+        // Double-click left
+        doubleClick.accept(/* x */ 10);
+        checkLetterboxPositions.run();
+        checkIsCentered.run();
+    }
+
+    @Test
+    public void testVerticalReachabilityEnabledForTranslucentActivities() {
+        setUpDisplaySizeWithApp(1000, 2500);
+        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        final LetterboxConfiguration config = mWm.mLetterboxConfiguration;
+        config.setTranslucentLetterboxingOverrideEnabled(true);
+        config.setLetterboxVerticalPositionMultiplier(0.5f);
+        config.setIsVerticalReachabilityEnabled(true);
+
+        // Opaque activity
+        prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+        addWindowToActivity(mActivity);
+        mActivity.mRootWindowContainer.performSurfacePlacement();
+
+        // Translucent Activity
+        final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
+                .setLaunchedFromUid(mActivity.getUid())
+                .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE)
+                .build();
+        doReturn(false).when(translucentActivity).fillsParent();
+        mTask.addChild(translucentActivity);
+
+        spyOn(translucentActivity.mLetterboxUiController);
+        doReturn(true).when(translucentActivity.mLetterboxUiController)
+                .shouldShowLetterboxUi(any());
+
+        addWindowToActivity(translucentActivity);
+        translucentActivity.mRootWindowContainer.performSurfacePlacement();
+
+        final Function<ActivityRecord, Rect> innerBoundsOf =
+                (ActivityRecord a) -> {
+                    final Rect bounds = new Rect();
+                    a.mLetterboxUiController.getLetterboxInnerBounds(bounds);
+                    return bounds;
+                };
+        final Runnable checkLetterboxPositions = () -> assertEquals(innerBoundsOf.apply(mActivity),
+                innerBoundsOf.apply(translucentActivity));
+        final Runnable checkIsTop = () -> assertThat(
+                innerBoundsOf.apply(translucentActivity).top).isEqualTo(0);
+        final Runnable checkIsBottom = () -> assertThat(
+                innerBoundsOf.apply(translucentActivity).bottom).isEqualTo(2500);
+        final Runnable checkIsCentered = () -> assertThat(
+                innerBoundsOf.apply(translucentActivity).top > 0
+                        && innerBoundsOf.apply(translucentActivity).bottom < 2500).isTrue();
+
+        final Consumer<Integer> doubleClick =
+                (Integer y) -> {
+                    mActivity.mLetterboxUiController.handleVerticalDoubleTap(y);
+                    mActivity.mRootWindowContainer.performSurfacePlacement();
+                };
+
+        // Initial state
+        checkIsCentered.run();
+
+        // Double-click top
+        doubleClick.accept(/* y */ 10);
+        checkLetterboxPositions.run();
+        checkIsTop.run();
+
+        // Double-click bottom
+        doubleClick.accept(/* y */ 1990);
+        checkLetterboxPositions.run();
+        checkIsCentered.run();
+
+        // Double-click bottom
+        doubleClick.accept(/* y */ 1990);
+        checkLetterboxPositions.run();
+        checkIsBottom.run();
+
+        // Double-click top
+        doubleClick.accept(/* y */ 10);
+        checkLetterboxPositions.run();
+        checkIsCentered.run();
+    }
+
+    @Test
     public void testApplyStrategyToTranslucentActivities() {
         mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true);
         setUpDisplaySizeWithApp(2000, 1000);
@@ -822,7 +974,7 @@
                 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
                 .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
                 .build();
-        assertFalse(activity.shouldCreateCompatDisplayInsets());
+        assertTrue(activity.shouldCreateCompatDisplayInsets());
 
         // The non-resizable activity should not be size compat because it is on a resizable task
         // in multi-window mode.
@@ -855,7 +1007,7 @@
     }
 
     @Test
-    public void testShouldNotCreateCompatDisplayInsetsWhenRootActivityIsResizeable() {
+    public void testShouldCreateCompatDisplayInsetsWhenUnresizeableAndSupportsSizeChangesFalse() {
         setUpDisplaySizeWithApp(1000, 2500);
 
         // Make the task root resizable.
@@ -864,7 +1016,7 @@
         // Create an activity on the same task.
         final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false,
                 RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
-        assertFalse(activity.shouldCreateCompatDisplayInsets());
+        assertTrue(activity.shouldCreateCompatDisplayInsets());
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index f4a266c..013c6d5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -545,7 +545,6 @@
             mDevEnableNonResizableMultiWindow = false;
             mMinPercentageMultiWindowSupportHeight = 0.3f;
             mMinPercentageMultiWindowSupportWidth = 0.5f;
-            mLargeScreenSmallestScreenWidthDp = 600;
             mSupportsNonResizableMultiWindow = 0;
             mRespectsActivityMinWidthHeightMultiWindow = 0;
             mForceResizableActivities = false;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 9cd80a3..5208e5a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -535,6 +535,34 @@
         assertEquals(reqBounds.height(), task.getBounds().height());
     }
 
+    /** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */
+    @Test
+    public void testBoundsOnModeChangeFreeformToFullscreen() {
+        DisplayContent display = mAtm.mRootWindowContainer.getDefaultDisplay();
+        Task rootTask = new TaskBuilder(mSupervisor).setDisplay(display).setCreateActivity(true)
+                .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+        Task task = rootTask.getBottomMostTask();
+        task.getRootActivity().setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
+        DisplayInfo info = new DisplayInfo();
+        display.mDisplay.getDisplayInfo(info);
+        final Rect fullScreenBounds = new Rect(0, 0, info.logicalWidth, info.logicalHeight);
+        final Rect freeformBounds = new Rect(fullScreenBounds);
+        freeformBounds.inset((int) (freeformBounds.width() * 0.2),
+                (int) (freeformBounds.height() * 0.2));
+        task.setBounds(freeformBounds);
+
+        assertEquals(freeformBounds, task.getBounds());
+
+        // FULLSCREEN inherits bounds
+        rootTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        assertEquals(fullScreenBounds, task.getBounds());
+        assertEquals(freeformBounds, task.mLastNonFullscreenBounds);
+
+        // FREEFORM restores bounds
+        rootTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        assertEquals(freeformBounds, task.getBounds());
+    }
+
     /**
      * Tests that a task with forced orientation has orientation-consistent bounds within the
      * parent.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index fec079b..7e4a9de 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -30,6 +30,9 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
@@ -39,6 +42,7 @@
 import android.graphics.Rect;
 import android.hardware.display.DisplayManagerGlobal;
 import android.util.DisplayMetrics;
+import android.util.TypedValue;
 import android.view.Display;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
@@ -47,6 +51,8 @@
 
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 
 class TestDisplayContent extends DisplayContent {
 
@@ -197,10 +203,21 @@
             MockitoAnnotations.initMocks(this);
             doReturn(mMockContext).when(mService.mContext).createConfigurationContext(any());
             doReturn(mResources).when(mMockContext).getResources();
-            doReturn(valueDp * mDisplayMetrics.density)
-                    .when(mResources)
-                    .getDimension(
-                        com.android.internal.R.dimen.default_minimal_size_resizable_task);
+            doAnswer(
+                    new Answer() {
+                        @Override
+                        public Object answer(InvocationOnMock i) {
+                            Object[] args = i.getArguments();
+                            TypedValue v = (TypedValue) args[1];
+                            v.type = TypedValue.TYPE_DIMENSION;
+                            v.data = TypedValue.createComplexDimension(valueDp,
+                                    TypedValue.COMPLEX_UNIT_DIP);
+                            return null;
+                        }
+                    }
+            ).when(mResources).getValue(
+                    eq(com.android.internal.R.dimen.default_minimal_size_resizable_task),
+                    any(TypedValue.class), eq(true));
             return this;
         }
         Builder setDeviceStateController(@NonNull DeviceStateController deviceStateController) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 3f14217..048e2cc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -19,6 +19,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
@@ -1376,6 +1377,9 @@
         enteringAnimReports.clear();
         closeTransition.finishTransition();
 
+        assertEquals(ActivityTaskManagerService.APP_SWITCH_DISALLOW, mAtm.getBalAppSwitchesState());
+        assertFalse(activity1.app.hasActivityInVisibleTask());
+
         verify(snapshotController, times(1)).recordSnapshot(eq(task1), eq(false));
         assertTrue(enteringAnimReports.contains(activity2));
     }
@@ -1696,7 +1700,8 @@
     @Test
     public void testTransitionVisibleChange() {
         registerTestTransitionPlayer();
-        final ActivityRecord app = createActivityRecord(mDisplayContent);
+        final ActivityRecord app = createActivityRecord(
+                mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
         final Transition transition = new Transition(TRANSIT_OPEN, 0 /* flags */,
                 app.mTransitionController, mWm.mSyncEngine);
         app.mTransitionController.moveToCollecting(transition, BLASTSyncEngine.METHOD_NONE);
@@ -1746,7 +1751,8 @@
     @Test
     public void testVisibleChange_snapshot() {
         registerTestTransitionPlayer();
-        final ActivityRecord app = createActivityRecord(mDisplayContent);
+        final ActivityRecord app = createActivityRecord(
+                mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
         final Transition transition = new Transition(TRANSIT_CHANGE, 0 /* flags */,
                 app.mTransitionController, mWm.mSyncEngine);
         app.mTransitionController.moveToCollecting(transition, BLASTSyncEngine.METHOD_NONE);
diff --git a/telecomm/java/android/telecom/CallControl.java b/telecomm/java/android/telecom/CallControl.java
index 97538c1..50f2ad4 100644
--- a/telecomm/java/android/telecom/CallControl.java
+++ b/telecomm/java/android/telecom/CallControl.java
@@ -294,18 +294,21 @@
     /**
      * Raises an event to the {@link android.telecom.InCallService} implementations tracking this
      * call via {@link android.telecom.Call.Callback#onConnectionEvent(Call, String, Bundle)}.
-     * These events and the associated extra keys for the {@code Bundle} parameter are defined
-     * in Android X. This API is used to relay additional information about a call other than
-     * what is specified in the {@link android.telecom.CallAttributes} to
-     * {@link android.telecom.InCallService}s. This might include, for example, a change to the list
-     * of participants in a meeting, or the name of the speakers who have their hand raised. Where
-     * appropriate, the {@link InCallService}s tracking this call may choose to render this
-     * additional information about the call. An automotive calling UX, for example may have enough
-     * screen real estate to indicate the number of participants in a meeting, but to prevent
-     * distractions could suppress the list of participants.
+     * These events and the associated extra keys for the {@code Bundle} parameter are mutually
+     * defined by a VoIP application and {@link android.telecom.InCallService}. This API is used to
+     * relay additional information about a call other than what is specified in the
+     * {@link android.telecom.CallAttributes} to {@link android.telecom.InCallService}s. This might
+     * include, for example, a change to the list of participants in a meeting, or the name of the
+     * speakers who have their hand raised. Where appropriate, the {@link InCallService}s tracking
+     * this call may choose to render this additional information about the call. An automotive
+     * calling UX, for example may have enough screen real estate to indicate the number of
+     * participants in a meeting, but to prevent distractions could suppress the list of
+     * participants.
      *
-     * @param event  that is defined in AndroidX (ex. The number of participants changed)
-     * @param extras the updated value in relation to the event (ex. 4 participants)
+     * @param event a string event identifier agreed upon between a VoIP application and an
+     *              {@link android.telecom.InCallService}
+     * @param extras a {@link android.os.Bundle} containing information about the event, as agreed
+     *              upon between a VoIP application and {@link android.telecom.InCallService}.
      */
     public void sendEvent(@NonNull String event, @NonNull Bundle extras) {
         Objects.requireNonNull(event);
diff --git a/telecomm/java/android/telecom/CallEventCallback.java b/telecomm/java/android/telecom/CallEventCallback.java
index d96c406..a41c011 100644
--- a/telecomm/java/android/telecom/CallEventCallback.java
+++ b/telecomm/java/android/telecom/CallEventCallback.java
@@ -60,14 +60,17 @@
 
     /**
      * Informs this {@link android.telecom.CallEventCallback} on events raised from a
-     * {@link android.telecom.InCallService} presenting this call. The event key and extra values
-     * are defined in AndroidX. This enables alternative calling surfaces, such as an automotive
-     * UI, to relay requests to perform other non-standard call actions to the app. For example,
-     * an automotive calling solution may offer the ability for the user to raise their hand
-     * during a meeting.
+     * {@link android.telecom.InCallService} presenting this call. These events and the
+     * associated extra keys for the {@code Bundle} parameter are mutually defined by a VoIP
+     * application and {@link android.telecom.InCallService}. This enables alternative calling
+     * surfaces, such as an automotive UI, to relay requests to perform other non-standard call
+     * actions to the app. For example, an automotive calling solution may offer the ability for
+     * the user to raise their hand during a meeting.
      *
-     * @param event that is defined in AndroidX (ex. the number of participants changed)
-     * @param extras the updated value in relation to the event (ex. 4 participants)
+     * @param event a string event identifier agreed upon between a VoIP application and an
+     *              {@link android.telecom.InCallService}
+     * @param extras a {@link android.os.Bundle} containing information about the event, as agreed
+     *              upon between a VoIP application and {@link android.telecom.InCallService}.
      */
     void onEvent(@NonNull String event, @NonNull Bundle extras);
 }
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 9170117..e39af5a 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -895,9 +895,13 @@
             "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
 
     /**
-     * The intent to clear missed calls.
+     * Included in the extras of the {@link #ACTION_SHOW_MISSED_CALLS_NOTIFICATION}, provides a
+     * pending intent which can be used to clear the missed calls notification and mark unread
+     * missed call log entries as read.
      * @hide
+     * @deprecated Use {@link #cancelMissedCallsNotification()} instead.
      */
+    @Deprecated
     @SystemApi
     public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT =
             "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT";
@@ -2262,9 +2266,10 @@
     }
 
     /**
-     * Removes the missed-call notification if one is present.
+     * Removes the missed-call notification if one is present and marks missed calls in the call
+     * log as read.
      * <p>
-     * Requires that the method-caller be set as the system dialer app.
+     * Requires that the method-caller be set as the default dialer app.
      * </p>
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 77af956..918ae79 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -537,10 +537,9 @@
 
     /**
      * CDMA activation goes through OTASP.
-     * <p>
-     * TODO: This should be combined with config_use_hfa_for_provisioning and implemented as an enum
-     * (NONE, HFA, OTASP).
      */
+    // TODO: This should be combined with config_use_hfa_for_provisioning and implemented as an enum
+    // (NONE, HFA, OTASP).
     public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL =
             "use_otasp_for_provisioning_bool";
 
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 3e2c7c4..758372a 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -3964,7 +3964,12 @@
 
     /** @hide */
     public static void invalidateActiveDataSubIdCaches() {
-        PropertyInvalidatedCache.invalidateCache(CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY);
+        if (isSubscriptionManagerServiceEnabled()) {
+            PropertyInvalidatedCache.invalidateCache(
+                    CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY);
+        } else {
+            PropertyInvalidatedCache.invalidateCache(CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY);
+        }
     }
 
     /** @hide */
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapImage.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapImage.kt
index 3875644..e079b6d 100644
--- a/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapImage.kt
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapImage.kt
@@ -80,10 +80,10 @@
         spinner.adapter = adapter
         spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
             override fun onItemSelected(
-                parent: AdapterView<*>?,
-                view: View?,
-                position: Int,
-                id: Long
+                    parent: AdapterView<*>?,
+                    view: View?,
+                    position: Int,
+                    id: Long
             ) {
                 setImage(position)
             }
@@ -108,7 +108,7 @@
         if (selectedImage == position) return
         selectedImage = position
         val source = ImageDecoder.createSource(resources.assets,
-            "gainmaps/${gainmapImages[position]}")
+                "gainmaps/${gainmapImages[position]}")
         doDecode(source)
     }
 
@@ -137,16 +137,16 @@
                 gainmapVisualizer = map
             } else {
                 gainmapVisualizer = Bitmap.createBitmap(map.width, map.height,
-                    Bitmap.Config.ARGB_8888)
+                        Bitmap.Config.ARGB_8888)
                 val canvas = Canvas(gainmapVisualizer!!)
                 val paint = Paint()
                 paint.colorFilter = ColorMatrixColorFilter(
-                    floatArrayOf(
-                        0f, 0f, 0f, 1f, 0f,
-                        0f, 0f, 0f, 1f, 0f,
-                        0f, 0f, 0f, 1f, 0f,
-                        0f, 0f, 0f, 0f, 255f
-                    )
+                        floatArrayOf(
+                                0f, 0f, 0f, 1f, 0f,
+                                0f, 0f, 0f, 1f, 0f,
+                                0f, 0f, 0f, 1f, 0f,
+                                0f, 0f, 0f, 0f, 255f
+                        )
                 )
                 canvas.drawBitmap(map, 0f, 0f, paint)
                 canvas.setBitmap(null)
@@ -174,8 +174,14 @@
         if (bitmap == null) return
 
         imageView.setImage(ImageSource.cachedBitmap(when (outputMode) {
-            R.id.output_hdr -> { bitmap!!.gainmap = gainmap; bitmap!! }
-            R.id.output_sdr -> { bitmap!!.gainmap = null; bitmap!! }
+            R.id.output_hdr -> {
+                bitmap!!.gainmap = gainmap; bitmap!!
+            }
+
+            R.id.output_sdr -> {
+                bitmap!!.gainmap = null; bitmap!!
+            }
+
             R.id.output_gainmap -> gainmapVisualizer!!
             else -> throw IllegalStateException()
         }))
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index 7b94e71..34a1b11 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -15,7 +15,7 @@
 $(aapt2_results): $(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests
 	-$(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests --gtest_output=xml:$@ > /dev/null 2>&1
 
-$(call declare-0p-target,$(aapt2_results))
+$(call declare-1p-target,$(aapt2_results))
 
 aapt2_results :=
 
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/DeviceInfo.aidl b/wifi/java/src/android/net/wifi/sharedconnectivity/app/DeviceInfo.aidl
deleted file mode 100644
index 35d5c15..0000000
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/DeviceInfo.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.sharedconnectivity.app;
-
-parcelable DeviceInfo;
\ No newline at end of file
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetwork.aidl b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.aidl
similarity index 95%
copy from wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetwork.aidl
copy to wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.aidl
index 6cc4cfe..f9c4829 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetwork.aidl
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.aidl
@@ -16,4 +16,4 @@
 
 package android.net.wifi.sharedconnectivity.app;
 
-parcelable TetherNetwork;
+parcelable HotspotNetwork;
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetwork.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java
similarity index 76%
rename from wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetwork.java
rename to wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java
index 7b591d3..d3b7b12 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetwork.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetwork.java
@@ -33,14 +33,14 @@
 import java.util.Set;
 
 /**
- * A data class representing an Instant Tether network.
+ * A data class representing a hotspot network.
  * This class is used in IPC calls between the implementer of {@link SharedConnectivityService} and
  * the consumers of {@link com.android.wifitrackerlib}.
  *
  * @hide
  */
 @SystemApi
-public final class TetherNetwork implements Parcelable {
+public final class HotspotNetwork implements Parcelable {
     /**
      * Remote device is connected to the internet via an unknown connection.
      */
@@ -71,33 +71,44 @@
             NETWORK_TYPE_WIFI,
             NETWORK_TYPE_ETHERNET
     })
-    public @interface NetworkType {}
+    public @interface NetworkType {
+    }
 
     private final long mDeviceId;
-    private final DeviceInfo mDeviceInfo;
-    @NetworkType private final int mNetworkType;
+    private final NetworkProviderInfo mNetworkProviderInfo;
+    @NetworkType
+    private final int mNetworkType;
     private final String mNetworkName;
-    @Nullable private final String mHotspotSsid;
-    @Nullable private final String mHotspotBssid;
-    @Nullable @SecurityType private final ArraySet<Integer> mHotspotSecurityTypes;
+    @Nullable
+    private final String mHotspotSsid;
+    @Nullable
+    private final String mHotspotBssid;
+    @Nullable
+    @SecurityType
+    private final ArraySet<Integer> mHotspotSecurityTypes;
 
     /**
-     * Builder class for {@link TetherNetwork}.
+     * Builder class for {@link HotspotNetwork}.
      */
     public static final class Builder {
         private long mDeviceId = -1;
-        private DeviceInfo mDeviceInfo;
-        @NetworkType private int mNetworkType;
+        private NetworkProviderInfo mNetworkProviderInfo;
+        @NetworkType
+        private int mNetworkType;
         private String mNetworkName;
-        @Nullable private String mHotspotSsid;
-        @Nullable private String mHotspotBssid;
-        @Nullable @SecurityType private final ArraySet<Integer> mHotspotSecurityTypes =
+        @Nullable
+        private String mHotspotSsid;
+        @Nullable
+        private String mHotspotBssid;
+        @Nullable
+        @SecurityType
+        private final ArraySet<Integer> mHotspotSecurityTypes =
                 new ArraySet<>();
 
         /**
          * Set the remote device ID.
          *
-         * @param deviceId Locally unique ID for this Instant Tether network.
+         * @param deviceId Locally unique ID for this Hotspot network.
          * @return Returns the Builder object.
          */
         @NonNull
@@ -109,12 +120,12 @@
         /**
          * Sets information about the device providing connectivity.
          *
-         * @param deviceInfo The device information object.
+         * @param networkProviderInfo The device information object.
          * @return Returns the Builder object.
          */
         @NonNull
-        public Builder setDeviceInfo(@NonNull DeviceInfo deviceInfo) {
-            mDeviceInfo = deviceInfo;
+        public Builder setNetworkProviderInfo(@NonNull NetworkProviderInfo networkProviderInfo) {
+            mNetworkProviderInfo = networkProviderInfo;
             return this;
         }
 
@@ -125,7 +136,7 @@
          * @return Returns the Builder object.
          */
         @NonNull
-        public Builder setNetworkType(@NetworkType int networkType) {
+        public Builder setHostNetworkType(@NetworkType int networkType) {
             mNetworkType = networkType;
             return this;
         }
@@ -179,15 +190,15 @@
         }
 
         /**
-         * Builds the {@link TetherNetwork} object.
+         * Builds the {@link HotspotNetwork} object.
          *
-         * @return Returns the built {@link TetherNetwork} object.
+         * @return Returns the built {@link HotspotNetwork} object.
          */
         @NonNull
-        public TetherNetwork build() {
-            return new TetherNetwork(
+        public HotspotNetwork build() {
+            return new HotspotNetwork(
                     mDeviceId,
-                    mDeviceInfo,
+                    mNetworkProviderInfo,
                     mNetworkType,
                     mNetworkName,
                     mHotspotSsid,
@@ -196,7 +207,7 @@
         }
     }
 
-    private static void validate(long deviceId, int networkType, String networkName) {
+    private static void validate(long deviceId, @NetworkType int networkType, String networkName) {
         if (deviceId < 0) {
             throw new IllegalArgumentException("DeviceId must be set");
         }
@@ -209,9 +220,9 @@
         }
     }
 
-    private TetherNetwork(
+    private HotspotNetwork(
             long deviceId,
-            DeviceInfo deviceInfo,
+            NetworkProviderInfo networkProviderInfo,
             @NetworkType int networkType,
             @NonNull String networkName,
             @Nullable String hotspotSsid,
@@ -221,7 +232,7 @@
                 networkType,
                 networkName);
         mDeviceId = deviceId;
-        mDeviceInfo = deviceInfo;
+        mNetworkProviderInfo = networkProviderInfo;
         mNetworkType = networkType;
         mNetworkName = networkName;
         mHotspotSsid = hotspotSsid;
@@ -232,7 +243,7 @@
     /**
      * Gets the remote device ID.
      *
-     * @return Returns the locally unique ID for this Instant Tether network.
+     * @return Returns the locally unique ID for this Hotspot network.
      */
     public long getDeviceId() {
         return mDeviceId;
@@ -241,11 +252,11 @@
     /**
      * Gets information about the device providing connectivity.
      *
-     * @return Returns the information of the device providing the Instant Tether network.
+     * @return Returns the information of the device providing the Hotspot network.
      */
     @NonNull
-    public DeviceInfo getDeviceInfo() {
-        return mDeviceInfo;
+    public NetworkProviderInfo getNetworkProviderInfo() {
+        return mNetworkProviderInfo;
     }
 
     /**
@@ -254,7 +265,7 @@
      * @return Returns the network type as represented by IntDef {@link NetworkType}.
      */
     @NetworkType
-    public int getNetworkType() {
+    public int getHostNetworkType() {
         return mNetworkType;
     }
 
@@ -301,11 +312,11 @@
 
     @Override
     public boolean equals(Object obj) {
-        if (!(obj instanceof TetherNetwork)) return false;
-        TetherNetwork other = (TetherNetwork) obj;
+        if (!(obj instanceof HotspotNetwork)) return false;
+        HotspotNetwork other = (HotspotNetwork) obj;
         return mDeviceId == other.getDeviceId()
-                && Objects.equals(mDeviceInfo, other.getDeviceInfo())
-                && mNetworkType == other.getNetworkType()
+                && Objects.equals(mNetworkProviderInfo, other.getNetworkProviderInfo())
+                && mNetworkType == other.getHostNetworkType()
                 && Objects.equals(mNetworkName, other.getNetworkName())
                 && Objects.equals(mHotspotSsid, other.getHotspotSsid())
                 && Objects.equals(mHotspotBssid, other.getHotspotBssid())
@@ -314,8 +325,8 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mDeviceId, mDeviceInfo, mNetworkName, mHotspotSsid, mHotspotBssid,
-                mHotspotSecurityTypes);
+        return Objects.hash(mDeviceId, mNetworkProviderInfo, mNetworkName, mHotspotSsid,
+                mHotspotBssid, mHotspotSecurityTypes);
     }
 
     @Override
@@ -326,7 +337,7 @@
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeLong(mDeviceId);
-        mDeviceInfo.writeToParcel(dest, flags);
+        mNetworkProviderInfo.writeToParcel(dest, flags);
         dest.writeInt(mNetworkType);
         dest.writeString(mNetworkName);
         dest.writeString(mHotspotSsid);
@@ -335,36 +346,36 @@
     }
 
     /**
-     * Creates a {@link TetherNetwork} object from a parcel.
+     * Creates a {@link HotspotNetwork} object from a parcel.
      *
      * @hide
      */
     @NonNull
-    public static TetherNetwork readFromParcel(@NonNull Parcel in) {
-        return new TetherNetwork(in.readLong(), DeviceInfo.readFromParcel(in),
+    public static HotspotNetwork readFromParcel(@NonNull Parcel in) {
+        return new HotspotNetwork(in.readLong(), NetworkProviderInfo.readFromParcel(in),
                 in.readInt(), in.readString(), in.readString(), in.readString(),
                 (ArraySet<Integer>) in.readArraySet(null));
     }
 
     @NonNull
-    public static final Creator<TetherNetwork> CREATOR = new Creator<>() {
+    public static final Creator<HotspotNetwork> CREATOR = new Creator<>() {
         @Override
-        public TetherNetwork createFromParcel(Parcel in) {
+        public HotspotNetwork createFromParcel(Parcel in) {
             return readFromParcel(in);
         }
 
         @Override
-        public TetherNetwork[] newArray(int size) {
-            return new TetherNetwork[size];
+        public HotspotNetwork[] newArray(int size) {
+            return new HotspotNetwork[size];
         }
     };
 
     @Override
     public String toString() {
-        return new StringBuilder("TetherNetwork[")
+        return new StringBuilder("HotspotNetwork[")
                 .append("deviceId=").append(mDeviceId)
                 .append(", networkType=").append(mNetworkType)
-                .append(", deviceInfo=").append(mDeviceInfo.toString())
+                .append(", networkProviderInfo=").append(mNetworkProviderInfo.toString())
                 .append(", networkName=").append(mNetworkName)
                 .append(", hotspotSsid=").append(mHotspotSsid)
                 .append(", hotspotBssid=").append(mHotspotBssid)
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetwork.aidl b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.aidl
similarity index 93%
copy from wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetwork.aidl
copy to wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.aidl
index 6cc4cfe..d32d15e 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetwork.aidl
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.aidl
@@ -16,4 +16,4 @@
 
 package android.net.wifi.sharedconnectivity.app;
 
-parcelable TetherNetwork;
+parcelable HotspotNetworkConnectionStatus;
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.java
new file mode 100644
index 0000000..69767f3
--- /dev/null
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatus.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.sharedconnectivity.app;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * The status of a connection to a hotspot network after the client called
+ * {@link SharedConnectivityManager#connectHotspotNetwork}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class HotspotNetworkConnectionStatus implements Parcelable {
+
+    /**
+     * Connection status is unknown.
+     */
+    public static final int CONNECTION_STATUS_UNKNOWN = 0;
+
+    /**
+     * The connection is being initiated.
+     */
+    public static final int CONNECTION_STATUS_ENABLING_HOTSPOT = 1;
+
+    /**
+     * Device providing the hotspot failed to initiate it.
+     */
+    public static final int CONNECTION_STATUS_UNKNOWN_ERROR = 2;
+
+    /**
+     * Failed to provision tethering.
+     */
+    public static final int CONNECTION_STATUS_PROVISIONING_FAILED = 3;
+
+    /**
+     * Timeout while trying to provision tethering.
+     */
+    public static final int CONNECTION_STATUS_TETHERING_TIMEOUT = 4;
+
+    /**
+     * Device doesn't support tethering.
+     */
+    public static final int CONNECTION_STATUS_TETHERING_UNSUPPORTED = 5;
+
+    /**
+     * Device has no cell data.
+     */
+    public static final int CONNECTION_STATUS_NO_CELL_DATA = 6;
+
+    /**
+     * Device failed to enable hotspot
+     */
+    public static final int CONNECTION_STATUS_ENABLING_HOTSPOT_FAILED = 7;
+
+    /**
+     * Timeout while trying to enable hotspot
+     */
+    public static final int CONNECTION_STATUS_ENABLING_HOTSPOT_TIMEOUT = 8;
+
+    /**
+     * Failed to connect to hotspot
+     */
+    public static final int CONNECTION_STATUS_CONNECT_TO_HOTSPOT_FAILED = 9;
+
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            CONNECTION_STATUS_UNKNOWN,
+            CONNECTION_STATUS_ENABLING_HOTSPOT,
+            CONNECTION_STATUS_UNKNOWN_ERROR,
+            CONNECTION_STATUS_PROVISIONING_FAILED,
+            CONNECTION_STATUS_TETHERING_TIMEOUT,
+            CONNECTION_STATUS_TETHERING_UNSUPPORTED,
+            CONNECTION_STATUS_NO_CELL_DATA,
+            CONNECTION_STATUS_ENABLING_HOTSPOT_FAILED,
+            CONNECTION_STATUS_ENABLING_HOTSPOT_TIMEOUT,
+            CONNECTION_STATUS_CONNECT_TO_HOTSPOT_FAILED,
+    })
+    public @interface ConnectionStatus {
+    }
+
+    @ConnectionStatus
+    private final int mStatus;
+    private final HotspotNetwork mHotspotNetwork;
+    private final Bundle mExtras;
+
+    /**
+     * Builder class for {@link HotspotNetworkConnectionStatus}.
+     */
+    public static final class Builder {
+        @ConnectionStatus
+        private int mStatus;
+        private HotspotNetwork mHotspotNetwork;
+        private Bundle mExtras;
+
+        /**
+         * Sets the status of the connection
+         *
+         * @return Returns the Builder object.
+         */
+        @NonNull
+        public Builder setStatus(@ConnectionStatus int status) {
+            mStatus = status;
+            return this;
+        }
+
+        /**
+         * Sets the {@link HotspotNetwork} object of the connection.
+         *
+         * @return Returns the Builder object.
+         */
+        @NonNull
+        public Builder setHotspotNetwork(@NonNull HotspotNetwork hotspotNetwork) {
+            mHotspotNetwork = hotspotNetwork;
+            return this;
+        }
+
+        /**
+         * Sets the extras bundle
+         *
+         * @return Returns the Builder object.
+         */
+        @NonNull
+        public Builder setExtras(@NonNull Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Builds the {@link HotspotNetworkConnectionStatus} object.
+         *
+         * @return Returns the built {@link HotspotNetworkConnectionStatus} object.
+         */
+        @NonNull
+        public HotspotNetworkConnectionStatus build() {
+            return new HotspotNetworkConnectionStatus(mStatus, mHotspotNetwork, mExtras);
+        }
+    }
+
+    private static void validate(@ConnectionStatus int status) {
+        if (status != CONNECTION_STATUS_UNKNOWN
+                && status != CONNECTION_STATUS_ENABLING_HOTSPOT
+                && status != CONNECTION_STATUS_UNKNOWN_ERROR
+                && status != CONNECTION_STATUS_PROVISIONING_FAILED
+                && status != CONNECTION_STATUS_TETHERING_TIMEOUT
+                && status != CONNECTION_STATUS_TETHERING_UNSUPPORTED
+                && status != CONNECTION_STATUS_NO_CELL_DATA
+                && status != CONNECTION_STATUS_ENABLING_HOTSPOT_FAILED
+                && status != CONNECTION_STATUS_ENABLING_HOTSPOT_TIMEOUT
+                && status != CONNECTION_STATUS_CONNECT_TO_HOTSPOT_FAILED) {
+            throw new IllegalArgumentException("Illegal connection status");
+        }
+    }
+
+    private HotspotNetworkConnectionStatus(@ConnectionStatus int status,
+            HotspotNetwork hotspotNetwork, Bundle extras) {
+        validate(status);
+        mStatus = status;
+        mHotspotNetwork = hotspotNetwork;
+        mExtras = extras;
+    }
+
+    /**
+     * Gets the status of the connection
+     *
+     * @return Returns true for enabled, false otherwise.
+     */
+    @ConnectionStatus
+    public int getStatus() {
+        return mStatus;
+    }
+
+    /**
+     * Gets the {@link HotspotNetwork} object of the connection.
+     *
+     * @return Returns a HotspotNetwork object.
+     */
+    @NonNull
+    public HotspotNetwork getHotspotNetwork() {
+        return mHotspotNetwork;
+    }
+
+    /**
+     * Gets the extras Bundle.
+     *
+     * @return Returns a Bundle object.
+     */
+    @NonNull
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof HotspotNetworkConnectionStatus)) return false;
+        HotspotNetworkConnectionStatus other = (HotspotNetworkConnectionStatus) obj;
+        return mStatus == other.getStatus()
+                && Objects.equals(mHotspotNetwork, other.getHotspotNetwork());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mStatus, mHotspotNetwork);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mStatus);
+        mHotspotNetwork.writeToParcel(dest, flags);
+        dest.writeBundle(mExtras);
+    }
+
+    /**
+     * Creates a {@link HotspotNetworkConnectionStatus} object from a parcel.
+     *
+     * @hide
+     */
+    @NonNull
+    public static HotspotNetworkConnectionStatus readFromParcel(@NonNull Parcel in) {
+        return new HotspotNetworkConnectionStatus(in.readInt(),
+                HotspotNetwork.readFromParcel(in), in.readBundle());
+    }
+
+    @NonNull
+    public static final Creator<HotspotNetworkConnectionStatus> CREATOR = new Creator<>() {
+        @Override
+        public HotspotNetworkConnectionStatus createFromParcel(Parcel in) {
+            return readFromParcel(in);
+        }
+
+        @Override
+        public HotspotNetworkConnectionStatus[] newArray(int size) {
+            return new HotspotNetworkConnectionStatus[size];
+        }
+    };
+
+    @Override
+    public String toString() {
+        return new StringBuilder("HotspotNetworkConnectionStatus[")
+                .append("status=").append(mStatus)
+                .append("hotspot network=").append(mHotspotNetwork.toString())
+                .append("extras=").append(mExtras.toString())
+                .append("]").toString();
+    }
+}
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetwork.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetwork.java
index fe23caa..64412bc 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetwork.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetwork.java
@@ -64,21 +64,26 @@
             NETWORK_SOURCE_NEARBY_SELF,
             NETWORK_SOURCE_CLOUD_SELF
     })
-    public @interface NetworkSource {}
+    public @interface NetworkSource {
+    }
 
-    @NetworkSource private final int mNetworkSource;
+    @NetworkSource
+    private final int mNetworkSource;
     private final String mSsid;
-    @SecurityType private final ArraySet<Integer> mSecurityTypes;
-    private final DeviceInfo mDeviceInfo;
+    @SecurityType
+    private final ArraySet<Integer> mSecurityTypes;
+    private final NetworkProviderInfo mNetworkProviderInfo;
 
     /**
      * Builder class for {@link KnownNetwork}.
      */
     public static final class Builder {
-        @NetworkSource private int mNetworkSource = -1;
+        @NetworkSource
+        private int mNetworkSource = -1;
         private String mSsid;
-        @SecurityType private final ArraySet<Integer> mSecurityTypes = new ArraySet<>();
-        private android.net.wifi.sharedconnectivity.app.DeviceInfo mDeviceInfo;
+        @SecurityType
+        private final ArraySet<Integer> mSecurityTypes = new ArraySet<>();
+        private NetworkProviderInfo mNetworkProviderInfo;
 
         /**
          * Sets the indicated source of the known network.
@@ -120,12 +125,12 @@
          * Sets the device information of the device providing connectivity.
          * Must be set if network source is {@link KnownNetwork#NETWORK_SOURCE_NEARBY_SELF}.
          *
-         * @param deviceInfo The device information object.
+         * @param networkProviderInfo The device information object.
          * @return Returns the Builder object.
          */
         @NonNull
-        public Builder setDeviceInfo(@Nullable DeviceInfo deviceInfo) {
-            mDeviceInfo = deviceInfo;
+        public Builder setNetworkProviderInfo(@Nullable NetworkProviderInfo networkProviderInfo) {
+            mNetworkProviderInfo = networkProviderInfo;
             return this;
         }
 
@@ -140,12 +145,13 @@
                     mNetworkSource,
                     mSsid,
                     mSecurityTypes,
-                    mDeviceInfo);
+                    mNetworkProviderInfo);
         }
     }
 
-    private static void validate(int networkSource, String ssid, Set<Integer> securityTypes,
-            DeviceInfo deviceInfo) {
+    private static void validate(@NetworkSource int networkSource, String ssid,
+            @SecurityType Set<Integer> securityTypes,
+            NetworkProviderInfo networkProviderInfo) {
         if (networkSource != NETWORK_SOURCE_UNKNOWN
                 && networkSource != NETWORK_SOURCE_CLOUD_SELF
                 && networkSource != NETWORK_SOURCE_NEARBY_SELF) {
@@ -157,7 +163,7 @@
         if (securityTypes.isEmpty()) {
             throw new IllegalArgumentException("SecurityTypes must be set");
         }
-        if (networkSource == NETWORK_SOURCE_NEARBY_SELF && deviceInfo == null) {
+        if (networkSource == NETWORK_SOURCE_NEARBY_SELF && networkProviderInfo == null) {
             throw new IllegalArgumentException("Device info must be provided when network source"
                     + " is NETWORK_SOURCE_NEARBY_SELF");
         }
@@ -167,12 +173,12 @@
             @NetworkSource int networkSource,
             @NonNull String ssid,
             @NonNull @SecurityType ArraySet<Integer> securityTypes,
-            @Nullable DeviceInfo deviceInfo) {
-        validate(networkSource, ssid, securityTypes, deviceInfo);
+            @Nullable NetworkProviderInfo networkProviderInfo) {
+        validate(networkSource, ssid, securityTypes, networkProviderInfo);
         mNetworkSource = networkSource;
         mSsid = ssid;
         mSecurityTypes = new ArraySet<>(securityTypes);
-        mDeviceInfo = deviceInfo;
+        mNetworkProviderInfo = networkProviderInfo;
     }
 
     /**
@@ -213,8 +219,8 @@
      * network source is cloud or unknown.
      */
     @Nullable
-    public DeviceInfo getDeviceInfo() {
-        return mDeviceInfo;
+    public NetworkProviderInfo getNetworkProviderInfo() {
+        return mNetworkProviderInfo;
     }
 
     @Override
@@ -224,12 +230,12 @@
         return mNetworkSource == other.getNetworkSource()
                 && Objects.equals(mSsid, other.getSsid())
                 && Objects.equals(mSecurityTypes, other.getSecurityTypes())
-                && Objects.equals(mDeviceInfo, other.getDeviceInfo());
+                && Objects.equals(mNetworkProviderInfo, other.getNetworkProviderInfo());
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mNetworkSource, mSsid, mSecurityTypes, mDeviceInfo);
+        return Objects.hash(mNetworkSource, mSsid, mSecurityTypes, mNetworkProviderInfo);
     }
 
     @Override
@@ -242,7 +248,7 @@
         dest.writeInt(mNetworkSource);
         dest.writeString(mSsid);
         dest.writeArraySet(mSecurityTypes);
-        mDeviceInfo.writeToParcel(dest, flags);
+        mNetworkProviderInfo.writeToParcel(dest, flags);
     }
 
     /**
@@ -254,7 +260,7 @@
     public static KnownNetwork readFromParcel(@NonNull Parcel in) {
         return new KnownNetwork(in.readInt(), in.readString(),
                 (ArraySet<Integer>) in.readArraySet(null),
-                DeviceInfo.readFromParcel(in));
+                NetworkProviderInfo.readFromParcel(in));
     }
 
     @NonNull
@@ -276,7 +282,7 @@
                 .append("NetworkSource=").append(mNetworkSource)
                 .append(", ssid=").append(mSsid)
                 .append(", securityTypes=").append(mSecurityTypes.toString())
-                .append(", deviceInfo=").append(mDeviceInfo.toString())
+                .append(", networkProviderInfo=").append(mNetworkProviderInfo.toString())
                 .append("]").toString();
     }
 }
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatus.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatus.java
index b2f04ff..6bd0a5e 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatus.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatus.java
@@ -120,8 +120,16 @@
         }
     }
 
+    private static void validate(@ConnectionStatus int status) {
+        if (status != CONNECTION_STATUS_UNKNOWN && status != CONNECTION_STATUS_SAVED
+                && status != CONNECTION_STATUS_SAVE_FAILED) {
+            throw new IllegalArgumentException("Illegal connection status");
+        }
+    }
+
     private KnownNetworkConnectionStatus(@ConnectionStatus int status, KnownNetwork knownNetwork,
             Bundle extras) {
+        validate(status);
         mStatus = status;
         mKnownNetwork = knownNetwork;
         mExtras = extras;
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetwork.aidl b/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.aidl
similarity index 95%
rename from wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetwork.aidl
rename to wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.aidl
index 6cc4cfe..f3cbbc2 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetwork.aidl
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.aidl
@@ -16,4 +16,4 @@
 
 package android.net.wifi.sharedconnectivity.app;
 
-parcelable TetherNetwork;
+parcelable NetworkProviderInfo;
\ No newline at end of file
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/DeviceInfo.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java
similarity index 79%
rename from wifi/java/src/android/net/wifi/sharedconnectivity/app/DeviceInfo.java
rename to wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java
index 52abf33..ed4d699 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/DeviceInfo.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java
@@ -36,7 +36,7 @@
  * @hide
  */
 @SystemApi
-public final class DeviceInfo implements Parcelable {
+public final class NetworkProviderInfo implements Parcelable {
 
     /**
      * Device type providing connectivity is unknown.
@@ -59,6 +59,16 @@
     public static final int DEVICE_TYPE_LAPTOP = 3;
 
     /**
+     * Device providing connectivity is a watch.
+     */
+    public static final int DEVICE_TYPE_WATCH = 4;
+
+    /**
+     * Device providing connectivity is a watch.
+     */
+    public static final int DEVICE_TYPE_AUTO = 5;
+
+    /**
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
@@ -66,18 +76,22 @@
             DEVICE_TYPE_UNKNOWN,
             DEVICE_TYPE_PHONE,
             DEVICE_TYPE_TABLET,
-            DEVICE_TYPE_LAPTOP
+            DEVICE_TYPE_LAPTOP,
+            DEVICE_TYPE_WATCH,
+            DEVICE_TYPE_AUTO
     })
-    public @interface DeviceType {}
+    public @interface DeviceType {
+    }
 
-    @DeviceType private final int mDeviceType;
+    @DeviceType
+    private final int mDeviceType;
     private final String mDeviceName;
     private final String mModelName;
     private final int mBatteryPercentage;
     private final int mConnectionStrength;
 
     /**
-     * Builder class for {@link DeviceInfo}.
+     * Builder class for {@link NetworkProviderInfo}.
      */
     public static final class Builder {
         private int mDeviceType;
@@ -86,7 +100,12 @@
         private int mBatteryPercentage;
         private int mConnectionStrength;
 
-        public Builder() {}
+        public Builder(@NonNull String deviceName, @NonNull String modelName) {
+            Objects.requireNonNull(deviceName);
+            Objects.requireNonNull(modelName);
+            mDeviceName = deviceName;
+            mModelName = modelName;
+        }
 
         /**
          * Sets the device type that provides connectivity.
@@ -108,6 +127,7 @@
          */
         @NonNull
         public Builder setDeviceName(@NonNull String deviceName) {
+            Objects.requireNonNull(deviceName);
             mDeviceName = deviceName;
             return this;
         }
@@ -120,6 +140,7 @@
          */
         @NonNull
         public Builder setModelName(@NonNull String modelName) {
+            Objects.requireNonNull(modelName);
             mModelName = modelName;
             return this;
         }
@@ -149,29 +170,24 @@
         }
 
         /**
-         * Builds the {@link DeviceInfo} object.
+         * Builds the {@link NetworkProviderInfo} object.
          *
-         * @return Returns the built {@link DeviceInfo} object.
+         * @return Returns the built {@link NetworkProviderInfo} object.
          */
         @NonNull
-        public DeviceInfo build() {
-            return new DeviceInfo(mDeviceType, mDeviceName, mModelName, mBatteryPercentage,
+        public NetworkProviderInfo build() {
+            return new NetworkProviderInfo(mDeviceType, mDeviceName, mModelName, mBatteryPercentage,
                     mConnectionStrength);
         }
     }
 
-    private static void validate(int deviceType, String deviceName, String modelName,
+    private static void validate(@DeviceType int deviceType, String deviceName, String modelName,
             int batteryPercentage, int connectionStrength) {
         if (deviceType != DEVICE_TYPE_UNKNOWN && deviceType != DEVICE_TYPE_PHONE
-                && deviceType != DEVICE_TYPE_TABLET && deviceType != DEVICE_TYPE_LAPTOP) {
+                && deviceType != DEVICE_TYPE_TABLET && deviceType != DEVICE_TYPE_LAPTOP
+                && deviceType != DEVICE_TYPE_WATCH && deviceType != DEVICE_TYPE_AUTO) {
             throw new IllegalArgumentException("Illegal device type");
         }
-        if (Objects.isNull(deviceName)) {
-            throw new IllegalArgumentException("DeviceName must be set");
-        }
-        if (Objects.isNull(modelName)) {
-            throw new IllegalArgumentException("ModelName must be set");
-        }
         if (batteryPercentage < 0 || batteryPercentage > 100) {
             throw new IllegalArgumentException("BatteryPercentage must be in range 0-100");
         }
@@ -180,7 +196,7 @@
         }
     }
 
-    private DeviceInfo(@DeviceType int deviceType, @NonNull String deviceName,
+    private NetworkProviderInfo(@DeviceType int deviceType, @NonNull String deviceName,
             @NonNull String modelName, int batteryPercentage, int connectionStrength) {
         validate(deviceType, deviceName, modelName, batteryPercentage, connectionStrength);
         mDeviceType = deviceType;
@@ -242,8 +258,8 @@
 
     @Override
     public boolean equals(Object obj) {
-        if (!(obj instanceof DeviceInfo)) return false;
-        DeviceInfo other = (DeviceInfo) obj;
+        if (!(obj instanceof NetworkProviderInfo)) return false;
+        NetworkProviderInfo other = (NetworkProviderInfo) obj;
         return mDeviceType == other.getDeviceType()
                 && Objects.equals(mDeviceName, other.mDeviceName)
                 && Objects.equals(mModelName, other.mModelName)
@@ -256,6 +272,7 @@
         return Objects.hash(mDeviceType, mDeviceName, mModelName, mBatteryPercentage,
                 mConnectionStrength);
     }
+
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeInt(mDeviceType);
@@ -271,32 +288,32 @@
     }
 
     /**
-     * Creates a {@link DeviceInfo} object from a parcel.
+     * Creates a {@link NetworkProviderInfo} object from a parcel.
      *
      * @hide
      */
     @NonNull
-    public static DeviceInfo readFromParcel(@NonNull Parcel in) {
-        return new DeviceInfo(in.readInt(), in.readString(), in.readString(), in.readInt(),
+    public static NetworkProviderInfo readFromParcel(@NonNull Parcel in) {
+        return new NetworkProviderInfo(in.readInt(), in.readString(), in.readString(), in.readInt(),
                 in.readInt());
     }
 
     @NonNull
-    public static final Creator<DeviceInfo> CREATOR = new Creator<DeviceInfo>() {
+    public static final Creator<NetworkProviderInfo> CREATOR = new Creator<NetworkProviderInfo>() {
         @Override
-        public DeviceInfo createFromParcel(Parcel in) {
+        public NetworkProviderInfo createFromParcel(Parcel in) {
             return readFromParcel(in);
         }
 
         @Override
-        public DeviceInfo[] newArray(int size) {
-            return new DeviceInfo[size];
+        public NetworkProviderInfo[] newArray(int size) {
+            return new NetworkProviderInfo[size];
         }
     };
 
     @Override
     public String toString() {
-        return new StringBuilder("DeviceInfo[")
+        return new StringBuilder("NetworkProviderInfo[")
                 .append("deviceType=").append(mDeviceType)
                 .append(", deviceName=").append(mDeviceName)
                 .append(", modelName=").append(mModelName)
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityClientCallback.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityClientCallback.java
index d2b9be7..eb04df6 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityClientCallback.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityClientCallback.java
@@ -32,14 +32,16 @@
 public interface SharedConnectivityClientCallback {
     /**
      * This method is being called by {@link SharedConnectivityService} to notify of a change in the
-     * list of available Tether Networks.
-     * @param networks Updated Tether Network list.
+     * list of available Hotspot Networks.
+     *
+     * @param networks Updated Hotspot Network list.
      */
-    void onTetherNetworksUpdated(@NonNull List<TetherNetwork> networks);
+    void onHotspotNetworksUpdated(@NonNull List<HotspotNetwork> networks);
 
     /**
      * This method is being called by {@link SharedConnectivityService} to notify of a change in the
      * list of available Known Networks.
+     *
      * @param networks Updated Known Network list.
      */
     void onKnownNetworksUpdated(@NonNull List<KnownNetwork> networks);
@@ -47,20 +49,23 @@
     /**
      * This method is being called by {@link SharedConnectivityService} to notify of a change in the
      * state of share connectivity settings.
+     *
      * @param state The new state.
      */
     void onSharedConnectivitySettingsChanged(@NonNull SharedConnectivitySettingsState state);
 
     /**
      * This method is being called by {@link SharedConnectivityService} to notify of a change in the
-     * status of the current tether network connection.
+     * status of the current hotspot network connection.
+     *
      * @param status The new status.
      */
-    void onTetherNetworkConnectionStatusChanged(@NonNull TetherNetworkConnectionStatus status);
+    void onHotspotNetworkConnectionStatusChanged(@NonNull HotspotNetworkConnectionStatus status);
 
     /**
      * This method is being called by {@link SharedConnectivityService} to notify of a change in the
      * status of the current known network connection.
+     *
      * @param status The new status.
      */
     void onKnownNetworkConnectionStatusChanged(@NonNull KnownNetworkConnectionStatus status);
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
index c09f85b..684b385d 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
@@ -49,7 +49,7 @@
  * This class is the library used by consumers of Shared Connectivity data to bind to the service,
  * receive callbacks from, and send user actions to the service.
  *
- * The methods {@link #connectTetherNetwork}, {@link #disconnectTetherNetwork},
+ * The methods {@link #connectHotspotNetwork}, {@link #disconnectHotspotNetwork},
  * {@link #connectKnownNetwork} and {@link #forgetKnownNetwork} are not valid and will return false
  * if not called between {@link SharedConnectivityClientCallback#onServiceConnected()}
  * and {@link SharedConnectivityClientCallback#onServiceDisconnected()} or if
@@ -74,12 +74,11 @@
             mCallback = callback;
         }
 
-        @Override
-        public void onTetherNetworksUpdated(@NonNull List<TetherNetwork> networks) {
+        public void onHotspotNetworksUpdated(@NonNull List<HotspotNetwork> networks) {
             if (mCallback != null) {
                 final long token = Binder.clearCallingIdentity();
                 try {
-                    mExecutor.execute(() -> mCallback.onTetherNetworksUpdated(networks));
+                    mExecutor.execute(() -> mCallback.onHotspotNetworksUpdated(networks));
                 } finally {
                     Binder.restoreCallingIdentity(token);
                 }
@@ -111,14 +110,13 @@
             }
         }
 
-        @Override
-        public void onTetherNetworkConnectionStatusChanged(
-                @NonNull TetherNetworkConnectionStatus status) {
+        public void onHotspotNetworkConnectionStatusChanged(
+                @NonNull HotspotNetworkConnectionStatus status) {
             if (mCallback != null) {
                 final long token = Binder.clearCallingIdentity();
                 try {
                     mExecutor.execute(() ->
-                            mCallback.onTetherNetworkConnectionStatusChanged(status));
+                            mCallback.onHotspotNetworkConnectionStatusChanged(status));
                 } finally {
                     Binder.restoreCallingIdentity(token);
                 }
@@ -259,8 +257,8 @@
     }
 
     /**
-     * Registers a callback for receiving updates to the list of Tether Networks, Known Networks,
-     * shared connectivity settings state, tether network connection status and known network
+     * Registers a callback for receiving updates to the list of Hotspot Networks, Known Networks,
+     * shared connectivity settings state, hotspot network connection status and known network
      * connection status.
      * The {@link SharedConnectivityClientCallback#onRegisterCallbackFailed} will be called if the
      * registration failed.
@@ -331,26 +329,26 @@
 
     /**
      * Send command to the implementation of {@link SharedConnectivityService} requesting connection
-     * to the specified Tether Network.
+     * to the specified Hotspot Network.
      *
-     * @param network {@link TetherNetwork} object representing the network the user has requested
+     * @param network {@link HotspotNetwork} object representing the network the user has requested
      *                a connection to.
      * @return Returns true if the service received the command. Does not guarantee that the
-     *         connection was successful.
+     * connection was successful.
      */
     @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS,
             android.Manifest.permission.NETWORK_SETUP_WIZARD})
-    public boolean connectTetherNetwork(@NonNull TetherNetwork network) {
-        Objects.requireNonNull(network, "Tether network cannot be null");
+    public boolean connectHotspotNetwork(@NonNull HotspotNetwork network) {
+        Objects.requireNonNull(network, "Hotspot network cannot be null");
 
         if (mService == null) {
             return false;
         }
 
         try {
-            mService.connectTetherNetwork(network);
+            mService.connectHotspotNetwork(network);
         } catch (RemoteException e) {
-            Log.e(TAG, "Exception in connectTetherNetwork", e);
+            Log.e(TAG, "Exception in connectHotspotNetwork", e);
             return false;
         }
         return true;
@@ -358,24 +356,24 @@
 
     /**
      * Send command to the implementation of {@link SharedConnectivityService} requesting
-     * disconnection from the active Tether Network.
+     * disconnection from the active Hotspot Network.
      *
-     * @param network {@link TetherNetwork} object representing the network the user has requested
+     * @param network {@link HotspotNetwork} object representing the network the user has requested
      *                to disconnect from.
      * @return Returns true if the service received the command. Does not guarantee that the
-     *         disconnection was successful.
+     * disconnection was successful.
      */
     @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS,
             android.Manifest.permission.NETWORK_SETUP_WIZARD})
-    public boolean disconnectTetherNetwork(@NonNull TetherNetwork network) {
+    public boolean disconnectHotspotNetwork(@NonNull HotspotNetwork network) {
         if (mService == null) {
             return false;
         }
 
         try {
-            mService.disconnectTetherNetwork(network);
+            mService.disconnectHotspotNetwork(network);
         } catch (RemoteException e) {
-            Log.e(TAG, "Exception in disconnectTetherNetwork", e);
+            Log.e(TAG, "Exception in disconnectHotspotNetwork", e);
             return false;
         }
         return true;
@@ -388,7 +386,7 @@
      * @param network {@link KnownNetwork} object representing the network the user has requested
      *                a connection to.
      * @return Returns true if the service received the command. Does not guarantee that the
-     *         connection was successful.
+     * connection was successful.
      */
     @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS,
             android.Manifest.permission.NETWORK_SETUP_WIZARD})
@@ -413,7 +411,7 @@
      * the specified Known Network from the list of Known Networks.
      *
      * @return Returns true if the service received the command. Does not guarantee that the
-     *         forget action was successful.
+     * forget action was successful.
      */
     @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS,
             android.Manifest.permission.NETWORK_SETUP_WIZARD})
@@ -434,22 +432,22 @@
     }
 
     /**
-     * Gets the list of tether networks the user can select to connect to.
+     * Gets the list of hotspot networks the user can select to connect to.
      *
-     * @return Returns a {@link List} of {@link TetherNetwork} objects, empty list on failure.
+     * @return Returns a {@link List} of {@link HotspotNetwork} objects, empty list on failure.
      */
     @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS,
             android.Manifest.permission.NETWORK_SETUP_WIZARD})
     @NonNull
-    public List<TetherNetwork> getTetherNetworks() {
+    public List<HotspotNetwork> getHotspotNetworks() {
         if (mService == null) {
             return List.of();
         }
 
         try {
-            return mService.getTetherNetworks();
+            return mService.getHotspotNetworks();
         } catch (RemoteException e) {
-            Log.e(TAG, "Exception in getTetherNetworks", e);
+            Log.e(TAG, "Exception in getHotspotNetworks", e);
         }
         return List.of();
     }
@@ -498,24 +496,24 @@
     }
 
     /**
-     * Gets the connection status of the tether network the user selected to connect to.
+     * Gets the connection status of the hotspot network the user selected to connect to.
      *
-     * @return Returns a {@link TetherNetworkConnectionStatus} object with the connection status,
+     * @return Returns a {@link HotspotNetworkConnectionStatus} object with the connection status,
      * null on failure. If no connection is active the status will be
-     * {@link TetherNetworkConnectionStatus#CONNECTION_STATUS_UNKNOWN}.
+     * {@link HotspotNetworkConnectionStatus#CONNECTION_STATUS_UNKNOWN}.
      */
     @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS,
             android.Manifest.permission.NETWORK_SETUP_WIZARD})
     @Nullable
-    public TetherNetworkConnectionStatus getTetherNetworkConnectionStatus() {
+    public HotspotNetworkConnectionStatus getHotspotNetworkConnectionStatus() {
         if (mService == null) {
             return null;
         }
 
         try {
-            return mService.getTetherNetworkConnectionStatus();
+            return mService.getHotspotNetworkConnectionStatus();
         } catch (RemoteException e) {
-            Log.e(TAG, "Exception in getTetherNetworkConnectionStatus", e);
+            Log.e(TAG, "Exception in getHotspotNetworkConnectionStatus", e);
         }
         return null;
     }
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetworkConnectionStatus.aidl b/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetworkConnectionStatus.aidl
deleted file mode 100644
index c677a6c..0000000
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetworkConnectionStatus.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.sharedconnectivity.app;
-
-parcelable TetherNetworkConnectionStatus;
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetworkConnectionStatus.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetworkConnectionStatus.java
deleted file mode 100644
index 3cf44ed..0000000
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/TetherNetworkConnectionStatus.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.sharedconnectivity.app;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Objects;
-
-/**
- * The status of a connection to an instant tether network after the client called
- * {@link SharedConnectivityManager#connectTetherNetwork}.
- *
- * @hide
- */
-@SystemApi
-public final class TetherNetworkConnectionStatus implements Parcelable {
-
-    /**
-     * Connection status is unknown.
-     */
-    public static final int CONNECTION_STATUS_UNKNOWN  = 0;
-
-    /**
-     * The connection is being initiated.
-     */
-    public static final int CONNECTION_STATUS_ENABLING_HOTSPOT  = 1;
-
-    /**
-     * Device providing the hotspot failed to initiate it.
-     */
-    public static final int CONNECTION_STATUS_UNKNOWN_ERROR = 2;
-
-    /**
-     * Failed to provision tethering.
-     */
-    public static final int CONNECTION_STATUS_PROVISIONING_FAILED = 3;
-
-    /**
-     * Timeout while trying to provision tethering.
-     */
-    public static final int CONNECTION_STATUS_TETHERING_TIMEOUT = 4;
-
-    /**
-     * Device doesn't support tethering.
-     */
-    public static final int CONNECTION_STATUS_TETHERING_UNSUPPORTED = 5;
-
-    /**
-     * Device has no cell data.
-     */
-    public static final int CONNECTION_STATUS_NO_CELL_DATA = 6;
-
-    /**
-     * Device failed to enable hotspot
-     */
-    public static final int CONNECTION_STATUS_ENABLING_HOTSPOT_FAILED = 7;
-
-    /**
-     * Timeout while trying to enable hotspot
-     */
-    public static final int CONNECTION_STATUS_ENABLING_HOTSPOT_TIMEOUT = 8;
-
-    /**
-     * Failed to connect to hotspot
-     */
-    public static final int CONNECTION_STATUS_CONNECT_TO_HOTSPOT_FAILED = 9;
-
-    /**
-     * @hide
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({
-            CONNECTION_STATUS_UNKNOWN,
-            CONNECTION_STATUS_ENABLING_HOTSPOT,
-            CONNECTION_STATUS_UNKNOWN_ERROR,
-            CONNECTION_STATUS_PROVISIONING_FAILED,
-            CONNECTION_STATUS_TETHERING_TIMEOUT,
-            CONNECTION_STATUS_TETHERING_UNSUPPORTED,
-            CONNECTION_STATUS_NO_CELL_DATA,
-            CONNECTION_STATUS_ENABLING_HOTSPOT_FAILED,
-            CONNECTION_STATUS_ENABLING_HOTSPOT_TIMEOUT,
-            CONNECTION_STATUS_CONNECT_TO_HOTSPOT_FAILED,
-    })
-    public @interface ConnectionStatus {}
-
-    @ConnectionStatus private final int mStatus;
-    private final TetherNetwork mTetherNetwork;
-    private final Bundle mExtras;
-
-    /**
-     * Builder class for {@link TetherNetworkConnectionStatus}.
-     */
-    public static final class Builder {
-        @ConnectionStatus private int mStatus;
-        private TetherNetwork mTetherNetwork;
-        private Bundle mExtras;
-
-        public Builder() {}
-
-        /**
-         * Sets the status of the connection
-         *
-         * @return Returns the Builder object.
-         */
-        @NonNull
-        public Builder setStatus(@ConnectionStatus int status) {
-            mStatus = status;
-            return this;
-        }
-
-        /**
-         * Sets the {@link TetherNetwork} object of the connection.
-         *
-         * @return Returns the Builder object.
-         */
-        @NonNull
-        public Builder setTetherNetwork(@NonNull TetherNetwork tetherNetwork) {
-            mTetherNetwork = tetherNetwork;
-            return this;
-        }
-
-        /**
-         * Sets the extras bundle
-         *
-         * @return Returns the Builder object.
-         */
-        @NonNull
-        public Builder setExtras(@NonNull Bundle extras) {
-            mExtras = extras;
-            return this;
-        }
-
-        /**
-         * Builds the {@link TetherNetworkConnectionStatus} object.
-         *
-         * @return Returns the built {@link TetherNetworkConnectionStatus} object.
-         */
-        @NonNull
-        public TetherNetworkConnectionStatus build() {
-            return new TetherNetworkConnectionStatus(mStatus, mTetherNetwork, mExtras);
-        }
-    }
-
-    private TetherNetworkConnectionStatus(@ConnectionStatus int status, TetherNetwork tetherNetwork,
-            Bundle extras) {
-        mStatus = status;
-        mTetherNetwork = tetherNetwork;
-        mExtras = extras;
-    }
-
-    /**
-     * Gets the status of the connection
-     *
-     * @return Returns true for enabled, false otherwise.
-     */
-    @ConnectionStatus
-    public int getStatus() {
-        return mStatus;
-    }
-
-    /**
-     * Gets the {@link TetherNetwork} object of the connection.
-     *
-     * @return Returns a TetherNetwork object.
-     */
-    @NonNull
-    public TetherNetwork getTetherNetwork() {
-        return mTetherNetwork;
-    }
-
-    /**
-     * Gets the extras Bundle.
-     *
-     * @return Returns a Bundle object.
-     */
-    @NonNull
-    public Bundle getExtras() {
-        return mExtras;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof TetherNetworkConnectionStatus)) return false;
-        TetherNetworkConnectionStatus other = (TetherNetworkConnectionStatus) obj;
-        return mStatus == other.getStatus()
-                && Objects.equals(mTetherNetwork, other.getTetherNetwork());
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mStatus, mTetherNetwork);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeInt(mStatus);
-        mTetherNetwork.writeToParcel(dest, flags);
-        dest.writeBundle(mExtras);
-    }
-
-    /**
-     * Creates a {@link TetherNetworkConnectionStatus} object from a parcel.
-     *
-     * @hide
-     */
-    @NonNull
-    public static TetherNetworkConnectionStatus readFromParcel(@NonNull Parcel in) {
-        return new TetherNetworkConnectionStatus(in.readInt(),
-                TetherNetwork.readFromParcel(in), in.readBundle());
-    }
-
-    @NonNull
-    public static final Creator<TetherNetworkConnectionStatus> CREATOR = new Creator<>() {
-        @Override
-        public TetherNetworkConnectionStatus createFromParcel(Parcel in) {
-            return readFromParcel(in);
-        }
-
-        @Override
-        public TetherNetworkConnectionStatus[] newArray(int size) {
-            return new TetherNetworkConnectionStatus[size];
-        }
-    };
-
-    @Override
-    public String toString() {
-        return new StringBuilder("TetherNetworkConnectionStatus[")
-                .append("status=").append(mStatus)
-                .append("tether network=").append(mTetherNetwork.toString())
-                .append("extras=").append(mExtras.toString())
-                .append("]").toString();
-    }
-}
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityCallback.aidl b/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityCallback.aidl
index 6f6f162..737aa6d 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityCallback.aidl
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityCallback.aidl
@@ -19,15 +19,15 @@
 import android.net.wifi.sharedconnectivity.app.KnownNetwork;
 import android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus;
 import android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState;
-import android.net.wifi.sharedconnectivity.app.TetherNetwork;
-import android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus;
+import android.net.wifi.sharedconnectivity.app.HotspotNetwork;
+import android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus;
 
 /*
  * @hide
  */
 interface ISharedConnectivityCallback {
-    oneway void onTetherNetworksUpdated(in List<TetherNetwork> networks);
-    oneway void onTetherNetworkConnectionStatusChanged(in TetherNetworkConnectionStatus status);
+    oneway void onHotspotNetworksUpdated(in List<HotspotNetwork> networks);
+    oneway void onHotspotNetworkConnectionStatusChanged(in HotspotNetworkConnectionStatus status);
     oneway void onKnownNetworksUpdated(in List<KnownNetwork> networks);
     oneway void onKnownNetworkConnectionStatusChanged(in KnownNetworkConnectionStatus status);
     oneway void onSharedConnectivitySettingsChanged(in SharedConnectivitySettingsState state);
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityService.aidl b/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityService.aidl
index 9f33e99..c81380d 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityService.aidl
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityService.aidl
@@ -17,10 +17,10 @@
 package android.net.wifi.sharedconnectivity.service;
 
 import android.net.wifi.sharedconnectivity.app.KnownNetwork;
-import android.net.wifi.sharedconnectivity.app.TetherNetwork;
+import android.net.wifi.sharedconnectivity.app.HotspotNetwork;
 import android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus;
 import android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState;
-import android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus;
+import android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus;
 import android.net.wifi.sharedconnectivity.service.ISharedConnectivityCallback;
 
 /*
@@ -29,13 +29,13 @@
 interface ISharedConnectivityService {
     void registerCallback(in ISharedConnectivityCallback callback);
     void unregisterCallback(in ISharedConnectivityCallback callback);
-    void connectTetherNetwork(in TetherNetwork network);
-    void disconnectTetherNetwork(in TetherNetwork network);
+    void connectHotspotNetwork(in HotspotNetwork network);
+    void disconnectHotspotNetwork(in HotspotNetwork network);
     void connectKnownNetwork(in KnownNetwork network);
     void forgetKnownNetwork(in KnownNetwork network);
-    List<TetherNetwork> getTetherNetworks();
+    List<HotspotNetwork> getHotspotNetworks();
     List<KnownNetwork> getKnownNetworks();
     SharedConnectivitySettingsState getSettingsState();
-    TetherNetworkConnectionStatus getTetherNetworkConnectionStatus();
+    HotspotNetworkConnectionStatus getHotspotNetworkConnectionStatus();
     KnownNetworkConnectionStatus getKnownNetworkConnectionStatus();
 }
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java b/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
index 4c88c1b..c53da9c 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
@@ -27,12 +27,12 @@
 import android.app.Service;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.net.wifi.sharedconnectivity.app.HotspotNetwork;
+import android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus;
 import android.net.wifi.sharedconnectivity.app.KnownNetwork;
 import android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus;
 import android.net.wifi.sharedconnectivity.app.SharedConnectivityManager;
 import android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState;
-import android.net.wifi.sharedconnectivity.app.TetherNetwork;
-import android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -62,14 +62,14 @@
     private Handler mHandler;
     private final RemoteCallbackList<ISharedConnectivityCallback> mRemoteCallbackList =
             new RemoteCallbackList<>();
-    private List<TetherNetwork> mTetherNetworks = Collections.emptyList();
+    private List<HotspotNetwork> mHotspotNetworks = Collections.emptyList();
     private List<KnownNetwork> mKnownNetworks = Collections.emptyList();
     private SharedConnectivitySettingsState mSettingsState =
             new SharedConnectivitySettingsState.Builder().setInstantTetherEnabled(false)
                     .setExtras(Bundle.EMPTY).build();
-    private TetherNetworkConnectionStatus mTetherNetworkConnectionStatus =
-            new TetherNetworkConnectionStatus.Builder()
-                    .setStatus(TetherNetworkConnectionStatus.CONNECTION_STATUS_UNKNOWN)
+    private HotspotNetworkConnectionStatus mHotspotNetworkConnectionStatus =
+            new HotspotNetworkConnectionStatus.Builder()
+                    .setStatus(HotspotNetworkConnectionStatus.CONNECTION_STATUS_UNKNOWN)
                     .setExtras(Bundle.EMPTY).build();
     private KnownNetworkConnectionStatus mKnownNetworkConnectionStatus =
             new KnownNetworkConnectionStatus.Builder()
@@ -84,8 +84,8 @@
         IBinder serviceStub = new ISharedConnectivityService.Stub() {
 
             /**
-             * Registers a callback for receiving updates to the list of Tether Networks, Known
-             * Networks, shared connectivity settings state, tether network connection status and
+             * Registers a callback for receiving updates to the list of Hotspot Networks, Known
+             * Networks, shared connectivity settings state, hotspot network connection status and
              * known network connection status.
              *
              * @param callback The callback of type {@link ISharedConnectivityCallback} to be called
@@ -113,29 +113,28 @@
             }
 
             /**
-             * Connects to a tether network.
+             * Connects to a hotspot network.
              *
              * @param network The network to connect to.
              */
             @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS,
                     android.Manifest.permission.NETWORK_SETUP_WIZARD})
             @Override
-            public void connectTetherNetwork(TetherNetwork network) {
+            public void connectHotspotNetwork(HotspotNetwork network) {
                 checkPermissions();
-                mHandler.post(() -> onConnectTetherNetwork(network));
+                mHandler.post(() -> onConnectHotspotNetwork(network));
             }
 
             /**
-             * Disconnects from a previously connected tether network.
+             * Disconnects from a previously connected hotspot network.
              *
              * @param network The network to disconnect from.
              */
             @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS,
                     android.Manifest.permission.NETWORK_SETUP_WIZARD})
-            @Override
-            public void disconnectTetherNetwork(TetherNetwork network) {
+            public void disconnectHotspotNetwork(HotspotNetwork network) {
                 checkPermissions();
-                mHandler.post(() -> onDisconnectTetherNetwork(network));
+                mHandler.post(() -> onDisconnectHotspotNetwork(network));
             }
 
             /**
@@ -164,16 +163,16 @@
             }
 
             /**
-             * Gets the list of tether networks the user can select to connect to.
+             * Gets the list of hotspot networks the user can select to connect to.
              *
-             * @return Returns a {@link List} of {@link TetherNetwork} objects
+             * @return Returns a {@link List} of {@link HotspotNetwork} objects
              */
             @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS,
                     android.Manifest.permission.NETWORK_SETUP_WIZARD})
             @Override
-            public List<TetherNetwork> getTetherNetworks() {
+            public List<HotspotNetwork> getHotspotNetworks() {
                 checkPermissions();
-                return mTetherNetworks;
+                return mHotspotNetworks;
             }
 
             /**
@@ -203,17 +202,17 @@
             }
 
             /**
-             * Gets the connection status of the tether network the user selected to connect to.
+             * Gets the connection status of the hotspot network the user selected to connect to.
              *
-             * @return Returns a {@link TetherNetworkConnectionStatus} object with the connection
+             * @return Returns a {@link HotspotNetworkConnectionStatus} object with the connection
              * status.
              */
             @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS,
                     android.Manifest.permission.NETWORK_SETUP_WIZARD})
             @Override
-            public TetherNetworkConnectionStatus getTetherNetworkConnectionStatus() {
+            public HotspotNetworkConnectionStatus getHotspotNetworkConnectionStatus() {
                 checkPermissions();
-                return mTetherNetworkConnectionStatus;
+                return mHotspotNetworkConnectionStatus;
             }
 
             /**
@@ -254,7 +253,8 @@
 
     /** @hide */
     @TestApi
-    public void onBind() {}
+    public void onBind() {
+    }
 
     private void onRegisterCallback(ISharedConnectivityCallback callback) {
         mRemoteCallbackList.register(callback);
@@ -265,23 +265,23 @@
     }
 
     /**
-     * Implementing application should call this method to provide an up-to-date list of Tether
+     * Implementing application should call this method to provide an up-to-date list of Hotspot
      * Networks to be displayed to the user.
      *
      * This method updates the cached list and notifies all registered callbacks. Any callbacks that
      * are inaccessible will be unregistered.
      *
-     * @param networks The updated list of {@link TetherNetwork} objects.
+     * @param networks The updated list of {@link HotspotNetwork} objects.
      */
-    public final void setTetherNetworks(@NonNull List<TetherNetwork> networks) {
-        mTetherNetworks = networks;
+    public final void setHotspotNetworks(@NonNull List<HotspotNetwork> networks) {
+        mHotspotNetworks = networks;
 
         int count = mRemoteCallbackList.beginBroadcast();
         for (int i = 0; i < count; i++) {
             try {
-                mRemoteCallbackList.getBroadcastItem(i).onTetherNetworksUpdated(mTetherNetworks);
+                mRemoteCallbackList.getBroadcastItem(i).onHotspotNetworksUpdated(mHotspotNetworks);
             } catch (RemoteException e) {
-                if (DEBUG) Log.w(TAG, "Exception in setTetherNetworks", e);
+                if (DEBUG) Log.w(TAG, "Exception in setHotspotNetworks", e);
             }
         }
         mRemoteCallbackList.finishBroadcast();
@@ -318,7 +318,7 @@
      * that are inaccessible will be unregistered.
      *
      * @param settingsState The updated state {@link SharedConnectivitySettingsState}
-     *                 objects.
+     *                      objects.
      */
     public final void setSettingsState(@NonNull SharedConnectivitySettingsState settingsState) {
         mSettingsState = settingsState;
@@ -337,23 +337,22 @@
 
     /**
      * Implementing application should call this method to provide an up-to-date status of enabling
-     * and connecting to the tether network.
+     * and connecting to the hotspot network.
      *
-     * @param status The updated status {@link TetherNetworkConnectionStatus} of the connection.
-     *
+     * @param status The updated status {@link HotspotNetworkConnectionStatus} of the connection.
      */
-    public final void updateTetherNetworkConnectionStatus(
-            @NonNull TetherNetworkConnectionStatus status) {
-        mTetherNetworkConnectionStatus = status;
+    public final void updateHotspotNetworkConnectionStatus(
+            @NonNull HotspotNetworkConnectionStatus status) {
+        mHotspotNetworkConnectionStatus = status;
 
         int count = mRemoteCallbackList.beginBroadcast();
         for (int i = 0; i < count; i++) {
             try {
                 mRemoteCallbackList
-                        .getBroadcastItem(i).onTetherNetworkConnectionStatusChanged(
-                                mTetherNetworkConnectionStatus);
+                        .getBroadcastItem(i).onHotspotNetworkConnectionStatusChanged(
+                                mHotspotNetworkConnectionStatus);
             } catch (RemoteException e) {
-                if (DEBUG) Log.w(TAG, "Exception in updateTetherNetworkConnectionStatus", e);
+                if (DEBUG) Log.w(TAG, "Exception in updateHotspotNetworkConnectionStatus", e);
             }
         }
         mRemoteCallbackList.finishBroadcast();
@@ -364,7 +363,6 @@
      * connecting to a known network.
      *
      * @param status The updated status {@link KnownNetworkConnectionStatus} of the connection.
-     *
      */
     public final void updateKnownNetworkConnectionStatus(
             @NonNull KnownNetworkConnectionStatus status) {
@@ -386,20 +384,20 @@
     /**
      * Implementing application should implement this method.
      *
-     * Implementation should initiate a connection to the Tether Network indicated.
+     * Implementation should initiate a connection to the Hotspot Network indicated.
      *
-     * @param network Object identifying the Tether Network the user has requested a connection to.
+     * @param network Object identifying the Hotspot Network the user has requested a connection to.
      */
-    public abstract void onConnectTetherNetwork(@NonNull TetherNetwork network);
+    public abstract void onConnectHotspotNetwork(@NonNull HotspotNetwork network);
 
     /**
      * Implementing application should implement this method.
      *
-     * Implementation should initiate a disconnection from the active Tether Network.
+     * Implementation should initiate a disconnection from the active Hotspot Network.
      *
-     * @param network Object identifying the Tether Network the user has requested to disconnect.
+     * @param network Object identifying the Hotspot Network the user has requested to disconnect.
      */
-    public abstract void onDisconnectTetherNetwork(@NonNull TetherNetwork network);
+    public abstract void onDisconnectHotspotNetwork(@NonNull HotspotNetwork network);
 
     /**
      * Implementing application should implement this method.
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/TetherNetworkConnectionStatusTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatusTest.java
similarity index 62%
rename from wifi/tests/src/android/net/wifi/sharedconnectivity/app/TetherNetworkConnectionStatusTest.java
rename to wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatusTest.java
index 0844364..b18ab50 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/TetherNetworkConnectionStatusTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkConnectionStatusTest.java
@@ -18,10 +18,10 @@
 
 import static android.net.wifi.WifiInfo.SECURITY_TYPE_EAP;
 import static android.net.wifi.WifiInfo.SECURITY_TYPE_WEP;
-import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_TABLET;
-import static android.net.wifi.sharedconnectivity.app.TetherNetwork.NETWORK_TYPE_CELLULAR;
-import static android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT;
-import static android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus.CONNECTION_STATUS_TETHERING_TIMEOUT;
+import static android.net.wifi.sharedconnectivity.app.HotspotNetwork.NETWORK_TYPE_CELLULAR;
+import static android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT;
+import static android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus.CONNECTION_STATUS_TETHERING_TIMEOUT;
+import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_TABLET;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -35,14 +35,15 @@
 import java.util.Arrays;
 
 /**
- * Unit tests for {@link TetherNetworkConnectionStatus}.
+ * Unit tests for {@link HotspotNetworkConnectionStatus}.
  */
 @SmallTest
-public class TetherNetworkConnectionStatusTest {
+public class HotspotNetworkConnectionStatusTest {
     private static final long DEVICE_ID = 11L;
-    private static final DeviceInfo DEVICE_INFO = new DeviceInfo.Builder()
-            .setDeviceType(DEVICE_TYPE_TABLET).setDeviceName("TEST_NAME").setModelName("TEST_MODEL")
-            .setConnectionStrength(2).setBatteryPercentage(50).build();
+    private static final NetworkProviderInfo NETWORK_PROVIDER_INFO =
+            new NetworkProviderInfo.Builder("TEST_NAME", "TEST_MODEL")
+                    .setDeviceType(DEVICE_TYPE_TABLET).setConnectionStrength(2)
+                    .setBatteryPercentage(50).build();
     private static final int NETWORK_TYPE = NETWORK_TYPE_CELLULAR;
     private static final String NETWORK_NAME = "TEST_NETWORK";
     private static final String HOTSPOT_SSID = "TEST_SSID";
@@ -57,7 +58,7 @@
      */
     @Test
     public void testParcelOperation() {
-        TetherNetworkConnectionStatus status = buildConnectionStatusBuilder().build();
+        HotspotNetworkConnectionStatus status = buildConnectionStatusBuilder().build();
 
         Parcel parcelW = Parcel.obtain();
         status.writeToParcel(parcelW, 0);
@@ -67,8 +68,8 @@
         Parcel parcelR = Parcel.obtain();
         parcelR.unmarshall(bytes, 0, bytes.length);
         parcelR.setDataPosition(0);
-        TetherNetworkConnectionStatus fromParcel =
-                TetherNetworkConnectionStatus.CREATOR.createFromParcel(parcelR);
+        HotspotNetworkConnectionStatus fromParcel =
+                HotspotNetworkConnectionStatus.CREATOR.createFromParcel(parcelR);
 
         assertThat(fromParcel).isEqualTo(status);
         assertThat(fromParcel.hashCode()).isEqualTo(status.hashCode());
@@ -79,16 +80,16 @@
      */
     @Test
     public void testEqualsOperation() {
-        TetherNetworkConnectionStatus status1 = buildConnectionStatusBuilder().build();
-        TetherNetworkConnectionStatus status2 = buildConnectionStatusBuilder().build();
+        HotspotNetworkConnectionStatus status1 = buildConnectionStatusBuilder().build();
+        HotspotNetworkConnectionStatus status2 = buildConnectionStatusBuilder().build();
         assertThat(status1).isEqualTo(status2);
 
-        TetherNetworkConnectionStatus.Builder builder = buildConnectionStatusBuilder()
+        HotspotNetworkConnectionStatus.Builder builder = buildConnectionStatusBuilder()
                 .setStatus(CONNECTION_STATUS_TETHERING_TIMEOUT);
         assertThat(builder.build()).isNotEqualTo(status1);
 
         builder = buildConnectionStatusBuilder()
-                .setTetherNetwork(buildTetherNetworkBuilder().setDeviceId(DEVICE_ID_1).build());
+                .setHotspotNetwork(buildHotspotNetworkBuilder().setDeviceId(DEVICE_ID_1).build());
         assertThat(builder.build()).isNotEqualTo(status1);
     }
 
@@ -97,24 +98,24 @@
      */
     @Test
     public void testGetMethods() {
-        TetherNetworkConnectionStatus status = buildConnectionStatusBuilder().build();
+        HotspotNetworkConnectionStatus status = buildConnectionStatusBuilder().build();
         assertThat(status.getStatus()).isEqualTo(CONNECTION_STATUS_ENABLING_HOTSPOT);
-        assertThat(status.getTetherNetwork()).isEqualTo(buildTetherNetworkBuilder().build());
+        assertThat(status.getHotspotNetwork()).isEqualTo(buildHotspotNetworkBuilder().build());
         assertThat(status.getExtras().getInt(BUNDLE_KEY)).isEqualTo(BUNDLE_VALUE);
     }
 
     @Test
     public void testHashCode() {
-        TetherNetworkConnectionStatus status1 = buildConnectionStatusBuilder().build();
-        TetherNetworkConnectionStatus status2 = buildConnectionStatusBuilder().build();
+        HotspotNetworkConnectionStatus status1 = buildConnectionStatusBuilder().build();
+        HotspotNetworkConnectionStatus status2 = buildConnectionStatusBuilder().build();
 
         assertThat(status1.hashCode()).isEqualTo(status2.hashCode());
     }
 
-    private TetherNetworkConnectionStatus.Builder buildConnectionStatusBuilder() {
-        return new TetherNetworkConnectionStatus.Builder()
+    private HotspotNetworkConnectionStatus.Builder buildConnectionStatusBuilder() {
+        return new HotspotNetworkConnectionStatus.Builder()
                 .setStatus(CONNECTION_STATUS_ENABLING_HOTSPOT)
-                .setTetherNetwork(buildTetherNetworkBuilder().build())
+                .setHotspotNetwork(buildHotspotNetworkBuilder().build())
                 .setExtras(buildBundle());
     }
 
@@ -124,11 +125,11 @@
         return bundle;
     }
 
-    private TetherNetwork.Builder buildTetherNetworkBuilder() {
-        TetherNetwork.Builder builder =  new TetherNetwork.Builder()
+    private HotspotNetwork.Builder buildHotspotNetworkBuilder() {
+        HotspotNetwork.Builder builder = new HotspotNetwork.Builder()
                 .setDeviceId(DEVICE_ID)
-                .setDeviceInfo(DEVICE_INFO)
-                .setNetworkType(NETWORK_TYPE)
+                .setNetworkProviderInfo(NETWORK_PROVIDER_INFO)
+                .setHostNetworkType(NETWORK_TYPE)
                 .setNetworkName(NETWORK_NAME)
                 .setHotspotSsid(HOTSPOT_SSID)
                 .setHotspotBssid(HOTSPOT_BSSID);
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/TetherNetworkTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java
similarity index 62%
rename from wifi/tests/src/android/net/wifi/sharedconnectivity/app/TetherNetworkTest.java
rename to wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java
index a50d767..8e396b6 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/TetherNetworkTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/HotspotNetworkTest.java
@@ -19,10 +19,10 @@
 import static android.net.wifi.WifiInfo.SECURITY_TYPE_EAP;
 import static android.net.wifi.WifiInfo.SECURITY_TYPE_PSK;
 import static android.net.wifi.WifiInfo.SECURITY_TYPE_WEP;
-import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_PHONE;
-import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_TABLET;
-import static android.net.wifi.sharedconnectivity.app.TetherNetwork.NETWORK_TYPE_CELLULAR;
-import static android.net.wifi.sharedconnectivity.app.TetherNetwork.NETWORK_TYPE_WIFI;
+import static android.net.wifi.sharedconnectivity.app.HotspotNetwork.NETWORK_TYPE_CELLULAR;
+import static android.net.wifi.sharedconnectivity.app.HotspotNetwork.NETWORK_TYPE_WIFI;
+import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_PHONE;
+import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_TABLET;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -36,14 +36,15 @@
 import java.util.Arrays;
 
 /**
- * Unit tests for {@link TetherNetwork}.
+ * Unit tests for {@link HotspotNetwork}.
  */
 @SmallTest
-public class TetherNetworkTest {
+public class HotspotNetworkTest {
     private static final long DEVICE_ID = 11L;
-    private static final DeviceInfo DEVICE_INFO = new DeviceInfo.Builder()
-            .setDeviceType(DEVICE_TYPE_TABLET).setDeviceName("TEST_NAME").setModelName("TEST_MODEL")
-            .setConnectionStrength(2).setBatteryPercentage(50).build();
+    private static final NetworkProviderInfo NETWORK_PROVIDER_INFO =
+            new NetworkProviderInfo.Builder("TEST_NAME", "TEST_MODEL")
+                    .setDeviceType(DEVICE_TYPE_TABLET).setConnectionStrength(2)
+                    .setBatteryPercentage(50).build();
     private static final int NETWORK_TYPE = NETWORK_TYPE_CELLULAR;
     private static final String NETWORK_NAME = "TEST_NETWORK";
     private static final String HOTSPOT_SSID = "TEST_SSID";
@@ -51,9 +52,10 @@
     private static final int[] HOTSPOT_SECURITY_TYPES = {SECURITY_TYPE_WEP, SECURITY_TYPE_EAP};
 
     private static final long DEVICE_ID_1 = 111L;
-    private static final DeviceInfo DEVICE_INFO_1 = new DeviceInfo.Builder()
-            .setDeviceType(DEVICE_TYPE_PHONE).setDeviceName("TEST_NAME").setModelName("TEST_MODEL")
-            .setConnectionStrength(2).setBatteryPercentage(50).build();
+    private static final NetworkProviderInfo NETWORK_PROVIDER_INFO1 =
+            new NetworkProviderInfo.Builder("TEST_NAME", "TEST_MODEL")
+                    .setDeviceType(DEVICE_TYPE_PHONE).setConnectionStrength(2)
+                    .setBatteryPercentage(50).build();
     private static final int NETWORK_TYPE_1 = NETWORK_TYPE_WIFI;
     private static final String NETWORK_NAME_1 = "TEST_NETWORK1";
     private static final String HOTSPOT_SSID_1 = "TEST_SSID1";
@@ -65,7 +67,7 @@
      */
     @Test
     public void testParcelOperation() {
-        TetherNetwork network = buildTetherNetworkBuilder().build();
+        HotspotNetwork network = buildHotspotNetworkBuilder().build();
 
         Parcel parcelW = Parcel.obtain();
         network.writeToParcel(parcelW, 0);
@@ -75,7 +77,7 @@
         Parcel parcelR = Parcel.obtain();
         parcelR.unmarshall(bytes, 0, bytes.length);
         parcelR.setDataPosition(0);
-        TetherNetwork fromParcel = TetherNetwork.CREATOR.createFromParcel(parcelR);
+        HotspotNetwork fromParcel = HotspotNetwork.CREATOR.createFromParcel(parcelR);
 
         assertThat(fromParcel).isEqualTo(network);
         assertThat(fromParcel.hashCode()).isEqualTo(network.hashCode());
@@ -86,30 +88,30 @@
      */
     @Test
     public void testEqualsOperation() {
-        TetherNetwork network1 = buildTetherNetworkBuilder().build();
-        TetherNetwork network2 = buildTetherNetworkBuilder().build();
+        HotspotNetwork network1 = buildHotspotNetworkBuilder().build();
+        HotspotNetwork network2 = buildHotspotNetworkBuilder().build();
         assertThat(network1).isEqualTo(network2);
 
-        TetherNetwork.Builder builder = buildTetherNetworkBuilder().setDeviceId(DEVICE_ID_1);
+        HotspotNetwork.Builder builder = buildHotspotNetworkBuilder().setDeviceId(DEVICE_ID_1);
         assertThat(builder.build()).isNotEqualTo(network1);
 
-        builder = buildTetherNetworkBuilder().setDeviceInfo(DEVICE_INFO_1);
+        builder = buildHotspotNetworkBuilder().setNetworkProviderInfo(NETWORK_PROVIDER_INFO1);
         assertThat(builder.build()).isNotEqualTo(network1);
 
-        builder = buildTetherNetworkBuilder().setNetworkType(NETWORK_TYPE_1);
+        builder = buildHotspotNetworkBuilder().setHostNetworkType(NETWORK_TYPE_1);
         assertThat(builder.build()).isNotEqualTo(network1);
 
-        builder = buildTetherNetworkBuilder().setNetworkName(NETWORK_NAME_1);
+        builder = buildHotspotNetworkBuilder().setNetworkName(NETWORK_NAME_1);
         assertThat(builder.build()).isNotEqualTo(network1);
 
-        builder = buildTetherNetworkBuilder().setHotspotSsid(HOTSPOT_SSID_1);
+        builder = buildHotspotNetworkBuilder().setHotspotSsid(HOTSPOT_SSID_1);
         assertThat(builder.build()).isNotEqualTo(network1);
 
-        builder = buildTetherNetworkBuilder().setHotspotBssid(HOTSPOT_BSSID_1);
+        builder = buildHotspotNetworkBuilder().setHotspotBssid(HOTSPOT_BSSID_1);
         assertThat(builder.build()).isNotEqualTo(network1);
 
-        builder = buildTetherNetworkBuilder();
-        TetherNetwork.Builder builder1 = buildTetherNetworkBuilder();
+        builder = buildHotspotNetworkBuilder();
+        HotspotNetwork.Builder builder1 = buildHotspotNetworkBuilder();
         Arrays.stream(HOTSPOT_SECURITY_TYPES_1).forEach(builder1::addHotspotSecurityType);
 
         assertThat(builder1.build()).isNotEqualTo(builder.build());
@@ -120,13 +122,13 @@
      */
     @Test
     public void testGetMethods() {
-        TetherNetwork network = buildTetherNetworkBuilder().build();
+        HotspotNetwork network = buildHotspotNetworkBuilder().build();
         ArraySet<Integer> securityTypes = new ArraySet<>();
         Arrays.stream(HOTSPOT_SECURITY_TYPES).forEach(securityTypes::add);
 
         assertThat(network.getDeviceId()).isEqualTo(DEVICE_ID);
-        assertThat(network.getDeviceInfo()).isEqualTo(DEVICE_INFO);
-        assertThat(network.getNetworkType()).isEqualTo(NETWORK_TYPE);
+        assertThat(network.getNetworkProviderInfo()).isEqualTo(NETWORK_PROVIDER_INFO);
+        assertThat(network.getHostNetworkType()).isEqualTo(NETWORK_TYPE);
         assertThat(network.getNetworkName()).isEqualTo(NETWORK_NAME);
         assertThat(network.getHotspotSsid()).isEqualTo(HOTSPOT_SSID);
         assertThat(network.getHotspotBssid()).isEqualTo(HOTSPOT_BSSID);
@@ -135,17 +137,17 @@
 
     @Test
     public void testHashCode() {
-        TetherNetwork network1 = buildTetherNetworkBuilder().build();
-        TetherNetwork network2 = buildTetherNetworkBuilder().build();
+        HotspotNetwork network1 = buildHotspotNetworkBuilder().build();
+        HotspotNetwork network2 = buildHotspotNetworkBuilder().build();
 
         assertThat(network1.hashCode()).isEqualTo(network2.hashCode());
     }
 
-    private TetherNetwork.Builder buildTetherNetworkBuilder() {
-        TetherNetwork.Builder builder =  new TetherNetwork.Builder()
+    private HotspotNetwork.Builder buildHotspotNetworkBuilder() {
+        HotspotNetwork.Builder builder = new HotspotNetwork.Builder()
                 .setDeviceId(DEVICE_ID)
-                .setDeviceInfo(DEVICE_INFO)
-                .setNetworkType(NETWORK_TYPE)
+                .setNetworkProviderInfo(NETWORK_PROVIDER_INFO)
+                .setHostNetworkType(NETWORK_TYPE)
                 .setNetworkName(NETWORK_NAME)
                 .setHotspotSsid(HOTSPOT_SSID)
                 .setHotspotBssid(HOTSPOT_BSSID);
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatusTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatusTest.java
index 8a0f21e..f98a0fc 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatusTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkConnectionStatusTest.java
@@ -17,10 +17,10 @@
 package android.net.wifi.sharedconnectivity.app;
 
 import static android.net.wifi.WifiInfo.SECURITY_TYPE_WEP;
-import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_TABLET;
 import static android.net.wifi.sharedconnectivity.app.KnownNetwork.NETWORK_SOURCE_NEARBY_SELF;
 import static android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus.CONNECTION_STATUS_SAVED;
 import static android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus.CONNECTION_STATUS_SAVE_FAILED;
+import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_TABLET;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -41,9 +41,10 @@
     private static final int NETWORK_SOURCE = NETWORK_SOURCE_NEARBY_SELF;
     private static final String SSID = "TEST_SSID";
     private static final int[] SECURITY_TYPES = {SECURITY_TYPE_WEP};
-    private static final DeviceInfo DEVICE_INFO = new DeviceInfo.Builder()
-            .setDeviceType(DEVICE_TYPE_TABLET).setDeviceName("TEST_NAME").setModelName("TEST_MODEL")
-            .setConnectionStrength(2).setBatteryPercentage(50).build();
+    private static final NetworkProviderInfo NETWORK_PROVIDER_INFO =
+            new NetworkProviderInfo.Builder("TEST_NAME", "TEST_MODEL")
+                    .setDeviceType(DEVICE_TYPE_TABLET).setConnectionStrength(2)
+                    .setBatteryPercentage(50).build();
     private static final String SSID_1 = "TEST_SSID1";
     private static final String BUNDLE_KEY = "INT-KEY";
     private static final int BUNDLE_VALUE = 1;
@@ -121,8 +122,8 @@
     }
 
     private KnownNetwork.Builder buildKnownNetworkBuilder() {
-        KnownNetwork.Builder builder =  new KnownNetwork.Builder().setNetworkSource(NETWORK_SOURCE)
-                .setSsid(SSID).setDeviceInfo(DEVICE_INFO);
+        KnownNetwork.Builder builder = new KnownNetwork.Builder().setNetworkSource(NETWORK_SOURCE)
+                .setSsid(SSID).setNetworkProviderInfo(NETWORK_PROVIDER_INFO);
         Arrays.stream(SECURITY_TYPES).forEach(builder::addSecurityType);
         return builder;
     }
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkTest.java
index 872dd2e..1ecba76 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/KnownNetworkTest.java
@@ -18,10 +18,10 @@
 
 import static android.net.wifi.WifiInfo.SECURITY_TYPE_PSK;
 import static android.net.wifi.WifiInfo.SECURITY_TYPE_WEP;
-import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_PHONE;
-import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_TABLET;
 import static android.net.wifi.sharedconnectivity.app.KnownNetwork.NETWORK_SOURCE_CLOUD_SELF;
 import static android.net.wifi.sharedconnectivity.app.KnownNetwork.NETWORK_SOURCE_NEARBY_SELF;
+import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_PHONE;
+import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_TABLET;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -43,15 +43,17 @@
     private static final int NETWORK_SOURCE = NETWORK_SOURCE_NEARBY_SELF;
     private static final String SSID = "TEST_SSID";
     private static final int[] SECURITY_TYPES = {SECURITY_TYPE_WEP};
-    private static final DeviceInfo DEVICE_INFO = new DeviceInfo.Builder()
-            .setDeviceType(DEVICE_TYPE_TABLET).setDeviceName("TEST_NAME").setModelName("TEST_MODEL")
-            .setConnectionStrength(2).setBatteryPercentage(50).build();
+    private static final NetworkProviderInfo NETWORK_PROVIDER_INFO =
+            new NetworkProviderInfo.Builder("TEST_NAME", "TEST_MODEL")
+                    .setDeviceType(DEVICE_TYPE_TABLET).setConnectionStrength(2)
+                    .setBatteryPercentage(50).build();
     private static final int NETWORK_SOURCE_1 = NETWORK_SOURCE_CLOUD_SELF;
     private static final String SSID_1 = "TEST_SSID1";
     private static final int[] SECURITY_TYPES_1 = {SECURITY_TYPE_PSK};
-    private static final DeviceInfo DEVICE_INFO_1 = new DeviceInfo.Builder()
-            .setDeviceType(DEVICE_TYPE_PHONE).setDeviceName("TEST_NAME_1")
-            .setModelName("TEST_MODEL_1").setConnectionStrength(3).setBatteryPercentage(33).build();
+    private static final NetworkProviderInfo NETWORK_PROVIDER_INFO1 =
+            new NetworkProviderInfo.Builder("TEST_NAME_1", "TEST_MODEL_1")
+                    .setDeviceType(DEVICE_TYPE_PHONE).setConnectionStrength(3)
+                    .setBatteryPercentage(33).build();
 
     /**
      * Verifies parcel serialization/deserialization.
@@ -94,7 +96,7 @@
         Arrays.stream(SECURITY_TYPES_1).forEach(builder::addSecurityType);
         assertThat(builder.build()).isNotEqualTo(network1);
 
-        builder = buildKnownNetworkBuilder().setDeviceInfo(DEVICE_INFO_1);
+        builder = buildKnownNetworkBuilder().setNetworkProviderInfo(NETWORK_PROVIDER_INFO1);
         assertThat(builder.build()).isNotEqualTo(network1);
     }
 
@@ -110,7 +112,7 @@
         assertThat(network.getNetworkSource()).isEqualTo(NETWORK_SOURCE);
         assertThat(network.getSsid()).isEqualTo(SSID);
         assertThat(network.getSecurityTypes()).containsExactlyElementsIn(securityTypes);
-        assertThat(network.getDeviceInfo()).isEqualTo(DEVICE_INFO);
+        assertThat(network.getNetworkProviderInfo()).isEqualTo(NETWORK_PROVIDER_INFO);
     }
 
     @Test
@@ -122,8 +124,8 @@
     }
 
     private KnownNetwork.Builder buildKnownNetworkBuilder() {
-        KnownNetwork.Builder builder =  new KnownNetwork.Builder().setNetworkSource(NETWORK_SOURCE)
-                .setSsid(SSID).setDeviceInfo(DEVICE_INFO);
+        KnownNetwork.Builder builder = new KnownNetwork.Builder().setNetworkSource(NETWORK_SOURCE)
+                .setSsid(SSID).setNetworkProviderInfo(NETWORK_PROVIDER_INFO);
         Arrays.stream(SECURITY_TYPES).forEach(builder::addSecurityType);
         return builder;
     }
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/DeviceInfoTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfoTest.java
similarity index 68%
rename from wifi/tests/src/android/net/wifi/sharedconnectivity/app/DeviceInfoTest.java
rename to wifi/tests/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfoTest.java
index e6595eb..8f35d8d 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/DeviceInfoTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfoTest.java
@@ -16,8 +16,8 @@
 
 package android.net.wifi.sharedconnectivity.app;
 
-import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_LAPTOP;
-import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_PHONE;
+import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_LAPTOP;
+import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_PHONE;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -28,10 +28,10 @@
 import org.junit.Test;
 
 /**
- * Unit tests for {@link DeviceInfo}.
+ * Unit tests for {@link NetworkProviderInfo}.
  */
 @SmallTest
-public class DeviceInfoTest {
+public class NetworkProviderInfoTest {
 
     private static final int DEVICE_TYPE = DEVICE_TYPE_PHONE;
     private static final String DEVICE_NAME = "TEST_NAME";
@@ -50,7 +50,7 @@
      */
     @Test
     public void testParcelOperation() {
-        DeviceInfo info = buildDeviceInfoBuilder().build();
+        NetworkProviderInfo info = buildNetworkProviderInfoBuilder().build();
 
         Parcel parcelW = Parcel.obtain();
         info.writeToParcel(parcelW, 0);
@@ -60,7 +60,7 @@
         Parcel parcelR = Parcel.obtain();
         parcelR.unmarshall(bytes, 0, bytes.length);
         parcelR.setDataPosition(0);
-        DeviceInfo fromParcel = DeviceInfo.CREATOR.createFromParcel(parcelR);
+        NetworkProviderInfo fromParcel = NetworkProviderInfo.CREATOR.createFromParcel(parcelR);
 
         assertThat(fromParcel).isEqualTo(info);
         assertThat(fromParcel.hashCode()).isEqualTo(info.hashCode());
@@ -71,24 +71,25 @@
      */
     @Test
     public void testEqualsOperation() {
-        DeviceInfo info1 = buildDeviceInfoBuilder().build();
-        DeviceInfo info2 = buildDeviceInfoBuilder().build();
+        NetworkProviderInfo info1 = buildNetworkProviderInfoBuilder().build();
+        NetworkProviderInfo info2 = buildNetworkProviderInfoBuilder().build();
         assertThat(info1).isEqualTo(info2);
 
-        DeviceInfo.Builder builder = buildDeviceInfoBuilder().setDeviceType(DEVICE_TYPE_1);
+        NetworkProviderInfo.Builder builder = buildNetworkProviderInfoBuilder().setDeviceType(
+                DEVICE_TYPE_1);
         assertThat(builder.build()).isNotEqualTo(info1);
 
-        builder = buildDeviceInfoBuilder().setDeviceName(DEVICE_NAME_1);
+        builder = buildNetworkProviderInfoBuilder().setDeviceName(DEVICE_NAME_1);
         assertThat(builder.build()).isNotEqualTo(info1);
 
-        builder = buildDeviceInfoBuilder().setModelName(DEVICE_MODEL_1);
+        builder = buildNetworkProviderInfoBuilder().setModelName(DEVICE_MODEL_1);
         assertThat(builder.build()).isNotEqualTo(info1);
 
-        builder = buildDeviceInfoBuilder()
+        builder = buildNetworkProviderInfoBuilder()
                 .setBatteryPercentage(BATTERY_PERCENTAGE_1);
         assertThat(builder.build()).isNotEqualTo(info1);
 
-        builder = buildDeviceInfoBuilder()
+        builder = buildNetworkProviderInfoBuilder()
                 .setConnectionStrength(CONNECTION_STRENGTH_1);
         assertThat(builder.build()).isNotEqualTo(info1);
     }
@@ -98,7 +99,7 @@
      */
     @Test
     public void testGetMethods() {
-        DeviceInfo info = buildDeviceInfoBuilder().build();
+        NetworkProviderInfo info = buildNetworkProviderInfoBuilder().build();
         assertThat(info.getDeviceType()).isEqualTo(DEVICE_TYPE);
         assertThat(info.getDeviceName()).isEqualTo(DEVICE_NAME);
         assertThat(info.getModelName()).isEqualTo(DEVICE_MODEL);
@@ -108,15 +109,15 @@
 
     @Test
     public void testHashCode() {
-        DeviceInfo info1 = buildDeviceInfoBuilder().build();
-        DeviceInfo info2 = buildDeviceInfoBuilder().build();
+        NetworkProviderInfo info1 = buildNetworkProviderInfoBuilder().build();
+        NetworkProviderInfo info2 = buildNetworkProviderInfoBuilder().build();
 
         assertThat(info1.hashCode()).isEqualTo(info2.hashCode());
     }
 
-    private DeviceInfo.Builder buildDeviceInfoBuilder() {
-        return new DeviceInfo.Builder().setDeviceType(DEVICE_TYPE).setDeviceName(DEVICE_NAME)
-                .setModelName(DEVICE_MODEL).setBatteryPercentage(BATTERY_PERCENTAGE)
+    private NetworkProviderInfo.Builder buildNetworkProviderInfoBuilder() {
+        return new NetworkProviderInfo.Builder(DEVICE_NAME, DEVICE_MODEL).setDeviceType(DEVICE_TYPE)
+                .setBatteryPercentage(BATTERY_PERCENTAGE)
                 .setConnectionStrength(CONNECTION_STRENGTH);
     }
 }
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
index 7c0a8b6..8c573e3 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
@@ -18,9 +18,9 @@
 
 import static android.net.wifi.WifiInfo.SECURITY_TYPE_EAP;
 import static android.net.wifi.WifiInfo.SECURITY_TYPE_WEP;
-import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_TABLET;
+import static android.net.wifi.sharedconnectivity.app.HotspotNetwork.NETWORK_TYPE_CELLULAR;
 import static android.net.wifi.sharedconnectivity.app.KnownNetwork.NETWORK_SOURCE_NEARBY_SELF;
-import static android.net.wifi.sharedconnectivity.app.TetherNetwork.NETWORK_TYPE_CELLULAR;
+import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_TABLET;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -56,9 +56,10 @@
 @SmallTest
 public class SharedConnectivityManagerTest {
     private static final long DEVICE_ID = 11L;
-    private static final DeviceInfo DEVICE_INFO = new DeviceInfo.Builder()
-            .setDeviceType(DEVICE_TYPE_TABLET).setDeviceName("TEST_NAME").setModelName("TEST_MODEL")
-            .setConnectionStrength(2).setBatteryPercentage(50).build();
+    private static final NetworkProviderInfo NETWORK_PROVIDER_INFO =
+            new NetworkProviderInfo.Builder("TEST_NAME", "TEST_MODEL")
+                    .setDeviceType(DEVICE_TYPE_TABLET).setConnectionStrength(2)
+                    .setBatteryPercentage(50).build();
     private static final int NETWORK_TYPE = NETWORK_TYPE_CELLULAR;
     private static final String NETWORK_NAME = "TEST_NETWORK";
     private static final String HOTSPOT_SSID = "TEST_SSID";
@@ -72,13 +73,16 @@
     private static final String SERVICE_INTENT_ACTION = "TEST_INTENT_ACTION";
 
 
-    @Mock Context mContext;
+    @Mock
+    Context mContext;
     @Mock
     ISharedConnectivityService mService;
-    @Mock Executor mExecutor;
+    @Mock
+    Executor mExecutor;
     @Mock
     SharedConnectivityClientCallback mClientCallback;
-    @Mock Resources mResources;
+    @Mock
+    Resources mResources;
     @Mock
     ISharedConnectivityService.Stub mIBinder;
 
@@ -284,69 +288,69 @@
     }
 
     /**
-     * Verifies connectTetherNetwork behavior.
+     * Verifies connectHotspotNetwork behavior.
      */
     @Test
-    public void connectTetherNetwork_serviceNotConnected_shouldFail() {
-        TetherNetwork network = buildTetherNetwork();
+    public void connectHotspotNetwork_serviceNotConnected_shouldFail() {
+        HotspotNetwork network = buildHotspotNetwork();
         SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
         manager.setService(null);
 
-        assertThat(manager.connectTetherNetwork(network)).isFalse();
+        assertThat(manager.connectHotspotNetwork(network)).isFalse();
     }
 
     @Test
-    public void connectTetherNetwork() throws RemoteException {
-        TetherNetwork network = buildTetherNetwork();
+    public void connectHotspotNetwork() throws RemoteException {
+        HotspotNetwork network = buildHotspotNetwork();
         SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
         manager.setService(mService);
 
-        manager.connectTetherNetwork(network);
+        manager.connectHotspotNetwork(network);
 
-        verify(mService).connectTetherNetwork(network);
+        verify(mService).connectHotspotNetwork(network);
     }
 
     @Test
-    public void connectTetherNetwork_remoteException_shouldFail() throws RemoteException {
-        TetherNetwork network = buildTetherNetwork();
+    public void connectHotspotNetwork_remoteException_shouldFail() throws RemoteException {
+        HotspotNetwork network = buildHotspotNetwork();
         SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
         manager.setService(mService);
-        doThrow(new RemoteException()).when(mService).connectTetherNetwork(network);
+        doThrow(new RemoteException()).when(mService).connectHotspotNetwork(network);
 
-        assertThat(manager.connectTetherNetwork(network)).isFalse();
+        assertThat(manager.connectHotspotNetwork(network)).isFalse();
     }
 
     /**
-     * Verifies disconnectTetherNetwork behavior.
+     * Verifies disconnectHotspotNetwork behavior.
      */
     @Test
-    public void disconnectTetherNetwork_serviceNotConnected_shouldFail() {
-        TetherNetwork network = buildTetherNetwork();
+    public void disconnectHotspotNetwork_serviceNotConnected_shouldFail() {
+        HotspotNetwork network = buildHotspotNetwork();
         SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
         manager.setService(null);
 
-        assertThat(manager.disconnectTetherNetwork(network)).isFalse();
+        assertThat(manager.disconnectHotspotNetwork(network)).isFalse();
     }
 
     @Test
-    public void disconnectTetherNetwork() throws RemoteException {
-        TetherNetwork network = buildTetherNetwork();
+    public void disconnectHotspotNetwork() throws RemoteException {
+        HotspotNetwork network = buildHotspotNetwork();
         SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
         manager.setService(mService);
 
-        manager.disconnectTetherNetwork(network);
+        manager.disconnectHotspotNetwork(network);
 
-        verify(mService).disconnectTetherNetwork(network);
+        verify(mService).disconnectHotspotNetwork(network);
     }
 
     @Test
-    public void disconnectTetherNetwork_remoteException_shouldFail() throws RemoteException {
-        TetherNetwork network = buildTetherNetwork();
+    public void disconnectHotspotNetwork_remoteException_shouldFail() throws RemoteException {
+        HotspotNetwork network = buildHotspotNetwork();
         SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
         manager.setService(mService);
-        doThrow(new RemoteException()).when(mService).disconnectTetherNetwork(any());
+        doThrow(new RemoteException()).when(mService).disconnectHotspotNetwork(any());
 
-        assertThat(manager.disconnectTetherNetwork(network)).isFalse();
+        assertThat(manager.disconnectHotspotNetwork(network)).isFalse();
     }
 
     /**
@@ -419,7 +423,7 @@
      * Verify getters.
      */
     @Test
-    public void getTetherNetworks_serviceNotConnected_shouldReturnEmptyList() {
+    public void getHotspotNetworks_serviceNotConnected_shouldReturnEmptyList() {
         SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
         manager.setService(null);
 
@@ -427,22 +431,22 @@
     }
 
     @Test
-    public void getTetherNetworks_remoteException_shouldReturnEmptyList() throws RemoteException {
+    public void getHotspotNetworks_remoteException_shouldReturnEmptyList() throws RemoteException {
         SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
         manager.setService(mService);
-        doThrow(new RemoteException()).when(mService).getTetherNetworks();
+        doThrow(new RemoteException()).when(mService).getHotspotNetworks();
 
         assertThat(manager.getKnownNetworks()).isEmpty();
     }
 
     @Test
-    public void getTetherNetworks_shouldReturnNetworksList() throws RemoteException {
+    public void getHotspotNetworks_shouldReturnNetworksList() throws RemoteException {
         SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
-        List<TetherNetwork> networks = List.of(buildTetherNetwork());
+        List<HotspotNetwork> networks = List.of(buildHotspotNetwork());
         manager.setService(mService);
-        when(mService.getTetherNetworks()).thenReturn(networks);
+        when(mService.getHotspotNetworks()).thenReturn(networks);
 
-        assertThat(manager.getTetherNetworks()).containsExactly(buildTetherNetwork());
+        assertThat(manager.getHotspotNetworks()).containsExactly(buildHotspotNetwork());
     }
 
     @Test
@@ -502,35 +506,35 @@
     }
 
     @Test
-    public void getTetherNetworkConnectionStatus_serviceNotConnected_shouldReturnNull()
+    public void getHotspotNetworkConnectionStatus_serviceNotConnected_shouldReturnNull()
             throws RemoteException {
         SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
         manager.setService(null);
 
-        assertThat(manager.getTetherNetworkConnectionStatus()).isNull();
+        assertThat(manager.getHotspotNetworkConnectionStatus()).isNull();
     }
 
     @Test
-    public void getTetherNetworkConnectionStatus_remoteException_shouldReturnNull()
+    public void getHotspotNetworkConnectionStatus_remoteException_shouldReturnNull()
             throws RemoteException {
         SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
         manager.setService(mService);
-        doThrow(new RemoteException()).when(mService).getTetherNetworkConnectionStatus();
+        doThrow(new RemoteException()).when(mService).getHotspotNetworkConnectionStatus();
 
-        assertThat(manager.getTetherNetworkConnectionStatus()).isNull();
+        assertThat(manager.getHotspotNetworkConnectionStatus()).isNull();
     }
 
     @Test
-    public void getTetherNetworkConnectionStatus_serviceConnected_shouldReturnStatus()
+    public void getHotspotNetworkConnectionStatus_serviceConnected_shouldReturnStatus()
             throws RemoteException {
         SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
-        TetherNetworkConnectionStatus status = new TetherNetworkConnectionStatus.Builder()
-                .setStatus(TetherNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT)
+        HotspotNetworkConnectionStatus status = new HotspotNetworkConnectionStatus.Builder()
+                .setStatus(HotspotNetworkConnectionStatus.CONNECTION_STATUS_ENABLING_HOTSPOT)
                 .setExtras(new Bundle()).build();
         manager.setService(mService);
-        when(mService.getTetherNetworkConnectionStatus()).thenReturn(status);
+        when(mService.getHotspotNetworkConnectionStatus()).thenReturn(status);
 
-        assertThat(manager.getTetherNetworkConnectionStatus()).isEqualTo(status);
+        assertThat(manager.getHotspotNetworkConnectionStatus()).isEqualTo(status);
     }
 
     @Test
@@ -571,11 +575,11 @@
                 .thenReturn(SERVICE_PACKAGE_NAME, SERVICE_INTENT_ACTION);
     }
 
-    private TetherNetwork buildTetherNetwork() {
-        TetherNetwork.Builder builder =  new TetherNetwork.Builder()
+    private HotspotNetwork buildHotspotNetwork() {
+        HotspotNetwork.Builder builder = new HotspotNetwork.Builder()
                 .setDeviceId(DEVICE_ID)
-                .setDeviceInfo(DEVICE_INFO)
-                .setNetworkType(NETWORK_TYPE)
+                .setNetworkProviderInfo(NETWORK_PROVIDER_INFO)
+                .setHostNetworkType(NETWORK_TYPE)
                 .setNetworkName(NETWORK_NAME)
                 .setHotspotSsid(HOTSPOT_SSID);
         Arrays.stream(HOTSPOT_SECURITY_TYPES).forEach(builder::addHotspotSecurityType);
@@ -583,8 +587,8 @@
     }
 
     private KnownNetwork buildKnownNetwork() {
-        KnownNetwork.Builder builder =  new KnownNetwork.Builder().setNetworkSource(NETWORK_SOURCE)
-                .setSsid(SSID).setDeviceInfo(DEVICE_INFO);
+        KnownNetwork.Builder builder = new KnownNetwork.Builder().setNetworkSource(NETWORK_SOURCE)
+                .setSsid(SSID).setNetworkProviderInfo(NETWORK_PROVIDER_INFO);
         Arrays.stream(SECURITY_TYPES).forEach(builder::addSecurityType);
         return builder.build();
     }
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java
index 81efa79..19effe5 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java
@@ -18,11 +18,11 @@
 
 import static android.net.wifi.WifiInfo.SECURITY_TYPE_EAP;
 import static android.net.wifi.WifiInfo.SECURITY_TYPE_WEP;
-import static android.net.wifi.sharedconnectivity.app.DeviceInfo.DEVICE_TYPE_TABLET;
+import static android.net.wifi.sharedconnectivity.app.HotspotNetwork.NETWORK_TYPE_CELLULAR;
+import static android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus.CONNECTION_STATUS_UNKNOWN;
 import static android.net.wifi.sharedconnectivity.app.KnownNetwork.NETWORK_SOURCE_NEARBY_SELF;
 import static android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus.CONNECTION_STATUS_SAVED;
-import static android.net.wifi.sharedconnectivity.app.TetherNetwork.NETWORK_TYPE_CELLULAR;
-import static android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus.CONNECTION_STATUS_UNKNOWN;
+import static android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.DEVICE_TYPE_TABLET;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -30,12 +30,12 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.net.wifi.sharedconnectivity.app.DeviceInfo;
+import android.net.wifi.sharedconnectivity.app.HotspotNetwork;
+import android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus;
 import android.net.wifi.sharedconnectivity.app.KnownNetwork;
 import android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus;
+import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo;
 import android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState;
-import android.net.wifi.sharedconnectivity.app.TetherNetwork;
-import android.net.wifi.sharedconnectivity.app.TetherNetworkConnectionStatus;
 import android.os.Bundle;
 import android.os.Looper;
 import android.os.RemoteException;
@@ -55,27 +55,30 @@
  */
 @SmallTest
 public class SharedConnectivityServiceTest {
-    private static final DeviceInfo DEVICE_INFO = new DeviceInfo.Builder()
-            .setDeviceType(DEVICE_TYPE_TABLET).setDeviceName("TEST_NAME").setModelName("TEST_MODEL")
-            .setConnectionStrength(2).setBatteryPercentage(50).build();
-    private static final TetherNetwork TETHER_NETWORK =
-            new TetherNetwork.Builder().setDeviceId(1).setDeviceInfo(DEVICE_INFO)
-                    .setNetworkType(NETWORK_TYPE_CELLULAR).setNetworkName("TEST_NETWORK")
+    private static final NetworkProviderInfo NETWORK_PROVIDER_INFO =
+            new NetworkProviderInfo.Builder("TEST_NAME", "TEST_MODEL")
+                    .setDeviceType(DEVICE_TYPE_TABLET).setConnectionStrength(2)
+                    .setBatteryPercentage(50).build();
+    private static final HotspotNetwork HOTSPOT_NETWORK =
+            new HotspotNetwork.Builder().setDeviceId(1).setNetworkProviderInfo(
+                            NETWORK_PROVIDER_INFO)
+                    .setHostNetworkType(NETWORK_TYPE_CELLULAR).setNetworkName("TEST_NETWORK")
                     .setHotspotSsid("TEST_SSID").setHotspotBssid("TEST_BSSID")
                     .addHotspotSecurityType(SECURITY_TYPE_WEP)
                     .addHotspotSecurityType(SECURITY_TYPE_EAP).build();
-    private static final List<TetherNetwork> TETHER_NETWORKS = List.of(TETHER_NETWORK);
+    private static final List<HotspotNetwork> HOTSPOT_NETWORKS = List.of(HOTSPOT_NETWORK);
     private static final KnownNetwork KNOWN_NETWORK =
             new KnownNetwork.Builder().setNetworkSource(NETWORK_SOURCE_NEARBY_SELF)
                     .setSsid("TEST_SSID").addSecurityType(SECURITY_TYPE_WEP)
-                    .addSecurityType(SECURITY_TYPE_EAP).setDeviceInfo(DEVICE_INFO).build();
+                    .addSecurityType(SECURITY_TYPE_EAP).setNetworkProviderInfo(
+                            NETWORK_PROVIDER_INFO).build();
     private static final List<KnownNetwork> KNOWN_NETWORKS = List.of(KNOWN_NETWORK);
     private static final SharedConnectivitySettingsState SETTINGS_STATE =
             new SharedConnectivitySettingsState.Builder().setInstantTetherEnabled(true)
                     .setExtras(Bundle.EMPTY).build();
-    private static final TetherNetworkConnectionStatus TETHER_NETWORK_CONNECTION_STATUS =
-            new TetherNetworkConnectionStatus.Builder().setStatus(CONNECTION_STATUS_UNKNOWN)
-                    .setTetherNetwork(TETHER_NETWORK).setExtras(Bundle.EMPTY).build();
+    private static final HotspotNetworkConnectionStatus TETHER_NETWORK_CONNECTION_STATUS =
+            new HotspotNetworkConnectionStatus.Builder().setStatus(CONNECTION_STATUS_UNKNOWN)
+                    .setHotspotNetwork(HOTSPOT_NETWORK).setExtras(Bundle.EMPTY).build();
     private static final KnownNetworkConnectionStatus KNOWN_NETWORK_CONNECTION_STATUS =
             new KnownNetworkConnectionStatus.Builder().setStatus(CONNECTION_STATUS_SAVED)
                     .setKnownNetwork(KNOWN_NETWORK).setExtras(Bundle.EMPTY).build();
@@ -89,16 +92,20 @@
         }
 
         @Override
-        public void onConnectTetherNetwork(@NonNull TetherNetwork network) {}
+        public void onConnectHotspotNetwork(@NonNull HotspotNetwork network) {
+        }
 
         @Override
-        public void onDisconnectTetherNetwork(@NonNull TetherNetwork network) {}
+        public void onDisconnectHotspotNetwork(@NonNull HotspotNetwork network) {
+        }
 
         @Override
-        public void onConnectKnownNetwork(@NonNull KnownNetwork network) {}
+        public void onConnectKnownNetwork(@NonNull KnownNetwork network) {
+        }
 
         @Override
-        public void onForgetKnownNetwork(@NonNull KnownNetwork network) {}
+        public void onForgetKnownNetwork(@NonNull KnownNetwork network) {
+        }
     }
 
     @Before
@@ -115,15 +122,15 @@
     }
 
     @Test
-    public void getTetherNetworks() throws RemoteException {
+    public void getHotspotNetworks() throws RemoteException {
         SharedConnectivityService service = createService();
         ISharedConnectivityService.Stub binder =
                 (ISharedConnectivityService.Stub) service.onBind(new Intent());
 
-        service.setTetherNetworks(TETHER_NETWORKS);
+        service.setHotspotNetworks(HOTSPOT_NETWORKS);
 
-        assertThat(binder.getTetherNetworks())
-                .containsExactlyElementsIn(List.copyOf(TETHER_NETWORKS));
+        assertThat(binder.getHotspotNetworks())
+                .containsExactlyElementsIn(List.copyOf(HOTSPOT_NETWORKS));
     }
 
     @Test
@@ -150,14 +157,14 @@
     }
 
     @Test
-    public void updateTetherNetworkConnectionStatus() throws RemoteException {
+    public void updateHotspotNetworkConnectionStatus() throws RemoteException {
         SharedConnectivityService service = createService();
         ISharedConnectivityService.Stub binder =
                 (ISharedConnectivityService.Stub) service.onBind(new Intent());
 
-        service.updateTetherNetworkConnectionStatus(TETHER_NETWORK_CONNECTION_STATUS);
+        service.updateHotspotNetworkConnectionStatus(TETHER_NETWORK_CONNECTION_STATUS);
 
-        assertThat(binder.getTetherNetworkConnectionStatus())
+        assertThat(binder.getHotspotNetworkConnectionStatus())
                 .isEqualTo(TETHER_NETWORK_CONNECTION_STATUS);
     }