Merge changes from topic "b221419865" into tm-dev

* changes:
  Change Logcat to only log in background thread in debug mode
  Move logging to background thread in LogBuffer
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index aad8f9d..9e13133 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1895,11 +1895,14 @@
             // The job ran past its expected run window. Have it count towards the current window
             // and schedule a new job for the next window.
             if (DEBUG) {
-                Slog.i(TAG, "Periodic job ran after its intended window.");
+                Slog.i(TAG, "Periodic job ran after its intended window by " + diffMs + " ms");
             }
             long numSkippedWindows = (diffMs / period) + 1; // +1 to include original window
-            if (period != flex && diffMs > Math.min(PERIODIC_JOB_WINDOW_BUFFER,
-                    (period - flex) / 2)) {
+            // Determine how far into a single period the job ran, and determine if it's too close
+            // to the start of the next period. If the difference between the start of the execution
+            // window and the previous execution time inside of the period is less than the
+            // threshold, then we say that the job ran too close to the next period.
+            if (period != flex && (period - flex - (diffMs % period)) <= flex / 6) {
                 if (DEBUG) {
                     Slog.d(TAG, "Custom flex job ran too close to next window.");
                 }
diff --git a/core/api/current.txt b/core/api/current.txt
index 2a6536e..e260ad0 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -335,15 +335,15 @@
     field public static final int allowClearUserData = 16842757; // 0x1010005
     field public static final int allowClickWhenDisabled = 16844312; // 0x1010618
     field public static final int allowEmbedded = 16843765; // 0x10103f5
-    field public static final int allowGameAngleDriver;
-    field public static final int allowGameDownscaling;
-    field public static final int allowGameFpsOverride;
+    field public static final int allowGameAngleDriver = 16844376; // 0x1010658
+    field public static final int allowGameDownscaling = 16844377; // 0x1010659
+    field public static final int allowGameFpsOverride = 16844378; // 0x101065a
     field public static final int allowNativeHeapPointerTagging = 16844306; // 0x1010612
     field public static final int allowParallelSyncs = 16843570; // 0x1010332
     field public static final int allowSingleTap = 16843353; // 0x1010259
     field public static final int allowTaskReparenting = 16843268; // 0x1010204
     field public static final int allowUndo = 16843999; // 0x10104df
-    field public static final int allowUntrustedActivityEmbedding;
+    field public static final int allowUntrustedActivityEmbedding = 16844393; // 0x1010669
     field public static final int alpha = 16843551; // 0x101031f
     field public static final int alphabeticModifiers = 16844110; // 0x101054e
     field public static final int alphabeticShortcut = 16843235; // 0x10101e3
@@ -374,7 +374,7 @@
     field public static final int authorities = 16842776; // 0x1010018
     field public static final int autoAdvanceViewId = 16843535; // 0x101030f
     field public static final int autoCompleteTextViewStyle = 16842859; // 0x101006b
-    field public static final int autoHandwritingEnabled;
+    field public static final int autoHandwritingEnabled = 16844382; // 0x101065e
     field public static final int autoLink = 16842928; // 0x10100b0
     field public static final int autoMirrored = 16843754; // 0x10103ea
     field public static final int autoRemoveFromRecents = 16843847; // 0x1010447
@@ -390,7 +390,7 @@
     field public static final int autoVerify = 16844014; // 0x10104ee
     field public static final int autofillHints = 16844118; // 0x1010556
     field public static final int autofilledHighlight = 16844136; // 0x1010568
-    field public static final int backdropColor;
+    field public static final int backdropColor = 16844402; // 0x1010672
     field public static final int background = 16842964; // 0x10100d4
     field public static final int backgroundDimAmount = 16842802; // 0x1010032
     field public static final int backgroundDimEnabled = 16843295; // 0x101021f
@@ -437,7 +437,7 @@
     field public static final int calendarViewShown = 16843596; // 0x101034c
     field public static final int calendarViewStyle = 16843613; // 0x101035d
     field public static final int canControlMagnification = 16844039; // 0x1010507
-    field public static final int canDisplayOnRemoteDevices;
+    field public static final int canDisplayOnRemoteDevices = 16844368; // 0x1010650
     field public static final int canPauseRecording = 16844314; // 0x101061a
     field public static final int canPerformGestures = 16844045; // 0x101050d
     field public static final int canRecord = 16844060; // 0x101051c
@@ -632,7 +632,7 @@
     field public static final int elevation = 16843840; // 0x1010440
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
-    field public static final int enableOnBackInvokedCallback;
+    field public static final int enableOnBackInvokedCallback = 16844396; // 0x101066c
     field public static final int enableVrMode = 16844069; // 0x1010525
     field public static final int enabled = 16842766; // 0x101000e
     field public static final int end = 16843996; // 0x10104dc
@@ -744,10 +744,10 @@
     field public static final int freezesText = 16843116; // 0x101016c
     field public static final int fromAlpha = 16843210; // 0x10101ca
     field public static final int fromDegrees = 16843187; // 0x10101b3
-    field public static final int fromExtendBottom;
-    field public static final int fromExtendLeft;
-    field public static final int fromExtendRight;
-    field public static final int fromExtendTop;
+    field public static final int fromExtendBottom = 16844386; // 0x1010662
+    field public static final int fromExtendLeft = 16844383; // 0x101065f
+    field public static final int fromExtendRight = 16844385; // 0x1010661
+    field public static final int fromExtendTop = 16844384; // 0x1010660
     field public static final int fromId = 16843850; // 0x101044a
     field public static final int fromScene = 16843741; // 0x10103dd
     field public static final int fromXDelta = 16843206; // 0x10101c6
@@ -867,7 +867,7 @@
     field public static final int installLocation = 16843447; // 0x10102b7
     field public static final int interactiveUiTimeout = 16844181; // 0x1010595
     field public static final int interpolator = 16843073; // 0x1010141
-    field public static final int intro;
+    field public static final int intro = 16844395; // 0x101066b
     field public static final int isAccessibilityTool = 16844353; // 0x1010641
     field public static final int isAlwaysSyncable = 16843571; // 0x1010333
     field public static final int isAsciiCapable = 16843753; // 0x10103e9
@@ -910,7 +910,7 @@
     field public static final int keyboardNavigationCluster = 16844096; // 0x1010540
     field public static final int keycode = 16842949; // 0x10100c5
     field public static final int killAfterRestore = 16843420; // 0x101029c
-    field public static final int knownActivityEmbeddingCerts;
+    field public static final int knownActivityEmbeddingCerts = 16844394; // 0x101066a
     field public static final int knownCerts = 16844330; // 0x101062a
     field public static final int lStar = 16844359; // 0x1010647
     field public static final int label = 16842753; // 0x1010001
@@ -978,8 +978,8 @@
     field public static final int left = 16843181; // 0x10101ad
     field public static final int letterSpacing = 16843958; // 0x10104b6
     field public static final int level = 16844032; // 0x1010500
-    field public static final int lineBreakStyle;
-    field public static final int lineBreakWordStyle;
+    field public static final int lineBreakStyle = 16844398; // 0x101066e
+    field public static final int lineBreakWordStyle = 16844399; // 0x101066f
     field public static final int lineHeight = 16844159; // 0x101057f
     field public static final int lineSpacingExtra = 16843287; // 0x1010217
     field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
@@ -1003,7 +1003,7 @@
     field public static final int listSeparatorTextViewStyle = 16843272; // 0x1010208
     field public static final int listViewStyle = 16842868; // 0x1010074
     field public static final int listViewWhiteStyle = 16842869; // 0x1010075
-    field public static final int localeConfig;
+    field public static final int localeConfig = 16844379; // 0x101065b
     field public static final int lockTaskMode = 16844013; // 0x10104ed
     field public static final int logo = 16843454; // 0x10102be
     field public static final int logoDescription = 16844009; // 0x10104e9
@@ -1162,7 +1162,7 @@
     field public static final int popupWindowStyle = 16842870; // 0x1010076
     field public static final int port = 16842793; // 0x1010029
     field public static final int positiveButtonText = 16843253; // 0x10101f5
-    field public static final int preferKeepClear;
+    field public static final int preferKeepClear = 16844381; // 0x101065d
     field public static final int preferMinimalPostProcessing = 16844300; // 0x101060c
     field public static final int preferenceCategoryStyle = 16842892; // 0x101008c
     field public static final int preferenceFragmentStyle = 16844038; // 0x1010506
@@ -1238,10 +1238,10 @@
     field public static final int requiredFeature = 16844116; // 0x1010554
     field public static final int requiredForAllUsers = 16843728; // 0x10103d0
     field public static final int requiredNotFeature = 16844117; // 0x1010555
-    field public static final int requiredSplitTypes;
+    field public static final int requiredSplitTypes = 16844366; // 0x101064e
     field public static final int requiresFadingEdge = 16843685; // 0x10103a5
     field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
-    field public static final int resetEnabledSettingsOnAppDataCleared;
+    field public static final int resetEnabledSettingsOnAppDataCleared = 16844370; // 0x1010652
     field public static final int resizeClip = 16843983; // 0x10104cf
     field public static final int resizeMode = 16843619; // 0x1010363
     field public static final int resizeable = 16843405; // 0x101028d
@@ -1337,7 +1337,7 @@
     field public static final int shareInterpolator = 16843195; // 0x10101bb
     field @Deprecated public static final int sharedUserId = 16842763; // 0x101000b
     field @Deprecated public static final int sharedUserLabel = 16843361; // 0x1010261
-    field public static final int sharedUserMaxSdkVersion;
+    field public static final int sharedUserMaxSdkVersion = 16844365; // 0x101064d
     field public static final int shell = 16844180; // 0x1010594
     field public static final int shortcutDisabledMessage = 16844075; // 0x101052b
     field public static final int shortcutId = 16844072; // 0x1010528
@@ -1346,8 +1346,8 @@
     field public static final int shouldDisableView = 16843246; // 0x10101ee
     field public static final int shouldUseDefaultUnfoldTransition = 16844364; // 0x101064c
     field public static final int showAsAction = 16843481; // 0x10102d9
-    field public static final int showBackdrop;
-    field public static final int showClockAndComplications;
+    field public static final int showBackdrop = 16844380; // 0x101065c
+    field public static final int showClockAndComplications = 16844372; // 0x1010654
     field public static final int showDefault = 16843258; // 0x10101fa
     field public static final int showDividers = 16843561; // 0x1010329
     field public static final int showForAllUsers = 16844015; // 0x10104ef
@@ -1378,7 +1378,7 @@
     field public static final int splitMotionEvents = 16843503; // 0x10102ef
     field public static final int splitName = 16844105; // 0x1010549
     field public static final int splitTrack = 16843852; // 0x101044c
-    field public static final int splitTypes;
+    field public static final int splitTypes = 16844367; // 0x101064f
     field public static final int spotShadowAlpha = 16843967; // 0x10104bf
     field public static final int src = 16843033; // 0x1010119
     field public static final int ssp = 16843747; // 0x10103e3
@@ -1449,18 +1449,18 @@
     field public static final int summaryColumn = 16843426; // 0x10102a2
     field public static final int summaryOff = 16843248; // 0x10101f0
     field public static final int summaryOn = 16843247; // 0x10101ef
-    field public static final int supportedTypes;
+    field public static final int supportedTypes = 16844369; // 0x1010651
     field public static final int supportsAssist = 16844016; // 0x10104f0
-    field public static final int supportsBatteryGameMode;
+    field public static final int supportsBatteryGameMode = 16844374; // 0x1010656
     field public static final int supportsInlineSuggestions = 16844301; // 0x101060d
-    field public static final int supportsInlineSuggestionsWithTouchExploration;
+    field public static final int supportsInlineSuggestionsWithTouchExploration = 16844397; // 0x101066d
     field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
     field public static final int supportsLocalInteraction = 16844047; // 0x101050f
     field public static final int supportsMultipleDisplays = 16844182; // 0x1010596
-    field public static final int supportsPerformanceGameMode;
+    field public static final int supportsPerformanceGameMode = 16844375; // 0x1010657
     field public static final int supportsPictureInPicture = 16844023; // 0x10104f7
     field public static final int supportsRtl = 16843695; // 0x10103af
-    field public static final int supportsStylusHandwriting;
+    field public static final int supportsStylusHandwriting = 16844371; // 0x1010653
     field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
     field public static final int supportsUploading = 16843419; // 0x101029b
     field public static final int suppressesSpellChecker = 16844355; // 0x1010643
@@ -1579,7 +1579,7 @@
     field public static final int tileMode = 16843265; // 0x1010201
     field public static final int tileModeX = 16843895; // 0x1010477
     field public static final int tileModeY = 16843896; // 0x1010478
-    field public static final int tileService;
+    field public static final int tileService = 16844391; // 0x1010667
     field public static final int timePickerDialogTheme = 16843934; // 0x101049e
     field public static final int timePickerMode = 16843956; // 0x10104b4
     field public static final int timePickerStyle = 16843933; // 0x101049d
@@ -1598,10 +1598,10 @@
     field public static final int titleTextStyle = 16843512; // 0x10102f8
     field public static final int toAlpha = 16843211; // 0x10101cb
     field public static final int toDegrees = 16843188; // 0x10101b4
-    field public static final int toExtendBottom;
-    field public static final int toExtendLeft;
-    field public static final int toExtendRight;
-    field public static final int toExtendTop;
+    field public static final int toExtendBottom = 16844390; // 0x1010666
+    field public static final int toExtendLeft = 16844387; // 0x1010663
+    field public static final int toExtendRight = 16844389; // 0x1010665
+    field public static final int toExtendTop = 16844388; // 0x1010664
     field public static final int toId = 16843849; // 0x1010449
     field public static final int toScene = 16843742; // 0x10103de
     field public static final int toXDelta = 16843207; // 0x10101c7
@@ -1753,7 +1753,7 @@
     field public static final int windowSplashScreenAnimatedIcon = 16844333; // 0x101062d
     field @Deprecated public static final int windowSplashScreenAnimationDuration = 16844334; // 0x101062e
     field public static final int windowSplashScreenBackground = 16844332; // 0x101062c
-    field public static final int windowSplashScreenBehavior;
+    field public static final int windowSplashScreenBehavior = 16844392; // 0x1010668
     field public static final int windowSplashScreenBrandingImage = 16844335; // 0x101062f
     field public static final int windowSplashScreenIconBackgroundColor = 16844336; // 0x1010630
     field @Deprecated public static final int windowSplashscreenContent = 16844132; // 0x1010564
@@ -2092,7 +2092,7 @@
     field public static final int accessibilityActionScrollUp = 16908344; // 0x1020038
     field public static final int accessibilityActionSetProgress = 16908349; // 0x102003d
     field public static final int accessibilityActionShowOnScreen = 16908342; // 0x1020036
-    field public static final int accessibilityActionShowTextSuggestions;
+    field public static final int accessibilityActionShowTextSuggestions = 16908376; // 0x1020058
     field public static final int accessibilityActionShowTooltip = 16908356; // 0x1020044
     field public static final int accessibilitySystemActionBack = 16908363; // 0x102004b
     field public static final int accessibilitySystemActionHome = 16908364; // 0x102004c
@@ -2128,8 +2128,8 @@
     field public static final int icon_frame = 16908350; // 0x102003e
     field public static final int input = 16908297; // 0x1020009
     field public static final int inputArea = 16908318; // 0x102001e
-    field public static final int inputExtractAccessories;
-    field public static final int inputExtractAction;
+    field public static final int inputExtractAccessories = 16908378; // 0x102005a
+    field public static final int inputExtractAction = 16908377; // 0x1020059
     field public static final int inputExtractEditText = 16908325; // 0x1020025
     field @Deprecated public static final int keyboardView = 16908326; // 0x1020026
     field public static final int list = 16908298; // 0x102000a
@@ -2301,7 +2301,7 @@
     field public static final int TextAppearance = 16973886; // 0x103003e
     field public static final int TextAppearance_DeviceDefault = 16974253; // 0x10301ad
     field public static final int TextAppearance_DeviceDefault_DialogWindowTitle = 16974264; // 0x10301b8
-    field public static final int TextAppearance_DeviceDefault_Headline;
+    field public static final int TextAppearance_DeviceDefault_Headline = 16974565; // 0x10302e5
     field public static final int TextAppearance_DeviceDefault_Inverse = 16974254; // 0x10301ae
     field public static final int TextAppearance_DeviceDefault_Large = 16974255; // 0x10301af
     field public static final int TextAppearance_DeviceDefault_Large_Inverse = 16974256; // 0x10301b0
@@ -30977,7 +30977,7 @@
     field public static final int R = 30; // 0x1e
     field public static final int S = 31; // 0x1f
     field public static final int S_V2 = 32; // 0x20
-    field public static final int TIRAMISU = 10000; // 0x2710
+    field public static final int TIRAMISU = 33; // 0x21
   }
 
   public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 66af50c..b25d1e3 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -367,12 +367,12 @@
 
   public static final class R.array {
     field public static final int config_keySystemUuidMapping = 17235973; // 0x1070005
-    field public static final int config_optionalIpSecAlgorithms;
+    field public static final int config_optionalIpSecAlgorithms = 17235974; // 0x1070006
   }
 
   public static final class R.attr {
     field public static final int allowClearUserDataOnFailedRestore = 16844288; // 0x1010600
-    field public static final int gameSessionService;
+    field public static final int gameSessionService = 16844373; // 0x1010655
     field public static final int hotwordDetectionService = 16844326; // 0x1010626
     field public static final int isVrOnly = 16844152; // 0x1010578
     field public static final int minExtensionVersion = 16844305; // 0x1010611
@@ -385,7 +385,7 @@
   }
 
   public static final class R.bool {
-    field public static final int config_enableQrCodeScannerOnLockScreen;
+    field public static final int config_enableQrCodeScannerOnLockScreen = 17891336; // 0x1110008
     field public static final int config_sendPackageName = 17891328; // 0x1110000
     field public static final int config_showDefaultAssistant = 17891329; // 0x1110001
     field public static final int config_showDefaultEmergency = 17891330; // 0x1110002
@@ -402,7 +402,7 @@
 
   public static final class R.drawable {
     field public static final int ic_info = 17301684; // 0x10800b4
-    field public static final int ic_safety_protection;
+    field public static final int ic_safety_protection = 17301685; // 0x10800b5
   }
 
   public static final class R.raw {
@@ -414,13 +414,13 @@
     field public static final int config_customMediaKeyDispatcher = 17039404; // 0x104002c
     field public static final int config_customMediaSessionPolicyProvider = 17039405; // 0x104002d
     field public static final int config_defaultAssistant = 17039393; // 0x1040021
-    field public static final int config_defaultAutomotiveNavigation;
+    field public static final int config_defaultAutomotiveNavigation = 17039424; // 0x1040040
     field public static final int config_defaultBrowser = 17039394; // 0x1040022
     field public static final int config_defaultCallRedirection = 17039397; // 0x1040025
     field public static final int config_defaultCallScreening = 17039398; // 0x1040026
     field public static final int config_defaultDialer = 17039395; // 0x1040023
     field public static final int config_defaultSms = 17039396; // 0x1040024
-    field public static final int config_devicePolicyManagement;
+    field public static final int config_devicePolicyManagement = 17039421; // 0x104003d
     field public static final int config_feedbackIntentExtraKey = 17039391; // 0x104001f
     field public static final int config_feedbackIntentNameKey = 17039392; // 0x1040020
     field public static final int config_helpIntentExtraKey = 17039389; // 0x104001d
@@ -429,19 +429,19 @@
     field public static final int config_helpPackageNameValue = 17039388; // 0x104001c
     field public static final int config_systemActivityRecognizer = 17039416; // 0x1040038
     field public static final int config_systemAmbientAudioIntelligence = 17039411; // 0x1040033
-    field public static final int config_systemAppProtectionService;
+    field public static final int config_systemAppProtectionService = 17039422; // 0x104003e
     field public static final int config_systemAudioIntelligence = 17039412; // 0x1040034
-    field public static final int config_systemAutomotiveCalendarSyncManager;
+    field public static final int config_systemAutomotiveCalendarSyncManager = 17039423; // 0x104003f
     field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028
     field public static final int config_systemAutomotiveProjection = 17039401; // 0x1040029
     field public static final int config_systemCompanionDeviceProvider = 17039417; // 0x1040039
     field public static final int config_systemContacts = 17039403; // 0x104002b
     field public static final int config_systemGallery = 17039399; // 0x1040027
     field public static final int config_systemNotificationIntelligence = 17039413; // 0x1040035
-    field public static final int config_systemSettingsIntelligence;
+    field public static final int config_systemSettingsIntelligence = 17039426; // 0x1040042
     field public static final int config_systemShell = 17039402; // 0x104002a
     field public static final int config_systemSpeechRecognizer = 17039406; // 0x104002e
-    field public static final int config_systemSupervision;
+    field public static final int config_systemSupervision = 17039420; // 0x104003c
     field public static final int config_systemTelevisionNotificationHandler = 17039409; // 0x1040031
     field public static final int config_systemTextIntelligence = 17039414; // 0x1040036
     field public static final int config_systemUi = 17039418; // 0x104003a
@@ -449,7 +449,7 @@
     field public static final int config_systemVisualIntelligence = 17039415; // 0x1040037
     field public static final int config_systemWellbeing = 17039408; // 0x1040030
     field public static final int config_systemWifiCoexManager = 17039407; // 0x104002f
-    field public static final int safety_protection_display_text;
+    field public static final int safety_protection_display_text = 17039425; // 0x1040041
   }
 
   public static final class R.style {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 27f5b92..f4a12a5 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -63,14 +63,14 @@
   public static final class R.bool {
     field public static final int config_assistantOnTopOfDream = 17891333; // 0x1110005
     field public static final int config_perDisplayFocusEnabled = 17891332; // 0x1110004
-    field public static final int config_preventImeStartupUnlessTextEditor;
+    field public static final int config_preventImeStartupUnlessTextEditor = 17891335; // 0x1110007
     field public static final int config_remoteInsetsControllerControlsSystemBars = 17891334; // 0x1110006
   }
 
   public static final class R.string {
     field public static final int config_defaultAssistant = 17039393; // 0x1040021
     field public static final int config_defaultDialer = 17039395; // 0x1040023
-    field public static final int config_systemAutomotiveCalendarSyncManager;
+    field public static final int config_systemAutomotiveCalendarSyncManager = 17039423; // 0x104003f
     field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028
     field public static final int config_systemAutomotiveProjection = 17039401; // 0x1040029
     field public static final int config_systemGallery = 17039399; // 0x1040027
diff --git a/core/java/android/accessibilityservice/InputMethod.java b/core/java/android/accessibilityservice/InputMethod.java
index c0e5e84..a393604 100644
--- a/core/java/android/accessibilityservice/InputMethod.java
+++ b/core/java/android/accessibilityservice/InputMethod.java
@@ -624,7 +624,6 @@
         @Override
         public void invalidateInputInternal(EditorInfo editorInfo, IInputContext inputContext,
                 int sessionId) {
-            // TODO(b/217788708): Add automated test.
             if (mStartedInputConnection instanceof RemoteInputConnection) {
                 final RemoteInputConnection ric =
                         (RemoteInputConnection) mStartedInputConnection;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6bb35db..bfb1168 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -628,6 +628,9 @@
      * Bit to be bitwise-ored into the {@link #flags} field that should be
      * set if you would only like the sound, vibrate and ticker to be played
      * if the notification was not already showing.
+     *
+     * Note that using this flag will stop any ongoing alerting behaviour such
+     * as sound, vibration or blinking notification LED.
      */
     public static final int FLAG_ONLY_ALERT_ONCE    = 0x00000008;
 
@@ -4633,6 +4636,9 @@
          * Set this flag if you would only like the sound, vibrate
          * and ticker to be played if the notification is not already showing.
          *
+         * Note that using this flag will stop any ongoing alerting behaviour such
+         * as sound, vibration or blinking notification LED.
+         *
          * @see Notification#FLAG_ONLY_ALERT_ONCE
          */
         @NonNull
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index f5cf73b..d11b23c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2542,7 +2542,7 @@
      * that has this delegation. If another app already had delegated security logging access, it
      * will lose the delegation when a new app is delegated.
      *
-     * <p> Can only be granted by Device Owner or Profile Owner of an organnization owned and
+     * <p> Can only be granted by Device Owner or Profile Owner of an organization-owned
      * managed profile.
      */
     public static final String DELEGATION_SECURITY_LOGGING = "delegation-security-logging";
diff --git a/core/java/android/hardware/CameraSessionStats.java b/core/java/android/hardware/CameraSessionStats.java
index 698cc76..9ef6306 100644
--- a/core/java/android/hardware/CameraSessionStats.java
+++ b/core/java/android/hardware/CameraSessionStats.java
@@ -61,6 +61,7 @@
     private boolean mDeviceError;
     private float mMaxPreviewFps;
     private ArrayList<CameraStreamStats> mStreamStats;
+    private String mUserTag;
 
     public CameraSessionStats() {
         mFacing = -1;
@@ -131,6 +132,7 @@
         dest.writeLong(mResultErrorCount);
         dest.writeBoolean(mDeviceError);
         dest.writeTypedList(mStreamStats);
+        dest.writeString(mUserTag);
     }
 
     public void readFromParcel(Parcel in) {
@@ -151,6 +153,8 @@
         ArrayList<CameraStreamStats> streamStats = new ArrayList<CameraStreamStats>();
         in.readTypedList(streamStats, CameraStreamStats.CREATOR);
         mStreamStats = streamStats;
+
+        mUserTag = in.readString();
     }
 
     public String getCameraId() {
@@ -208,4 +212,8 @@
     public List<CameraStreamStats> getStreamStats() {
         return mStreamStats;
     }
+
+    public String getUserTag() {
+        return mUserTag;
+    }
 }
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 9884c38..15e59e0 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -266,6 +266,8 @@
 
     private int mRequestType = -1;
 
+    private static final String SET_TAG_STRING_PREFIX =
+            "android.hardware.camera2.CaptureRequest.setTag.";
     /**
      * Get the type of the capture request
      *
@@ -614,6 +616,11 @@
                 throw new RuntimeException("Reading cached CaptureRequest is not supported");
             }
         }
+
+        boolean hasUserTagStr = (in.readInt() == 1) ? true : false;
+        if (hasUserTagStr) {
+            mUserTag = in.readString();
+        }
     }
 
     @Override
@@ -656,6 +663,19 @@
                 dest.writeInt(0);
             }
         }
+
+        // Write string for user tag if set to something in the same namespace
+        if (mUserTag != null) {
+            String userTagStr = mUserTag.toString();
+            if (userTagStr != null && userTagStr.startsWith(SET_TAG_STRING_PREFIX)) {
+                dest.writeInt(1);
+                dest.writeString(userTagStr.substring(SET_TAG_STRING_PREFIX.length()));
+            } else {
+                dest.writeInt(0);
+            }
+        } else {
+            dest.writeInt(0);
+        }
     }
 
     /**
@@ -938,7 +958,10 @@
          * <p>This tag is not used for anything by the camera device, but can be
          * used by an application to easily identify a CaptureRequest when it is
          * returned by
-         * {@link CameraCaptureSession.CaptureCallback#onCaptureCompleted CaptureCallback.onCaptureCompleted}
+         * {@link CameraCaptureSession.CaptureCallback#onCaptureCompleted CaptureCallback.onCaptureCompleted}.</p>
+         *
+         * <p>If the application overrides the tag object's {@link Object#toString} function, the
+         * returned string must not contain personal identifiable information.</p>
          *
          * @param tag an arbitrary Object to store with this request
          * @see CaptureRequest#getTag
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 4fdd534..6ece5ef 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -101,6 +101,7 @@
 import android.view.Choreographer;
 import android.view.Gravity;
 import android.view.InputChannel;
+import android.view.InputDevice;
 import android.view.InputEventReceiver;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
@@ -134,7 +135,10 @@
 import android.widget.ImageButton;
 import android.widget.LinearLayout;
 import android.widget.TextView;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
 import android.window.WindowMetricsHelper;
+import android.window.WindowOnBackInvokedDispatcher;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.inputmethod.IInputContentUriToken;
@@ -345,6 +349,9 @@
      **/
     private RingBuffer<MotionEvent> mPendingEvents;
 
+    /** Callback to handle back invocation when IME window is shown. */
+    private OnBackInvokedCallback mBackCallback;
+
     /**
      * Returns whether {@link InputMethodService} is responsible for rendering the back button and
      * the IME switcher button or not when the gestural navigation is enabled.
@@ -1605,6 +1612,7 @@
     @Override public void onDestroy() {
         mDestroyed = true;
         super.onDestroy();
+        unregisterOnBackInvokedCallback();
         mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
                 mInsetsComputer);
         doFinishInput();
@@ -2579,6 +2587,7 @@
         cancelImeSurfaceRemoval();
         mInShowWindow = false;
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+        registerOnBackInvokedCallback();
     }
 
 
@@ -2625,6 +2634,56 @@
     }
 
     /**
+     * Registers an {@link OnBackInvokedCallback} to handle back invocation when ahead-of-time
+     *  back dispatching is enabled. We keep the KEYCODE_BACK based legacy code around to handle
+     *  back on older devices.
+     */
+    private void registerOnBackInvokedCallback() {
+        if (mBackCallback != null) {
+            // A back callback has already been registered.
+            return;
+        }
+        final ViewRootImpl viewRootImpl = mRootView == null ? null : mRootView.getViewRootImpl();
+        if (viewRootImpl != null && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(
+                viewRootImpl.mContext)) {
+            final OnBackInvokedCallback callback = () -> {
+                KeyEvent downEvent = createKeyEvent(
+                        KeyEvent.ACTION_DOWN, false /* isTracking */);
+                onKeyDown(KeyEvent.KEYCODE_BACK, downEvent);
+                boolean hasStartedTracking =
+                        (downEvent.getFlags() & KeyEvent.FLAG_START_TRACKING) != 0;
+                KeyEvent upEvent = createKeyEvent(KeyEvent.ACTION_UP, hasStartedTracking);
+                onKeyUp(KeyEvent.KEYCODE_BACK, upEvent);
+            };
+            viewRootImpl.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+                    OnBackInvokedDispatcher.PRIORITY_DEFAULT, callback);
+            mBackCallback = callback;
+        }
+    }
+
+    private KeyEvent createKeyEvent(int action, boolean isTracking) {
+        final long when = SystemClock.uptimeMillis();
+        return new KeyEvent(when, when, action,
+                KeyEvent.KEYCODE_BACK, 0 /* repeat */, 0 /* metaState */,
+                KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
+                KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY
+                        | (isTracking ? KeyEvent.FLAG_TRACKING : 0),
+                InputDevice.SOURCE_KEYBOARD);
+    }
+
+    private void unregisterOnBackInvokedCallback() {
+        final ViewRootImpl viewRootImpl = mRootView == null ? null : mRootView.getViewRootImpl();
+        if (viewRootImpl != null
+                && mBackCallback != null
+                && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(
+                viewRootImpl.mContext)) {
+            viewRootImpl.getOnBackInvokedDispatcher()
+                    .unregisterOnBackInvokedCallback(mBackCallback);
+        }
+        mBackCallback = null;
+    }
+
+    /**
      * Applies the IME visibility in {@link android.view.ImeInsetsSourceConsumer}.
      *
      * @param setVisible {@code true} to make it visible, false to hide it.
@@ -2669,6 +2728,7 @@
         }
         mLastWasInFullscreenMode = mIsFullscreen;
         updateFullscreenMode();
+        unregisterOnBackInvokedCallback();
     }
 
     /**
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 42e6ac4..0b956f8 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1166,7 +1166,7 @@
         /**
          * Tiramisu.
          */
-        public static final int TIRAMISU = CUR_DEVELOPMENT;
+        public static final int TIRAMISU = 33;
     }
 
     /** The type of build, like "user" or "eng". */
diff --git a/core/java/android/view/AccessibilityEmbeddedConnection.java b/core/java/android/view/AccessibilityEmbeddedConnection.java
index de895d9..a7d3164 100644
--- a/core/java/android/view/AccessibilityEmbeddedConnection.java
+++ b/core/java/android/view/AccessibilityEmbeddedConnection.java
@@ -33,7 +33,7 @@
  */
 final class AccessibilityEmbeddedConnection extends IAccessibilityEmbeddedConnection.Stub {
     private final WeakReference<ViewRootImpl> mViewRootImpl;
-    private final Matrix mTmpScreenMatrix = new Matrix();
+    private final Matrix mTmpWindowMatrix = new Matrix();
 
     AccessibilityEmbeddedConnection(ViewRootImpl viewRootImpl) {
         mViewRootImpl = new WeakReference<>(viewRootImpl);
@@ -70,14 +70,14 @@
     }
 
     @Override
-    public void setScreenMatrix(float[] matrixValues) {
+    public void setWindowMatrix(float[] matrixValues) {
         final ViewRootImpl viewRootImpl = mViewRootImpl.get();
         if (viewRootImpl != null) {
-            mTmpScreenMatrix.setValues(matrixValues);
-            if (viewRootImpl.mAttachInfo.mScreenMatrixInEmbeddedHierarchy == null) {
-                viewRootImpl.mAttachInfo.mScreenMatrixInEmbeddedHierarchy = new Matrix();
+            mTmpWindowMatrix.setValues(matrixValues);
+            if (viewRootImpl.mAttachInfo.mWindowMatrixInEmbeddedHierarchy == null) {
+                viewRootImpl.mAttachInfo.mWindowMatrixInEmbeddedHierarchy = new Matrix();
             }
-            viewRootImpl.mAttachInfo.mScreenMatrixInEmbeddedHierarchy.set(mTmpScreenMatrix);
+            viewRootImpl.mAttachInfo.mWindowMatrixInEmbeddedHierarchy.set(mTmpWindowMatrix);
         }
     }
 }
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 7e0b794..23e1505 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -22,7 +22,6 @@
 import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY;
 
 import android.graphics.Matrix;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
@@ -112,10 +111,7 @@
 
     private final ArrayList<View> mTempArrayList = new ArrayList<View>();
 
-    private final Point mTempPoint = new Point();
     private final Rect mTempRect = new Rect();
-    private final Rect mTempRect1 = new Rect();
-    private final Rect mTempRect2 = new Rect();
     private final RectF mTempRectF = new RectF();
 
     private AddNodeInfosForViewId mAddNodeInfosForViewId;
@@ -131,7 +127,7 @@
     private int mActiveRequestPreparerId;
 
     public AccessibilityInteractionController(ViewRootImpl viewRootImpl) {
-        Looper looper =  viewRootImpl.mHandler.getLooper();
+        Looper looper = viewRootImpl.mHandler.getLooper();
         mMyLooperThreadId = looper.getThread().getId();
         mMyProcessId = Process.myPid();
         mHandler = new PrivateHandler(looper);
@@ -173,7 +169,8 @@
     public void findAccessibilityNodeInfoByAccessibilityIdClientThread(
             long accessibilityNodeId, Region interactiveRegion, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
-            long interrogatingTid, MagnificationSpec spec, Bundle arguments) {
+            long interrogatingTid, MagnificationSpec spec, float[] matrixValues,
+            Bundle arguments) {
         final Message message = mHandler.obtainMessage();
         message.what = PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID;
         message.arg1 = flags;
@@ -186,6 +183,7 @@
         args.arg2 = spec;
         args.arg3 = interactiveRegion;
         args.arg4 = arguments;
+        args.arg5 = matrixValues;
         message.obj = args;
 
         synchronized (mLock) {
@@ -344,6 +342,7 @@
         final MagnificationSpec spec = (MagnificationSpec) args.arg2;
         final Region interactiveRegion = (Region) args.arg3;
         final Bundle arguments = (Bundle) args.arg4;
+        final float[] matrixValues = (float[]) args.arg5;
 
         args.recycle();
 
@@ -378,7 +377,7 @@
             if (!interruptPrefetch) {
                 // Return found node and prefetched nodes in one IPC.
                 updateInfosForViewportAndReturnFindNodeResult(infos, callback, interactionId, spec,
-                        interactiveRegion);
+                        matrixValues, interactiveRegion);
 
                 final SatisfiedFindAccessibilityNodeByAccessibilityIdRequest satisfiedRequest =
                         getSatisfiedRequestInPrefetch(requestedNode == null ? null : requestedNode,
@@ -391,13 +390,13 @@
                 // Return found node.
                 updateInfoForViewportAndReturnFindNodeResult(
                         requestedNode == null ? null : new AccessibilityNodeInfo(requestedNode),
-                        callback, interactionId, spec, interactiveRegion);
+                        callback, interactionId, spec, matrixValues, interactiveRegion);
             }
         }
         mPrefetcher.prefetchAccessibilityNodeInfos(requestedView,
                 requestedNode == null ? null : new AccessibilityNodeInfo(requestedNode), infos);
         mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
-        updateInfosForViewPort(infos, spec, interactiveRegion);
+        updateInfosForViewPort(infos, spec, matrixValues, interactiveRegion);
         final SatisfiedFindAccessibilityNodeByAccessibilityIdRequest satisfiedRequest =
                 getSatisfiedRequestInPrefetch(requestedNode == null ? null : requestedNode, infos,
                         flags);
@@ -439,7 +438,7 @@
     public void findAccessibilityNodeInfosByViewIdClientThread(long accessibilityNodeId,
             String viewId, Region interactiveRegion, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
-            long interrogatingTid, MagnificationSpec spec) {
+            long interrogatingTid, MagnificationSpec spec, float[] matrixValues) {
         Message message = mHandler.obtainMessage();
         message.what = PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFOS_BY_VIEW_ID;
         message.arg1 = flags;
@@ -451,6 +450,7 @@
         args.arg2 = spec;
         args.arg3 = viewId;
         args.arg4 = interactiveRegion;
+        args.arg5 = matrixValues;
         message.obj = args;
 
         scheduleMessage(message, interrogatingPid, interrogatingTid, CONSIDER_REQUEST_PREPARERS);
@@ -467,6 +467,7 @@
         final MagnificationSpec spec = (MagnificationSpec) args.arg2;
         final String viewId = (String) args.arg3;
         final Region interactiveRegion = (Region) args.arg4;
+        final float[] matrixValues = (float[]) args.arg5;
         args.recycle();
 
         final List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
@@ -494,14 +495,14 @@
         } finally {
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
             updateInfosForViewportAndReturnFindNodeResult(
-                    infos, callback, interactionId, spec, interactiveRegion);
+                    infos, callback, interactionId, spec, matrixValues, interactiveRegion);
         }
     }
 
     public void findAccessibilityNodeInfosByTextClientThread(long accessibilityNodeId,
             String text, Region interactiveRegion, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
-            long interrogatingTid, MagnificationSpec spec) {
+            long interrogatingTid, MagnificationSpec spec, float[] matrixValues) {
         Message message = mHandler.obtainMessage();
         message.what = PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_TEXT;
         message.arg1 = flags;
@@ -514,6 +515,7 @@
         args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
         args.argi3 = interactionId;
         args.arg4 = interactiveRegion;
+        args.arg5 = matrixValues;
         message.obj = args;
 
         scheduleMessage(message, interrogatingPid, interrogatingTid, CONSIDER_REQUEST_PREPARERS);
@@ -531,6 +533,7 @@
         final int virtualDescendantId = args.argi2;
         final int interactionId = args.argi3;
         final Region interactiveRegion = (Region) args.arg4;
+        final float[] matrixValues = (float[]) args.arg5;
         args.recycle();
 
         List<AccessibilityNodeInfo> infos = null;
@@ -577,14 +580,14 @@
         } finally {
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
             updateInfosForViewportAndReturnFindNodeResult(
-                    infos, callback, interactionId, spec, interactiveRegion);
+                    infos, callback, interactionId, spec, matrixValues, interactiveRegion);
         }
     }
 
     public void findFocusClientThread(long accessibilityNodeId, int focusType,
             Region interactiveRegion, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
-            long interrogatingTid, MagnificationSpec spec) {
+            long interrogatingTid, MagnificationSpec spec, float[] matrixValues) {
         Message message = mHandler.obtainMessage();
         message.what = PrivateHandler.MSG_FIND_FOCUS;
         message.arg1 = flags;
@@ -597,7 +600,7 @@
         args.arg1 = callback;
         args.arg2 = spec;
         args.arg3 = interactiveRegion;
-
+        args.arg4 = matrixValues;
         message.obj = args;
 
         scheduleMessage(message, interrogatingPid, interrogatingTid, CONSIDER_REQUEST_PREPARERS);
@@ -615,6 +618,7 @@
             (IAccessibilityInteractionConnectionCallback) args.arg1;
         final MagnificationSpec spec = (MagnificationSpec) args.arg2;
         final Region interactiveRegion = (Region) args.arg3;
+        final float[] matrixValues = (float[]) args.arg4;
         args.recycle();
 
         AccessibilityNodeInfo focused = null;
@@ -672,14 +676,14 @@
         } finally {
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
             updateInfoForViewportAndReturnFindNodeResult(
-                    focused, callback, interactionId, spec, interactiveRegion);
+                    focused, callback, interactionId, spec, matrixValues, interactiveRegion);
         }
     }
 
     public void focusSearchClientThread(long accessibilityNodeId, int direction,
             Region interactiveRegion, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
-            long interrogatingTid, MagnificationSpec spec) {
+            long interrogatingTid, MagnificationSpec spec, float[] matrixValues) {
         Message message = mHandler.obtainMessage();
         message.what = PrivateHandler.MSG_FOCUS_SEARCH;
         message.arg1 = flags;
@@ -691,6 +695,7 @@
         args.arg1 = callback;
         args.arg2 = spec;
         args.arg3 = interactiveRegion;
+        args.arg4 = matrixValues;
 
         message.obj = args;
 
@@ -708,7 +713,7 @@
             (IAccessibilityInteractionConnectionCallback) args.arg1;
         final MagnificationSpec spec = (MagnificationSpec) args.arg2;
         final Region interactiveRegion = (Region) args.arg3;
-
+        final float[] matrixValues = (float[]) args.arg4;
         args.recycle();
 
         AccessibilityNodeInfo next = null;
@@ -727,7 +732,7 @@
         } finally {
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
             updateInfoForViewportAndReturnFindNodeResult(
-                    next, callback, interactionId, spec, interactiveRegion);
+                    next, callback, interactionId, spec, matrixValues, interactiveRegion);
         }
     }
 
@@ -882,13 +887,20 @@
         }
     }
 
+    // The boundInScreen includes magnification effect, so we need to normalize it before
+    // determine the visibility.
     private void adjustIsVisibleToUserIfNeeded(AccessibilityNodeInfo info,
-            Region interactiveRegion) {
+            Region interactiveRegion, MagnificationSpec spec) {
         if (interactiveRegion == null || info == null) {
             return;
         }
         Rect boundsInScreen = mTempRect;
         info.getBoundsInScreen(boundsInScreen);
+        if (spec != null && !spec.isNop()) {
+            boundsInScreen.offset((int) -spec.offsetX, (int) -spec.offsetY);
+            boundsInScreen.scale(1 / spec.scale);
+        }
+
         if (interactiveRegion.quickReject(boundsInScreen) && !shouldBypassAdjustIsVisible()) {
             info.setVisibleToUser(false);
         }
@@ -902,36 +914,30 @@
         return false;
     }
 
-    private void applyScreenMatrixIfNeeded(List<AccessibilityNodeInfo> infos) {
-        if (infos == null || shouldBypassApplyScreenMatrix()) {
-            return;
-        }
-        final int infoCount = infos.size();
-        for (int i = 0; i < infoCount; i++) {
-            final AccessibilityNodeInfo info = infos.get(i);
-            applyScreenMatrixIfNeeded(info);
-        }
-    }
-
-    private void applyScreenMatrixIfNeeded(AccessibilityNodeInfo info) {
-        if (info == null || shouldBypassApplyScreenMatrix()) {
+    /**
+     * Applies the host-window matrix to the embedded node. After this transform, The node bounds
+     *  will be transformed from embedded window coordinates to host-window coordinates.
+     *
+     */
+    private void applyHostWindowMatrixIfNeeded(AccessibilityNodeInfo info) {
+        if (info == null || shouldBypassApplyWindowMatrix()) {
             return;
         }
         final Rect boundsInScreen = mTempRect;
         final RectF transformedBounds = mTempRectF;
-        final Matrix screenMatrix = mViewRootImpl.mAttachInfo.mScreenMatrixInEmbeddedHierarchy;
+        final Matrix windowMatrix = mViewRootImpl.mAttachInfo.mWindowMatrixInEmbeddedHierarchy;
 
         info.getBoundsInScreen(boundsInScreen);
         transformedBounds.set(boundsInScreen);
-        screenMatrix.mapRect(transformedBounds);
+        windowMatrix.mapRect(transformedBounds);
         boundsInScreen.set((int) transformedBounds.left, (int) transformedBounds.top,
                 (int) transformedBounds.right, (int) transformedBounds.bottom);
         info.setBoundsInScreen(boundsInScreen);
     }
 
-    private boolean shouldBypassApplyScreenMatrix() {
-        final Matrix screenMatrix = mViewRootImpl.mAttachInfo.mScreenMatrixInEmbeddedHierarchy;
-        return screenMatrix == null || screenMatrix.isIdentity();
+    private boolean shouldBypassApplyWindowMatrix() {
+        final Matrix windowMatrix = mViewRootImpl.mAttachInfo.mWindowMatrixInEmbeddedHierarchy;
+        return windowMatrix == null || windowMatrix.isIdentity();
     }
 
     private void associateLeashedParentIfNeeded(AccessibilityNodeInfo info) {
@@ -963,46 +969,17 @@
         if (!shouldApplyAppScaleAndMagnificationSpec(applicationScale, spec)) {
             return;
         }
-
         Rect boundsInParent = mTempRect;
-        Rect boundsInScreen = mTempRect1;
 
         info.getBoundsInParent(boundsInParent);
-        info.getBoundsInScreen(boundsInScreen);
         if (applicationScale != 1.0f) {
             boundsInParent.scale(applicationScale);
-            boundsInScreen.scale(applicationScale);
         }
         if (spec != null) {
             boundsInParent.scale(spec.scale);
             // boundsInParent must not be offset.
-            boundsInScreen.scale(spec.scale);
-            boundsInScreen.offset((int) spec.offsetX, (int) spec.offsetY);
         }
         info.setBoundsInParent(boundsInParent);
-        info.setBoundsInScreen(boundsInScreen);
-
-        // Scale text locations if they are present
-        if (info.hasExtras()) {
-            Bundle extras = info.getExtras();
-            Parcelable[] textLocations =
-                    extras.getParcelableArray(EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY);
-            if (textLocations != null) {
-                for (int i = 0; i < textLocations.length; i++) {
-                    // Unchecked cast - an app that puts other objects in this bundle with this
-                    // key will crash.
-                    RectF textLocation = ((RectF) textLocations[i]);
-                    if (textLocation == null) {
-                        continue;
-                    }
-                    textLocation.scale(applicationScale);
-                    if (spec != null) {
-                        textLocation.scale(spec.scale);
-                        textLocation.offset(spec.offsetX, spec.offsetY);
-                    }
-                }
-            }
-        }
     }
 
     private boolean shouldApplyAppScaleAndMagnificationSpec(float appScale,
@@ -1011,27 +988,88 @@
     }
 
     private void updateInfosForViewPort(List<AccessibilityNodeInfo> infos, MagnificationSpec spec,
-                                        Region interactiveRegion) {
+            float[] matrixValues, Region interactiveRegion) {
         for (int i = 0; i < infos.size(); i++) {
-            updateInfoForViewPort(infos.get(i), spec, interactiveRegion);
+            updateInfoForViewPort(infos.get(i), spec, matrixValues, interactiveRegion);
         }
     }
 
     private void updateInfoForViewPort(AccessibilityNodeInfo info, MagnificationSpec spec,
-                                       Region interactiveRegion) {
+            float[] matrixValues, Region interactiveRegion) {
         associateLeashedParentIfNeeded(info);
-        applyScreenMatrixIfNeeded(info);
-        // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node,
-        // then impact the visibility result, we need to adjust visibility before apply scale.
-        adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
+
+        applyHostWindowMatrixIfNeeded(info);
+        // Transform view bounds from window coordinates to screen coordinates.
+        transformBoundsWithScreenMatrix(info, matrixValues);
+        adjustIsVisibleToUserIfNeeded(info, interactiveRegion, spec);
         applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
     }
 
+
+    /**
+     * Transforms the regions from local screen coordinate to global screen coordinate with the
+     * given transform matrix used in on-screen coordinate.
+     *
+     * @param info the AccessibilityNodeInfo that has the region in application screen coordinate
+     * @param matrixValues the matrix to be applied
+     */
+    private void transformBoundsWithScreenMatrix(AccessibilityNodeInfo info,
+            float[] matrixValues) {
+        if (info == null || matrixValues == null) {
+            return;
+        }
+        final Rect boundInScreen = mTempRect;
+        final RectF transformedBounds = mTempRectF;
+
+        info.getBoundsInScreen(boundInScreen);
+        transformedBounds.set(boundInScreen);
+
+        final Matrix transformMatrix = new Matrix();
+        transformMatrix.setValues(matrixValues);
+        final float applicationScale = mViewRootImpl.mAttachInfo.mApplicationScale;
+        if (applicationScale != 1f) {
+            transformMatrix.preScale(applicationScale, applicationScale);
+        }
+        // Transform the bounds from application screen coordinates to global window coordinates.
+        // For the embedded node, the bounds we get is already in window coordinates, so we don't
+        // need to do it.
+        if (mViewRootImpl.mAttachInfo.mWindowMatrixInEmbeddedHierarchy == null) {
+            transformMatrix.preTranslate(-mViewRootImpl.mAttachInfo.mWindowLeft,
+                    -mViewRootImpl.mAttachInfo.mWindowTop);
+        }
+
+        if (transformMatrix.isIdentity()) {
+            return;
+        }
+        transformMatrix.mapRect(transformedBounds);
+        // Offset 0.5f to round after casting.
+        transformedBounds.offset(0.5f, 0.5f);
+        boundInScreen.set((int) (transformedBounds.left), (int) transformedBounds.top,
+                (int) transformedBounds.right, (int) transformedBounds.bottom);
+        info.setBoundsInScreen(boundInScreen);
+        // Scale text locations if they are present
+        if (info.hasExtras()) {
+            final Bundle extras = info.getExtras();
+            final RectF[] textLocations =
+                    extras.getParcelableArray(EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY, RectF.class);
+            if (textLocations != null) {
+                for (int i = 0; i < textLocations.length; i++) {
+                    // Unchecked cast - an app that puts other objects in this bundle with this
+                    // key will crash.
+                    final RectF textLocation = textLocations[i];
+                    if (textLocation != null) {
+                        transformMatrix.mapRect(textLocation);
+                    }
+                }
+            }
+        }
+    }
+
     private void updateInfosForViewportAndReturnFindNodeResult(List<AccessibilityNodeInfo> infos,
             IAccessibilityInteractionConnectionCallback callback, int interactionId,
-            MagnificationSpec spec, Region interactiveRegion) {
+            MagnificationSpec spec, float[] matrixValues, Region interactiveRegion) {
         if (infos != null) {
-            updateInfosForViewPort(infos, spec, interactiveRegion);
+            updateInfosForViewPort(infos, spec, matrixValues, interactiveRegion);
         }
         returnFindNodesResult(infos, callback, interactionId);
     }
@@ -1141,8 +1179,8 @@
 
     private void updateInfoForViewportAndReturnFindNodeResult(AccessibilityNodeInfo info,
             IAccessibilityInteractionConnectionCallback callback, int interactionId,
-            MagnificationSpec spec, Region interactiveRegion) {
-        updateInfoForViewPort(info, spec, interactiveRegion);
+            MagnificationSpec spec, float[] matrixValues, Region interactiveRegion) {
+        updateInfoForViewPort(info, spec, matrixValues, interactiveRegion);
         returnFindNodeResult(info, callback, interactionId);
     }
 
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 7b6a0d6..cce3e8c 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -833,10 +833,12 @@
     }
 
     /**
-     * @see InsetsState#calculateVisibleInsets(Rect, int)
+     * @see InsetsState#calculateVisibleInsets(Rect, int, int, int, int)
      */
-    public Insets calculateVisibleInsets(@SoftInputModeFlags int softInputMode) {
-        return mState.calculateVisibleInsets(mFrame, softInputMode);
+    public Insets calculateVisibleInsets(int windowType, int windowingMode,
+            @SoftInputModeFlags int softInputMode, int windowFlags) {
+        return mState.calculateVisibleInsets(mFrame, windowType, windowingMode, softInputMode,
+                windowFlags);
     }
 
     /**
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index b1b630e..eb74608 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -23,11 +23,11 @@
 import static android.view.WindowInsets.Type.displayCutout;
 import static android.view.WindowInsets.Type.ime;
 import static android.view.WindowInsets.Type.indexOf;
-import static android.view.WindowInsets.Type.isVisibleInsetsType;
 import static android.view.WindowInsets.Type.statusBars;
 import static android.view.WindowInsets.Type.systemBars;
 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
@@ -257,7 +257,7 @@
         if ((legacyWindowFlags & FLAG_FULLSCREEN) != 0) {
             compatInsetsTypes &= ~statusBars();
         }
-        if (clearCompatInsets(windowType, legacyWindowFlags, windowingMode)) {
+        if (clearsCompatInsets(windowType, legacyWindowFlags, windowingMode)) {
             compatInsetsTypes = 0;
         }
 
@@ -358,17 +358,23 @@
         return insets;
     }
 
-    public Insets calculateVisibleInsets(Rect frame, @SoftInputModeFlags int softInputMode) {
+    public Insets calculateVisibleInsets(Rect frame, int windowType, int windowingMode,
+            @SoftInputModeFlags int softInputMode, int windowFlags) {
+        if (clearsCompatInsets(windowType, windowFlags, windowingMode)) {
+            return Insets.NONE;
+        }
+        final int softInputAdjustMode = softInputMode & SOFT_INPUT_MASK_ADJUST;
+        final int visibleInsetsTypes = softInputAdjustMode != SOFT_INPUT_ADJUST_NOTHING
+                ? systemBars() | ime()
+                : systemBars();
         Insets insets = Insets.NONE;
         for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
             InsetsSource source = mSources[type];
             if (source == null) {
                 continue;
             }
-
-            // Ignore everything that's not a system bar or IME.
-            int publicType = InsetsState.toPublicType(type);
-            if (!isVisibleInsetsType(publicType, softInputMode)) {
+            final int publicType = InsetsState.toPublicType(type);
+            if ((publicType & visibleInsetsTypes) == 0) {
                 continue;
             }
             insets = Insets.max(source.calculateVisibleInsets(frame), insets);
@@ -676,7 +682,7 @@
         mSources[source.getType()] = source;
     }
 
-    public static boolean clearCompatInsets(int windowType, int windowFlags, int windowingMode) {
+    public static boolean clearsCompatInsets(int windowType, int windowFlags, int windowingMode) {
         return (windowFlags & FLAG_LAYOUT_NO_LIMITS) != 0
                 && windowType != TYPE_WALLPAPER && windowType != TYPE_SYSTEM_ERROR
                 && !WindowConfiguration.inMultiWindowMode(windowingMode);
diff --git a/core/java/android/view/RemoteAccessibilityController.java b/core/java/android/view/RemoteAccessibilityController.java
index bc0fab1b..8855fb5 100644
--- a/core/java/android/view/RemoteAccessibilityController.java
+++ b/core/java/android/view/RemoteAccessibilityController.java
@@ -28,7 +28,7 @@
     private static final String TAG = "RemoteAccessibilityController";
     private int mHostId;
     private RemoteAccessibilityEmbeddedConnection mConnectionWrapper;
-    private Matrix mScreenMatrixForEmbeddedHierarchy = new Matrix();
+    private Matrix mWindowMatrixForEmbeddedHierarchy = new Matrix();
     private final float[] mMatrixValues = new float[9];
     private View mHostView;
 
@@ -140,9 +140,9 @@
         return mConnectionWrapper;
     }
 
-    void setScreenMatrix(Matrix m) {
-        // If the screen matrix is identity or doesn't change, do nothing.
-        if (m.isIdentity() || m.equals(mScreenMatrixForEmbeddedHierarchy)) {
+    void setWindowMatrix(Matrix m) {
+        // If the window matrix is identity or doesn't change, do nothing.
+        if (m.isIdentity() || m.equals(mWindowMatrixForEmbeddedHierarchy)) {
             return;
         }
 
@@ -153,8 +153,8 @@
                 return;
             }
             m.getValues(mMatrixValues);
-            wrapper.getConnection().setScreenMatrix(mMatrixValues);
-            mScreenMatrixForEmbeddedHierarchy.set(m);
+            wrapper.getConnection().setWindowMatrix(mMatrixValues);
+            mWindowMatrixForEmbeddedHierarchy.set(m);
         } catch (RemoteException e) {
             Log.d(TAG, "Error while setScreenMatrix " + e);
         }
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index ed57136..017f2e4 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1781,11 +1781,16 @@
             return;
         }
         getBoundsOnScreen(mTmpRect);
+
+        // To compute the node bounds of the node on the embedded window,
+        // apply this matrix to get the bounds in host window-relative coordinates,
+        // then using the global transform to get the actual bounds on screen.
+        mTmpRect.offset(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
         mTmpMatrix.reset();
         mTmpMatrix.setTranslate(mTmpRect.left, mTmpRect.top);
         mTmpMatrix.postScale(mScreenRect.width() / (float) mSurfaceWidth,
                 mScreenRect.height() / (float) mSurfaceHeight);
-        mRemoteAccessibilityController.setScreenMatrix(mTmpMatrix);
+        mRemoteAccessibilityController.setWindowMatrix(mTmpMatrix);
     }
 
     @Override
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8b9a86b9..569461e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -29938,10 +29938,10 @@
         boolean mHandlingPointerEvent;
 
         /**
-         * The screen matrix of this view when it's on a {@link SurfaceControlViewHost} that is
+         * The window matrix of this view when it's on a {@link SurfaceControlViewHost} that is
          * embedded within a SurfaceView.
          */
-        Matrix mScreenMatrixInEmbeddedHierarchy;
+        Matrix mWindowMatrixInEmbeddedHierarchy;
 
         /**
          * Global to the view hierarchy used as a temporary for dealing with
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index a3d0bf7..92289d9 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2570,7 +2570,8 @@
             mAttachInfo.mContentInsets.set(mLastWindowInsets.getSystemWindowInsets().toRect());
             mAttachInfo.mStableInsets.set(mLastWindowInsets.getStableInsets().toRect());
             mAttachInfo.mVisibleInsets.set(mInsetsController.calculateVisibleInsets(
-                    mWindowAttributes.softInputMode).toRect());
+                    mWindowAttributes.type, config.windowConfiguration.getWindowingMode(),
+                    mWindowAttributes.softInputMode, mWindowAttributes.flags).toRect());
         }
         return mLastWindowInsets;
     }
@@ -10249,13 +10250,14 @@
         public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
                 Region interactiveRegion, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int flags,
-                int interrogatingPid, long interrogatingTid, MagnificationSpec spec, Bundle args) {
+                int interrogatingPid, long interrogatingTid, MagnificationSpec spec, float[] matrix,
+                Bundle args) {
             ViewRootImpl viewRootImpl = mViewRootImpl.get();
             if (viewRootImpl != null && viewRootImpl.mView != null) {
                 viewRootImpl.getAccessibilityInteractionController()
                     .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
                             interactiveRegion, interactionId, callback, flags, interrogatingPid,
-                            interrogatingTid, spec, args);
+                            interrogatingTid, spec, matrix, args);
             } else {
                 // We cannot make the call and notify the caller so it does not wait.
                 try {
@@ -10290,13 +10292,14 @@
         public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
                 String viewId, Region interactiveRegion, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int flags,
-                int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
+                int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
+                float[] matrix) {
             ViewRootImpl viewRootImpl = mViewRootImpl.get();
             if (viewRootImpl != null && viewRootImpl.mView != null) {
                 viewRootImpl.getAccessibilityInteractionController()
                     .findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
                             viewId, interactiveRegion, interactionId, callback, flags,
-                            interrogatingPid, interrogatingTid, spec);
+                            interrogatingPid, interrogatingTid, spec, matrix);
             } else {
                 // We cannot make the call and notify the caller so it does not wait.
                 try {
@@ -10311,13 +10314,14 @@
         public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
                 Region interactiveRegion, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int flags,
-                int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
+                int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
+                float[] matrix) {
             ViewRootImpl viewRootImpl = mViewRootImpl.get();
             if (viewRootImpl != null && viewRootImpl.mView != null) {
                 viewRootImpl.getAccessibilityInteractionController()
                     .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
                             interactiveRegion, interactionId, callback, flags, interrogatingPid,
-                            interrogatingTid, spec);
+                            interrogatingTid, spec, matrix);
             } else {
                 // We cannot make the call and notify the caller so it does not wait.
                 try {
@@ -10331,13 +10335,14 @@
         @Override
         public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion,
                 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
-                int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
+                int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
+                float[] matrix) {
             ViewRootImpl viewRootImpl = mViewRootImpl.get();
             if (viewRootImpl != null && viewRootImpl.mView != null) {
                 viewRootImpl.getAccessibilityInteractionController()
                     .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion,
                             interactionId, callback, flags, interrogatingPid, interrogatingTid,
-                            spec);
+                            spec, matrix);
             } else {
                 // We cannot make the call and notify the caller so it does not wait.
                 try {
@@ -10351,13 +10356,14 @@
         @Override
         public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion,
                 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
-                int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
+                int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
+                float[] matrix) {
             ViewRootImpl viewRootImpl = mViewRootImpl.get();
             if (viewRootImpl != null && viewRootImpl.mView != null) {
                 viewRootImpl.getAccessibilityInteractionController()
                     .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion,
                             interactionId, callback, flags, interrogatingPid, interrogatingTid,
-                            spec);
+                            spec, matrix);
             } else {
                 // We cannot make the call and notify the caller so it does not wait.
                 try {
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index 1edbbba..a5b8720 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.app.ActivityTaskManager;
+import android.graphics.Matrix;
 import android.graphics.Region;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -53,6 +54,11 @@
     public boolean hasFlagWatchOutsideTouch;
     public int displayId = Display.INVALID_DISPLAY;
     public int taskId = ActivityTaskManager.INVALID_TASK_ID;
+    // The matrix applied to the bounds in window coordinate to get the corresponding values in
+    // screen coordinates.
+    public float[] mTransformMatrix = new float[9];
+
+    public MagnificationSpec mMagnificationSpec = new MagnificationSpec();
 
     private WindowInfo() {
         /* do nothing - hide constructor */
@@ -81,6 +87,9 @@
         window.accessibilityIdOfAnchor = other.accessibilityIdOfAnchor;
         window.inPictureInPicture = other.inPictureInPicture;
         window.hasFlagWatchOutsideTouch = other.hasFlagWatchOutsideTouch;
+        for (int i = 0; i < window.mTransformMatrix.length; i++) {
+            window.mTransformMatrix[i] = other.mTransformMatrix[i];
+        }
 
         if (other.childTokens != null && !other.childTokens.isEmpty()) {
             if (window.childTokens == null) {
@@ -89,7 +98,7 @@
                 window.childTokens.addAll(other.childTokens);
             }
         }
-
+        window.mMagnificationSpec.setTo(other.mMagnificationSpec);
         return window;
     }
 
@@ -118,6 +127,7 @@
         parcel.writeLong(accessibilityIdOfAnchor);
         parcel.writeInt(inPictureInPicture ? 1 : 0);
         parcel.writeInt(hasFlagWatchOutsideTouch ? 1 : 0);
+        parcel.writeFloatArray(mTransformMatrix);
 
         if (childTokens != null && !childTokens.isEmpty()) {
             parcel.writeInt(1);
@@ -125,6 +135,7 @@
         } else {
             parcel.writeInt(0);
         }
+        mMagnificationSpec.writeToParcel(parcel, flags);
     }
 
     @Override
@@ -145,6 +156,10 @@
         builder.append(", accessibility anchor=").append(accessibilityIdOfAnchor);
         builder.append(", pictureInPicture=").append(inPictureInPicture);
         builder.append(", watchOutsideTouch=").append(hasFlagWatchOutsideTouch);
+        Matrix matrix = new Matrix();
+        matrix.setValues(mTransformMatrix);
+        builder.append(", mTransformMatrix=").append(matrix);
+        builder.append(", mMagnificationSpec=").append(mMagnificationSpec);
         builder.append(']');
         return builder.toString();
     }
@@ -163,7 +178,7 @@
         accessibilityIdOfAnchor = parcel.readLong();
         inPictureInPicture = (parcel.readInt() == 1);
         hasFlagWatchOutsideTouch = (parcel.readInt() == 1);
-
+        parcel.readFloatArray(mTransformMatrix);
         final boolean hasChildren = (parcel.readInt() == 1);
         if (hasChildren) {
             if (childTokens == null) {
@@ -171,6 +186,7 @@
             }
             parcel.readBinderList(childTokens);
         }
+        mMagnificationSpec = MagnificationSpec.CREATOR.createFromParcel(parcel);
     }
 
     private void clear() {
@@ -188,6 +204,10 @@
         }
         inPictureInPicture = false;
         hasFlagWatchOutsideTouch = false;
+        for (int i = 0; i < mTransformMatrix.length; i++) {
+            mTransformMatrix[i] = 0;
+        }
+        mMagnificationSpec.clear();
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<WindowInfo> CREATOR =
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 1c6d93d..c846175 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -32,8 +32,6 @@
 import static android.view.WindowInsets.Type.ime;
 import static android.view.WindowInsets.Type.indexOf;
 import static android.view.WindowInsets.Type.systemBars;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
 
 import android.annotation.IntDef;
 import android.annotation.IntRange;
@@ -46,7 +44,6 @@
 import android.util.SparseArray;
 import android.view.View.OnApplyWindowInsetsListener;
 import android.view.WindowInsets.Type.InsetsType;
-import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethod;
 
@@ -1600,17 +1597,6 @@
         public static @InsetsType int all() {
             return 0xFFFFFFFF;
         }
-
-        /**
-         * Checks whether the specified type is considered to be part of visible insets.
-         * @hide
-         */
-        public static boolean isVisibleInsetsType(int type,
-                @SoftInputModeFlags int softInputModeFlags) {
-            int softInputMode = softInputModeFlags & SOFT_INPUT_MASK_ADJUST;
-            return (type & Type.systemBars()) != 0
-                    || (softInputMode != SOFT_INPUT_ADJUST_NOTHING && (type & Type.ime()) != 0);
-        }
     }
 
     /**
diff --git a/core/java/android/view/accessibility/IAccessibilityEmbeddedConnection.aidl b/core/java/android/view/accessibility/IAccessibilityEmbeddedConnection.aidl
index 707099e..75d81ed 100644
--- a/core/java/android/view/accessibility/IAccessibilityEmbeddedConnection.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityEmbeddedConnection.aidl
@@ -28,5 +28,5 @@
 
     void disassociateEmbeddedHierarchy();
 
-    oneway void setScreenMatrix(in float[] matrixValues);
+    oneway void setWindowMatrix(in float[] matrixValues);
 }
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
index deb0d2a..472a363 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
@@ -34,23 +34,24 @@
     void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, in Region bounds,
         int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
         int interrogatingPid, long interrogatingTid, in MagnificationSpec spec,
-        in Bundle arguments);
+        in float[] matrixValues, in Bundle arguments);
 
     void findAccessibilityNodeInfosByViewId(long accessibilityNodeId, String viewId,
         in Region bounds, int interactionId, IAccessibilityInteractionConnectionCallback callback,
-        int flags, int interrogatingPid, long interrogatingTid, in MagnificationSpec spec);
+        int flags, int interrogatingPid, long interrogatingTid, in MagnificationSpec spec,
+         in float[] matrix);
 
     void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, in Region bounds,
         int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
-        int interrogatingPid, long interrogatingTid, in MagnificationSpec spec);
+        int interrogatingPid, long interrogatingTid, in MagnificationSpec spec, in float[] matrixValues);
 
     void findFocus(long accessibilityNodeId, int focusType, in Region bounds, int interactionId,
         IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
-        long interrogatingTid, in MagnificationSpec spec);
+        long interrogatingTid, in MagnificationSpec spec, in float[] matrixValues);
 
     void focusSearch(long accessibilityNodeId, int direction, in Region bounds, int interactionId,
         IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
-        long interrogatingTid, in MagnificationSpec spec);
+        long interrogatingTid, in MagnificationSpec spec, in float[] matrixValues);
 
     void performAccessibilityAction(long accessibilityNodeId, int action, in Bundle arguments,
         int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java
index a118f9a..f72164e 100644
--- a/core/java/android/window/TaskFragmentInfo.java
+++ b/core/java/android/window/TaskFragmentInfo.java
@@ -52,9 +52,6 @@
     @NonNull
     private final Configuration mConfiguration = new Configuration();
 
-    /** Whether the TaskFragment contains any child Window Container. */
-    private final boolean mIsEmpty;
-
     /** The number of the running activities in the TaskFragment. */
     private final int mRunningActivityCount;
 
@@ -77,21 +74,27 @@
      */
     private final boolean mIsTaskClearedForReuse;
 
+    /**
+     * Whether the last running activity in the TaskFragment was reparented to a different Task
+     * because it is entering PiP.
+     */
+    private final boolean mIsTaskFragmentClearedForPip;
+
     /** @hide */
     public TaskFragmentInfo(
             @NonNull IBinder fragmentToken, @NonNull WindowContainerToken token,
-            @NonNull Configuration configuration, boolean isEmpty, int runningActivityCount,
+            @NonNull Configuration configuration, int runningActivityCount,
             boolean isVisible, @NonNull List<IBinder> activities, @NonNull Point positionInParent,
-            boolean isTaskClearedForReuse) {
+            boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip) {
         mFragmentToken = requireNonNull(fragmentToken);
         mToken = requireNonNull(token);
         mConfiguration.setTo(configuration);
-        mIsEmpty = isEmpty;
         mRunningActivityCount = runningActivityCount;
         mIsVisible = isVisible;
         mActivities.addAll(activities);
         mPositionInParent = requireNonNull(positionInParent);
         mIsTaskClearedForReuse = isTaskClearedForReuse;
+        mIsTaskFragmentClearedForPip = isTaskFragmentClearedForPip;
     }
 
     @NonNull
@@ -110,7 +113,7 @@
     }
 
     public boolean isEmpty() {
-        return mIsEmpty;
+        return mRunningActivityCount == 0;
     }
 
     public boolean hasRunningActivity() {
@@ -140,6 +143,11 @@
         return mIsTaskClearedForReuse;
     }
 
+    /** @hide */
+    public boolean isTaskFragmentClearedForPip() {
+        return mIsTaskFragmentClearedForPip;
+    }
+
     @WindowingMode
     public int getWindowingMode() {
         return mConfiguration.windowConfiguration.getWindowingMode();
@@ -156,25 +164,25 @@
 
         return mFragmentToken.equals(that.mFragmentToken)
                 && mToken.equals(that.mToken)
-                && mIsEmpty == that.mIsEmpty
                 && mRunningActivityCount == that.mRunningActivityCount
                 && mIsVisible == that.mIsVisible
                 && getWindowingMode() == that.getWindowingMode()
                 && mActivities.equals(that.mActivities)
                 && mPositionInParent.equals(that.mPositionInParent)
-                && mIsTaskClearedForReuse == that.mIsTaskClearedForReuse;
+                && mIsTaskClearedForReuse == that.mIsTaskClearedForReuse
+                && mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip;
     }
 
     private TaskFragmentInfo(Parcel in) {
         mFragmentToken = in.readStrongBinder();
         mToken = in.readTypedObject(WindowContainerToken.CREATOR);
         mConfiguration.readFromParcel(in);
-        mIsEmpty = in.readBoolean();
         mRunningActivityCount = in.readInt();
         mIsVisible = in.readBoolean();
         in.readBinderList(mActivities);
         mPositionInParent = requireNonNull(in.readTypedObject(Point.CREATOR));
         mIsTaskClearedForReuse = in.readBoolean();
+        mIsTaskFragmentClearedForPip = in.readBoolean();
     }
 
     /** @hide */
@@ -183,12 +191,12 @@
         dest.writeStrongBinder(mFragmentToken);
         dest.writeTypedObject(mToken, flags);
         mConfiguration.writeToParcel(dest, flags);
-        dest.writeBoolean(mIsEmpty);
         dest.writeInt(mRunningActivityCount);
         dest.writeBoolean(mIsVisible);
         dest.writeBinderList(mActivities);
         dest.writeTypedObject(mPositionInParent, flags);
         dest.writeBoolean(mIsTaskClearedForReuse);
+        dest.writeBoolean(mIsTaskFragmentClearedForPip);
     }
 
     @NonNull
@@ -210,12 +218,12 @@
         return "TaskFragmentInfo{"
                 + " fragmentToken=" + mFragmentToken
                 + " token=" + mToken
-                + " isEmpty=" + mIsEmpty
                 + " runningActivityCount=" + mRunningActivityCount
                 + " isVisible=" + mIsVisible
                 + " activities=" + mActivities
                 + " positionInParent=" + mPositionInParent
                 + " isTaskClearedForReuse=" + mIsTaskClearedForReuse
+                + " isTaskFragmentClearedForPip" + mIsTaskFragmentClearedForPip
                 + "}";
     }
 
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 2f7c015..1db4bbb 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -22,7 +22,7 @@
 import static android.os.Build.VERSION_CODES.N;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
-import static android.view.InsetsState.clearCompatInsets;
+import static android.view.InsetsState.clearsCompatInsets;
 import static android.view.View.MeasureSpec.AT_MOST;
 import static android.view.View.MeasureSpec.EXACTLY;
 import static android.view.View.MeasureSpec.getMode;
@@ -1120,11 +1120,11 @@
                     : controller.getSystemBarsAppearance();
 
             if (insets != null) {
-                final boolean clearCompatInsets = clearCompatInsets(attrs.type, attrs.flags,
+                final boolean clearsCompatInsets = clearsCompatInsets(attrs.type, attrs.flags,
                         getResources().getConfiguration().windowConfiguration.getWindowingMode());
                 final Insets stableBarInsets = insets.getInsetsIgnoringVisibility(
                         WindowInsets.Type.systemBars());
-                final Insets systemInsets = clearCompatInsets
+                final Insets systemInsets = clearsCompatInsets
                         ? Insets.NONE
                         : Insets.min(insets.getInsets(WindowInsets.Type.systemBars()
                                 | WindowInsets.Type.displayCutout()), stableBarInsets);
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index bce4ed7..8012e0c 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -33,12 +33,13 @@
 
 #include <nativehelper/ScopedUtfChars.h>
 
+#include "android_media_AudioAttributes.h"
 #include "android_media_AudioFormat.h"
 #include "android_media_AudioErrors.h"
 #include "android_media_DeviceCallback.h"
+#include "android_media_JNIUtils.h"
 #include "android_media_MediaMetricsJNI.h"
 #include "android_media_MicrophoneInfo.h"
-#include "android_media_AudioAttributes.h"
 
 
 // ----------------------------------------------------------------------------
@@ -57,8 +58,7 @@
     // these fields provide access from C++ to the...
     jmethodID postNativeEventInJava; //... event post callback method
     jfieldID  nativeRecorderInJavaObj; // provides access to the C++ AudioRecord object
-    jfieldID  nativeCallbackCookie;    // provides access to the AudioRecord callback data
-    jfieldID  nativeDeviceCallback;    // provides access to the JNIDeviceCallback instance
+    jfieldID  jniData;    // provides access to AudioRecord JNI Handle
 };
 static audio_record_fields_t     javaAudioRecordFields;
 static struct {
@@ -66,15 +66,68 @@
     jfieldID  fieldNanoTime;          // AudioTimestamp.nanoTime
 } javaAudioTimestampFields;
 
-struct audiorecord_callback_cookie {
-    jclass      audioRecord_class;
-    jobject     audioRecord_ref;
-    bool        busy;
-    Condition   cond;
-};
 
-static Mutex sLock;
-static SortedVector <audiorecord_callback_cookie *> sAudioRecordCallBackCookies;
+class AudioRecordJNIStorage : public AudioRecord::IAudioRecordCallback {
+ private:
+   // Keep in sync with frameworks/base/media/java/android/media/AudioRecord.java NATIVE_EVENT_*.
+   enum class EventType {
+        EVENT_MORE_DATA = 0,        // Request to read available data from buffer.
+                                    // If this event is delivered but the callback handler
+                                    // does not want to read the available data, the handler must
+                                    // explicitly ignore the event by setting frameCount to zero.
+        EVENT_OVERRUN = 1,          // Buffer overrun occurred.
+        EVENT_MARKER = 2,           // Record head is at the specified marker position
+                                    // (See setMarkerPosition()).
+        EVENT_NEW_POS = 3,          // Record head is at a new position
+                                    // (See setPositionUpdatePeriod()).
+        EVENT_NEW_IAUDIORECORD = 4, // IAudioRecord was re-created, either due to re-routing and
+                                    // voluntary invalidation by mediaserver, or mediaserver crash.
+    };
+
+  public:
+    AudioRecordJNIStorage(jclass audioRecordClass, jobject audioRecordWeakRef)
+          : mAudioRecordClass(audioRecordClass), mAudioRecordWeakRef(audioRecordWeakRef) {}
+    AudioRecordJNIStorage(const AudioRecordJNIStorage &) = delete;
+    AudioRecordJNIStorage& operator=(const AudioRecordJNIStorage &) = delete;
+
+    void onMarker(uint32_t) override {
+        postEvent(EventType::EVENT_MARKER);
+    }
+
+    void onNewPos(uint32_t) override {
+        postEvent(EventType::EVENT_NEW_POS);
+    }
+
+    void setDeviceCallback(const sp<JNIDeviceCallback>& callback) {
+        mDeviceCallback = callback;
+    }
+
+    sp<JNIDeviceCallback> getDeviceCallback() const { return mDeviceCallback; }
+
+    jobject getAudioTrackWeakRef() const & { return mAudioRecordWeakRef.get(); }
+
+    // If we attempt to get a jobject from a rvalue, it will soon go out of
+    // scope, and the reference count can drop to zero, which is unsafe.
+    jobject getAudioTrackWeakRef() const && = delete;
+
+  private:
+    void postEvent(EventType event, int arg = 0) const {
+      JNIEnv *env = getJNIEnvOrDie();
+      env->CallStaticVoidMethod(
+          static_cast<jclass>(mAudioRecordClass.get()),
+          javaAudioRecordFields.postNativeEventInJava,
+          mAudioRecordWeakRef.get(), static_cast<int>(event), arg, 0, nullptr);
+      if (env->ExceptionCheck()) {
+          env->ExceptionDescribe();
+          env->ExceptionClear();
+      }
+    }
+
+    // Mutation of this object is protected using Java concurrency constructs
+    sp<JNIDeviceCallback> mDeviceCallback;
+    const GlobalRef   mAudioRecordClass;
+    const GlobalRef   mAudioRecordWeakRef;
+};
 
 // ----------------------------------------------------------------------------
 
@@ -85,103 +138,9 @@
 #define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED    (-20)
 
 // ----------------------------------------------------------------------------
-static void recorderCallback(int event, void* user, void *info) {
-
-    audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
-    {
-        Mutex::Autolock l(sLock);
-        if (sAudioRecordCallBackCookies.indexOf(callbackInfo) < 0) {
-            return;
-        }
-        callbackInfo->busy = true;
-    }
-
-    switch (event) {
-    case AudioRecord::EVENT_MARKER: {
-        JNIEnv *env = AndroidRuntime::getJNIEnv();
-        if (user != NULL && env != NULL) {
-            env->CallStaticVoidMethod(
-                callbackInfo->audioRecord_class,
-                javaAudioRecordFields.postNativeEventInJava,
-                callbackInfo->audioRecord_ref, event, 0,0, NULL);
-            if (env->ExceptionCheck()) {
-                env->ExceptionDescribe();
-                env->ExceptionClear();
-            }
-        }
-        } break;
-
-    case AudioRecord::EVENT_NEW_POS: {
-        JNIEnv *env = AndroidRuntime::getJNIEnv();
-        if (user != NULL && env != NULL) {
-            env->CallStaticVoidMethod(
-                callbackInfo->audioRecord_class,
-                javaAudioRecordFields.postNativeEventInJava,
-                callbackInfo->audioRecord_ref, event, 0,0, NULL);
-            if (env->ExceptionCheck()) {
-                env->ExceptionDescribe();
-                env->ExceptionClear();
-            }
-        }
-        } break;
-    }
-
-    {
-        Mutex::Autolock l(sLock);
-        callbackInfo->busy = false;
-        callbackInfo->cond.broadcast();
-    }
-}
-
-static sp<JNIDeviceCallback> getJniDeviceCallback(JNIEnv* env, jobject thiz)
-{
-    Mutex::Autolock l(sLock);
-    JNIDeviceCallback* const cb =
-            (JNIDeviceCallback*)env->GetLongField(thiz,
-                                                  javaAudioRecordFields.nativeDeviceCallback);
-    return sp<JNIDeviceCallback>(cb);
-}
-
-static sp<JNIDeviceCallback> setJniDeviceCallback(JNIEnv* env,
-                                                  jobject thiz,
-                                                  const sp<JNIDeviceCallback>& cb)
-{
-    Mutex::Autolock l(sLock);
-    sp<JNIDeviceCallback> old =
-            (JNIDeviceCallback*)env->GetLongField(thiz,
-                                                  javaAudioRecordFields.nativeDeviceCallback);
-    if (cb.get()) {
-        cb->incStrong((void*)setJniDeviceCallback);
-    }
-    if (old != 0) {
-        old->decStrong((void*)setJniDeviceCallback);
-    }
-    env->SetLongField(thiz, javaAudioRecordFields.nativeDeviceCallback, (jlong)cb.get());
-    return old;
-}
-
-// ----------------------------------------------------------------------------
 static sp<AudioRecord> getAudioRecord(JNIEnv* env, jobject thiz)
 {
-    Mutex::Autolock l(sLock);
-    AudioRecord* const ar =
-            (AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
-    return sp<AudioRecord>(ar);
-}
-
-static sp<AudioRecord> setAudioRecord(JNIEnv* env, jobject thiz, const sp<AudioRecord>& ar)
-{
-    Mutex::Autolock l(sLock);
-    sp<AudioRecord> old =
-            (AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
-    if (ar.get()) {
-        ar->incStrong((void*)setAudioRecord);
-    }
-    if (old != 0) {
-        old->decStrong((void*)setAudioRecord);
-    }
-    env->SetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (jlong)ar.get());
-    return old;
+    return getFieldSp<AudioRecord>(env, thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
 }
 
 // ----------------------------------------------------------------------------
@@ -211,9 +170,8 @@
     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
     nSession = NULL;
 
-    sp<AudioRecord> lpRecorder = 0;
-    audiorecord_callback_cookie *lpCallbackData = NULL;
-
+    sp<AudioRecord> lpRecorder;
+    sp<AudioRecordJNIStorage> callbackData;
     jclass clazz = env->GetObjectClass(thiz);
     if (clazz == NULL) {
         ALOGE("Can't find %s when setting up callback.", kClassPathName);
@@ -287,18 +245,14 @@
         }
         // create the callback information:
         // this data will be passed with every AudioRecord callback
-        lpCallbackData = new audiorecord_callback_cookie;
-        lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
         // we use a weak reference so the AudioRecord object can be garbage collected.
-        lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
-        lpCallbackData->busy = false;
+        callbackData = sp<AudioRecordJNIStorage>::make(clazz, weak_this);
 
         const status_t status =
                 lpRecorder->set(paa->source, sampleRateInHertz,
                                 format, // word length, PCM
                                 localChanMask, frameCount,
-                                recorderCallback, // callback_t
-                                lpCallbackData,   // void* user
+                                callbackData,   // callback
                                 0,                // notificationFrames,
                                 true,             // threadCanCallJava
                                 sessionId, AudioRecord::TRANSFER_DEFAULT, flags, -1,
@@ -330,11 +284,8 @@
 
         // create the callback information:
         // this data will be passed with every AudioRecord callback
-        lpCallbackData = new audiorecord_callback_cookie;
-        lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
-        // we use a weak reference so the AudioRecord object can be garbage collected.
-        lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
-        lpCallbackData->busy = false;
+        // This next line makes little sense
+        // callbackData = sp<AudioRecordJNIStorage>::make(clazz, weak_this);
     }
 
     nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
@@ -352,26 +303,20 @@
         env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
     }
 
-    {   // scope for the lock
-        Mutex::Autolock l(sLock);
-        sAudioRecordCallBackCookies.add(lpCallbackData);
-    }
     // save our newly created C++ AudioRecord in the "nativeRecorderInJavaObj" field
     // of the Java object
-    setAudioRecord(env, thiz, lpRecorder);
+    setFieldSp(env, thiz, lpRecorder, javaAudioRecordFields.nativeRecorderInJavaObj);
 
-    // save our newly created callback information in the "nativeCallbackCookie" field
-    // of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
-    env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, (jlong)lpCallbackData);
+    // save our newly created callback information in the "jniData" field
+    // of the Java object (in mNativeJNIDataHandle) so we can free the memory in finalize()
+    setFieldSp(env, thiz, callbackData, javaAudioRecordFields.jniData);
 
     return (jint) AUDIO_JAVA_SUCCESS;
 
     // failure:
 native_init_failure:
-    env->DeleteGlobalRef(lpCallbackData->audioRecord_class);
-    env->DeleteGlobalRef(lpCallbackData->audioRecord_ref);
-    delete lpCallbackData;
-    env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
+    setFieldSp(env, thiz, sp<AudioRecord>{}, javaAudioRecordFields.nativeRecorderInJavaObj);
+    setFieldSp(env, thiz, sp<AudioRecordJNIStorage>{}, javaAudioRecordFields.jniData);
 
     // lpRecorder goes out of scope, so reference count drops to zero
     return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
@@ -411,36 +356,9 @@
 
 #define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
 static void android_media_AudioRecord_release(JNIEnv *env,  jobject thiz) {
-    sp<AudioRecord> lpRecorder = setAudioRecord(env, thiz, 0);
-    if (lpRecorder == NULL) {
-        return;
-    }
-    ALOGV("About to delete lpRecorder: %p", lpRecorder.get());
-    lpRecorder->stop();
 
-    audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetLongField(
-        thiz, javaAudioRecordFields.nativeCallbackCookie);
-
-    // reset the native resources in the Java object so any attempt to access
-    // them after a call to release fails.
-    env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
-
-    // delete the callback information
-    if (lpCookie) {
-        Mutex::Autolock l(sLock);
-        ALOGV("deleting lpCookie: %p", lpCookie);
-        while (lpCookie->busy) {
-            if (lpCookie->cond.waitRelative(sLock,
-                                            milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
-                                                    NO_ERROR) {
-                break;
-            }
-        }
-        sAudioRecordCallBackCookies.remove(lpCookie);
-        env->DeleteGlobalRef(lpCookie->audioRecord_class);
-        env->DeleteGlobalRef(lpCookie->audioRecord_ref);
-        delete lpCookie;
-    }
+    setFieldSp(env, thiz, sp<AudioRecord>{}, javaAudioRecordFields.nativeRecorderInJavaObj);
+    setFieldSp(env, thiz, sp<AudioRecordJNIStorage>{}, javaAudioRecordFields.jniData);
 }
 
 
@@ -685,43 +603,40 @@
     return (jint)lpRecorder->getRoutedDeviceId();
 }
 
+// Enable and Disable Callback methods are synchronized on the Java side
 static void android_media_AudioRecord_enableDeviceCallback(
                 JNIEnv *env,  jobject thiz) {
 
     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
-    if (lpRecorder == 0) {
+    if (lpRecorder == nullptr) {
         return;
     }
-    sp<JNIDeviceCallback> cb = getJniDeviceCallback(env, thiz);
-    if (cb != 0) {
-        return;
-    }
-    audiorecord_callback_cookie *cookie =
-            (audiorecord_callback_cookie *)env->GetLongField(thiz,
-                                                     javaAudioRecordFields.nativeCallbackCookie);
-    if (cookie == NULL) {
+    const auto pJniStorage =
+            getFieldSp<AudioRecordJNIStorage>(env, thiz, javaAudioRecordFields.jniData);
+   if (pJniStorage == nullptr || pJniStorage->getDeviceCallback() != nullptr) {
         return;
     }
 
-    cb = new JNIDeviceCallback(env, thiz, cookie->audioRecord_ref,
-                               javaAudioRecordFields.postNativeEventInJava);
-    status_t status = lpRecorder->addAudioDeviceCallback(cb);
-    if (status == NO_ERROR) {
-        setJniDeviceCallback(env, thiz, cb);
-    }
+    pJniStorage->setDeviceCallback(
+            sp<JNIDeviceCallback>::make(env, thiz, pJniStorage->getAudioTrackWeakRef(),
+                                        javaAudioRecordFields.postNativeEventInJava));
+    lpRecorder->addAudioDeviceCallback(pJniStorage->getDeviceCallback());
 }
 
 static void android_media_AudioRecord_disableDeviceCallback(
                 JNIEnv *env,  jobject thiz) {
-
     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
-    if (lpRecorder == 0) {
+    if (lpRecorder == nullptr) {
         return;
     }
-    sp<JNIDeviceCallback> cb = setJniDeviceCallback(env, thiz, 0);
-    if (cb != 0) {
-        lpRecorder->removeAudioDeviceCallback(cb);
+    const auto pJniStorage =
+            getFieldSp<AudioRecordJNIStorage>(env, thiz, javaAudioRecordFields.jniData);
+
+    if (pJniStorage == nullptr || pJniStorage->getDeviceCallback() == nullptr) {
+        return;
     }
+    lpRecorder->removeAudioDeviceCallback(pJniStorage->getDeviceCallback());
+    pJniStorage->setDeviceCallback(nullptr);
 }
 
 // ----------------------------------------------------------------------------
@@ -962,17 +877,15 @@
 
 // field names found in android/media/AudioRecord.java
 #define JAVA_POSTEVENT_CALLBACK_NAME  "postEventFromNative"
-#define JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME  "mNativeRecorderInJavaObj"
-#define JAVA_NATIVECALLBACKINFO_FIELD_NAME       "mNativeCallbackCookie"
-#define JAVA_NATIVEDEVICECALLBACK_FIELD_NAME       "mNativeDeviceCallback"
+#define JAVA_NATIVEAUDIORECORDERHANDLE_FIELD_NAME  "mNativeAudioRecordHandle"
+#define JAVA_NATIVEJNIDATAHANDLE_FIELD_NAME        "mNativeJNIDataHandle"
 
 // ----------------------------------------------------------------------------
 int register_android_media_AudioRecord(JNIEnv *env)
 {
     javaAudioRecordFields.postNativeEventInJava = NULL;
     javaAudioRecordFields.nativeRecorderInJavaObj = NULL;
-    javaAudioRecordFields.nativeCallbackCookie = NULL;
-    javaAudioRecordFields.nativeDeviceCallback = NULL;
+    javaAudioRecordFields.jniData = NULL;
 
 
     // Get the AudioRecord class
@@ -983,15 +896,12 @@
             "(Ljava/lang/Object;IIILjava/lang/Object;)V");
 
     // Get the variables
-    //    mNativeRecorderInJavaObj
+    //    mNativeAudioRecordHandle
     javaAudioRecordFields.nativeRecorderInJavaObj = GetFieldIDOrDie(env,
-            audioRecordClass, JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME, "J");
-    //     mNativeCallbackCookie
-    javaAudioRecordFields.nativeCallbackCookie = GetFieldIDOrDie(env,
-            audioRecordClass, JAVA_NATIVECALLBACKINFO_FIELD_NAME, "J");
-
-    javaAudioRecordFields.nativeDeviceCallback = GetFieldIDOrDie(env,
-            audioRecordClass, JAVA_NATIVEDEVICECALLBACK_FIELD_NAME, "J");
+            audioRecordClass, JAVA_NATIVEAUDIORECORDERHANDLE_FIELD_NAME, "J");
+    //   mNativeJNIDataHandle
+    javaAudioRecordFields.jniData = GetFieldIDOrDie(env,
+            audioRecordClass, JAVA_NATIVEJNIDATAHANDLE_FIELD_NAME, "J");
 
     // Get the RecordTimestamp class and fields
     jclass audioTimestampClass = FindClassOrDie(env, "android/media/AudioTimestamp");
diff --git a/core/jni/android_media_JNIUtils.h b/core/jni/android_media_JNIUtils.h
index 9da5fa3..a413d09 100644
--- a/core/jni/android_media_JNIUtils.h
+++ b/core/jni/android_media_JNIUtils.h
@@ -64,5 +64,39 @@
     return env;
 }
 
+class GlobalRef {
+  public:
+    GlobalRef(jobject object) : GlobalRef(object, AndroidRuntime::getJNIEnv()) {}
+
+    GlobalRef(jobject object, JNIEnv* env) {
+        LOG_ALWAYS_FATAL_IF(env == nullptr, "Invalid JNIEnv when attempting to create a GlobalRef");
+        mGlobalRef = env->NewGlobalRef(object);
+        LOG_ALWAYS_FATAL_IF(env->IsSameObject(object, nullptr) == JNI_TRUE,
+                            "Creating GlobalRef from null object");
+    }
+
+    GlobalRef(const GlobalRef& other) : GlobalRef(other.mGlobalRef) {}
+
+    GlobalRef(GlobalRef&& other) : mGlobalRef(other.mGlobalRef) { other.mGlobalRef = nullptr; }
+
+    // Logically const
+    GlobalRef& operator=(const GlobalRef& other) = delete;
+
+    GlobalRef& operator=(GlobalRef&& other) = delete;
+
+    ~GlobalRef() {
+        if (mGlobalRef == nullptr) return; // No reference to decrement
+        getJNIEnvOrDie()->DeleteGlobalRef(mGlobalRef);
+    }
+
+    // Valid as long as this wrapper is in scope.
+    jobject get() const {
+      return mGlobalRef;
+    }
+
+  private:
+    // Logically const. Not actually const so we can move from GlobalRef
+    jobject mGlobalRef;
+};
 
 } // namespace android
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 518fc09..51a708b 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -24,7 +24,9 @@
 
 #include <memory>
 
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
 #include <android-base/chrono_utils.h>
+#include <android/graphics/properties.h>
 #include <android/graphics/region.h>
 #include <android/gui/BnScreenCaptureListener.h>
 #include <android/hardware/display/IDeviceProductInfoConstants.h>
@@ -1888,6 +1890,11 @@
         return nullptr;
     }
 
+    using aidl::android::hardware::graphics::common::PixelFormat;
+    if (support.value().format == PixelFormat::R_8 && !hwui_uses_vulkan()) {
+        return nullptr;
+    }
+
     jobject jDisplayDecorationSupport =
             env->NewObject(gDisplayDecorationSupportInfo.clazz, gDisplayDecorationSupportInfo.ctor);
     if (jDisplayDecorationSupport == nullptr) {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cd3ba1e..0e3840a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5678,8 +5678,8 @@
          restricted level.
     -->
     <array name="config_bg_current_drain_threshold_to_bg_restricted">
-        <item>4.0</item> <!-- regular device -->
-        <item>8.0</item> <!-- low ram device -->
+        <item>10.0</item> <!-- regular device -->
+        <item>20.0</item> <!-- low ram device -->
     </array>
 
     <!-- The background current drain monitoring window size. -->
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index cd3578c..77500c4 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -17,9 +17,9 @@
 <resources>
     <!-- This file defines Android telephony related resources -->
 
-    <!-- Whether force to enable telephony new data stack or not -->
-    <bool name="config_force_enable_telephony_new_data_stack">true</bool>
-    <java-symbol type="bool" name="config_force_enable_telephony_new_data_stack" />
+    <!-- Whether force disabling telephony new data stack or not -->
+    <bool name="config_force_disable_telephony_new_data_stack">false</bool>
+    <java-symbol type="bool" name="config_force_disable_telephony_new_data_stack" />
 
     <!-- Configure tcp buffer sizes per network type in the form:
          network-type:rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max
diff --git a/core/res/res/values/public-final.xml b/core/res/res/values/public-final.xml
index 19a4842..85325fe 100644
--- a/core/res/res/values/public-final.xml
+++ b/core/res/res/values/public-final.xml
@@ -3222,4 +3222,184 @@
   <public type="id" name="accessibilityActionDragDrop" id="0x01020056" />
   <public type="id" name="accessibilityActionDragCancel" id="0x01020057" />
 
+  <!-- ===============================================================
+    Resources added in version T of the platform
+
+    NOTE: After this version of the platform is forked, changes cannot be made to the root
+    branch's groups for that release. Only merge changes to the forked platform branch.
+    =============================================================== -->
+  <eat-comment/>
+
+  <staging-public-group-final type="attr" first-id="0x01df0000">
+    <public name="sharedUserMaxSdkVersion" />
+    <public name="requiredSplitTypes" />
+    <public name="splitTypes" />
+    <public name="canDisplayOnRemoteDevices" />
+    <public name="supportedTypes" />
+    <public name="resetEnabledSettingsOnAppDataCleared" />
+    <public name="supportsStylusHandwriting" />
+    <public name="showClockAndComplications" />
+    <!-- @hide @SystemApi -->
+    <public name="gameSessionService" />
+    <public name="supportsBatteryGameMode" />
+    <public name="supportsPerformanceGameMode" />
+    <public name="allowGameAngleDriver" />
+    <public name="allowGameDownscaling" />
+    <public name="allowGameFpsOverride" />
+    <public name="localeConfig" />
+    <public name="showBackdrop" />
+    <public name="removed_useTargetActivityForQuickAccess"/>
+    <public name="removed_inheritKeyStoreKeys" />
+    <public name="preferKeepClear" />
+    <public name="autoHandwritingEnabled" />
+    <public name="fromExtendLeft" />
+    <public name="fromExtendTop" />
+    <public name="fromExtendRight" />
+    <public name="fromExtendBottom" />
+    <public name="toExtendLeft" />
+    <public name="toExtendTop" />
+    <public name="toExtendRight" />
+    <public name="toExtendBottom" />
+    <public name="tileService" />
+    <public name="windowSplashScreenBehavior" />
+    <public name="allowUntrustedActivityEmbedding" />
+    <public name="knownActivityEmbeddingCerts" />
+    <public name="intro" />
+    <public name="enableOnBackInvokedCallback" />
+    <public name="supportsInlineSuggestionsWithTouchExploration" />
+    <public name="lineBreakStyle" />
+    <public name="lineBreakWordStyle" />
+    <!-- @hide -->
+    <public name="maxDrawableWidth" />
+    <!-- @hide -->
+    <public name="maxDrawableHeight" />
+    <public name="backdropColor" />
+  </staging-public-group-final>
+
+  <public type="attr" name="sharedUserMaxSdkVersion" id="0x0101064d" />
+  <public type="attr" name="requiredSplitTypes" id="0x0101064e" />
+  <public type="attr" name="splitTypes" id="0x0101064f" />
+  <public type="attr" name="canDisplayOnRemoteDevices" id="0x01010650" />
+  <public type="attr" name="supportedTypes" id="0x01010651" />
+  <public type="attr" name="resetEnabledSettingsOnAppDataCleared" id="0x01010652" />
+  <public type="attr" name="supportsStylusHandwriting" id="0x01010653" />
+  <public type="attr" name="showClockAndComplications" id="0x01010654" />
+    <!-- @hide @SystemApi -->
+  <public type="attr" name="gameSessionService" id="0x01010655" />
+  <public type="attr" name="supportsBatteryGameMode" id="0x01010656" />
+  <public type="attr" name="supportsPerformanceGameMode" id="0x01010657" />
+  <public type="attr" name="allowGameAngleDriver" id="0x01010658" />
+  <public type="attr" name="allowGameDownscaling" id="0x01010659" />
+  <public type="attr" name="allowGameFpsOverride" id="0x0101065a" />
+  <public type="attr" name="localeConfig" id="0x0101065b" />
+  <public type="attr" name="showBackdrop" id="0x0101065c" />
+  <public type="attr" name="preferKeepClear" id="0x0101065d" />
+  <public type="attr" name="autoHandwritingEnabled" id="0x0101065e" />
+  <public type="attr" name="fromExtendLeft" id="0x0101065f" />
+  <public type="attr" name="fromExtendTop" id="0x01010660" />
+  <public type="attr" name="fromExtendRight" id="0x01010661" />
+  <public type="attr" name="fromExtendBottom" id="0x01010662" />
+  <public type="attr" name="toExtendLeft" id="0x01010663" />
+  <public type="attr" name="toExtendTop" id="0x01010664" />
+  <public type="attr" name="toExtendRight" id="0x01010665" />
+  <public type="attr" name="toExtendBottom" id="0x01010666" />
+  <public type="attr" name="tileService" id="0x01010667" />
+  <public type="attr" name="windowSplashScreenBehavior" id="0x01010668" />
+  <public type="attr" name="allowUntrustedActivityEmbedding" id="0x01010669" />
+  <public type="attr" name="knownActivityEmbeddingCerts" id="0x0101066a" />
+  <public type="attr" name="intro" id="0x0101066b" />
+  <public type="attr" name="enableOnBackInvokedCallback" id="0x0101066c" />
+  <public type="attr" name="supportsInlineSuggestionsWithTouchExploration" id="0x0101066d" />
+  <public type="attr" name="lineBreakStyle" id="0x0101066e" />
+  <public type="attr" name="lineBreakWordStyle" id="0x0101066f" />
+    <!-- @hide -->
+  <public type="attr" name="maxDrawableWidth" id="0x01010670" />
+    <!-- @hide -->
+  <public type="attr" name="maxDrawableHeight" id="0x01010671" />
+  <public type="attr" name="backdropColor" id="0x01010672" />
+
+  <staging-public-group-final type="id" first-id="0x01de0000">
+    <public name="removed_accessibilityActionSwipeLeft" />
+    <public name="removed_accessibilityActionSwipeRight" />
+    <public name="removed_accessibilityActionSwipeUp" />
+    <public name="removed_accessibilityActionSwipeDown" />
+    <public name="accessibilityActionShowTextSuggestions" />
+    <public name="inputExtractAction" />
+    <public name="inputExtractAccessories" />
+  </staging-public-group-final>
+
+  <public type="id" name="accessibilityActionShowTextSuggestions" id="0x01020058" />
+  <public type="id" name="inputExtractAction" id="0x01020059" />
+  <public type="id" name="inputExtractAccessories" id="0x0102005a" />
+
+  <staging-public-group-final type="style" first-id="0x01dd0000">
+    <public name="TextAppearance.DeviceDefault.Headline" />
+  </staging-public-group-final>
+
+  <public type="style" name="TextAppearance.DeviceDefault.Headline" id="0x010302e5" />
+
+  <staging-public-group-final type="string" first-id="0x01dc0000">
+    <!-- @hide @SystemApi -->
+    <public name="config_systemSupervision" />
+    <!-- @hide @SystemApi -->
+    <public name="config_devicePolicyManagement" />
+    <!-- @hide @SystemApi -->
+    <public name="config_systemAppProtectionService" />
+    <!-- @hide @SystemApi @TestApi -->
+    <public name="config_systemAutomotiveCalendarSyncManager" />
+    <!-- @hide @SystemApi -->
+    <public name="config_defaultAutomotiveNavigation" />
+    <!-- @hide @SystemApi -->
+    <public name="safety_protection_display_text" />
+    <!-- @hide @SystemApi -->
+    <public name="config_systemSettingsIntelligence" />
+    <!-- @hide -->
+    <public name="config_systemBluetoothStack" />
+  </staging-public-group-final>
+
+    <!-- @hide @SystemApi -->
+  <public type="string" name="config_systemSupervision" id="0x0104003c" />
+    <!-- @hide @SystemApi -->
+  <public type="string" name="config_devicePolicyManagement" id="0x0104003d" />
+    <!-- @hide @SystemApi -->
+  <public type="string" name="config_systemAppProtectionService" id="0x0104003e" />
+    <!-- @hide @SystemApi @TestApi -->
+  <public type="string" name="config_systemAutomotiveCalendarSyncManager" id="0x0104003f" />
+    <!-- @hide @SystemApi -->
+  <public type="string" name="config_defaultAutomotiveNavigation" id="0x01040040" />
+    <!-- @hide @SystemApi -->
+  <public type="string" name="safety_protection_display_text" id="0x01040041" />
+    <!-- @hide @SystemApi -->
+  <public type="string" name="config_systemSettingsIntelligence" id="0x01040042" />
+    <!-- @hide -->
+  <public type="string" name="config_systemBluetoothStack" id="0x01040043" />
+
+  <staging-public-group-final type="array" first-id="0x01d90000">
+    <!-- @hide @SystemApi -->
+    <public name="config_optionalIpSecAlgorithms" />
+  </staging-public-group-final>
+
+    <!-- @hide @SystemApi -->
+  <public type="array" name="config_optionalIpSecAlgorithms" id="0x01070006" />
+
+  <staging-public-group-final type="drawable" first-id="0x01d80000">
+    <!-- @hide @SystemApi -->
+    <public name="ic_safety_protection" />
+  </staging-public-group-final>
+
+    <!-- @hide @SystemApi -->
+  <public type="drawable" name="ic_safety_protection" id="0x010800b5" />
+
+  <staging-public-group-final type="bool" first-id="0x01cf0000">
+    <!-- @hide @TestApi -->
+    <public name="config_preventImeStartupUnlessTextEditor" />
+    <!-- @hide @SystemApi -->
+    <public name="config_enableQrCodeScannerOnLockScreen" />
+  </staging-public-group-final>
+
+    <!-- @hide @TestApi -->
+  <public type="bool" name="config_preventImeStartupUnlessTextEditor" id="0x01110007" />
+    <!-- @hide @SystemApi -->
+  <public type="bool" name="config_enableQrCodeScannerOnLockScreen" id="0x01110008" />
+
 </resources>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index 86bad7f..f09ffbe 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -102,140 +102,65 @@
 <resources>
 
   <!-- ===============================================================
-    Resources added in version T of the platform
+    Resources added in version U of the platform
 
     NOTE: After this version of the platform is forked, changes cannot be made to the root
     branch's groups for that release. Only merge changes to the forked platform branch.
     =============================================================== -->
   <eat-comment/>
 
-  <staging-public-group type="attr" first-id="0x01df0000">
-    <public name="sharedUserMaxSdkVersion" />
-    <public name="requiredSplitTypes" />
-    <public name="splitTypes" />
-    <public name="canDisplayOnRemoteDevices" />
-    <public name="supportedTypes" />
-    <public name="resetEnabledSettingsOnAppDataCleared" />
-    <public name="supportsStylusHandwriting" />
-    <public name="showClockAndComplications" />
-    <!-- @hide @SystemApi -->
-    <public name="gameSessionService" />
-    <public name="supportsBatteryGameMode" />
-    <public name="supportsPerformanceGameMode" />
-    <public name="allowGameAngleDriver" />
-    <public name="allowGameDownscaling" />
-    <public name="allowGameFpsOverride" />
-    <public name="localeConfig" />
-    <public name="showBackdrop" />
-    <public name="removed_useTargetActivityForQuickAccess"/>
-    <public name="removed_inheritKeyStoreKeys" />
-    <public name="preferKeepClear" />
-    <public name="autoHandwritingEnabled" />
-    <public name="fromExtendLeft" />
-    <public name="fromExtendTop" />
-    <public name="fromExtendRight" />
-    <public name="fromExtendBottom" />
-    <public name="toExtendLeft" />
-    <public name="toExtendTop" />
-    <public name="toExtendRight" />
-    <public name="toExtendBottom" />
-    <public name="tileService" />
-    <public name="windowSplashScreenBehavior" />
-    <public name="allowUntrustedActivityEmbedding" />
-    <public name="knownActivityEmbeddingCerts" />
-    <public name="intro" />
-    <public name="enableOnBackInvokedCallback" />
-    <public name="supportsInlineSuggestionsWithTouchExploration" />
-    <public name="lineBreakStyle" />
-    <public name="lineBreakWordStyle" />
-    <!-- @hide -->
-    <public name="maxDrawableWidth" />
-    <!-- @hide -->
-    <public name="maxDrawableHeight" />
-    <public name="backdropColor" />
+  <staging-public-group type="attr" first-id="0x01ce0000">
   </staging-public-group>
 
-  <staging-public-group type="id" first-id="0x01de0000">
-    <public name="removed_accessibilityActionSwipeLeft" />
-    <public name="removed_accessibilityActionSwipeRight" />
-    <public name="removed_accessibilityActionSwipeUp" />
-    <public name="removed_accessibilityActionSwipeDown" />
-    <public name="accessibilityActionShowTextSuggestions" />
-    <public name="inputExtractAction" />
-    <public name="inputExtractAccessories" />
+  <staging-public-group type="id" first-id="0x01cd0000">
   </staging-public-group>
 
-  <staging-public-group type="style" first-id="0x01dd0000">
-    <public name="TextAppearance.DeviceDefault.Headline" />
+  <staging-public-group type="style" first-id="0x01cc0000">
   </staging-public-group>
 
-  <staging-public-group type="string" first-id="0x01dc0000">
-    <!-- @hide @SystemApi -->
-    <public name="config_systemSupervision" />
-    <!-- @hide @SystemApi -->
-    <public name="config_devicePolicyManagement" />
-    <!-- @hide @SystemApi -->
-    <public name="config_systemAppProtectionService" />
-    <!-- @hide @SystemApi @TestApi -->
-    <public name="config_systemAutomotiveCalendarSyncManager" />
-    <!-- @hide @SystemApi -->
-    <public name="config_defaultAutomotiveNavigation" />
-    <!-- @hide @SystemApi -->
-    <public name="safety_protection_display_text" />
-    <!-- @hide @SystemApi -->
-    <public name="config_systemSettingsIntelligence" />
-    <!-- @hide -->
-    <public name="config_systemBluetoothStack" />
+  <staging-public-group type="string" first-id="0x01cb0000">
   </staging-public-group>
 
-  <staging-public-group type="dimen" first-id="0x01db0000">
+  <staging-public-group type="dimen" first-id="0x01ca0000">
   </staging-public-group>
 
-  <staging-public-group type="color" first-id="0x01da0000">
+  <staging-public-group type="color" first-id="0x01c90000">
   </staging-public-group>
 
-  <staging-public-group type="array" first-id="0x01d90000">
-    <!-- @hide @SystemApi -->
-    <public name="config_optionalIpSecAlgorithms" />
+  <staging-public-group type="array" first-id="0x01c80000">
   </staging-public-group>
 
-  <staging-public-group type="drawable" first-id="0x01d80000">
-    <!-- @hide @SystemApi -->
-    <public name="ic_safety_protection" />
+  <staging-public-group type="drawable" first-id="0x01c70000">
   </staging-public-group>
 
-  <staging-public-group type="layout" first-id="0x01d70000">
+  <staging-public-group type="layout" first-id="0x01c60000">
   </staging-public-group>
 
-  <staging-public-group type="anim" first-id="0x01d60000">
+  <staging-public-group type="anim" first-id="0x01c50000">
   </staging-public-group>
 
-  <staging-public-group type="animator" first-id="0x01d50000">
+  <staging-public-group type="animator" first-id="0x01c40000">
   </staging-public-group>
 
-  <staging-public-group type="interpolator" first-id="0x01d40000">
+  <staging-public-group type="interpolator" first-id="0x01c30000">
   </staging-public-group>
 
-  <staging-public-group type="mipmap" first-id="0x01d30000">
+  <staging-public-group type="mipmap" first-id="0x01c20000">
   </staging-public-group>
 
-  <staging-public-group type="integer" first-id="0x01d20000">
+  <staging-public-group type="integer" first-id="0x01c10000">
   </staging-public-group>
 
-  <staging-public-group type="transition" first-id="0x01d10000">
+  <staging-public-group type="transition" first-id="0x01c00000">
   </staging-public-group>
 
-  <staging-public-group type="raw" first-id="0x01d00000">
+  <staging-public-group type="raw" first-id="0x01bf0000">
   </staging-public-group>
 
-  <staging-public-group type="bool" first-id="0x01cf0000">
-    <!-- @hide @TestApi -->
-    <public name="config_preventImeStartupUnlessTextEditor" />
-    <!-- @hide @SystemApi -->
-    <public name="config_enableQrCodeScannerOnLockScreen" />
+  <staging-public-group type="bool" first-id="0x01be0000">
   </staging-public-group>
 
-  <staging-public-group type="fraction" first-id="0x01ce0000">
+  <staging-public-group type="fraction" first-id="0x01bd0000">
   </staging-public-group>
 
 </resources>
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index bf8bb76..be9da11 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -217,7 +217,8 @@
         mState.getSource(ITYPE_CAPTION_BAR).setVisible(true);
 
         Insets visibleInsets = mState.calculateVisibleInsets(
-                new Rect(0, 0, 100, 400), SOFT_INPUT_ADJUST_NOTHING);
+                new Rect(0, 0, 100, 400), TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                SOFT_INPUT_ADJUST_NOTHING, 0 /* windowFlags */);
         assertEquals(Insets.of(0, 300, 0, 0), visibleInsets);
     }
 
@@ -227,7 +228,8 @@
         mState.getSource(ITYPE_CAPTION_BAR).setVisible(true);
 
         Insets visibleInsets = mState.calculateVisibleInsets(
-                new Rect(0, 0, 150, 400), SOFT_INPUT_ADJUST_NOTHING);
+                new Rect(0, 0, 150, 400), TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                SOFT_INPUT_ADJUST_NOTHING, 0 /* windowFlags */);
         assertEquals(Insets.of(0, 300, 0, 0), visibleInsets);
     }
 
@@ -414,7 +416,8 @@
         mState.getSource(ITYPE_BOTTOM_GESTURES).setFrame(new Rect(0, 100, 100, 300));
         mState.getSource(ITYPE_BOTTOM_GESTURES).setVisible(true);
         Insets visibleInsets = mState.calculateVisibleInsets(
-                new Rect(0, 0, 100, 300), SOFT_INPUT_ADJUST_PAN);
+                new Rect(0, 0, 100, 300), TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                SOFT_INPUT_ADJUST_PAN, 0 /* windowFlags */);
         assertEquals(Insets.of(0, 100, 0, 100), visibleInsets);
     }
 
@@ -429,11 +432,28 @@
         mState.getSource(ITYPE_BOTTOM_GESTURES).setFrame(new Rect(0, 100, 100, 300));
         mState.getSource(ITYPE_BOTTOM_GESTURES).setVisible(true);
         Insets visibleInsets = mState.calculateVisibleInsets(
-                new Rect(0, 0, 100, 300), SOFT_INPUT_ADJUST_NOTHING);
+                new Rect(0, 0, 100, 300), TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                SOFT_INPUT_ADJUST_NOTHING, 0 /* windowFlags */);
         assertEquals(Insets.of(0, 100, 0, 0), visibleInsets);
     }
 
     @Test
+    public void testCalculateVisibleInsets_layoutNoLimits() {
+        mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100));
+        mState.getSource(ITYPE_STATUS_BAR).setVisible(true);
+        mState.getSource(ITYPE_IME).setFrame(new Rect(0, 200, 100, 300));
+        mState.getSource(ITYPE_IME).setVisible(true);
+
+        // Make sure bottom gestures are ignored
+        mState.getSource(ITYPE_BOTTOM_GESTURES).setFrame(new Rect(0, 100, 100, 300));
+        mState.getSource(ITYPE_BOTTOM_GESTURES).setVisible(true);
+        Insets visibleInsets = mState.calculateVisibleInsets(
+                new Rect(0, 0, 100, 300), TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                SOFT_INPUT_ADJUST_PAN, FLAG_LAYOUT_NO_LIMITS);
+        assertEquals(Insets.NONE, visibleInsets);
+    }
+
+    @Test
     public void testCalculateUncontrollableInsets() {
         mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 200, 100));
         mState.getSource(ITYPE_STATUS_BAR).setVisible(true);
diff --git a/core/tests/coretests/src/android/view/WindowInfoTest.java b/core/tests/coretests/src/android/view/WindowInfoTest.java
index 0a99b08..afc2c00 100644
--- a/core/tests/coretests/src/android/view/WindowInfoTest.java
+++ b/core/tests/coretests/src/android/view/WindowInfoTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.Mockito.mock;
 
 import android.app.ActivityTaskManager;
+import android.graphics.Matrix;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
@@ -38,6 +39,7 @@
 import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 
 /**
  * Class for testing {@link WindowInfo}.
@@ -94,6 +96,8 @@
         assertFalse(w.inPictureInPicture);
         assertFalse(w.hasFlagWatchOutsideTouch);
         assertTrue(w.regionInScreen.isEmpty());
+        assertEquals(w.mTransformMatrix.length, 9);
+        assertTrue(w.mMagnificationSpec.isNop());
     }
 
     @SmallTest
@@ -117,6 +121,8 @@
         equality &= w1.parentToken == w2.parentToken;
         equality &= w1.activityToken == w2.activityToken;
         equality &= w1.regionInScreen.equals(w2.regionInScreen);
+        equality &= w1.mMagnificationSpec.equals(w2.mMagnificationSpec);
+        equality &= Arrays.equals(w1.mTransformMatrix, w2.mTransformMatrix);
         return equality;
     }
 
@@ -136,5 +142,9 @@
         windowInfo.inPictureInPicture = true;
         windowInfo.hasFlagWatchOutsideTouch = true;
         windowInfo.regionInScreen.set(0, 0, 1080, 1080);
+        windowInfo.mMagnificationSpec.scale = 2.0f;
+        windowInfo.mMagnificationSpec.offsetX = 100f;
+        windowInfo.mMagnificationSpec.offsetY = 200f;
+        Matrix.IDENTITY_MATRIX.getValues(windowInfo.mTransformMatrix);
     }
 }
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 3ec8843..33a41ec 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -155,13 +155,18 @@
         // Check if there are no running activities - consider the container empty if there are no
         // non-finishing activities left.
         if (!taskFragmentInfo.hasRunningActivity()) {
-            // TODO(b/225371112): Don't finish dependent if the last activity is moved to the PIP
-            // Task.
-            // Do not finish the dependents if this TaskFragment was cleared due to launching
-            // activity in the Task.
-            final boolean shouldFinishDependent =
-                    !taskFragmentInfo.isTaskClearedForReuse();
-            mPresenter.cleanupContainer(container, shouldFinishDependent);
+            if (taskFragmentInfo.isTaskFragmentClearedForPip()) {
+                // Do not finish the dependents if the last activity is reparented to PiP.
+                // Instead, the original split should be cleanup, and the dependent may be expanded
+                // to fullscreen.
+                cleanupForEnterPip(container);
+                mPresenter.cleanupContainer(container, false /* shouldFinishDependent */);
+            } else {
+                // Do not finish the dependents if this TaskFragment was cleared due to launching
+                // activity in the Task.
+                final boolean shouldFinishDependent = !taskFragmentInfo.isTaskClearedForReuse();
+                mPresenter.cleanupContainer(container, shouldFinishDependent);
+            }
         } else if (wasInPip && isInPip) {
             // No update until exit PIP.
             return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index f60b659..322c0bf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -913,8 +913,10 @@
                             afterExpandedViewAnimation();
                             showManageMenu(mShowingManage);
                         } /* after */);
+                        PointF p = mPositioner.getExpandedBubbleXY(getBubbleIndex(mExpandedBubble),
+                                getState());
                         final float translationY = mPositioner.getExpandedViewY(mExpandedBubble,
-                                getBubbleIndex(mExpandedBubble));
+                                mPositioner.showBubblesVertically() ? p.y : p.x);
                         mExpandedViewContainer.setTranslationX(0f);
                         mExpandedViewContainer.setTranslationY(translationY);
                         mExpandedViewContainer.setAlpha(1f);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index 6f4e22f..79d795e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -32,6 +32,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Resources;
@@ -336,6 +337,12 @@
         return navigationBarPosition(res, mWidth, mHeight, mRotation);
     }
 
+    /** @return {@link DisplayCutout} instance. */
+    @Nullable
+    public DisplayCutout getDisplayCutout() {
+        return mCutout;
+    }
+
     /**
      * Calculates the stable insets if we already have the non-decor insets.
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
index e28c58c..9754a03 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
@@ -37,7 +37,6 @@
 import android.graphics.Region.Op;
 import android.hardware.display.DisplayManager;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.util.AttributeSet;
 import android.util.Slog;
 import android.view.Choreographer;
@@ -241,22 +240,6 @@
         }
     };
 
-    private Runnable mUpdateEmbeddedMatrix = () -> {
-        if (getViewRootImpl() == null) {
-            return;
-        }
-        if (isHorizontalDivision()) {
-            mTmpMatrix.setTranslate(0, mDividerPositionY - mDividerInsets);
-        } else {
-            mTmpMatrix.setTranslate(mDividerPositionX - mDividerInsets, 0);
-        }
-        mTmpMatrix.getValues(mTmpValues);
-        try {
-            getViewRootImpl().getAccessibilityEmbeddedConnection().setScreenMatrix(mTmpValues);
-        } catch (RemoteException e) {
-        }
-    };
-
     public DividerView(Context context) {
         this(context, null);
     }
@@ -1045,10 +1028,6 @@
                 t.setPosition(dividerCtrl, mDividerPositionX - mDividerInsets, 0);
             }
         }
-        if (getViewRootImpl() != null) {
-            getHandler().removeCallbacks(mUpdateEmbeddedMatrix);
-            getHandler().post(mUpdateEmbeddedMatrix);
-        }
     }
 
     void setResizeDimLayer(Transaction t, boolean primary, float alpha) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index 5e4c12e..f73b81e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -135,19 +135,6 @@
         }
     };
 
-    private final float[] mTmpValues = new float[9];
-    private final Runnable mUpdateEmbeddedMatrix = () -> {
-        if (mPipMenuView == null || mPipMenuView.getViewRootImpl() == null) {
-            return;
-        }
-        mMoveTransform.getValues(mTmpValues);
-        try {
-            mPipMenuView.getViewRootImpl().getAccessibilityEmbeddedConnection()
-                    .setScreenMatrix(mTmpValues);
-        } catch (RemoteException e) {
-        }
-    };
-
     public PhonePipMenuController(Context context, PipBoundsState pipBoundsState,
             PipMediaController mediaController, SystemWindows systemWindows,
             Optional<SplitScreenController> splitScreenOptional,
@@ -348,11 +335,6 @@
         } else {
             mApplier.scheduleApply(params);
         }
-
-        if (mPipMenuView.getViewRootImpl() != null) {
-            mPipMenuView.getHandler().removeCallbacks(mUpdateEmbeddedMatrix);
-            mPipMenuView.getHandler().post(mUpdateEmbeddedMatrix);
-        }
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
index 69ae45d..7365b95 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
@@ -285,7 +285,7 @@
                 Region bounds, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int flags,
                 int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
-                Bundle arguments) throws RemoteException {
+                float[] matrixValues, Bundle arguments) throws RemoteException {
             mMainExcutor.execute(() -> {
                 PipAccessibilityInteractionConnection.this
                         .findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId, bounds,
@@ -298,7 +298,8 @@
         public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId, String viewId,
                 Region bounds, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int flags,
-                int interrogatingPid, long interrogatingTid, MagnificationSpec spec)
+                int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
+                float[] matrixValues)
                 throws RemoteException {
             mMainExcutor.execute(() -> {
                 PipAccessibilityInteractionConnection.this.findAccessibilityNodeInfosByViewId(
@@ -311,7 +312,8 @@
         public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
                 Region bounds, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int flags,
-                int interrogatingPid, long interrogatingTid, MagnificationSpec spec)
+                int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
+                float[] matrixValues)
                 throws RemoteException {
             mMainExcutor.execute(() -> {
                 PipAccessibilityInteractionConnection.this.findAccessibilityNodeInfosByText(
@@ -323,7 +325,8 @@
         @Override
         public void findFocus(long accessibilityNodeId, int focusType, Region bounds,
                 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
-                int interrogatingPid, long interrogatingTid, MagnificationSpec spec)
+                int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
+                float[] matrixValues)
                 throws RemoteException {
             mMainExcutor.execute(() -> {
                 PipAccessibilityInteractionConnection.this.findFocus(accessibilityNodeId, focusType,
@@ -335,7 +338,8 @@
         @Override
         public void focusSearch(long accessibilityNodeId, int direction, Region bounds,
                 int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
-                int interrogatingPid, long interrogatingTid, MagnificationSpec spec)
+                int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
+                float[] matrixValues)
                 throws RemoteException {
             mMainExcutor.execute(() -> {
                 PipAccessibilityInteractionConnection.this.focusSearch(accessibilityNodeId,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 147a272..ac7b9033b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -36,6 +36,7 @@
 import android.graphics.Rect;
 import android.provider.DeviceConfig;
 import android.util.Size;
+import android.view.DisplayCutout;
 import android.view.InputEvent;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
@@ -959,21 +960,38 @@
         }
 
         private boolean shouldStash(PointF vel, Rect motionBounds) {
+            final boolean flingToLeft = vel.x < -mStashVelocityThreshold;
+            final boolean flingToRight = vel.x > mStashVelocityThreshold;
+            final int offset = motionBounds.width() / 2;
+            final boolean droppingOnLeft =
+                    motionBounds.left < mPipBoundsState.getDisplayBounds().left - offset;
+            final boolean droppingOnRight =
+                    motionBounds.right > mPipBoundsState.getDisplayBounds().right + offset;
+
+            // Do not allow stash if the destination edge contains display cutout. We only
+            // compare the left and right edges since we do not allow stash on top / bottom.
+            final DisplayCutout displayCutout =
+                    mPipBoundsState.getDisplayLayout().getDisplayCutout();
+            if (displayCutout != null) {
+                if ((flingToLeft || droppingOnLeft)
+                        && !displayCutout.getBoundingRectLeft().isEmpty()) {
+                    return false;
+                } else if ((flingToRight || droppingOnRight)
+                        && !displayCutout.getBoundingRectRight().isEmpty()) {
+                    return false;
+                }
+            }
+
             // If user flings the PIP window above the minimum velocity, stash PIP.
             // Only allow stashing to the edge if PIP wasn't previously stashed on the opposite
             // edge.
-            final boolean stashFromFlingToEdge = ((vel.x < -mStashVelocityThreshold
-                    && mPipBoundsState.getStashedState() != STASH_TYPE_RIGHT)
-                    || (vel.x > mStashVelocityThreshold
-                    && mPipBoundsState.getStashedState() != STASH_TYPE_LEFT));
+            final boolean stashFromFlingToEdge =
+                    (flingToLeft && mPipBoundsState.getStashedState() != STASH_TYPE_RIGHT)
+                    || (flingToRight && mPipBoundsState.getStashedState() != STASH_TYPE_LEFT);
 
             // If User releases the PIP window while it's out of the display bounds, put
             // PIP into stashed mode.
-            final int offset = motionBounds.width() / 2;
-            final boolean stashFromDroppingOnEdge =
-                    (motionBounds.right > mPipBoundsState.getDisplayBounds().right + offset
-                            || motionBounds.left
-                            < mPipBoundsState.getDisplayBounds().left - offset);
+            final boolean stashFromDroppingOnEdge = droppingOnLeft || droppingOnRight;
 
             return stashFromFlingToEdge || stashFromDroppingOnEdge;
         }
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 7b8dcf7..2d67254 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
@@ -30,7 +30,6 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.Handler;
-import android.os.RemoteException;
 import android.view.LayoutInflater;
 import android.view.SurfaceControl;
 import android.view.SyncRtSurfaceTransactionApplier;
@@ -88,19 +87,6 @@
     RectF mTmpDestinationRectF = new RectF();
     Matrix mMoveTransform = new Matrix();
 
-    private final float[] mTmpValues = new float[9];
-    private final Runnable mUpdateEmbeddedMatrix = () -> {
-        if (mPipMenuView == null || mPipMenuView.getViewRootImpl() == null) {
-            return;
-        }
-        mMoveTransform.getValues(mTmpValues);
-        try {
-            mPipMenuView.getViewRootImpl().getAccessibilityEmbeddedConnection()
-                    .setScreenMatrix(mTmpValues);
-        } catch (RemoteException e) {
-            if (DEBUG) e.printStackTrace();
-        }
-    };
     private final Runnable mCloseEduTextRunnable = this::closeEduText;
 
     public TvPipMenuController(Context context, TvPipBoundsState tvPipBoundsState,
@@ -525,11 +511,6 @@
             mApplier.scheduleApply(frontParams);
         }
 
-        if (mPipMenuView.getViewRootImpl() != null) {
-            mPipMenuView.getHandler().removeCallbacks(mUpdateEmbeddedMatrix);
-            mPipMenuView.getHandler().post(mUpdateEmbeddedMatrix);
-        }
-
         updateMenuBounds(pipDestBounds);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index aec51ba..10dfdc3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -190,7 +190,7 @@
             mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
                     mTaskOrganizer, mDisplayController, mDisplayImeController,
                     mDisplayInsetsController, mTransitions, mTransactionPool, mLogger,
-                    mIconProvider, mRecentTasksOptional, mUnfoldControllerProvider);
+                    mIconProvider, mMainExecutor, mRecentTasksOptional, mUnfoldControllerProvider);
         }
     }
 
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 45931de..9d6e34d 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
@@ -94,6 +94,7 @@
 import com.android.wm.shell.common.DisplayImeController;
 import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.split.SplitLayout;
@@ -157,6 +158,7 @@
     private final TransactionPool mTransactionPool;
     private final SplitScreenTransitions mSplitTransitions;
     private final SplitscreenEventLogger mLogger;
+    private final ShellExecutor mMainExecutor;
     private final Optional<RecentTasksController> mRecentTasks;
 
     /**
@@ -196,13 +198,15 @@
             DisplayImeController displayImeController,
             DisplayInsetsController displayInsetsController, Transitions transitions,
             TransactionPool transactionPool, SplitscreenEventLogger logger,
-            IconProvider iconProvider, Optional<RecentTasksController> recentTasks,
+            IconProvider iconProvider, ShellExecutor mainExecutor,
+            Optional<RecentTasksController> recentTasks,
             Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
         mContext = context;
         mDisplayId = displayId;
         mSyncQueue = syncQueue;
         mTaskOrganizer = taskOrganizer;
         mLogger = logger;
+        mMainExecutor = mainExecutor;
         mRecentTasks = recentTasks;
         mMainUnfoldController = unfoldControllerProvider.get().orElse(null);
         mSideUnfoldController = unfoldControllerProvider.get().orElse(null);
@@ -247,7 +251,7 @@
             DisplayController displayController, DisplayImeController displayImeController,
             DisplayInsetsController displayInsetsController, SplitLayout splitLayout,
             Transitions transitions, TransactionPool transactionPool,
-            SplitscreenEventLogger logger,
+            SplitscreenEventLogger logger, ShellExecutor mainExecutor,
             Optional<RecentTasksController> recentTasks,
             Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
         mContext = context;
@@ -266,6 +270,7 @@
         mMainUnfoldController = unfoldControllerProvider.get().orElse(null);
         mSideUnfoldController = unfoldControllerProvider.get().orElse(null);
         mLogger = logger;
+        mMainExecutor = mainExecutor;
         mRecentTasks = recentTasks;
         mDisplayController.addDisplayWindowListener(this);
         mDisplayLayout = new DisplayLayout();
@@ -394,6 +399,7 @@
             @Nullable PendingIntent pendingIntent, @Nullable Intent fillInIntent,
             @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
             @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
+        final boolean withIntent = pendingIntent != null && fillInIntent != null;
         // Init divider first to make divider leash for remote animation target.
         mSplitLayout.init();
         // Set false to avoid record new bounds with old task still on top;
@@ -423,10 +429,7 @@
                         new IRemoteAnimationFinishedCallback.Stub() {
                             @Override
                             public void onAnimationFinished() throws RemoteException {
-                                mIsDividerRemoteAnimating = false;
-                                mShouldUpdateRecents = true;
-                                mSyncQueue.queue(evictWct);
-                                mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
+                                onRemoteAnimationFinishedOrCancelled(evictWct);
                                 finishedCallback.onAnimationFinished();
                             }
                         };
@@ -447,10 +450,7 @@
 
             @Override
             public void onAnimationCancelled() {
-                mIsDividerRemoteAnimating = false;
-                mShouldUpdateRecents = true;
-                mSyncQueue.queue(evictWct);
-                mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
+                onRemoteAnimationFinishedOrCancelled(evictWct);
                 try {
                     adapter.getRunner().onAnimationCancelled();
                 } catch (RemoteException e) {
@@ -486,20 +486,37 @@
         addActivityOptions(sideOptions, mSideStage);
 
         // Add task launch requests
-        if (pendingIntent != null && fillInIntent != null) {
-            wct.startTask(mainTaskId, mainOptions);
+        wct.startTask(mainTaskId, mainOptions);
+        if (withIntent) {
             wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions);
         } else {
-            wct.startTask(mainTaskId, mainOptions);
             wct.startTask(sideTaskId, sideOptions);
         }
-
         // Using legacy transitions, so we can't use blast sync since it conflicts.
         mTaskOrganizer.applyTransaction(wct);
         mSyncQueue.runInSync(t ->
                 updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */));
     }
 
+    private void onRemoteAnimationFinishedOrCancelled(WindowContainerTransaction evictWct) {
+        mIsDividerRemoteAnimating = false;
+        mShouldUpdateRecents = true;
+        // If any stage has no child after animation finished, it means that split will display
+        // nothing, such status will happen if task and intent is same app but not support
+        // multi-instagce, we should exit split and expand that app as full screen.
+        if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
+            mMainExecutor.execute(() ->
+                    exitSplitScreen(mMainStage.getChildCount() == 0
+                        ? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
+        } else {
+            mSyncQueue.queue(evictWct);
+            mSyncQueue.runInSync(t -> {
+                setDividerVisibility(true, t);
+                updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
+            });
+        }
+    }
+
     /**
      * Collects all the current child tasks of a specific split and prepares transaction to evict
      * them to display.
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index 49f36a4..eb9d3a1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -31,6 +31,7 @@
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayImeController;
 import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.split.SplitLayout;
@@ -72,11 +73,13 @@
                 DisplayController displayController, DisplayImeController imeController,
                 DisplayInsetsController insetsController, SplitLayout splitLayout,
                 Transitions transitions, TransactionPool transactionPool,
-                SplitscreenEventLogger logger, Optional<RecentTasksController> recentTasks,
+                SplitscreenEventLogger logger, ShellExecutor mainExecutor,
+                Optional<RecentTasksController> recentTasks,
                 Provider<Optional<StageTaskUnfoldController>> unfoldController) {
             super(context, displayId, syncQueue, taskOrganizer, mainStage,
                     sideStage, displayController, imeController, insetsController, splitLayout,
-                    transitions, transactionPool, logger, recentTasks, unfoldController);
+                    transitions, transactionPool, logger, mainExecutor, recentTasks,
+                    unfoldController);
 
             // Prepare root task for testing.
             mRootTask = new TestRunningTaskInfoBuilder().build();
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 f847e6e..a55f737 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
@@ -97,6 +97,7 @@
     @Mock private SurfaceSession mSurfaceSession;
     @Mock private SplitscreenEventLogger mLogger;
     @Mock private IconProvider mIconProvider;
+    @Mock private ShellExecutor mMainExecutor;
     private SplitLayout mSplitLayout;
     private MainStage mMainStage;
     private SideStage mSideStage;
@@ -126,7 +127,7 @@
         mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
                 mSyncQueue, mTaskOrganizer, mMainStage, mSideStage, mDisplayController,
                 mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions,
-                mTransactionPool, mLogger, Optional.empty(), Optional::empty);
+                mTransactionPool, mLogger, mMainExecutor, Optional.empty(), Optional::empty);
         mSplitScreenTransitions = mStageCoordinator.getSplitTransitions();
         doAnswer((Answer<IBinder>) invocation -> mock(IBinder.class))
                 .when(mTransitions).startTransition(anyInt(), any(), any());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index c571d44..42d998f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -54,6 +54,7 @@
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayImeController;
 import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.split.SplitLayout;
@@ -101,6 +102,8 @@
     private TransactionPool mTransactionPool;
     @Mock
     private SplitscreenEventLogger mLogger;
+    @Mock
+    private ShellExecutor mMainExecutor;
 
     private final Rect mBounds1 = new Rect(10, 20, 30, 40);
     private final Rect mBounds2 = new Rect(5, 10, 15, 20);
@@ -116,7 +119,7 @@
         mStageCoordinator = spy(new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
                 mTaskOrganizer, mMainStage, mSideStage, mDisplayController, mDisplayImeController,
                 mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool, mLogger,
-                Optional.empty(), new UnfoldControllerProvider()));
+                mMainExecutor, Optional.empty(), new UnfoldControllerProvider()));
         doNothing().when(mStageCoordinator).updateActivityOptions(any(), anyInt());
 
         when(mSplitLayout.getBounds1()).thenReturn(mBounds1);
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index ece150a..d8b077b 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -249,6 +249,7 @@
         "apex/android_matrix.cpp",
         "apex/android_paint.cpp",
         "apex/android_region.cpp",
+        "apex/properties.cpp",
     ],
 
     header_libs: ["android_graphics_apex_headers"],
diff --git a/libs/hwui/apex/include/android/graphics/properties.h b/libs/hwui/apex/include/android/graphics/properties.h
new file mode 100644
index 0000000..f24f840
--- /dev/null
+++ b/libs/hwui/apex/include/android/graphics/properties.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef ANDROID_GRAPHICS_PROPERTIES_H
+#define ANDROID_GRAPHICS_PROPERTIES_H
+
+#include <cutils/compiler.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * Returns true if libhwui is using the vulkan backend.
+ */
+ANDROID_API bool hwui_uses_vulkan();
+
+__END_DECLS
+
+#endif  // ANDROID_GRAPHICS_PROPERTIES_H
diff --git a/libs/hwui/apex/properties.cpp b/libs/hwui/apex/properties.cpp
new file mode 100644
index 0000000..abb333b
--- /dev/null
+++ b/libs/hwui/apex/properties.cpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+#include "android/graphics/properties.h"
+
+#include <Properties.h>
+
+bool hwui_uses_vulkan() {
+    return android::uirenderer::Properties::peekRenderPipelineType() ==
+           android::uirenderer::RenderPipelineType::SkiaVulkan;
+}
diff --git a/libs/hwui/libhwui.map.txt b/libs/hwui/libhwui.map.txt
index 087c006..fdb2373 100644
--- a/libs/hwui/libhwui.map.txt
+++ b/libs/hwui/libhwui.map.txt
@@ -39,6 +39,7 @@
     ARegionIterator_next;
     ARegionIterator_getRect;
     ARegionIterator_getTotalBounds;
+    hwui_uses_vulkan;
   local:
     *;
 };
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 5283889..8be1bcd 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -187,22 +187,14 @@
      */
     @SuppressWarnings("unused")
     @UnsupportedAppUsage
-    private long mNativeRecorderInJavaObj;
+    private long mNativeAudioRecordHandle;
 
     /**
      * Accessed by native methods: provides access to the callback data.
      */
     @SuppressWarnings("unused")
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    private long mNativeCallbackCookie;
-
-    /**
-     * Accessed by native methods: provides access to the JNIDeviceCallback instance.
-     */
-    @SuppressWarnings("unused")
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    private long mNativeDeviceCallback;
-
+    private long mNativeJNIDataHandle;
 
     //---------------------------------------------------------
     // Member variables
@@ -492,9 +484,8 @@
      * value here as no error checking is or can be done.
      */
     /*package*/ AudioRecord(long nativeRecordInJavaObj) {
-        mNativeRecorderInJavaObj = 0;
-        mNativeCallbackCookie = 0;
-        mNativeDeviceCallback = 0;
+        mNativeAudioRecordHandle = 0;
+        mNativeJNIDataHandle = 0;
 
         // other initialization...
         if (nativeRecordInJavaObj != 0) {
@@ -2131,7 +2122,7 @@
      * @hide
      */
     public int getPortId() {
-        if (mNativeRecorderInJavaObj == 0) {
+        if (mNativeAudioRecordHandle == 0) {
             return 0;
         }
         try {
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index 62e53d6..a41399f 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -16,17 +16,18 @@
 
 package com.android.dynsystem;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.gsi.AvbPublicKey;
 import android.gsi.IGsiService;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Build;
-import android.os.MemoryFile;
-import android.os.ParcelFileDescriptor;
+import android.os.SharedMemory;
 import android.os.SystemProperties;
 import android.os.image.DynamicSystemManager;
 import android.service.persistentdata.PersistentDataBlockManager;
+import android.system.ErrnoException;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Range;
@@ -39,6 +40,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Enumeration;
 import java.util.List;
@@ -154,6 +156,22 @@
         void onResult(int resultCode, Throwable detail);
     }
 
+    private static class MappedMemoryBuffer implements AutoCloseable {
+        public ByteBuffer mBuffer;
+
+        MappedMemoryBuffer(@NonNull ByteBuffer buffer) {
+            mBuffer = buffer;
+        }
+
+        @Override
+        public void close() {
+            if (mBuffer != null) {
+                SharedMemory.unmap(mBuffer);
+                mBuffer = null;
+            }
+        }
+    }
+
     private final int mSharedMemorySize;
     private final String mUrl;
     private final String mDsuSlot;
@@ -674,59 +692,66 @@
 
         Log.d(TAG, "Start installing: " + partitionName);
 
-        MemoryFile memoryFile = new MemoryFile("dsu_" + partitionName, mSharedMemorySize);
-        ParcelFileDescriptor pfd = new ParcelFileDescriptor(memoryFile.getFileDescriptor());
-
-        mInstallationSession.setAshmem(pfd, memoryFile.length());
-
-        initPartitionProgress(partitionName, partitionSize, /* readonly = */ true);
-        publishProgress(/* installedSize = */ 0L);
-
         long prevInstalledSize = 0;
-        long installedSize = 0;
-        byte[] bytes = new byte[memoryFile.length()];
-        ExecutorService executor = Executors.newSingleThreadExecutor();
-        Future<Boolean> submitPromise = null;
+        try (SharedMemory sharedMemory =
+                        SharedMemory.create("dsu_buffer_" + partitionName, mSharedMemorySize);
+                MappedMemoryBuffer mappedBuffer =
+                        new MappedMemoryBuffer(sharedMemory.mapReadWrite())) {
+            mInstallationSession.setAshmem(sharedMemory.getFdDup(), sharedMemory.getSize());
 
-        while (true) {
-            final int numBytesRead = sis.read(bytes, 0, bytes.length);
+            initPartitionProgress(partitionName, partitionSize, /* readonly = */ true);
+            publishProgress(/* installedSize = */ 0L);
 
-            if (submitPromise != null) {
-                // Wait until the previous submit task is complete.
-                while (true) {
-                    try {
-                        if (!submitPromise.get()) {
-                            throw new IOException("Failed submitFromAshmem() to DynamicSystem");
+            long installedSize = 0;
+            byte[] readBuffer = new byte[sharedMemory.getSize()];
+            ByteBuffer buffer = mappedBuffer.mBuffer;
+            ExecutorService executor = Executors.newSingleThreadExecutor();
+            Future<Boolean> submitPromise = null;
+
+            while (true) {
+                final int numBytesRead = sis.read(readBuffer, 0, readBuffer.length);
+
+                if (submitPromise != null) {
+                    // Wait until the previous submit task is complete.
+                    while (true) {
+                        try {
+                            if (!submitPromise.get()) {
+                                throw new IOException("Failed submitFromAshmem() to DynamicSystem");
+                            }
+                            break;
+                        } catch (InterruptedException e) {
+                            // Ignore.
                         }
-                        break;
-                    } catch (InterruptedException e) {
-                        // Ignore.
+                    }
+
+                    // Publish the progress of the previous submit task.
+                    if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
+                        publishProgress(installedSize);
+                        prevInstalledSize = installedSize;
                     }
                 }
 
-                // Publish the progress of the previous submit task.
-                if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
-                    publishProgress(installedSize);
-                    prevInstalledSize = installedSize;
+                // Ensure the previous submit task (submitPromise) is complete before exiting the
+                // loop.
+                if (numBytesRead < 0) {
+                    break;
                 }
+
+                if (isCancelled()) {
+                    return;
+                }
+
+                buffer.position(0);
+                buffer.put(readBuffer, 0, numBytesRead);
+                submitPromise =
+                        executor.submit(() -> mInstallationSession.submitFromAshmem(numBytesRead));
+
+                // Even though we update the bytes counter here, the actual progress is updated only
+                // after the submit task (submitPromise) is complete.
+                installedSize += numBytesRead;
             }
-
-            // Ensure the previous submit task (submitPromise) is complete before exiting the loop.
-            if (numBytesRead < 0) {
-                break;
-            }
-
-            if (isCancelled()) {
-                return;
-            }
-
-            memoryFile.writeBytes(bytes, 0, 0, numBytesRead);
-            submitPromise =
-                    executor.submit(() -> mInstallationSession.submitFromAshmem(numBytesRead));
-
-            // Even though we update the bytes counter here, the actual progress is updated only
-            // after the submit task (submitPromise) is complete.
-            installedSize += numBytesRead;
+        } catch (ErrnoException e) {
+            e.rethrowAsIOException();
         }
 
         AvbPublicKey avbPublicKey = new AvbPublicKey();
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 6d7172e..6887d03 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -523,7 +523,8 @@
                   android:launchMode="singleTop"
                   android:permission="android.permission.MANAGE_SENSOR_PRIVACY"
                   android:theme="@style/Theme.SystemUI.Dialog.Alert"
-                  android:finishOnCloseSystemDialogs="true">
+                  android:finishOnCloseSystemDialogs="true"
+                  android:showForAllUsers="true">
         </activity>
 
         <!-- started from SensoryPrivacyService -->
@@ -532,7 +533,8 @@
                   android:launchMode="singleTop"
                   android:permission="android.permission.MANAGE_SENSOR_PRIVACY"
                   android:theme="@style/BottomSheet"
-                  android:finishOnCloseSystemDialogs="true">
+                  android:finishOnCloseSystemDialogs="true"
+                  android:showForAllUsers="true">
         </activity>
 
 
diff --git a/packages/SystemUI/res/anim/media_metadata_enter.xml b/packages/SystemUI/res/anim/media_metadata_enter.xml
new file mode 100644
index 0000000..fccb766
--- /dev/null
+++ b/packages/SystemUI/res/anim/media_metadata_enter.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:ordering="together">
+    <objectAnimator
+        android:propertyName="translationX"
+        android:valueFrom="32dp"
+        android:valueTo="0dp"
+        android:duration="600"
+        android:valueType="floatType" />
+    <objectAnimator
+        android:propertyName="transitionAlpha"
+        android:valueFrom="0"
+        android:valueTo="1"
+        android:duration="167"
+        android:valueType="floatType" />
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/media_metadata_exit.xml b/packages/SystemUI/res/anim/media_metadata_exit.xml
new file mode 100644
index 0000000..0ee1171
--- /dev/null
+++ b/packages/SystemUI/res/anim/media_metadata_exit.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:ordering="together">
+    <objectAnimator
+        android:propertyName="translationX"
+        android:valueFrom="0dp"
+        android:valueTo="-32dp"
+        android:duration="167"
+        android:valueType="floatType" />
+    <objectAnimator
+        android:propertyName="transitionAlpha"
+        android:valueFrom="1"
+        android:valueTo="0"
+        android:duration="83"
+        android:startOffset="83"
+        android:valueType="floatType" />
+</set>
diff --git a/packages/SystemUI/src/com/android/systemui/media/AnimationBindHandler.kt b/packages/SystemUI/src/com/android/systemui/media/AnimationBindHandler.kt
new file mode 100644
index 0000000..013683e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/AnimationBindHandler.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media
+
+import android.graphics.drawable.Animatable2
+import android.graphics.drawable.Drawable
+
+/**
+ * AnimationBindHandler is responsible for tracking the bound animation state and preventing
+ * jank and conflicts due to media notifications arriving at any time during an animation. It
+ * does this in two parts.
+ *  - Exit animations fired as a result of user input are tracked. When these are running, any
+ *      bind actions are delayed until the animation completes (and then fired in sequence).
+ *  - Continuous animations are tracked using their rebind id. Later calls using the same
+ *      rebind id will be totally ignored to prevent the continuous animation from restarting.
+ */
+internal class AnimationBindHandler : Animatable2.AnimationCallback() {
+    private val onAnimationsComplete = mutableListOf<() -> Unit>()
+    private val registrations = mutableListOf<Animatable2>()
+    private var rebindId: Int? = null
+
+    val isAnimationRunning: Boolean
+        get() = registrations.any { it.isRunning }
+
+    /**
+     * This check prevents rebinding to the action button if the identifier has not changed. A
+     * null value is always considered to be changed. This is used to prevent the connecting
+     * animation from rebinding (and restarting) if multiple buffer PlaybackStates are pushed by
+     * an application in a row.
+     */
+    fun updateRebindId(newRebindId: Int?): Boolean {
+        if (rebindId == null || newRebindId == null || rebindId != newRebindId) {
+            rebindId = newRebindId
+            return true
+        }
+        return false
+    }
+
+    fun tryRegister(drawable: Drawable?) {
+        if (drawable is Animatable2) {
+            val anim = drawable as Animatable2
+            anim.registerAnimationCallback(this)
+            registrations.add(anim)
+        }
+    }
+
+    fun unregisterAll() {
+        registrations.forEach { it.unregisterAnimationCallback(this) }
+        registrations.clear()
+    }
+
+    fun tryExecute(action: () -> Unit) {
+        if (isAnimationRunning) {
+            onAnimationsComplete.add(action)
+        } else {
+            action()
+        }
+    }
+
+    override fun onAnimationEnd(drawable: Drawable) {
+        super.onAnimationEnd(drawable)
+        if (!isAnimationRunning) {
+            onAnimationsComplete.forEach { it() }
+            onAnimationsComplete.clear()
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt b/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt
new file mode 100644
index 0000000..8f0305f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media
+
+import android.animation.ArgbEvaluator
+import android.animation.ValueAnimator.AnimatorUpdateListener
+import android.animation.ValueAnimator
+import android.content.Context
+import android.content.res.ColorStateList
+import com.android.internal.R
+import com.android.internal.annotations.VisibleForTesting
+import com.android.settingslib.Utils
+import com.android.systemui.monet.ColorScheme
+
+/**
+ * ColorTransition is responsible for managing the animation between two specific colors.
+ * It uses a ValueAnimator to execute the animation and interpolate between the source color and
+ * the target color.
+ *
+ * Selection of the target color from the scheme, and application of the interpolated color
+ * are delegated to callbacks.
+ */
+open class ColorTransition(
+    private val defaultColor: Int,
+    private val extractColor: (ColorScheme) -> Int,
+    private val applyColor: (Int) -> Unit
+) : AnimatorUpdateListener {
+
+    private val argbEvaluator = ArgbEvaluator()
+    private val valueAnimator = buildAnimator()
+    var sourceColor: Int = defaultColor
+    var currentColor: Int = defaultColor
+    var targetColor: Int = defaultColor
+
+    override fun onAnimationUpdate(animation: ValueAnimator) {
+        currentColor = argbEvaluator.evaluate(
+            animation.animatedFraction, sourceColor, targetColor
+        ) as Int
+        applyColor(currentColor)
+    }
+
+    fun updateColorScheme(scheme: ColorScheme?) {
+        val newTargetColor = if (scheme == null) defaultColor else extractColor(scheme)
+        if (newTargetColor != targetColor) {
+            sourceColor = currentColor
+            targetColor = newTargetColor
+            valueAnimator.cancel()
+            valueAnimator.start()
+        }
+    }
+
+    init {
+        applyColor(defaultColor)
+    }
+
+    @VisibleForTesting
+    open fun buildAnimator(): ValueAnimator {
+        val animator = ValueAnimator.ofFloat(0f, 1f)
+        animator.duration = 333
+        animator.addUpdateListener(this)
+        return animator
+    }
+}
+
+typealias ColorTransitionFactory = (Int, (ColorScheme) -> Int, (Int) -> Unit) -> ColorTransition
+
+/**
+ * ColorSchemeTransition constructs a ColorTransition for each color in the scheme
+ * that needs to be transitioned when changed. It also sets up the assignment functions for sending
+ * the sending the interpolated colors to the appropriate views.
+ */
+class ColorSchemeTransition internal constructor(
+    private val context: Context,
+    bgColor: Int,
+    mediaViewHolder: MediaViewHolder,
+    colorTransitionFactory: ColorTransitionFactory
+) {
+    constructor(context: Context, bgColor: Int, mediaViewHolder: MediaViewHolder) :
+        this(context, bgColor, mediaViewHolder, ::ColorTransition)
+
+    val surfaceColor = colorTransitionFactory(
+        bgColor,
+        { colorScheme -> colorScheme.accent2[9] }, // A2-800
+        { surfaceColor ->
+            val colorList = ColorStateList.valueOf(surfaceColor)
+            mediaViewHolder.player.backgroundTintList = colorList
+            mediaViewHolder.albumView.foregroundTintList = colorList
+            mediaViewHolder.albumView.backgroundTintList = colorList
+            mediaViewHolder.seamlessIcon.imageTintList = colorList
+            mediaViewHolder.seamlessText.setTextColor(surfaceColor)
+            mediaViewHolder.dismissText.setTextColor(surfaceColor)
+        })
+
+    val accentPrimary = colorTransitionFactory(
+        loadDefaultColor(R.attr.textColorPrimary),
+        { colorScheme -> colorScheme.accent1[2] }, // A1-100
+        { accentPrimary ->
+            val accentColorList = ColorStateList.valueOf(accentPrimary)
+            mediaViewHolder.actionPlayPause.backgroundTintList = accentColorList
+            mediaViewHolder.seamlessButton.backgroundTintList = accentColorList
+            mediaViewHolder.settings.imageTintList = accentColorList
+            mediaViewHolder.cancelText.backgroundTintList = accentColorList
+            mediaViewHolder.dismissText.backgroundTintList = accentColorList
+        })
+
+    val textPrimary = colorTransitionFactory(
+        loadDefaultColor(R.attr.textColorPrimary),
+        { colorScheme -> colorScheme.neutral1[1] }, // N1-50
+        { textPrimary ->
+            mediaViewHolder.titleText.setTextColor(textPrimary)
+            val textColorList = ColorStateList.valueOf(textPrimary)
+            mediaViewHolder.seekBar.thumb.setTintList(textColorList)
+            mediaViewHolder.seekBar.progressTintList = textColorList
+            mediaViewHolder.longPressText.setTextColor(textColorList)
+            mediaViewHolder.cancelText.setTextColor(textColorList)
+            mediaViewHolder.scrubbingElapsedTimeView.setTextColor(textColorList)
+            mediaViewHolder.scrubbingTotalTimeView.setTextColor(textColorList)
+            for (button in mediaViewHolder.getTransparentActionButtons()) {
+                button.imageTintList = textColorList
+            }
+        })
+
+    val textPrimaryInverse = colorTransitionFactory(
+        loadDefaultColor(R.attr.textColorPrimaryInverse),
+        { colorScheme -> colorScheme.neutral1[10] }, // N1-900
+        { textPrimaryInverse ->
+            mediaViewHolder.actionPlayPause.imageTintList =
+                ColorStateList.valueOf(textPrimaryInverse)
+        })
+
+    val textSecondary = colorTransitionFactory(
+        loadDefaultColor(R.attr.textColorSecondary),
+        { colorScheme -> colorScheme.neutral2[3] }, // N2-200
+        { textSecondary -> mediaViewHolder.artistText.setTextColor(textSecondary) })
+
+    val textTertiary = colorTransitionFactory(
+        loadDefaultColor(R.attr.textColorTertiary),
+        { colorScheme -> colorScheme.neutral2[5] }, // N2-400
+        { textTertiary ->
+            mediaViewHolder.seekBar.progressBackgroundTintList =
+                ColorStateList.valueOf(textTertiary)
+        })
+
+    val colorTransitions = arrayOf(
+        surfaceColor, accentPrimary, textPrimary,
+        textPrimaryInverse, textSecondary, textTertiary)
+
+    private fun loadDefaultColor(id: Int): Int {
+        return Utils.getColorAttr(context, id).defaultColor
+    }
+
+    fun updateColorScheme(colorScheme: ColorScheme?) {
+        colorTransitions.forEach { it.updateColorScheme(colorScheme) }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index c956783..c9e888e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -18,6 +18,9 @@
 
 import static android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS;
 
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
 import android.app.PendingIntent;
 import android.app.WallpaperColors;
 import android.app.smartspace.SmartspaceAction;
@@ -31,20 +34,22 @@
 import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Rect;
 import android.graphics.drawable.Animatable;
-import android.graphics.drawable.Animatable2;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
+import android.graphics.drawable.TransitionDrawable;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.media.session.PlaybackState;
 import android.os.Process;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Pair;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.animation.Interpolator;
 import android.widget.ImageButton;
 import android.widget.ImageView;
-import android.widget.SeekBar;
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
@@ -52,12 +57,14 @@
 import androidx.annotation.UiThread;
 import androidx.constraintlayout.widget.ConstraintSet;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.InstanceId;
 import com.android.settingslib.widget.AdaptiveIcon;
 import com.android.systemui.R;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.animation.GhostedViewLaunchAnimatorController;
+import com.android.systemui.animation.Interpolators;
 import com.android.systemui.broadcast.BroadcastSender;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -148,6 +155,11 @@
     private MediaCarouselController mMediaCarouselController;
     private final MediaOutputDialogFactory mMediaOutputDialogFactory;
     private final FalsingManager mFalsingManager;
+    private MetadataAnimationHandler mMetadataAnimationHandler;
+    private ColorSchemeTransition mColorSchemeTransition;
+    private Drawable mPrevArtwork = null;
+    private int mArtworkBoundId = 0;
+    private int mArtworkNextBindRequestId = 0;
 
     // Used for logging.
     protected boolean mIsImpressed = false;
@@ -171,15 +183,20 @@
      * @param activityStarter    activity starter
      */
     @Inject
-    public MediaControlPanel(Context context,
+    public MediaControlPanel(
+            Context context,
             @Background Executor backgroundExecutor,
             @Main Executor mainExecutor,
-            ActivityStarter activityStarter, BroadcastSender broadcastSender,
-            MediaViewController mediaViewController, SeekBarViewModel seekBarViewModel,
+            ActivityStarter activityStarter,
+            BroadcastSender broadcastSender,
+            MediaViewController mediaViewController,
+            SeekBarViewModel seekBarViewModel,
             Lazy<MediaDataManager> lazyMediaDataManager,
             MediaOutputDialogFactory mediaOutputDialogFactory,
             MediaCarouselController mediaCarouselController,
-            FalsingManager falsingManager, SystemClock systemClock, MediaUiEventLogger logger) {
+            FalsingManager falsingManager,
+            SystemClock systemClock,
+            MediaUiEventLogger logger) {
         mContext = context;
         mBackgroundExecutor = backgroundExecutor;
         mMainExecutor = mainExecutor;
@@ -306,6 +323,33 @@
                 mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */);
             }
         });
+
+        TextView titleText = mMediaViewHolder.getTitleText();
+        TextView artistText = mMediaViewHolder.getArtistText();
+        AnimatorSet enter = loadAnimator(R.anim.media_metadata_enter,
+                Interpolators.EMPHASIZED_DECELERATE, titleText, artistText);
+        AnimatorSet exit = loadAnimator(R.anim.media_metadata_exit,
+                Interpolators.EMPHASIZED_ACCELERATE, titleText, artistText);
+
+        mColorSchemeTransition = new ColorSchemeTransition(
+            mContext, mBackgroundColor, mMediaViewHolder);
+        mMetadataAnimationHandler = new MetadataAnimationHandler(exit, enter);
+    }
+
+    @VisibleForTesting
+    protected AnimatorSet loadAnimator(int animId, Interpolator motionInterpolator,
+            View... targets) {
+        ArrayList<Animator> animators = new ArrayList<>();
+        for (View target : targets) {
+            AnimatorSet animator = (AnimatorSet) AnimatorInflater.loadAnimator(mContext, animId);
+            animator.getChildAnimations().get(0).setInterpolator(motionInterpolator);
+            animator.setTarget(target);
+            animators.add(animator);
+        }
+
+        AnimatorSet result = new AnimatorSet();
+        result.playTogether(animators);
+        return result;
     }
 
     /** Attaches the recommendations to the recommendation view holder. */
@@ -377,20 +421,6 @@
             });
         }
 
-        // Accessibility label
-        mMediaViewHolder.getPlayer().setContentDescription(
-                mContext.getString(
-                        R.string.controls_media_playing_item_description,
-                        data.getSong(), data.getArtist(), data.getApp()));
-
-        // Song name
-        TextView titleText = mMediaViewHolder.getTitleText();
-        titleText.setText(data.getSong());
-
-        // Artist name
-        TextView artistText = mMediaViewHolder.getArtistText();
-        artistText.setText(data.getArtist());
-
         // Seek Bar
         final MediaController controller = getController();
         mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller));
@@ -399,11 +429,16 @@
         bindLongPressMenu(data);
         bindActionButtons(data);
         bindScrubbingTime(data);
-        bindArtworkAndColors(data);
+
+        boolean isSongUpdated = bindSongMetadata(data);
+        bindArtworkAndColors(data, isSongUpdated);
 
         // TODO: We don't need to refresh this state constantly, only if the state actually changed
         // to something which might impact the measurement
-        mMediaViewController.refreshState();
+        // State refresh interferes with the translation animation, only run it if it's not running.
+        if (!mMetadataAnimationHandler.isRunning()) {
+            mMediaViewController.refreshState();
+        }
     }
 
     private void bindOutputSwitcherChip(MediaData data) {
@@ -494,120 +529,135 @@
         });
     }
 
-    private void bindArtworkAndColors(MediaData data) {
-        // Default colors
-        int surfaceColor = mBackgroundColor;
-        int accentPrimary = com.android.settingslib.Utils.getColorAttr(mContext,
-                com.android.internal.R.attr.textColorPrimary).getDefaultColor();
-        int textPrimary = com.android.settingslib.Utils.getColorAttr(mContext,
-                com.android.internal.R.attr.textColorPrimary).getDefaultColor();
-        int textPrimaryInverse = com.android.settingslib.Utils.getColorAttr(mContext,
-                com.android.internal.R.attr.textColorPrimaryInverse).getDefaultColor();
-        int textSecondary = com.android.settingslib.Utils.getColorAttr(mContext,
-                com.android.internal.R.attr.textColorSecondary).getDefaultColor();
-        int textTertiary = com.android.settingslib.Utils.getColorAttr(mContext,
-                com.android.internal.R.attr.textColorTertiary).getDefaultColor();
+    private boolean bindSongMetadata(MediaData data) {
+        // Accessibility label
+        mMediaViewHolder.getPlayer().setContentDescription(
+                mContext.getString(
+                        R.string.controls_media_playing_item_description,
+                        data.getSong(), data.getArtist(), data.getApp()));
 
-        // Album art
-        ColorScheme colorScheme = null;
-        ImageView albumView = mMediaViewHolder.getAlbumView();
-        boolean hasArtwork = data.getArtwork() != null;
-        if (hasArtwork) {
-            colorScheme = new ColorScheme(WallpaperColors.fromBitmap(data.getArtwork().getBitmap()),
-                    true);
+        TextView titleText = mMediaViewHolder.getTitleText();
+        TextView artistText = mMediaViewHolder.getArtistText();
+        return mMetadataAnimationHandler.setNext(
+            Pair.create(data.getSong(), data.getArtist()),
+            () -> {
+                titleText.setText(data.getSong());
+                artistText.setText(data.getArtist());
 
-            // Scale artwork to fit background
-            int width = mMediaViewHolder.getPlayer().getWidth();
-            int height = mMediaViewHolder.getPlayer().getHeight();
-            Drawable artwork = getScaledBackground(data.getArtwork(), width, height);
-            albumView.setPadding(0, 0, 0, 0);
-            albumView.setImageDrawable(artwork);
-            albumView.setClipToOutline(true);
-        } else {
-            // If there's no artwork, use colors from the app icon
-            try {
-                Drawable icon = mContext.getPackageManager().getApplicationIcon(
-                        data.getPackageName());
-                colorScheme = new ColorScheme(WallpaperColors.fromDrawable(icon), true);
-            } catch (PackageManager.NameNotFoundException e) {
-                Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e);
+                // refreshState is required here to resize the text views (and prevent ellipsis)
+                mMediaViewController.refreshState();
+
+                // Use OnPreDrawListeners to enforce zero alpha on these views for a frame.
+                // TransitionLayout insists on resetting the alpha of these views to 1 when onLayout
+                // is called which causes the animation to look bad. These suppress that behavior.
+                titleText.getViewTreeObserver().addOnPreDrawListener(
+                        new ViewTreeObserver.OnPreDrawListener() {
+                            @Override
+                            public boolean onPreDraw() {
+                                titleText.setAlpha(0);
+                                titleText.getViewTreeObserver().removeOnPreDrawListener(this);
+                                return true;
+                            }
+                        });
+
+                artistText.getViewTreeObserver().addOnPreDrawListener(
+                        new ViewTreeObserver.OnPreDrawListener() {
+                            @Override
+                            public boolean onPreDraw() {
+                                artistText.setAlpha(0);
+                                artistText.getViewTreeObserver().removeOnPreDrawListener(this);
+                                return true;
+                            }
+                        });
+
+                return Unit.INSTANCE;
+            },
+            () -> {
+                // After finishing the enter animation, we refresh state. This could pop if
+                // something is incorrectly bound, but needs to be run if other elements were
+                // updated while the enter animation was running
+                mMediaViewController.refreshState();
+                return Unit.INSTANCE;
+            });
+    }
+
+    private void bindArtworkAndColors(MediaData data, boolean updateBackground) {
+        final int reqId = mArtworkNextBindRequestId++;
+
+        // Capture width & height from views in foreground for artwork scaling in background
+        int width = mMediaViewHolder.getPlayer().getWidth();
+        int height = mMediaViewHolder.getPlayer().getHeight();
+
+        // WallpaperColors.fromBitmap takes a good amount of time. We do that work
+        // on the background executor to avoid stalling animations on the UI Thread.
+        mBackgroundExecutor.execute(() -> {
+            // Album art
+            ColorScheme mutableColorScheme = null;
+            Drawable artwork;
+            Icon artworkIcon = data.getArtwork();
+            if (artworkIcon != null) {
+                WallpaperColors wallpaperColors = WallpaperColors
+                        .fromBitmap(artworkIcon.getBitmap());
+                mutableColorScheme = new ColorScheme(wallpaperColors, true);
+                artwork = getScaledBackground(artworkIcon, width, height);
+            } else {
+                // If there's no artwork, use colors from the app icon
+                artwork = null;
+                try {
+                    Drawable icon = mContext.getPackageManager()
+                            .getApplicationIcon(data.getPackageName());
+                    mutableColorScheme = new ColorScheme(WallpaperColors.fromDrawable(icon), true);
+                } catch (PackageManager.NameNotFoundException e) {
+                    Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e);
+                }
             }
-        }
 
-        // Get colors for player
-        if (colorScheme != null) {
-            surfaceColor = colorScheme.getAccent2().get(9); // A2-800
-            accentPrimary = colorScheme.getAccent1().get(2); // A1-100
-            textPrimary = colorScheme.getNeutral1().get(1); // N1-50
-            textPrimaryInverse = colorScheme.getNeutral1().get(10); // N1-900
-            textSecondary = colorScheme.getNeutral2().get(3); // N2-200
-            textTertiary = colorScheme.getNeutral2().get(5); // N2-400
-        }
+            final ColorScheme colorScheme = mutableColorScheme;
+            mMainExecutor.execute(() -> {
+                // Cancel the request if a later one arrived first
+                if (reqId < mArtworkBoundId) return;
+                mArtworkBoundId = reqId;
 
-        ColorStateList bgColorList = ColorStateList.valueOf(surfaceColor);
-        ColorStateList accentColorList = ColorStateList.valueOf(accentPrimary);
-        ColorStateList textColorList = ColorStateList.valueOf(textPrimary);
+                // Bind the album view to the artwork or a transition drawable
+                ImageView albumView = mMediaViewHolder.getAlbumView();
+                albumView.setPadding(0, 0, 0, 0);
+                albumView.setClipToOutline(true);
+                if (updateBackground) {
+                    if (mPrevArtwork == null || artwork == null) {
+                        albumView.setImageDrawable(artwork);
+                    } else {
+                        TransitionDrawable transitionDrawable = new TransitionDrawable(
+                                new Drawable[] { mPrevArtwork, artwork });
+                        albumView.setImageDrawable(transitionDrawable);
+                        transitionDrawable.startTransition(333);
+                    }
+                    mPrevArtwork = artwork;
+                }
 
-        // Gradient and background (visible when there is no art)
-        albumView.setForegroundTintList(ColorStateList.valueOf(surfaceColor));
-        albumView.setBackgroundTintList(
-                ColorStateList.valueOf(surfaceColor));
-        mMediaViewHolder.getPlayer().setBackgroundTintList(bgColorList);
+                // Transition Colors to current color scheme
+                mColorSchemeTransition.updateColorScheme(colorScheme);
 
-        // App icon - use notification icon
-        ImageView appIconView = mMediaViewHolder.getAppIcon();
-        appIconView.clearColorFilter();
-        if (data.getAppIcon() != null && !data.getResumption()) {
-            appIconView.setImageIcon(data.getAppIcon());
-            appIconView.setColorFilter(accentPrimary);
-        } else {
-            // Resume players use launcher icon
-            appIconView.setColorFilter(getGrayscaleFilter());
-            try {
-                Drawable icon = mContext.getPackageManager().getApplicationIcon(
-                        data.getPackageName());
-                appIconView.setImageDrawable(icon);
-            } catch (PackageManager.NameNotFoundException e) {
-                Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e);
-                appIconView.setImageResource(R.drawable.ic_music_note);
-            }
-        }
-
-        // Metadata text
-        mMediaViewHolder.getTitleText().setTextColor(textPrimary);
-        mMediaViewHolder.getArtistText().setTextColor(textSecondary);
-
-        // Seekbar
-        SeekBar seekbar = mMediaViewHolder.getSeekBar();
-        seekbar.getThumb().setTintList(textColorList);
-        seekbar.setProgressTintList(textColorList);
-        seekbar.setProgressBackgroundTintList(ColorStateList.valueOf(textTertiary));
-        mMediaViewHolder.getScrubbingElapsedTimeView().setTextColor(textColorList);
-        mMediaViewHolder.getScrubbingTotalTimeView().setTextColor(textColorList);
-
-        // Action buttons
-        mMediaViewHolder.getActionPlayPause().setBackgroundTintList(accentColorList);
-        mMediaViewHolder.getActionPlayPause().setImageTintList(
-                ColorStateList.valueOf(textPrimaryInverse));
-        for (ImageButton button : mMediaViewHolder.getTransparentActionButtons()) {
-            button.setImageTintList(textColorList);
-        }
-
-        // Output switcher
-        View seamlessView = mMediaViewHolder.getSeamlessButton();
-        seamlessView.setBackgroundTintList(accentColorList);
-        ImageView seamlessIconView = mMediaViewHolder.getSeamlessIcon();
-        seamlessIconView.setImageTintList(bgColorList);
-        TextView seamlessText = mMediaViewHolder.getSeamlessText();
-        seamlessText.setTextColor(surfaceColor);
-
-        // Long press buttons
-        mMediaViewHolder.getLongPressText().setTextColor(textColorList);
-        mMediaViewHolder.getSettings().setImageTintList(accentColorList);
-        mMediaViewHolder.getCancelText().setTextColor(textColorList);
-        mMediaViewHolder.getCancelText().setBackgroundTintList(accentColorList);
-        mMediaViewHolder.getDismissText().setTextColor(surfaceColor);
-        mMediaViewHolder.getDismissText().setBackgroundTintList(accentColorList);
+                // App icon - use notification icon
+                ImageView appIconView = mMediaViewHolder.getAppIcon();
+                appIconView.clearColorFilter();
+                if (data.getAppIcon() != null && !data.getResumption()) {
+                    appIconView.setImageIcon(data.getAppIcon());
+                    appIconView.setColorFilter(
+                            mColorSchemeTransition.getAccentPrimary().getTargetColor());
+                } else {
+                    // Resume players use launcher icon
+                    appIconView.setColorFilter(getGrayscaleFilter());
+                    try {
+                        Drawable icon = mContext.getPackageManager()
+                                .getApplicationIcon(data.getPackageName());
+                        appIconView.setImageDrawable(icon);
+                    } catch (PackageManager.NameNotFoundException e) {
+                        Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e);
+                        appIconView.setImageResource(R.drawable.ic_music_note);
+                    }
+                }
+            });
+        });
     }
 
     private void bindActionButtons(MediaData data) {
@@ -714,6 +764,7 @@
         animHandler.tryExecute(() -> {
             bindButtonWithAnimations(button, mediaAction, animHandler);
             setSemanticButtonVisibleAndAlpha(button.getId(), mediaAction, semanticActions);
+            return Unit.INSTANCE;
         });
     }
 
@@ -786,7 +837,14 @@
                 scrubbingTimeViewsEnabled(semanticActions) && hideWhenScrubbing && mIsScrubbing;
         boolean visible = mediaAction != null && !shouldBeHiddenDueToScrubbing;
 
-        setVisibleAndAlpha(expandedSet, buttonId, visible);
+        int notVisibleValue;
+        if ((buttonId == R.id.actionPrev && semanticActions.getReservePrev())
+                || (buttonId == R.id.actionNext && semanticActions.getReserveNext())) {
+            notVisibleValue = ConstraintSet.INVISIBLE;
+        } else {
+            notVisibleValue = ConstraintSet.GONE;
+        }
+        setVisibleAndAlpha(expandedSet, buttonId, visible, notVisibleValue);
         setVisibleAndAlpha(collapsedSet, buttonId, visible && showInCompact);
     }
 
@@ -795,11 +853,12 @@
     private void updateDisplayForScrubbingChange(@NonNull MediaButton semanticActions) {
         // Update visibilities of the scrubbing time views and the scrubbing-dependent buttons.
         bindScrubbingTime(mMediaData);
-        SEMANTIC_ACTIONS_HIDE_WHEN_SCRUBBING.forEach((id) ->
-                setSemanticButtonVisibleAndAlpha(
-                        id, semanticActions.getActionById(id), semanticActions));
-        // Trigger a state refresh so that we immediately update visibilities.
-        mMediaViewController.refreshState();
+        SEMANTIC_ACTIONS_HIDE_WHEN_SCRUBBING.forEach((id) -> setSemanticButtonVisibleAndAlpha(
+                id, semanticActions.getActionById(id), semanticActions));
+        if (!mMetadataAnimationHandler.isRunning()) {
+            // Trigger a state refresh so that we immediately update visibilities.
+            mMediaViewController.refreshState();
+        }
     }
 
     private void bindScrubbingTime(MediaData data) {
@@ -824,74 +883,6 @@
         );
     }
 
-    // AnimationBindHandler is responsible for tracking the bound animation state and preventing
-    // jank and conflicts due to media notifications arriving at any time during an animation. It
-    // does this in two parts.
-    //  - Exit animations fired as a result of user input are tracked. When these are running, any
-    //      bind actions are delayed until the animation completes (and then fired in sequence).
-    //  - Continuous animations are tracked using their rebind id. Later calls using the same
-    //      rebind id will be totally ignored to prevent the continuous animation from restarting.
-    private static class AnimationBindHandler extends Animatable2.AnimationCallback {
-        private ArrayList<Runnable> mOnAnimationsComplete = new ArrayList<>();
-        private ArrayList<Animatable2> mRegistrations = new ArrayList<>();
-        private Integer mRebindId = null;
-
-        // This check prevents rebinding to the action button if the identifier has not changed. A
-        // null value is always considered to be changed. This is used to prevent the connecting
-        // animation from rebinding (and restarting) if multiple buffer PlaybackStates are pushed by
-        // an application in a row.
-        public boolean updateRebindId(Integer rebindId) {
-            if (mRebindId == null || rebindId == null || !mRebindId.equals(rebindId)) {
-                mRebindId = rebindId;
-                return true;
-            }
-            return false;
-        }
-
-        public void tryRegister(Drawable drawable) {
-            if (drawable instanceof Animatable2) {
-                Animatable2 anim = (Animatable2) drawable;
-                anim.registerAnimationCallback(this);
-                mRegistrations.add(anim);
-            }
-        }
-
-        public void unregisterAll() {
-            for (Animatable2 anim : mRegistrations) {
-                anim.unregisterAnimationCallback(this);
-            }
-            mRegistrations.clear();
-        }
-
-        public boolean isAnimationRunning() {
-            for (Animatable2 anim : mRegistrations) {
-                if (anim.isRunning()) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        public void tryExecute(Runnable action) {
-            if (isAnimationRunning()) {
-                mOnAnimationsComplete.add(action);
-            } else {
-                action.run();
-            }
-        }
-
-        @Override
-        public void onAnimationEnd(Drawable drawable) {
-            super.onAnimationEnd(drawable);
-            if (!isAnimationRunning()) {
-                for (Runnable action : mOnAnimationsComplete) {
-                    action.run();
-                }
-                mOnAnimationsComplete.clear();
-            }
-        }
-    }
-
     @Nullable
     private ActivityLaunchAnimator.Controller buildLaunchAnimatorController(
             TransitionLayout player) {
@@ -1097,7 +1088,9 @@
         });
 
         mController = null;
-        mMediaViewController.refreshState();
+        if (mMetadataAnimationHandler == null || !mMetadataAnimationHandler.isRunning()) {
+            mMediaViewController.refreshState();
+        }
     }
 
     /**
@@ -1191,7 +1184,12 @@
     }
 
     private void setVisibleAndAlpha(ConstraintSet set, int actionId, boolean visible) {
-        set.setVisibility(actionId, visible ? ConstraintSet.VISIBLE : ConstraintSet.GONE);
+        setVisibleAndAlpha(set, actionId, visible, ConstraintSet.GONE);
+    }
+
+    private void setVisibleAndAlpha(ConstraintSet set, int actionId, boolean visible,
+            int notVisibleValue) {
+        set.setVisibility(actionId, visible ? ConstraintSet.VISIBLE : notVisibleValue);
         set.setAlpha(actionId, visible ? 1.0f : 0.0f);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index bc8cca5..f6d531b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -149,23 +149,31 @@
     /**
      * Play/pause button
      */
-    var playOrPause: MediaAction? = null,
+    val playOrPause: MediaAction? = null,
     /**
      * Next button, or custom action
      */
-    var nextOrCustom: MediaAction? = null,
+    val nextOrCustom: MediaAction? = null,
     /**
      * Previous button, or custom action
      */
-    var prevOrCustom: MediaAction? = null,
+    val prevOrCustom: MediaAction? = null,
     /**
      * First custom action space
      */
-    var custom0: MediaAction? = null,
+    val custom0: MediaAction? = null,
     /**
      * Second custom action space
      */
-    var custom1: MediaAction? = null
+    val custom1: MediaAction? = null,
+    /**
+     * Whether to reserve the empty space when the nextOrCustom is null
+     */
+    val reserveNext: Boolean = false,
+    /**
+     * Whether to reserve the empty space when the prevOrCustom is null
+     */
+    val reservePrev: Boolean = false
 ) {
     fun getActionById(id: Int): MediaAction? {
         return when (id) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 0ad15fa..0d65514 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -173,10 +173,6 @@
         // Maximum number of actions allowed in expanded view
         @JvmField
         val MAX_NOTIFICATION_ACTIONS = MediaViewHolder.genericButtonIds.size
-
-        /** Maximum number of [PlaybackState.CustomAction] buttons supported */
-        @JvmField
-        val MAX_CUSTOM_ACTIONS = 4
     }
 
     private val themeText = com.android.settingslib.Utils.getColorAttr(context,
@@ -795,71 +791,74 @@
      */
     private fun createActionsFromState(packageName: String, controller: MediaController):
             MediaButton? {
-        val actions = MediaButton()
-        controller.playbackState?.let { state ->
-            // First, check for standard actions
-            actions.playOrPause = if (isConnectingState(state.state)) {
-                // Spinner needs to be animating to render anything. Start it here.
-                val drawable = context.getDrawable(
-                        com.android.internal.R.drawable.progress_small_material)
-                (drawable as Animatable).start()
-                MediaAction(
-                    drawable,
-                    null, // no action to perform when clicked
-                    context.getString(R.string.controls_media_button_connecting),
-                    context.getDrawable(R.drawable.ic_media_connecting_container),
-                    // Specify a rebind id to prevent the spinner from restarting on later binds.
-                    com.android.internal.R.drawable.progress_small_material
-                )
-            } else if (isPlayingState(state.state)) {
-                getStandardAction(controller, state.actions, PlaybackState.ACTION_PAUSE)
-            } else {
-                getStandardAction(controller, state.actions, PlaybackState.ACTION_PLAY)
-            }
-            val prevButton = getStandardAction(controller, state.actions,
-                    PlaybackState.ACTION_SKIP_TO_PREVIOUS)
-            val nextButton = getStandardAction(controller, state.actions,
-                    PlaybackState.ACTION_SKIP_TO_NEXT)
-
-            // Then, check for custom actions
-            val customActions = MutableList<MediaAction?>(MAX_CUSTOM_ACTIONS) { null }
-            var customCount = 0
-            for (i in 0..(MAX_CUSTOM_ACTIONS - 1)) {
-                getCustomAction(state, packageName, controller, customCount)?.let {
-                    customActions[customCount++] = it
-                }
-            }
-
-            // Finally, assign the remaining button slots: play/pause A B C D
-            // A = previous, else custom action (if not reserved)
-            // B = next, else custom action (if not reserved)
-            // C and D are always custom actions
-            val reservePrev = controller.extras?.getBoolean(
-                    MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV) == true
-            val reserveNext = controller.extras?.getBoolean(
-                    MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT) == true
-            var customIdx = 0
-
-            actions.prevOrCustom = if (prevButton != null) {
-                prevButton
-            } else if (!reservePrev) {
-                customActions[customIdx++]
-            } else {
-                null
-            }
-
-            actions.nextOrCustom = if (nextButton != null) {
-                nextButton
-            } else if (!reserveNext) {
-                customActions[customIdx++]
-            } else {
-                null
-            }
-
-            actions.custom0 = customActions[customIdx++]
-            actions.custom1 = customActions[customIdx++]
+        val state = controller.playbackState
+        if (state == null) {
+            return MediaButton()
         }
-        return actions
+        // First, check for} standard actions
+        val playOrPause = if (isConnectingState(state.state)) {
+            // Spinner needs to be animating to render anything. Start it here.
+            val drawable = context.getDrawable(
+                com.android.internal.R.drawable.progress_small_material)
+            (drawable as Animatable).start()
+            MediaAction(
+                drawable,
+                null, // no action to perform when clicked
+                context.getString(R.string.controls_media_button_connecting),
+                context.getDrawable(R.drawable.ic_media_connecting_container),
+                // Specify a rebind id to prevent the spinner from restarting on later binds.
+                com.android.internal.R.drawable.progress_small_material
+            )
+        } else if (isPlayingState(state.state)) {
+            getStandardAction(controller, state.actions, PlaybackState.ACTION_PAUSE)
+        } else {
+            getStandardAction(controller, state.actions, PlaybackState.ACTION_PLAY)
+        }
+        val prevButton = getStandardAction(controller, state.actions,
+            PlaybackState.ACTION_SKIP_TO_PREVIOUS)
+        val nextButton = getStandardAction(controller, state.actions,
+            PlaybackState.ACTION_SKIP_TO_NEXT)
+
+        // Then, create a way to build any custom actions that will be needed
+        val customActions = state.customActions.asSequence().filterNotNull().map {
+            getCustomAction(state, packageName, controller, it)
+        }.iterator()
+        fun nextCustomAction() = if (customActions.hasNext()) customActions.next() else null
+
+        // Finally, assign the remaining button slots: play/pause A B C D
+        // A = previous, else custom action (if not reserved)
+        // B = next, else custom action (if not reserved)
+        // C and D are always custom actions
+        val reservePrev = controller.extras?.getBoolean(
+            MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV) == true
+        val reserveNext = controller.extras?.getBoolean(
+            MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT) == true
+
+        val prevOrCustom = if (prevButton != null) {
+            prevButton
+        } else if (!reservePrev) {
+            nextCustomAction()
+        } else {
+            null
+        }
+
+        val nextOrCustom = if (nextButton != null) {
+            nextButton
+        } else if (!reserveNext) {
+            nextCustomAction()
+        } else {
+            null
+        }
+
+        return MediaButton(
+            playOrPause,
+            nextOrCustom,
+            prevOrCustom,
+            nextCustomAction(),
+            nextCustomAction(),
+            reserveNext,
+            reservePrev
+        )
     }
 
     /**
@@ -938,18 +937,12 @@
         state: PlaybackState,
         packageName: String,
         controller: MediaController,
-        index: Int
-    ): MediaAction? {
-        if (state.customActions.size <= index || state.customActions[index] == null) {
-            if (DEBUG) { Log.d(TAG, "not enough actions or action was null at $index") }
-            return null
-        }
-
-        val it = state.customActions[index]
+        customAction: PlaybackState.CustomAction
+    ): MediaAction {
         return MediaAction(
-            Icon.createWithResource(packageName, it.icon).loadDrawable(context),
-            { controller.transportControls.sendCustomAction(it, it.extras) },
-            it.name,
+            Icon.createWithResource(packageName, customAction.icon).loadDrawable(context),
+            { controller.transportControls.sendCustomAction(customAction, customAction.extras) },
+            customAction.name,
             null
         )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MetadataAnimationHandler.kt b/packages/SystemUI/src/com/android/systemui/media/MetadataAnimationHandler.kt
new file mode 100644
index 0000000..9a1a6d3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MetadataAnimationHandler.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
+import com.android.internal.annotations.VisibleForTesting
+
+/**
+ * MetadataAnimationHandler controls the current state of the MediaControlPanel's transition motion.
+ *
+ * It checks for a changed data object (artist & title from MediaControlPanel) and runs the
+ * animation if necessary. When the motion has fully transitioned the elements out, it runs the
+ * update callback to modify the view data, before the enter animation runs.
+ */
+internal open class MetadataAnimationHandler(
+    private val exitAnimator: Animator,
+    private val enterAnimator: Animator
+) : AnimatorListenerAdapter() {
+
+    private val animator: AnimatorSet
+    private var postExitUpdate: (() -> Unit)? = null
+    private var postEnterUpdate: (() -> Unit)? = null
+    private var targetData: Any? = null
+
+    val isRunning: Boolean
+        get() = animator.isRunning
+
+    fun setNext(targetData: Any, postExit: () -> Unit, postEnter: () -> Unit): Boolean {
+        if (targetData != this.targetData) {
+            this.targetData = targetData
+            postExitUpdate = postExit
+            postEnterUpdate = postEnter
+            if (!animator.isRunning) {
+                animator.start()
+            }
+            return true
+        }
+        return false
+    }
+
+    override fun onAnimationEnd(animator: Animator) {
+        if (animator === exitAnimator) {
+            postExitUpdate?.let { it() }
+            postExitUpdate = null
+        }
+
+        if (animator === enterAnimator) {
+            // Another new update appeared while entering
+            if (postExitUpdate != null) {
+                this.animator.start()
+            } else {
+                postEnterUpdate?.let { it() }
+                postEnterUpdate = null
+            }
+        }
+    }
+
+    init {
+        exitAnimator.addListener(this)
+        enterAnimator.addListener(this)
+        animator = buildAnimatorSet(exitAnimator, enterAnimator)
+    }
+
+    @VisibleForTesting
+    protected open fun buildAnimatorSet(exit: Animator, enter: Animator): AnimatorSet {
+        val result = AnimatorSet()
+        result.playSequentially(exitAnimator, enterAnimator)
+        return result
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
index 612a7f9..c9d300b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
@@ -16,20 +16,29 @@
 
 package com.android.systemui.media
 
+import android.animation.Animator
+import android.animation.ObjectAnimator
 import android.text.format.DateUtils
 import androidx.annotation.UiThread
 import androidx.lifecycle.Observer
+import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
 
 /**
  * Observer for changes from SeekBarViewModel.
  *
  * <p>Updates the seek bar views in response to changes to the model.
  */
-class SeekBarObserver(
+open class SeekBarObserver(
     private val holder: MediaViewHolder
 ) : Observer<SeekBarViewModel.Progress> {
 
+    companion object {
+        @JvmStatic val RESET_ANIMATION_DURATION_MS: Int = 750
+        @JvmStatic val RESET_ANIMATION_THRESHOLD_MS: Int = 250
+    }
+
     val seekBarEnabledMaxHeight = holder.seekBar.context.resources
         .getDimensionPixelSize(R.dimen.qs_media_enabled_seekbar_height)
     val seekBarDisabledHeight = holder.seekBar.context.resources
@@ -38,6 +47,7 @@
                 .getDimensionPixelSize(R.dimen.qs_media_session_enabled_seekbar_vertical_padding)
     val seekBarDisabledVerticalPadding = holder.seekBar.context.resources
                 .getDimensionPixelSize(R.dimen.qs_media_session_disabled_seekbar_vertical_padding)
+    var seekBarResetAnimator: Animator? = null
 
     init {
         val seekBarProgressWavelength = holder.seekBar.context.resources
@@ -91,7 +101,17 @@
         holder.scrubbingTotalTimeView.text = totalTimeString
 
         data.elapsedTime?.let {
-            holder.seekBar.setProgress(it)
+            if (!data.scrubbing && !(seekBarResetAnimator?.isRunning ?: false)) {
+                if (it <= RESET_ANIMATION_THRESHOLD_MS &&
+                        holder.seekBar.progress > RESET_ANIMATION_THRESHOLD_MS) {
+                    // This animation resets for every additional update to zero.
+                    val animator = buildResetAnimator(it)
+                    animator.start()
+                    seekBarResetAnimator = animator
+                } else {
+                    holder.seekBar.progress = it
+                }
+            }
             val elapsedTimeString = DateUtils.formatElapsedTime(
                 it / DateUtils.SECOND_IN_MILLIS)
             holder.scrubbingElapsedTimeView.text = elapsedTimeString
@@ -104,6 +124,16 @@
         }
     }
 
+    @VisibleForTesting
+    open fun buildResetAnimator(targetTime: Int): Animator {
+        val animator = ObjectAnimator.ofInt(holder.seekBar, "progress",
+                holder.seekBar.progress, targetTime + RESET_ANIMATION_DURATION_MS)
+        animator.setAutoCancel(true)
+        animator.duration = RESET_ANIMATION_DURATION_MS.toLong()
+        animator.interpolator = Interpolators.EMPHASIZED
+        return animator
+    }
+
     @UiThread
     fun setVerticalPadding(padding: Int) {
         val leftPadding = holder.seekBar.paddingLeft
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
index 097cf35..00aa138 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
@@ -706,7 +706,7 @@
                 Drawable drawable = resolveImage(imageUri, mContext);
                 Bitmap bitmap = convertDrawableToBitmap(drawable);
                 views.setImageViewBitmap(R.id.image, bitmap);
-            } catch (IOException e) {
+            } catch (IOException | SecurityException e) {
                 Log.e(TAG, "Could not decode image: " + e);
                 // If we couldn't load the image, show text that we have a new image.
                 views.setTextViewText(R.id.text_content, newImageDescription);
@@ -754,7 +754,7 @@
         return views;
     }
 
-    private Drawable resolveImage(Uri uri, Context context) throws IOException {
+     Drawable resolveImage(Uri uri, Context context) throws IOException {
         final ImageDecoder.Source source =
                 ImageDecoder.createSource(context.getContentResolver(), uri);
         final Drawable drawable =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index a64b670..76ec6bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -519,7 +519,10 @@
     @Override
     public void setOverScrollAmount(int overScrollAmount) {
         mOverScrolling = overScrollAmount != 0;
-        getView().setTranslationY(overScrollAmount);
+        View view = getView();
+        if (view != null) {
+            view.setTranslationY(overScrollAmount);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 15a93c8..b52fd61 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -417,7 +417,6 @@
     private NotificationShelf mShelf;
     private int mMaxDisplayedNotifications = -1;
     private float mKeyguardBottomPadding = -1;
-    private float mKeyguardNotificationAvailableSpace = -1;
     @VisibleForTesting int mStatusBarHeight;
     private int mMinInteractionHeight;
     private final Rect mClipRect = new Rect();
@@ -775,9 +774,11 @@
         y = (int) mMaxLayoutHeight;
         drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "mMaxLayoutHeight = " + y);
 
+        // The space between mTopPadding and mKeyguardBottomPadding determines the available space
+        // for notifications on keyguard.
         if (mKeyguardBottomPadding >= 0) {
             y = getHeight() - (int) mKeyguardBottomPadding;
-            drawDebugInfo(canvas, y, Color.GRAY,
+            drawDebugInfo(canvas, y, Color.RED,
                     /* label= */ "getHeight() - mKeyguardBottomPadding = " + y);
         }
 
@@ -789,7 +790,7 @@
         drawDebugInfo(canvas, y, Color.CYAN, /* label= */ "mAmbientState.getStackY() = " + y);
 
         y = (int) (mAmbientState.getStackY() + mAmbientState.getStackHeight());
-        drawDebugInfo(canvas, y, Color.BLUE,
+        drawDebugInfo(canvas, y, Color.LTGRAY,
                 /* label= */ "mAmbientState.getStackY() + mAmbientState.getStackHeight() = " + y);
 
         y = (int) mAmbientState.getStackY() + mContentHeight;
@@ -800,10 +801,6 @@
         drawDebugInfo(canvas, y, Color.YELLOW,
                 /* label= */ "mAmbientState.getStackY() + mIntrinsicContentHeight = " + y);
 
-        y = (int) (mAmbientState.getStackY() + mKeyguardNotificationAvailableSpace);
-        drawDebugInfo(canvas, y, Color.RED, /* label= */
-                "mAmbientState.getStackY() + mKeyguardNotificationAvailableSpace = " + y);
-
         drawDebugInfo(canvas, mRoundedRectClippingBottom, Color.DKGRAY,
                 /* label= */ "mRoundedRectClippingBottom) = " + y);
     }
@@ -2267,10 +2264,11 @@
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     private void updateContentHeight() {
         final float scrimTopPadding = mAmbientState.isOnKeyguard() ? 0 : mMinimumPaddings;
+        final int shelfIntrinsicHeight = mShelf != null ? mShelf.getIntrinsicHeight() : 0;
         final int height =
                 (int) scrimTopPadding + (int) mNotificationStackSizeCalculator.computeHeight(
                         /* notificationStackScrollLayout= */ this, mMaxDisplayedNotifications,
-                        mShelf != null ? mShelf.getIntrinsicHeight() : 0);
+                        shelfIntrinsicHeight);
         mIntrinsicContentHeight = height;
 
         // The topPadding can be bigger than the regular padding when qs is expanded, in that
@@ -4914,15 +4912,6 @@
         mKeyguardBottomPadding = keyguardBottomPadding;
     }
 
-    /**
-     * For debugging only. Enables to draw a line related to the available size for notifications in
-     * keyguard.
-     */
-    public void setKeyguardAvailableSpaceForDebug(float keyguardNotificationAvailableSpace) {
-        mKeyguardNotificationAvailableSpace = keyguardNotificationAvailableSpace;
-    }
-
-
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void setShouldShowShelfOnly(boolean shouldShowShelfOnly) {
         mShouldShowShelfOnly = shouldShowShelfOnly;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 440bea6..ea6987a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -1305,12 +1305,6 @@
         mView.setKeyguardBottomPadding(keyguardBottomPadding);
     }
 
-    /** For debugging only. */
-    public void mKeyguardNotificationAvailableSpaceForDebug(
-            float keyguardNotificationAvailableSpace) {
-        mView.setKeyguardAvailableSpaceForDebug(keyguardNotificationAvailableSpace);
-    }
-
     public RemoteInputController.Delegate createDelegate() {
         return new RemoteInputController.Delegate() {
             public void setRemoteInputActive(NotificationEntry entry,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
index 7fb115d..9417aac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.util.children
 import javax.inject.Inject
 import kotlin.math.max
+import kotlin.math.min
 import kotlin.properties.Delegates.notNull
 
 private const val TAG = "NotificationStackSizeCalculator"
@@ -51,9 +52,7 @@
      */
     private var maxKeyguardNotifications by notNull<Int>()
 
-    /**
-     * Minimum space between two notifications, see [calculateGapAndDividerHeight].
-     */
+    /** Minimum space between two notifications, see [calculateGapAndDividerHeight]. */
     private var dividerHeight by notNull<Int>()
 
     init {
@@ -61,55 +60,34 @@
     }
 
     /**
-     * Given the [availableSpace] constraint, calculates how many notification to show.
+     * Given the [totalAvailableSpace] constraint, calculates how many notification to show.
      *
      * This number is only valid in keyguard.
      *
-     * @param availableSpace space for notifications. This doesn't include the space for the shelf.
+     * @param totalAvailableSpace space for notifications. This includes the space for the shelf.
      */
     fun computeMaxKeyguardNotifications(
         stack: NotificationStackScrollLayout,
-        availableSpace: Float,
-        shelfHeight: Float
+        totalAvailableSpace: Float,
+        shelfIntrinsicHeight: Float
     ): Int {
+        val stackHeightSequence = computeHeightPerNotificationLimit(stack, shelfIntrinsicHeight)
+
+        var maxNotifications =
+            stackHeightSequence.lastIndexWhile { stackHeight -> stackHeight <= totalAvailableSpace }
+
+        if (onLockscreen()) {
+            maxNotifications = min(maxKeyguardNotifications, maxNotifications)
+        }
+
+        // Could be < 0 if the space available is less than the shelf size. Returns 0 in this case.
+        maxNotifications = max(0, maxNotifications)
         log {
             "computeMaxKeyguardNotifications(" +
-                "availableSpace=$availableSpace shelfHeight=$shelfHeight)"
+                "availableSpace=$totalAvailableSpace" +
+                " shelfHeight=$shelfIntrinsicHeight) -> $maxNotifications"
         }
-
-        val children: Sequence<ExpandableView> = stack.childrenSequence
-        var remainingSpace: Float = availableSpace
-        var count = 0
-        var previous: ExpandableView? = null
-        val onLockscreen = true
-        val showableRows = children.filter { it.isShowable(onLockscreen) }
-        val showableRowsCount = showableRows.count()
-        log { "\tshowableRowsCount=$showableRowsCount "}
-
-        showableRows.forEachIndexed { i, current ->
-            val spaceNeeded = current.spaceNeeded(count, previous, stack, onLockscreen)
-            val spaceAfter = remainingSpace - spaceNeeded
-            previous = current
-            log { "\ti=$i spaceNeeded=$spaceNeeded remainingSpace=$remainingSpace " +
-                    "spaceAfter=$spaceAfter" }
-
-            if (remainingSpace - spaceNeeded >= 0 && count < maxKeyguardNotifications) {
-                count += 1
-                remainingSpace -= spaceNeeded
-            } else if (remainingSpace - spaceNeeded > -shelfHeight && i == showableRowsCount - 1) {
-                log { "Show all notifications. Shelf not needed." }
-                // If this is the last one, and it fits using the space shelf would use, then we can
-                // display it, as the shelf will not be needed (as all notifications are shown).
-                return count + 1
-            } else {
-                log {
-                    "No more fit. Returning $count. Space used: ${availableSpace - remainingSpace}"
-                }
-                return count
-            }
-        }
-        log { "All fit. Returning $count" }
-        return count
+        return maxNotifications
     }
 
     /**
@@ -119,47 +97,60 @@
      * @param stack stack containing notifications as children.
      * @param maxNotifications Maximum number of notifications. When reached, the others will go
      * into the shelf.
-     * @param shelfHeight height of the shelf. It might be zero.
+     * @param shelfIntrinsicHeight height of the shelf, without any padding. It might be zero.
      *
      * @return height of the stack, including shelf height, if needed.
      */
     fun computeHeight(
         stack: NotificationStackScrollLayout,
         maxNotifications: Int,
-        shelfHeight: Float
+        shelfIntrinsicHeight: Float
     ): Float {
-        val children: Sequence<ExpandableView> = stack.childrenSequence
-        val maxNotificationsArg = infiniteIfNegative(maxNotifications)
+        val heightPerMaxNotifications =
+            computeHeightPerNotificationLimit(stack, shelfIntrinsicHeight)
+        val height =
+            heightPerMaxNotifications.elementAtOrElse(maxNotifications) {
+                heightPerMaxNotifications.last() // Height with all notifications visible.
+            }
+        log { "computeHeight(maxNotifications=$maxNotifications) -> $height" }
+        return height
+    }
+
+    /** The ith result in the sequence is the height with ith max notifications. */
+    private fun computeHeightPerNotificationLimit(
+        stack: NotificationStackScrollLayout,
+        shelfIntrinsicHeight: Float
+    ): Sequence<Float> = sequence {
+        val children = stack.showableChildren().toList()
         var height = 0f
         var previous: ExpandableView? = null
-        var count = 0
         val onLockscreen = onLockscreen()
 
-        log { "computeHeight(maxNotification=$maxNotifications, shelf=$shelfHeight" }
-        children.filter { it.isShowable(onLockscreen) }.forEach { current ->
-            if (count < maxNotificationsArg) {
-                val spaceNeeded = current.spaceNeeded(count, previous, stack, onLockscreen)
-                log { "\ti=$count spaceNeeded=$spaceNeeded" }
-                height += spaceNeeded
-                count += 1
-            } else {
-                height += current.calculateGapAndDividerHeight(stack, previous, count)
-                height += shelfHeight
-                log { "returning height with shelf -> $height" }
-                return height
-            }
-            previous = current
+        yield(dividerHeight + shelfIntrinsicHeight) // Only shelf.
+
+        children.forEachIndexed { i, currentNotification ->
+            height += currentNotification.spaceNeeded(i, previous, stack, onLockscreen)
+            previous = currentNotification
+
+            val shelfHeight =
+                if (i == children.lastIndex) {
+                    0f // No shelf needed.
+                } else {
+                    val spaceBeforeShelf =
+                        calculateGapAndDividerHeight(
+                            stack, previous = currentNotification, current = children[i + 1], i)
+                    spaceBeforeShelf + shelfIntrinsicHeight
+                }
+
+            yield(height + shelfHeight)
         }
-        log { "Returning height without shelf -> $height" }
-        return height
     }
 
     fun updateResources() {
         maxKeyguardNotifications =
             infiniteIfNegative(resources.getInteger(R.integer.keyguard_max_notification_count))
 
-        dividerHeight =
-            max(1, resources.getDimensionPixelSize(R.dimen.notification_divider_height))
+        dividerHeight = max(1, resources.getDimensionPixelSize(R.dimen.notification_divider_height))
     }
 
     private val NotificationStackScrollLayout.childrenSequence: Sequence<ExpandableView>
@@ -180,7 +171,7 @@
             } else {
                 intrinsicHeight.toFloat()
             }
-        size += calculateGapAndDividerHeight(stack, previousView, visibleIndex)
+        size += calculateGapAndDividerHeight(stack, previousView, current = this, visibleIndex)
         return size
     }
 
@@ -200,18 +191,22 @@
         return true
     }
 
-    private fun ExpandableView.calculateGapAndDividerHeight(
+    private fun calculateGapAndDividerHeight(
         stack: NotificationStackScrollLayout,
         previous: ExpandableView?,
+        current: ExpandableView?,
         visibleIndex: Int
-    ) : Float {
-        var height = stack.calculateGapHeight(previous, /* current= */ this, visibleIndex)
+    ): Float {
+        var height = stack.calculateGapHeight(previous, current, visibleIndex)
         if (visibleIndex != 0) {
             height += dividerHeight
         }
         return height
     }
 
+    private fun NotificationStackScrollLayout.showableChildren() =
+        this.childrenSequence.filter { it.isShowable(onLockscreen()) }
+
     /**
      * Can a view be shown on the lockscreen when calculating the number of allowed notifications to
      * show?
@@ -240,4 +235,8 @@
         } else {
             v
         }
+
+    /** Returns the last index where [predicate] returns true, or -1 if it was always false. */
+    private fun <T> Sequence<T>.lastIndexWhile(predicate: (T) -> Boolean): Int =
+        takeWhile(predicate).count() - 1
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index a19d5f1..54d39fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -31,8 +31,6 @@
 import android.util.Log;
 import android.util.MathUtils;
 
-import android.util.Log;
-
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
@@ -293,11 +291,6 @@
     }
 
     public void updateControlScreenOff() {
-        Log.i("TEST", "Display needs blanking?" + getDisplayNeedsBlanking());
-        Log.i("TEST", "Should control screen off?" + shouldControlUnlockedScreenOff());
-        Log.i("TEST", "alwaysOn?" + getAlwaysOn());
-        Log.i("TEST", "keyguard showing?" + mKeyguardShowing);
-        Log.i("TEST", "Flag enabled? " + mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS));
         if (!getDisplayNeedsBlanking()) {
             final boolean controlScreenOff =
                     getAlwaysOn() && (mKeyguardShowing || shouldControlUnlockedScreenOff());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index a6b5c4d..cb2d5b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -317,8 +317,6 @@
     private boolean mShouldUseSplitNotificationShade;
     // The bottom padding reserved for elements of the keyguard measuring notifications
     private float mKeyguardNotificationBottomPadding;
-    // Space available for notifications.
-    private float mKeyguardNotificationAvailableSpace;
     // Current max allowed keyguard notifications determined by measuring the panel
     private int mMaxAllowedKeyguardNotifications;
 
@@ -1245,8 +1243,6 @@
                     mMaxAllowedKeyguardNotifications);
             mNotificationStackScrollLayoutController.setKeyguardBottomPaddingForDebug(
                     mKeyguardNotificationBottomPadding);
-            mNotificationStackScrollLayoutController.mKeyguardNotificationAvailableSpaceForDebug(
-                    mKeyguardNotificationAvailableSpace);
         } else {
             // no max when not on the keyguard
             mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(-1);
@@ -1468,13 +1464,11 @@
      * @return the maximum keyguard notifications that can fit on the screen
      */
     private int computeMaxKeyguardNotifications() {
-        int notificationPadding = Math.max(
-                1, mResources.getDimensionPixelSize(R.dimen.notification_divider_height));
         float topPadding = mNotificationStackScrollLayoutController.getTopPadding();
-        float shelfHeight =
+        float shelfIntrinsicHeight =
                 mNotificationShelfController.getVisibility() == View.GONE
                         ? 0
-                        : mNotificationShelfController.getIntrinsicHeight() + notificationPadding;
+                        : mNotificationShelfController.getIntrinsicHeight();
 
         // Padding to add to the bottom of the stack to keep a minimum distance from the top of
         // the lock icon.
@@ -1493,13 +1487,11 @@
         float availableSpace =
                 mNotificationStackScrollLayoutController.getHeight()
                         - topPadding
-                        - shelfHeight
                         - bottomPadding;
-        mKeyguardNotificationAvailableSpace = availableSpace;
 
         return mNotificationStackSizeCalculator.computeMaxKeyguardNotifications(
                 mNotificationStackScrollLayoutController.getView(), availableSpace,
-                shelfHeight);
+                shelfIntrinsicHeight);
     }
 
     private void updateClock() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/AnimationBindHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/AnimationBindHandlerTest.kt
new file mode 100644
index 0000000..e4cab18
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/AnimationBindHandlerTest.kt
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media
+
+import org.mockito.Mockito.`when` as whenever
+import android.graphics.drawable.Animatable2
+import android.graphics.drawable.Drawable
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import com.android.systemui.SysuiTestCase
+import junit.framework.Assert.assertTrue
+import junit.framework.Assert.assertFalse
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.times
+import org.mockito.Mockito.never
+import org.mockito.junit.MockitoJUnit
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class AnimationBindHandlerTest : SysuiTestCase() {
+
+    private interface Callback : () -> Unit
+    private abstract class AnimatedDrawable : Drawable(), Animatable2
+    private lateinit var handler: AnimationBindHandler
+
+    @Mock private lateinit var animatable: AnimatedDrawable
+    @Mock private lateinit var animatable2: AnimatedDrawable
+    @Mock private lateinit var callback: Callback
+
+    @JvmField @Rule val mockito = MockitoJUnit.rule()
+
+    @Before
+    fun setUp() {
+        handler = AnimationBindHandler()
+    }
+
+    @After
+    fun tearDown() {}
+
+    @Test
+    fun registerNoAnimations_executeCallbackImmediately() {
+        handler.tryExecute(callback)
+        verify(callback).invoke()
+    }
+
+    @Test
+    fun registerStoppedAnimations_executeCallbackImmediately() {
+        whenever(animatable.isRunning).thenReturn(false)
+        whenever(animatable2.isRunning).thenReturn(false)
+
+        handler.tryExecute(callback)
+        verify(callback).invoke()
+    }
+
+    @Test
+    fun registerRunningAnimations_executeCallbackDelayed() {
+        whenever(animatable.isRunning).thenReturn(true)
+        whenever(animatable2.isRunning).thenReturn(true)
+
+        handler.tryRegister(animatable)
+        handler.tryRegister(animatable2)
+        handler.tryExecute(callback)
+
+        verify(callback, never()).invoke()
+
+        whenever(animatable.isRunning).thenReturn(false)
+        handler.onAnimationEnd(animatable)
+        verify(callback, never()).invoke()
+
+        whenever(animatable2.isRunning).thenReturn(false)
+        handler.onAnimationEnd(animatable2)
+        verify(callback, times(1)).invoke()
+    }
+
+    @Test
+    fun repeatedEndCallback_executeSingleCallback() {
+        whenever(animatable.isRunning).thenReturn(true)
+
+        handler.tryRegister(animatable)
+        handler.tryExecute(callback)
+
+        verify(callback, never()).invoke()
+
+        whenever(animatable.isRunning).thenReturn(false)
+        handler.onAnimationEnd(animatable)
+        handler.onAnimationEnd(animatable)
+        handler.onAnimationEnd(animatable)
+        verify(callback, times(1)).invoke()
+    }
+
+    @Test
+    fun registerUnregister_executeImmediately() {
+        whenever(animatable.isRunning).thenReturn(true)
+
+        handler.tryRegister(animatable)
+        handler.unregisterAll()
+        handler.tryExecute(callback)
+
+        verify(callback).invoke()
+    }
+
+    @Test
+    fun updateRebindId_returnsAsExpected() {
+        // Previous or current call is null, returns true
+        assertTrue(handler.updateRebindId(null))
+        assertTrue(handler.updateRebindId(null))
+        assertTrue(handler.updateRebindId(null))
+        assertTrue(handler.updateRebindId(10))
+        assertTrue(handler.updateRebindId(null))
+        assertTrue(handler.updateRebindId(20))
+
+        // Different integer from prevoius, returns true
+        assertTrue(handler.updateRebindId(10))
+        assertTrue(handler.updateRebindId(20))
+
+        // Matches previous call, returns false
+        assertFalse(handler.updateRebindId(20))
+        assertFalse(handler.updateRebindId(20))
+        assertTrue(handler.updateRebindId(10))
+        assertFalse(handler.updateRebindId(10))
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt
new file mode 100644
index 0000000..86527d9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media
+
+import org.mockito.Mockito.`when` as whenever
+import android.animation.ValueAnimator
+import android.graphics.Color
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.monet.ColorScheme
+import junit.framework.Assert.assertEquals
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+private const val DEFAULT_COLOR = Color.RED
+private const val TARGET_COLOR = Color.BLUE
+private const val BG_COLOR = Color.GREEN
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class ColorSchemeTransitionTest : SysuiTestCase() {
+
+    private interface ExtractCB : (ColorScheme) -> Int
+    private interface ApplyCB : (Int) -> Unit
+    private lateinit var colorTransition: ColorTransition
+    private lateinit var colorSchemeTransition: ColorSchemeTransition
+
+    @Mock private lateinit var mockTransition: ColorTransition
+    @Mock private lateinit var valueAnimator: ValueAnimator
+    @Mock private lateinit var colorScheme: ColorScheme
+    @Mock private lateinit var extractColor: ExtractCB
+    @Mock private lateinit var applyColor: ApplyCB
+
+    private lateinit var transitionFactory: ColorTransitionFactory
+    @Mock private lateinit var mediaViewHolder: MediaViewHolder
+
+    @JvmField @Rule val mockitoRule = MockitoJUnit.rule()
+
+    @Before
+    fun setUp() {
+        transitionFactory = { default, extractColor, applyColor -> mockTransition }
+        whenever(extractColor.invoke(colorScheme)).thenReturn(TARGET_COLOR)
+
+        colorSchemeTransition = ColorSchemeTransition(context,
+                BG_COLOR, mediaViewHolder, transitionFactory)
+
+        colorTransition = object : ColorTransition(DEFAULT_COLOR, extractColor, applyColor) {
+            override fun buildAnimator(): ValueAnimator {
+                return valueAnimator
+            }
+        }
+    }
+
+    @After
+    fun tearDown() {}
+
+    @Test
+    fun testColorTransition_nullColorScheme_keepsDefault() {
+        colorTransition.updateColorScheme(null)
+        verify(applyColor, times(1)).invoke(DEFAULT_COLOR)
+        verify(valueAnimator, never()).start()
+        assertEquals(DEFAULT_COLOR, colorTransition.sourceColor)
+        assertEquals(DEFAULT_COLOR, colorTransition.targetColor)
+    }
+
+    @Test
+    fun testColorTransition_newColor_startsAnimation() {
+        colorTransition.updateColorScheme(colorScheme)
+        verify(applyColor, times(1)).invoke(DEFAULT_COLOR)
+        verify(valueAnimator, times(1)).start()
+        assertEquals(DEFAULT_COLOR, colorTransition.sourceColor)
+        assertEquals(TARGET_COLOR, colorTransition.targetColor)
+    }
+
+    @Test
+    fun testColorTransition_sameColor_noAnimation() {
+        whenever(extractColor.invoke(colorScheme)).thenReturn(DEFAULT_COLOR)
+        colorTransition.updateColorScheme(colorScheme)
+        verify(valueAnimator, never()).start()
+        assertEquals(DEFAULT_COLOR, colorTransition.sourceColor)
+        assertEquals(DEFAULT_COLOR, colorTransition.targetColor)
+    }
+
+    @Test
+    fun testColorTransition_colorAnimation_startValues() {
+        val expectedColor = DEFAULT_COLOR
+        whenever(valueAnimator.animatedFraction).thenReturn(0f)
+        colorTransition.updateColorScheme(colorScheme)
+        colorTransition.onAnimationUpdate(valueAnimator)
+
+        assertEquals(expectedColor, colorTransition.currentColor)
+        assertEquals(expectedColor, colorTransition.sourceColor)
+        verify(applyColor, times(2)).invoke(expectedColor) // applied once in constructor
+    }
+
+    @Test
+    fun testColorTransition_colorAnimation_endValues() {
+        val expectedColor = TARGET_COLOR
+        whenever(valueAnimator.animatedFraction).thenReturn(1f)
+        colorTransition.updateColorScheme(colorScheme)
+        colorTransition.onAnimationUpdate(valueAnimator)
+
+        assertEquals(expectedColor, colorTransition.currentColor)
+        assertEquals(expectedColor, colorTransition.targetColor)
+        verify(applyColor).invoke(expectedColor)
+    }
+
+    @Test
+    fun testColorTransition_colorAnimation_interpolatedMidpoint() {
+        val expectedColor = Color.rgb(186, 0, 186)
+        whenever(valueAnimator.animatedFraction).thenReturn(0.5f)
+        colorTransition.updateColorScheme(colorScheme)
+        colorTransition.onAnimationUpdate(valueAnimator)
+
+        assertEquals(expectedColor, colorTransition.currentColor)
+        verify(applyColor).invoke(expectedColor)
+    }
+
+    @Test
+    fun testColorSchemeTransition_update() {
+        colorSchemeTransition.updateColorScheme(colorScheme)
+        verify(mockTransition, times(6)).updateColorScheme(colorScheme)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index a58a28e..1bc8881 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.media
 
+import android.animation.Animator
+import android.animation.AnimatorSet
 import android.app.PendingIntent
 import android.app.smartspace.SmartspaceAction
 import android.content.Context
@@ -39,6 +41,7 @@
 import android.testing.TestableLooper
 import android.view.View
 import android.view.ViewGroup
+import android.view.animation.Interpolator
 import android.widget.FrameLayout
 import android.widget.ImageButton
 import android.widget.ImageView
@@ -58,6 +61,7 @@
 import com.android.systemui.util.animation.TransitionLayout
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.KotlinArgumentCaptor
+import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.mockito.withArgCaptor
 import com.android.systemui.util.time.FakeSystemClock
@@ -140,6 +144,7 @@
     private lateinit var actionsTopBarrier: Barrier
     @Mock private lateinit var longPressText: TextView
     @Mock private lateinit var handler: Handler
+    @Mock private lateinit var mockAnimator: AnimatorSet
     private lateinit var settings: ImageButton
     private lateinit var cancel: View
     private lateinit var cancelText: TextView
@@ -181,7 +186,7 @@
         whenever(packageManager.getApplicationLabel(any())).thenReturn(PACKAGE)
         context.setMockPackageManager(packageManager)
 
-        player = MediaControlPanel(
+        player = object : MediaControlPanel(
             context,
             bgExecutor,
             mainExecutor,
@@ -194,8 +199,15 @@
             mediaCarouselController,
             falsingManager,
             clock,
-            logger
-        )
+            logger) {
+                override fun loadAnimator(
+                    animId: Int,
+                    otionInterpolator: Interpolator,
+                    vararg targets: View
+                ): AnimatorSet {
+                    return mockAnimator
+                }
+            }
 
         initMediaViewHolderMocks()
 
@@ -437,6 +449,64 @@
     }
 
     @Test
+    fun bindSemanticActions_reservedPrev() {
+        val icon = context.getDrawable(android.R.drawable.ic_media_play)
+        val bg = context.getDrawable(R.drawable.qs_media_round_button_background)
+
+        // Setup button state: no prev or next button and their slots reserved
+        val semanticActions = MediaButton(
+            playOrPause = MediaAction(icon, Runnable {}, "play", bg),
+            nextOrCustom = null,
+            prevOrCustom = null,
+            custom0 = MediaAction(icon, null, "custom 0", bg),
+            custom1 = MediaAction(icon, null, "custom 1", bg),
+            false,
+            true
+        )
+        val state = mediaData.copy(semanticActions = semanticActions)
+
+        player.attachPlayer(viewHolder)
+        player.bindPlayer(state, PACKAGE)
+
+        assertThat(actionPrev.isEnabled()).isFalse()
+        assertThat(actionPrev.drawable).isNull()
+        verify(expandedSet).setVisibility(R.id.actionPrev, ConstraintSet.INVISIBLE)
+
+        assertThat(actionNext.isEnabled()).isFalse()
+        assertThat(actionNext.drawable).isNull()
+        verify(expandedSet).setVisibility(R.id.actionNext, ConstraintSet.GONE)
+    }
+
+    @Test
+    fun bindSemanticActions_reservedNext() {
+        val icon = context.getDrawable(android.R.drawable.ic_media_play)
+        val bg = context.getDrawable(R.drawable.qs_media_round_button_background)
+
+        // Setup button state: no prev or next button and their slots reserved
+        val semanticActions = MediaButton(
+            playOrPause = MediaAction(icon, Runnable {}, "play", bg),
+            nextOrCustom = null,
+            prevOrCustom = null,
+            custom0 = MediaAction(icon, null, "custom 0", bg),
+            custom1 = MediaAction(icon, null, "custom 1", bg),
+            true,
+            false
+        )
+        val state = mediaData.copy(semanticActions = semanticActions)
+
+        player.attachPlayer(viewHolder)
+        player.bindPlayer(state, PACKAGE)
+
+        assertThat(actionPrev.isEnabled()).isFalse()
+        assertThat(actionPrev.drawable).isNull()
+        verify(expandedSet).setVisibility(R.id.actionPrev, ConstraintSet.GONE)
+
+        assertThat(actionNext.isEnabled()).isFalse()
+        assertThat(actionNext.drawable).isNull()
+        verify(expandedSet).setVisibility(R.id.actionNext, ConstraintSet.INVISIBLE)
+    }
+
+    @Test
     fun bind_seekBarDisabled_seekBarVisibilityIsSetToInvisible() {
         whenever(seekBarViewModel.getEnabled()).thenReturn(false)
 
@@ -470,7 +540,7 @@
         val icon = context.getDrawable(android.R.drawable.ic_media_play)
         val semanticActions = MediaButton(
             prevOrCustom = MediaAction(icon, {}, "prev", null),
-            nextOrCustom = MediaAction(icon, {}, "next", null),
+            nextOrCustom = MediaAction(icon, {}, "next", null)
         )
         val state = mediaData.copy(semanticActions = semanticActions)
 
@@ -504,7 +574,7 @@
         val icon = context.getDrawable(android.R.drawable.ic_media_play)
         val semanticActions = MediaButton(
             prevOrCustom = null,
-            nextOrCustom = MediaAction(icon, {}, "next", null),
+            nextOrCustom = MediaAction(icon, {}, "next", null)
         )
         val state = mediaData.copy(semanticActions = semanticActions)
         player.attachPlayer(viewHolder)
@@ -524,7 +594,7 @@
         val icon = context.getDrawable(android.R.drawable.ic_media_play)
         val semanticActions = MediaButton(
             prevOrCustom = MediaAction(icon, {}, "prev", null),
-            nextOrCustom = null,
+            nextOrCustom = null
         )
         val state = mediaData.copy(semanticActions = semanticActions)
         player.attachPlayer(viewHolder)
@@ -544,7 +614,7 @@
         val icon = context.getDrawable(android.R.drawable.ic_media_play)
         val semanticActions = MediaButton(
             prevOrCustom = MediaAction(icon, {}, "prev", null),
-            nextOrCustom = MediaAction(icon, {}, "next", null),
+            nextOrCustom = MediaAction(icon, {}, "next", null)
         )
         val state = mediaData.copy(semanticActions = semanticActions)
         player.attachPlayer(viewHolder)
@@ -566,7 +636,7 @@
         val icon = context.getDrawable(android.R.drawable.ic_media_play)
         val semanticActions = MediaButton(
             prevOrCustom = MediaAction(icon, {}, "prev", null),
-            nextOrCustom = MediaAction(icon, {}, "next", null),
+            nextOrCustom = MediaAction(icon, {}, "next", null)
         )
         val state = mediaData.copy(semanticActions = semanticActions)
 
@@ -709,8 +779,53 @@
     fun bindText() {
         player.attachPlayer(viewHolder)
         player.bindPlayer(mediaData, PACKAGE)
+
+        // Capture animation handler
+        val captor = argumentCaptor<Animator.AnimatorListener>()
+        verify(mockAnimator, times(2)).addListener(captor.capture())
+        val handler = captor.value
+
+        // Validate text views unchanged but animation started
+        assertThat(titleText.getText()).isEqualTo("")
+        assertThat(artistText.getText()).isEqualTo("")
+        verify(mockAnimator, times(1)).start()
+
+        // Binding only after animator runs
+        handler.onAnimationEnd(mockAnimator)
         assertThat(titleText.getText()).isEqualTo(TITLE)
         assertThat(artistText.getText()).isEqualTo(ARTIST)
+
+        // Rebinding should not trigger animation
+        player.bindPlayer(mediaData, PACKAGE)
+        verify(mockAnimator, times(1)).start()
+    }
+
+    @Test
+    fun bindTextInterrupted() {
+        val data0 = mediaData.copy(artist = "ARTIST_0")
+        val data1 = mediaData.copy(artist = "ARTIST_1")
+        val data2 = mediaData.copy(artist = "ARTIST_2")
+
+        player.attachPlayer(viewHolder)
+        player.bindPlayer(data0, PACKAGE)
+
+        // Capture animation handler
+        val captor = argumentCaptor<Animator.AnimatorListener>()
+        verify(mockAnimator, times(2)).addListener(captor.capture())
+        val handler = captor.value
+
+        handler.onAnimationEnd(mockAnimator)
+        assertThat(artistText.getText()).isEqualTo("ARTIST_0")
+
+        // Bind trigges new animation
+        player.bindPlayer(data1, PACKAGE)
+        verify(mockAnimator, times(2)).start()
+        whenever(mockAnimator.isRunning()).thenReturn(true)
+
+        // Rebind before animation end binds corrct data
+        player.bindPlayer(data2, PACKAGE)
+        handler.onAnimationEnd(mockAnimator)
+        assertThat(artistText.getText()).isEqualTo("ARTIST_2")
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 8582499..7ec31a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -838,6 +838,9 @@
 
         assertThat(actions.custom1).isNotNull()
         assertThat(actions.custom1!!.contentDescription).isEqualTo(customDesc[1])
+
+        assertThat(actions.reserveNext).isTrue()
+        assertThat(actions.reservePrev).isTrue()
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MetadataAnimationHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MetadataAnimationHandlerTest.kt
new file mode 100644
index 0000000..52cb902
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MetadataAnimationHandlerTest.kt
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media
+
+import org.mockito.Mockito.`when` as whenever
+import android.animation.Animator
+import android.animation.AnimatorSet
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import com.android.systemui.SysuiTestCase
+import junit.framework.Assert.fail
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.times
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.junit.MockitoJUnit
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class MetadataAnimationHandlerTest : SysuiTestCase() {
+
+    private interface Callback : () -> Unit
+    private lateinit var handler: MetadataAnimationHandler
+
+    @Mock private lateinit var animatorSet: AnimatorSet
+    @Mock private lateinit var enterAnimator: Animator
+    @Mock private lateinit var exitAnimator: Animator
+    @Mock private lateinit var postExitCB: Callback
+    @Mock private lateinit var postEnterCB: Callback
+
+    @JvmField @Rule val mockito = MockitoJUnit.rule()
+
+    @Before
+    fun setUp() {
+        handler = object : MetadataAnimationHandler(exitAnimator, enterAnimator) {
+            override fun buildAnimatorSet(exit: Animator, enter: Animator): AnimatorSet {
+                return animatorSet
+            }
+        }
+    }
+
+    @After
+    fun tearDown() {}
+
+    @Test
+    fun firstBind_startsAnimationSet() {
+        val cb = { fail("Unexpected callback") }
+        handler.setNext("data-1", cb, cb)
+
+        verify(animatorSet).start()
+    }
+
+    @Test
+    fun executeAnimationEnd_runsCallacks() {
+        handler.setNext("data-1", postExitCB, postEnterCB)
+        verify(animatorSet, times(1)).start()
+        verify(postExitCB, never()).invoke()
+
+        handler.onAnimationEnd(exitAnimator)
+        verify(animatorSet, times(1)).start()
+        verify(postExitCB, times(1)).invoke()
+        verify(postEnterCB, never()).invoke()
+
+        handler.onAnimationEnd(enterAnimator)
+        verify(animatorSet, times(1)).start()
+        verify(postExitCB, times(1)).invoke()
+        verify(postEnterCB, times(1)).invoke()
+    }
+
+    @Test
+    fun rebindSameData_executesFirstCallback() {
+        val postExitCB2 = mock(Callback::class.java)
+
+        handler.setNext("data-1", postExitCB, postEnterCB)
+        handler.setNext("data-1", postExitCB2, postEnterCB)
+        handler.onAnimationEnd(exitAnimator)
+
+        verify(postExitCB, times(1)).invoke()
+        verify(postExitCB2, never()).invoke()
+        verify(postEnterCB, never()).invoke()
+    }
+
+    @Test
+    fun rebindDifferentData_executesSecondCallback() {
+        val postExitCB2 = mock(Callback::class.java)
+
+        handler.setNext("data-1", postExitCB, postEnterCB)
+        handler.setNext("data-2", postExitCB2, postEnterCB)
+        handler.onAnimationEnd(exitAnimator)
+
+        verify(postExitCB, never()).invoke()
+        verify(postExitCB2, times(1)).invoke()
+        verify(postEnterCB, never()).invoke()
+    }
+
+    @Test
+    fun rebindBeforeEnterComplete_animationRestarts() {
+        val postExitCB2 = mock(Callback::class.java)
+        val postEnterCB2 = mock(Callback::class.java)
+
+        handler.setNext("data-1", postExitCB, postEnterCB)
+        verify(animatorSet, times(1)).start()
+        verify(postExitCB, never()).invoke()
+        verify(postExitCB2, never()).invoke()
+        verify(postEnterCB, never()).invoke()
+        verify(postEnterCB2, never()).invoke()
+
+        whenever(animatorSet.isRunning()).thenReturn(true)
+        handler.onAnimationEnd(exitAnimator)
+        verify(animatorSet, times(1)).start()
+        verify(postExitCB, times(1)).invoke()
+        verify(postExitCB2, never()).invoke()
+        verify(postEnterCB, never()).invoke()
+        verify(postEnterCB2, never()).invoke()
+
+        handler.setNext("data-2", postExitCB2, postEnterCB2)
+        handler.onAnimationEnd(enterAnimator)
+        verify(animatorSet, times(2)).start()
+        verify(postExitCB, times(1)).invoke()
+        verify(postExitCB2, never()).invoke()
+        verify(postEnterCB, never()).invoke()
+        verify(postEnterCB2, never()).invoke()
+
+        handler.onAnimationEnd(exitAnimator)
+        verify(animatorSet, times(2)).start()
+        verify(postExitCB, times(1)).invoke()
+        verify(postExitCB2, times(1)).invoke()
+        verify(postEnterCB, never()).invoke()
+        verify(postEnterCB2, never()).invoke()
+
+        handler.onAnimationEnd(enterAnimator)
+        verify(animatorSet, times(2)).start()
+        verify(postExitCB, times(1)).invoke()
+        verify(postExitCB2, times(1)).invoke()
+        verify(postEnterCB, never()).invoke()
+        verify(postEnterCB2, times(1)).invoke()
+    }
+
+    @Test
+    fun exitAnimationEndMultipleCalls_singleCallbackExecution() {
+        handler.setNext("data-1", postExitCB, postEnterCB)
+        handler.onAnimationEnd(exitAnimator)
+        handler.onAnimationEnd(exitAnimator)
+        handler.onAnimationEnd(exitAnimator)
+
+        verify(postExitCB, times(1)).invoke()
+    }
+
+    @Test
+    fun enterAnimatorEndsWithoutCallback_noAnimatiorStart() {
+        handler.onAnimationEnd(enterAnimator)
+
+        verify(animatorSet, never()).start()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
index c48d846..49be669 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.media
 
+import android.animation.Animator
+import android.animation.ObjectAnimator
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.View
@@ -43,6 +45,7 @@
     private val enabledHeight = 2
 
     private lateinit var observer: SeekBarObserver
+    @Mock private lateinit var mockSeekbarAnimator: ObjectAnimator
     @Mock private lateinit var mockHolder: MediaViewHolder
     @Mock private lateinit var mockSquigglyProgress: SquigglyProgress
     private lateinit var seekBarView: SeekBar
@@ -66,7 +69,11 @@
         whenever(mockHolder.scrubbingElapsedTimeView).thenReturn(scrubbingElapsedTimeView)
         whenever(mockHolder.scrubbingTotalTimeView).thenReturn(scrubbingTotalTimeView)
 
-        observer = SeekBarObserver(mockHolder)
+        observer = object : SeekBarObserver(mockHolder) {
+            override fun buildResetAnimator(targetTime: Int): Animator {
+                return mockSeekbarAnimator
+            }
+        }
     }
 
     @Test
@@ -189,4 +196,20 @@
         assertThat(scrubbingElapsedTimeView.text).isEqualTo("")
         assertThat(scrubbingTotalTimeView.text).isEqualTo("")
     }
+
+    @Test
+    fun seekBarJumpAnimation() {
+        val data0 = SeekBarViewModel.Progress(true, true, true, false, 4000, 120000)
+        val data1 = SeekBarViewModel.Progress(true, true, true, false, 10, 120000)
+
+        // Set initial position of progress bar
+        observer.onChanged(data0)
+        assertThat(seekBarView.progress).isEqualTo(4000)
+        assertThat(seekBarView.max).isEqualTo(120000)
+
+        // Change to second data & confirm no change to position (due to animation delay)
+        observer.onChanged(data1)
+        assertThat(seekBarView.progress).isEqualTo(4000)
+        verify(mockSeekbarAnimator).start()
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
index b4b4597..e6b960d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
@@ -33,8 +33,12 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import android.app.people.ConversationStatus;
@@ -44,6 +48,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.UserHandle;
@@ -581,6 +586,27 @@
     }
 
     @Test
+    public void testCreateRemoteViewsWithNotificationContent() throws Exception {
+        PeopleTileViewHelper helper = spy(getPeopleTileViewHelper(PERSON_TILE));
+        doReturn(new BitmapDrawable()).when(helper).resolveImage(any(), any());
+        RemoteViews views = helper.getViews();
+        View result = views.apply(mContext, null);
+
+        assertEquals(View.VISIBLE, result.findViewById(R.id.image).getVisibility());
+    }
+
+    @Test
+    public void testCreateRemoteViewsWithInvalidNotificationContent() throws Exception {
+        PeopleTileViewHelper helper = spy(getPeopleTileViewHelper(PERSON_TILE));
+        doThrow(SecurityException.class).when(helper).resolveImage(any(), any());
+        RemoteViews views = helper.getViews();
+        View result = views.apply(mContext, null);
+
+        assertEquals(View.GONE, result.findViewById(R.id.image).getVisibility());
+        assertEquals(View.VISIBLE, result.findViewById(R.id.text_content).getVisibility());
+    }
+
+    @Test
     public void testCreateRemoteViewsWithUserQuieted() {
         PeopleSpaceTile tile = PERSON_TILE.toBuilder()
                 .setIsUserQuieted(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index f5d19e2..4fbdb7c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -315,6 +315,24 @@
         verify(mQuickQSPanelController).setCollapseExpandAction(action);
     }
 
+    @Test
+    public void setOverScrollAmount_setsTranslationOnView() {
+        QSFragment fragment = resumeAndGetFragment();
+
+        fragment.setOverScrollAmount(123);
+
+        assertThat(mQsFragmentView.getTranslationY()).isEqualTo(123);
+    }
+
+    @Test
+    public void setOverScrollAmount_beforeViewCreated_translationIsNotSet() {
+        QSFragment fragment = getFragment();
+
+        fragment.setOverScrollAmount(123);
+
+        assertThat(mQsFragmentView.getTranslationY()).isEqualTo(0);
+    }
+
     @Override
     protected Fragment instantiate(Context context, String className, Bundle arguments) {
         MockitoAnnotations.initMocks(this);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
index dfd70a2..968e16a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.stack
 
+import android.annotation.DimenRes
 import android.service.notification.StatusBarNotification
 import android.testing.AndroidTestingRunner
 import android.view.View.VISIBLE
@@ -27,6 +28,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
 import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.mockito.nullable
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
@@ -34,8 +36,8 @@
 import org.junit.runner.RunWith
 import org.mockito.Mock
 import org.mockito.Mockito.mock
-import org.mockito.MockitoAnnotations
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
@@ -49,17 +51,15 @@
 
     private lateinit var sizeCalculator: NotificationStackSizeCalculator
 
+    private val gapHeight = px(R.dimen.notification_section_divider_height)
+    private val dividerHeight = px(R.dimen.notification_divider_height)
+    private val shelfHeight = px(R.dimen.notification_shelf_height)
+    private val rowHeight = px(R.dimen.notification_max_height)
+
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
-        whenever(stackLayout.calculateGapHeight(nullable(), nullable(), any()))
-            .thenReturn(GAP_HEIGHT)
-        with(testableResources) {
-            addOverride(R.integer.keyguard_max_notification_count, -1)
-            addOverride(R.dimen.notification_divider_height, DIVIDER_HEIGHT.toInt())
-        }
-
         sizeCalculator =
             NotificationStackSizeCalculator(
                 statusBarStateController = sysuiStatusBarStateController,
@@ -68,7 +68,7 @@
 
     @Test
     fun computeMaxKeyguardNotifications_zeroSpace_returnZero() {
-        val rows = listOf(createMockRow(height = ROW_HEIGHT))
+        val rows = listOf(createMockRow(height = rowHeight))
 
         val maxNotifications =
             computeMaxKeyguardNotifications(rows, availableSpace = 0f, shelfHeight = 0f)
@@ -87,105 +87,78 @@
     }
 
     @Test
-    fun computeMaxKeyguardNotifications_spaceForOne_returnsOne() {
-        val rowHeight = ROW_HEIGHT
-        val totalSpaceForEachRow = GAP_HEIGHT + rowHeight
-        val shelfHeight =
-            totalSpaceForEachRow / 2 // In this way shelf absence will not leave room for another.
-        val spaceForOne = totalSpaceForEachRow
-        val rows =
-            listOf(
-                createMockRow(rowHeight),
-                createMockRow(rowHeight))
+    fun computeMaxKeyguardNotifications_spaceForOneAndShelf_returnsOne() {
+        setGapHeight(gapHeight)
+        val shelfHeight = rowHeight / 2 // Shelf absence won't leave room for another row.
+        val availableSpace =
+            listOf(rowHeight + dividerHeight, gapHeight + dividerHeight + shelfHeight).sum()
+        val rows = listOf(createMockRow(rowHeight), createMockRow(rowHeight))
 
-        val maxNotifications =
-            computeMaxKeyguardNotifications(
-                rows, availableSpace = spaceForOne, shelfHeight = shelfHeight)
-
-        assertThat(maxNotifications).isEqualTo(1)
-    }
-
-    @Test
-    fun computeMaxKeyguardNotifications_spaceForOne_shelfUsableForLastNotification_returnsTwo() {
-        val rowHeight = ROW_HEIGHT
-        val totalSpaceForEachRow = GAP_HEIGHT + rowHeight
-        val shelfHeight = totalSpaceForEachRow + DIVIDER_HEIGHT
-        val spaceForOne = totalSpaceForEachRow
-        val rows =
-            listOf(
-                createMockRow(rowHeight),
-                createMockRow(rowHeight))
-
-        val maxNotifications =
-            computeMaxKeyguardNotifications(
-                rows, availableSpace = spaceForOne, shelfHeight = shelfHeight)
+        val maxNotifications = computeMaxKeyguardNotifications(rows, availableSpace, shelfHeight)
 
         assertThat(maxNotifications).isEqualTo(1)
     }
 
     @Test
     fun computeMaxKeyguardNotifications_spaceForTwo_returnsTwo() {
-        val rowHeight = ROW_HEIGHT
-        val totalSpaceForEachRow = GAP_HEIGHT + rowHeight
-        val spaceForTwo = totalSpaceForEachRow * 2 + DIVIDER_HEIGHT
-        val rows =
+        setGapHeight(gapHeight)
+        val shelfHeight = shelfHeight + dividerHeight
+        val availableSpace =
             listOf(
-                createMockRow(rowHeight),
-                createMockRow(rowHeight),
-                createMockRow(rowHeight))
+                    rowHeight + dividerHeight,
+                    gapHeight + rowHeight + dividerHeight,
+                    gapHeight + dividerHeight + shelfHeight)
+                .sum()
+        val rows =
+            listOf(createMockRow(rowHeight), createMockRow(rowHeight), createMockRow(rowHeight))
 
-        val maxNotifications = computeMaxKeyguardNotifications(rows, spaceForTwo, shelfHeight = 0f)
+        val maxNotifications = computeMaxKeyguardNotifications(rows, availableSpace, shelfHeight)
 
         assertThat(maxNotifications).isEqualTo(2)
     }
 
     @Test
     fun computeHeight_returnsAtMostSpaceAvailable_withGapBeforeShelf() {
-        val rowHeight = ROW_HEIGHT
-        val shelfHeight = SHELF_HEIGHT
-        val totalSpaceForEachRow = GAP_HEIGHT + rowHeight + DIVIDER_HEIGHT
-        val availableSpace = totalSpaceForEachRow * 2
+        setGapHeight(gapHeight)
+        val shelfHeight = shelfHeight
+        val availableSpace =
+            listOf(
+                    rowHeight + dividerHeight,
+                    gapHeight + rowHeight + dividerHeight,
+                    gapHeight + dividerHeight + shelfHeight)
+                .sum()
 
         // All rows in separate sections (default setup).
         val rows =
-            listOf(
-                createMockRow(rowHeight),
-                createMockRow(rowHeight),
-                createMockRow(rowHeight))
+            listOf(createMockRow(rowHeight), createMockRow(rowHeight), createMockRow(rowHeight))
 
         val maxNotifications = computeMaxKeyguardNotifications(rows, availableSpace, shelfHeight)
         assertThat(maxNotifications).isEqualTo(2)
 
-        val height = sizeCalculator.computeHeight(stackLayout, maxNotifications, SHELF_HEIGHT)
-        assertThat(height).isAtMost(availableSpace + GAP_HEIGHT + SHELF_HEIGHT)
+        val height = sizeCalculator.computeHeight(stackLayout, maxNotifications, this.shelfHeight)
+        assertThat(height).isAtMost(availableSpace)
     }
 
     @Test
-    fun computeHeight_returnsAtMostSpaceAvailable_noGapBeforeShelf() {
-        val rowHeight = ROW_HEIGHT
-        val shelfHeight = SHELF_HEIGHT
-        val totalSpaceForEachRow = GAP_HEIGHT + rowHeight + DIVIDER_HEIGHT
-        val availableSpace = totalSpaceForEachRow * 1
-
+    fun computeHeight_noGapBeforeShelf_returnsAtMostSpaceAvailable() {
         // Both rows are in the same section.
-        whenever(stackLayout.calculateGapHeight(nullable(), nullable(), any()))
-                .thenReturn(0f)
-        val rows =
-                listOf(
-                        createMockRow(rowHeight),
-                        createMockRow(rowHeight))
+        setGapHeight(0f)
+        val rowHeight = rowHeight
+        val shelfHeight = shelfHeight
+        val availableSpace = listOf(rowHeight + dividerHeight, dividerHeight + shelfHeight).sum()
+        val rows = listOf(createMockRow(rowHeight), createMockRow(rowHeight))
 
         val maxNotifications = computeMaxKeyguardNotifications(rows, availableSpace, shelfHeight)
         assertThat(maxNotifications).isEqualTo(1)
 
-        val height = sizeCalculator.computeHeight(stackLayout, maxNotifications, SHELF_HEIGHT)
-        assertThat(height).isAtMost(availableSpace + SHELF_HEIGHT)
+        val height = sizeCalculator.computeHeight(stackLayout, maxNotifications, this.shelfHeight)
+        assertThat(height).isAtMost(availableSpace)
     }
 
     private fun computeMaxKeyguardNotifications(
         rows: List<ExpandableView>,
         availableSpace: Float,
-        shelfHeight: Float = SHELF_HEIGHT
+        shelfHeight: Float = this.shelfHeight
     ): Int {
         setupChildren(rows)
         return sizeCalculator.computeMaxKeyguardNotifications(
@@ -204,9 +177,9 @@
         (1..number).map { createMockRow() }.toList()
 
     private fun createMockRow(
-        height: Float = ROW_HEIGHT,
+        height: Float = rowHeight,
         isRemoved: Boolean = false,
-        visibility: Int = VISIBLE,
+        visibility: Int = VISIBLE
     ): ExpandableNotificationRow {
         val row = mock(ExpandableNotificationRow::class.java)
         val entry = mock(NotificationEntry::class.java)
@@ -220,11 +193,12 @@
         return row
     }
 
-    /** Default dimensions for tests that don't overwrite them. */
-    companion object {
-        const val GAP_HEIGHT = 12f
-        const val DIVIDER_HEIGHT = 3f
-        const val SHELF_HEIGHT = 14f
-        const val ROW_HEIGHT = SHELF_HEIGHT * 3
+    private fun setGapHeight(height: Float) {
+        whenever(stackLayout.calculateGapHeight(nullable(), nullable(), any())).thenReturn(height)
+        whenever(stackLayout.calculateGapHeight(nullable(), nullable(), /* visibleIndex= */ eq(0)))
+            .thenReturn(0f)
     }
+
+    private fun px(@DimenRes id: Int): Float =
+        testableResources.resources.getDimensionPixelSize(id).toFloat()
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 5ef1008..562d11a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -69,6 +69,7 @@
 import android.os.SystemClock;
 import android.os.Trace;
 import android.provider.Settings;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
@@ -218,12 +219,6 @@
         @NonNull KeyEventDispatcher getKeyEventDispatcher();
 
         /**
-         * @param windowId The id of the window of interest
-         * @return The magnification spec for the window, or {@code null} if none is available
-         */
-        @Nullable MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId);
-
-        /**
          * @param displayId The display id.
          * @return The current injector of motion events used on the display, if one exists.
          */
@@ -557,7 +552,8 @@
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
-        MagnificationSpec spec;
+        final MagnificationSpec spec;
+        final float[] transformMatrix;
         synchronized (mLock) {
             mUsesAccessibilityCache = true;
             if (!hasRightsToCurrentUserLocked()) {
@@ -581,7 +577,10 @@
                 partialInteractiveRegion.recycle();
                 partialInteractiveRegion = null;
             }
-            spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
+            final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
+                    getTransformMatrixAndSpecLocked(resolvedWindowId);
+            transformMatrix = transformMatrixAndSpec.first;
+            spec = transformMatrixAndSpec.second;
         }
         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
             return null;
@@ -594,12 +593,12 @@
             logTraceIntConn("findAccessibilityNodeInfosByViewId",
                     accessibilityNodeId + ";" + viewIdResName + ";" + partialInteractiveRegion + ";"
                     + interactionId + ";" + callback + ";" + mFetchFlags + ";" + interrogatingPid
-                    + ";" + interrogatingTid + ";" + spec);
+                    + ";" + interrogatingTid + ";" + spec + ";" + Arrays.toString(transformMatrix));
         }
         try {
             connection.getRemote().findAccessibilityNodeInfosByViewId(accessibilityNodeId,
                     viewIdResName, partialInteractiveRegion, interactionId, callback, mFetchFlags,
-                    interrogatingPid, interrogatingTid, spec);
+                    interrogatingPid, interrogatingTid, spec, transformMatrix);
             return mSecurityPolicy.computeValidReportedPackages(
                     connection.getPackageName(), connection.getUid());
         } catch (RemoteException re) {
@@ -630,7 +629,8 @@
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
-        MagnificationSpec spec;
+        final MagnificationSpec spec;
+        final float [] transformMatrix;
         synchronized (mLock) {
             mUsesAccessibilityCache = true;
             if (!hasRightsToCurrentUserLocked()) {
@@ -654,7 +654,10 @@
                 partialInteractiveRegion.recycle();
                 partialInteractiveRegion = null;
             }
-            spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
+            final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
+                    getTransformMatrixAndSpecLocked(resolvedWindowId);
+            transformMatrix = transformMatrixAndSpec.first;
+            spec = transformMatrixAndSpec.second;
         }
         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
             return null;
@@ -667,12 +670,12 @@
             logTraceIntConn("findAccessibilityNodeInfosByText",
                     accessibilityNodeId + ";" + text + ";" + partialInteractiveRegion + ";"
                     + interactionId + ";" + callback + ";" + mFetchFlags + ";" + interrogatingPid
-                    + ";" + interrogatingTid + ";" + spec);
+                    + ";" + interrogatingTid + ";" + spec + ";" + Arrays.toString(transformMatrix));
         }
         try {
             connection.getRemote().findAccessibilityNodeInfosByText(accessibilityNodeId,
                     text, partialInteractiveRegion, interactionId, callback, mFetchFlags,
-                    interrogatingPid, interrogatingTid, spec);
+                    interrogatingPid, interrogatingTid, spec, transformMatrix);
             return mSecurityPolicy.computeValidReportedPackages(
                     connection.getPackageName(), connection.getUid());
         } catch (RemoteException re) {
@@ -704,7 +707,8 @@
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
-        MagnificationSpec spec;
+        final MagnificationSpec spec;
+        final float[] transformMatrix;
         synchronized (mLock) {
             mUsesAccessibilityCache = true;
             if (!hasRightsToCurrentUserLocked()) {
@@ -728,7 +732,10 @@
                 partialInteractiveRegion.recycle();
                 partialInteractiveRegion = null;
             }
-            spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
+            final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
+                    getTransformMatrixAndSpecLocked(resolvedWindowId);
+            transformMatrix = transformMatrixAndSpec.first;
+            spec = transformMatrixAndSpec.second;
         }
         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
             return null;
@@ -741,12 +748,14 @@
             logTraceIntConn("findAccessibilityNodeInfoByAccessibilityId",
                     accessibilityNodeId + ";" + partialInteractiveRegion + ";" + interactionId + ";"
                     + callback + ";" + (mFetchFlags | flags) + ";" + interrogatingPid + ";"
-                    + interrogatingTid + ";" + spec + ";" + arguments);
+                            + interrogatingTid + ";" + spec + ";" + Arrays.toString(transformMatrix)
+                            + ";" + arguments);
         }
         try {
             connection.getRemote().findAccessibilityNodeInfoByAccessibilityId(
                     accessibilityNodeId, partialInteractiveRegion, interactionId, callback,
-                    mFetchFlags | flags, interrogatingPid, interrogatingTid, spec, arguments);
+                    mFetchFlags | flags, interrogatingPid, interrogatingTid, spec, transformMatrix,
+                    arguments);
             return mSecurityPolicy.computeValidReportedPackages(
                     connection.getPackageName(), connection.getUid());
         } catch (RemoteException re) {
@@ -778,7 +787,8 @@
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
-        MagnificationSpec spec;
+        final MagnificationSpec spec;
+        final float[] transformMatrix;
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return null;
@@ -802,7 +812,10 @@
                 partialInteractiveRegion.recycle();
                 partialInteractiveRegion = null;
             }
-            spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
+            final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
+                    getTransformMatrixAndSpecLocked(resolvedWindowId);
+            transformMatrix = transformMatrixAndSpec.first;
+            spec = transformMatrixAndSpec.second;
         }
         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
             return null;
@@ -815,12 +828,13 @@
             logTraceIntConn("findFocus",
                     accessibilityNodeId + ";" + focusType + ";" + partialInteractiveRegion + ";"
                     + interactionId + ";" + callback + ";" + mFetchFlags + ";" + interrogatingPid
-                    + ";" + interrogatingTid + ";" + spec);
+                            + ";" + interrogatingTid + ";" + spec + ";"
+                            + Arrays.toString(transformMatrix));
         }
         try {
             connection.getRemote().findFocus(accessibilityNodeId, focusType,
                     partialInteractiveRegion, interactionId, callback, mFetchFlags,
-                    interrogatingPid, interrogatingTid, spec);
+                    interrogatingPid, interrogatingTid, spec, transformMatrix);
             return mSecurityPolicy.computeValidReportedPackages(
                     connection.getPackageName(), connection.getUid());
         } catch (RemoteException re) {
@@ -852,7 +866,8 @@
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
-        MagnificationSpec spec;
+        final MagnificationSpec spec;
+        final float[] transformMatrix;
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return null;
@@ -875,7 +890,11 @@
                 partialInteractiveRegion.recycle();
                 partialInteractiveRegion = null;
             }
-            spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
+
+            final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
+                    getTransformMatrixAndSpecLocked(resolvedWindowId);
+            transformMatrix = transformMatrixAndSpec.first;
+            spec = transformMatrixAndSpec.second;
         }
         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
             return null;
@@ -888,12 +907,13 @@
             logTraceIntConn("focusSearch",
                     accessibilityNodeId + ";" + direction + ";" + partialInteractiveRegion
                     + ";" + interactionId + ";" + callback + ";" + mFetchFlags + ";"
-                    + interrogatingPid + ";" + interrogatingTid + ";" + spec);
+                            + interrogatingPid + ";" + interrogatingTid + ";" + spec + ";"
+                             + Arrays.toString(transformMatrix));
         }
         try {
             connection.getRemote().focusSearch(accessibilityNodeId, direction,
                     partialInteractiveRegion, interactionId, callback, mFetchFlags,
-                    interrogatingPid, interrogatingTid, spec);
+                    interrogatingPid, interrogatingTid, spec, transformMatrix);
             return mSecurityPolicy.computeValidReportedPackages(
                     connection.getPackageName(), connection.getUid());
         } catch (RemoteException re) {
@@ -1652,6 +1672,23 @@
         mInvocationHandler.startInputLocked(startInputToken, inputContext, editorInfo, restarting);
     }
 
+
+
+    @Nullable
+    Pair<float[], MagnificationSpec> getTransformMatrixAndSpecLocked(int resolvedWindowId) {
+        final WindowInfo windowInfo =
+                mA11yWindowManager.findWindowInfoByIdLocked(resolvedWindowId);
+        if (windowInfo == null) {
+            Slog.w(LOG_TAG, "getTransformMatrixAndSpec, windowInfo is null window id = "
+                    + resolvedWindowId);
+            return new Pair<>(null, null);
+        }
+
+        final MagnificationSpec spec = new MagnificationSpec();
+        spec.setTo(windowInfo.mMagnificationSpec);
+        return new Pair<>(windowInfo.mTransformMatrix, spec);
+    }
+
     /**
      * Called by the invocation handler to notify the service that the
      * state of magnification has changed.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index e3226c7..ac0c051 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -106,6 +106,7 @@
 import android.view.KeyEvent;
 import android.view.MagnificationSpec;
 import android.view.MotionEvent;
+import android.view.WindowInfo;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityInteractionClient;
@@ -3045,22 +3046,6 @@
         userState.setInteractiveUiTimeoutLocked(newInteractiveUiTimeout);
     }
 
-    @GuardedBy("mLock")
-    @Override
-    public MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
-        IBinder windowToken = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
-                mCurrentUserId, windowId);
-        if (windowToken != null) {
-            if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL)) {
-                mTraceManager.logTrace(LOG_TAG + ".getCompatibleMagnificationSpecForWindow",
-                        FLAGS_WINDOW_MANAGER_INTERNAL, "windowToken=" + windowToken);
-            }
-
-            return mWindowManagerService.getCompatibleMagnificationSpecForWindow(windowToken);
-        }
-        return null;
-    }
-
     @Override
     public KeyEventDispatcher getKeyEventDispatcher() {
         if (mKeyEventDispatcher == null) {
@@ -3741,7 +3726,14 @@
                         boundsInScreenBeforeMagnification.centerY());
 
                 // Invert magnification if needed.
-                MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId());
+                final WindowInfo windowInfo = mA11yWindowManager.findWindowInfoByIdLocked(
+                        focus.getWindowId());
+                MagnificationSpec spec = null;
+                if (windowInfo != null) {
+                    spec = new MagnificationSpec();
+                    spec.setTo(windowInfo.mMagnificationSpec);
+                }
+
                 if (spec != null && !spec.isNop()) {
                     boundsInScreenBeforeMagnification.offset((int) -spec.offsetX,
                             (int) -spec.offsetY);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index aba32ec..e30639c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -52,6 +52,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -478,6 +479,9 @@
             if (oldWindow.taskId != newWindow.taskId) {
                 return true;
             }
+            if (!Arrays.equals(oldWindow.mTransformMatrix, newWindow.mTransformMatrix)) {
+                return true;
+            }
             return false;
         }
 
@@ -800,14 +804,24 @@
                         pw.append(',');
                         pw.println();
                     }
-                    pw.append("Window[");
+                    pw.append("A11yWindow[");
                     AccessibilityWindowInfo window = mWindows.get(j);
                     pw.append(window.toString());
                     pw.append(']');
+                    pw.println();
+                    final WindowInfo windowInfo = findWindowInfoByIdLocked(window.getId());
+                    if (windowInfo != null) {
+                        pw.append("WindowInfo[");
+                        pw.append(windowInfo.toString());
+                        pw.append("]");
+                        pw.println();
+                    }
+
                 }
                 pw.println();
             }
         }
+
     }
     /**
      * Interface to send {@link AccessibilityEvent}.
diff --git a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
index 6828dd9..6958b66 100644
--- a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
+++ b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
@@ -83,7 +83,7 @@
             mConnectionWithReplacementActions.findAccessibilityNodeInfoByAccessibilityId(
                     AccessibilityNodeInfo.ROOT_NODE_ID, null,
                     mNodeWithReplacementActionsInteractionId, this, 0,
-                    interrogatingPid, interrogatingTid, null, null);
+                    interrogatingPid, interrogatingTid, null, null, null);
         } catch (RemoteException re) {
             if (DEBUG) {
                 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index f944d4f..e529010 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -75,6 +75,13 @@
     @VisibleForTesting static final long CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS = 300;
 
     /**
+     * Min time in milliseconds to complete the emergency gesture for it count. If the gesture is
+     * completed faster than this, we assume it's not performed by human and the
+     * event gets ignored.
+     */
+    @VisibleForTesting static final int EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS = 160;
+
+    /**
      * Interval in milliseconds in which the power button must be depressed in succession to be
      * considered part of an extended sequence of taps. Note that this is a looser threshold than
      * the camera launch gesture, because the purpose of this threshold is to measure the
@@ -184,6 +191,7 @@
     private int mEmergencyGesturePowerButtonCooldownPeriodMs;
 
     private long mLastPowerDown;
+    private long mFirstPowerDown;
     private long mLastEmergencyGestureTriggered;
     private int mPowerButtonConsecutiveTaps;
     private int mPowerButtonSlowConsecutiveTaps;
@@ -553,10 +561,12 @@
             mLastPowerDown = event.getEventTime();
             if (powerTapInterval >= POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS) {
                 // Tap too slow, reset consecutive tap counts.
+                mFirstPowerDown  = event.getEventTime();
                 mPowerButtonConsecutiveTaps = 1;
                 mPowerButtonSlowConsecutiveTaps = 1;
             } else if (powerTapInterval >= CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS) {
                 // Tap too slow for shortcuts
+                mFirstPowerDown  = event.getEventTime();
                 mPowerButtonConsecutiveTaps = 1;
                 mPowerButtonSlowConsecutiveTaps++;
             } else {
@@ -575,7 +585,26 @@
                     intercept = interactive;
                 }
                 if (mPowerButtonConsecutiveTaps == EMERGENCY_GESTURE_POWER_TAP_COUNT_THRESHOLD) {
-                    launchEmergencyGesture = true;
+                    long emergencyGestureSpentTime = event.getEventTime() - mFirstPowerDown;
+                    long emergencyGestureTapDetectionMinTimeMs = Settings.Global.getInt(
+                            mContext.getContentResolver(),
+                            Settings.Global.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS,
+                            EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS);
+                    if (emergencyGestureSpentTime <= emergencyGestureTapDetectionMinTimeMs) {
+                        Slog.i(TAG, "Emergency gesture detected but it's too fast. Gesture time: "
+                                + emergencyGestureSpentTime + " ms");
+                        // Reset consecutive tap counts.
+                        mFirstPowerDown = event.getEventTime();
+                        mPowerButtonConsecutiveTaps = 1;
+                        mPowerButtonSlowConsecutiveTaps = 1;
+                    } else {
+                        Slog.i(TAG, "Emergency gesture detected. Gesture time: "
+                                + emergencyGestureSpentTime + " ms");
+                        launchEmergencyGesture = true;
+                        mMetricsLogger.histogram("emergency_gesture_spent_time",
+                                (int) emergencyGestureSpentTime);
+
+                    }
                 }
             }
             if (mCameraDoubleTapPowerEnabled
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index 64ff532..90201a0 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -654,7 +654,7 @@
             final long start = stats.getStatsStartTimestamp();
             final long end = stats.getStatsEndTimestamp();
             final double scale = expectedDuration > 0
-                    ? (expectedDuration * 1.0d) / (end - start) : 1.0d;
+                    ? Math.min((expectedDuration * 1.0d) / (end - start), 1.0d) : 1.0d;
             final AppBatteryPolicy bgPolicy = mInjector.getPolicy();
             for (UidBatteryConsumer uidConsumer : uidConsumers) {
                 // TODO: b/200326767 - as we are not supporting per proc state attribution yet,
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 0518899..8a7fece 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -61,7 +61,6 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
-import android.os.PowerExemptionManager;
 import android.os.PowerExemptionManager.ReasonCode;
 import android.os.PowerExemptionManager.TempAllowListType;
 import android.os.Process;
@@ -1934,9 +1933,6 @@
     }
 
     private void maybeReportBroadcastDispatchedEventLocked(BroadcastRecord r, int targetUid) {
-        // STOPSHIP (217251579): Temporarily use temp-allowlist reason to identify
-        // push messages and record response events.
-        useTemporaryAllowlistReasonAsSignal(r);
         if (r.options == null || r.options.getIdForResponseEvent() <= 0) {
             return;
         }
@@ -1951,17 +1947,6 @@
                 mService.getUidStateLocked(targetUid));
     }
 
-    private void useTemporaryAllowlistReasonAsSignal(BroadcastRecord r) {
-        if (r.options == null || r.options.getIdForResponseEvent() > 0) {
-            return;
-        }
-        final int reasonCode = r.options.getTemporaryAppAllowlistReasonCode();
-        if (reasonCode == PowerExemptionManager.REASON_PUSH_MESSAGING
-                || reasonCode == PowerExemptionManager.REASON_PUSH_MESSAGING_OVER_QUOTA) {
-            r.options.recordResponseEventWhileInBackground(reasonCode);
-        }
-    }
-
     @NonNull
     private UsageStatsManagerInternal getUsageStatsManagerInternal() {
         final UsageStatsManagerInternal usageStatsManagerInternal =
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 7db99f1..be11253 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -239,6 +239,8 @@
         public long mResultErrorCount;
         public boolean mDeviceError;
         public List<CameraStreamStats> mStreamStats;
+        public String mUserTag;
+
         private long mDurationOrStartTimeMs;  // Either start time, or duration once completed
 
         CameraUsageEvent(String cameraId, int facing, String clientName, int apiLevel,
@@ -257,7 +259,7 @@
 
         public void markCompleted(int internalReconfigure, long requestCount,
                 long resultErrorCount, boolean deviceError,
-                List<CameraStreamStats>  streamStats) {
+                List<CameraStreamStats>  streamStats, String userTag) {
             if (mCompleted) {
                 return;
             }
@@ -268,6 +270,7 @@
             mResultErrorCount = resultErrorCount;
             mDeviceError = deviceError;
             mStreamStats = streamStats;
+            mUserTag = userTag;
             if (CameraServiceProxy.DEBUG) {
                 Slog.v(TAG, "A camera facing " + cameraFacingToString(mCameraFacing) +
                         " was in use by " + mClientName + " for " +
@@ -794,7 +797,8 @@
                         + ", requestCount " + e.mRequestCount
                         + ", resultErrorCount " + e.mResultErrorCount
                         + ", deviceError " + e.mDeviceError
-                        + ", streamCount is " + streamCount);
+                        + ", streamCount is " + streamCount
+                        + ", userTag is " + e.mUserTag);
             }
             // Convert from CameraStreamStats to CameraStreamProto
             CameraStreamProto[] streamProtos = new CameraStreamProto[MAX_STREAM_STATISTICS];
@@ -851,7 +855,8 @@
                     MessageNano.toByteArray(streamProtos[1]),
                     MessageNano.toByteArray(streamProtos[2]),
                     MessageNano.toByteArray(streamProtos[3]),
-                    MessageNano.toByteArray(streamProtos[4]));
+                    MessageNano.toByteArray(streamProtos[4]),
+                    e.mUserTag);
         }
     }
 
@@ -1038,6 +1043,7 @@
         long resultErrorCount = cameraState.getResultErrorCount();
         boolean deviceError = cameraState.getDeviceErrorFlag();
         List<CameraStreamStats> streamStats = cameraState.getStreamStats();
+        String userTag = cameraState.getUserTag();
         synchronized(mLock) {
             // Update active camera list and notify NFC if necessary
             boolean wasEmpty = mActiveCameraUsage.isEmpty();
@@ -1091,7 +1097,8 @@
                     if (oldEvent != null) {
                         Slog.w(TAG, "Camera " + cameraId + " was already marked as active");
                         oldEvent.markCompleted(/*internalReconfigure*/0, /*requestCount*/0,
-                                /*resultErrorCount*/0, /*deviceError*/false, streamStats);
+                                /*resultErrorCount*/0, /*deviceError*/false, streamStats,
+                                /*userTag*/"");
                         mCameraUsageHistory.add(oldEvent);
                     }
                     break;
@@ -1101,7 +1108,7 @@
                     if (doneEvent != null) {
 
                         doneEvent.markCompleted(internalReconfigureCount, requestCount,
-                                resultErrorCount, deviceError, streamStats);
+                                resultErrorCount, deviceError, streamStats, userTag);
                         mCameraUsageHistory.add(doneEvent);
 
                         // Check current active camera IDs to see if this package is still
diff --git a/services/core/java/com/android/server/pm/AppsFilterImpl.java b/services/core/java/com/android/server/pm/AppsFilterImpl.java
index b4ddda5..dff7100 100644
--- a/services/core/java/com/android/server/pm/AppsFilterImpl.java
+++ b/services/core/java/com/android/server/pm/AppsFilterImpl.java
@@ -228,15 +228,6 @@
      * Watchable machinery
      */
     private final WatchableImpl mWatchable = new WatchableImpl();
-    /**
-     * The observer that watches for changes from array members
-     */
-    private final Watcher mObserver = new Watcher() {
-        @Override
-        public void onChange(@Nullable Watchable what) {
-            AppsFilterImpl.this.dispatchChange(what);
-        }
-    };
 
     /**
      * Ensures an observer is in the list, exactly once. The observer cannot be null.  The
@@ -331,8 +322,6 @@
         mProtectedBroadcastsSnapshot = new SnapshotCache.Auto<>(
                 mProtectedBroadcasts, mProtectedBroadcasts, "AppsFilter.mProtectedBroadcasts");
 
-        registerObservers();
-        Watchable.verifyWatchedAttributes(this, mObserver);
         mSnapshot = makeCache();
     }
 
@@ -375,18 +364,6 @@
         mSystemReady = true;
     }
 
-    @SuppressWarnings("GuardedBy")
-    private void registerObservers() {
-        mImplicitlyQueryable.registerObserver(mObserver);
-        mRetainedImplicitlyQueryable.registerObserver(mObserver);
-        mQueriesViaPackage.registerObserver(mObserver);
-        mQueriesViaComponent.registerObserver(mObserver);
-        mQueryableViaUsesLibrary.registerObserver(mObserver);
-        mForceQueryable.registerObserver(mObserver);
-        mProtectedBroadcasts.registerObserver(mObserver);
-        mShouldFilterCache.registerObserver(mObserver);
-    }
-
     /**
      * Return a snapshot.  If the cached snapshot is null, build a new one.  The logic in
      * the function ensures that this function returns a valid snapshot even if a race
@@ -773,9 +750,7 @@
                 mShouldFilterCache.put(recipientUid, visibleUid, false);
             }
         }
-        if (changed) {
-            onChanged();
-        }
+        onChanged();
         return changed;
     }
 
@@ -986,6 +961,7 @@
             }
             updateEntireShouldFilterCacheInner(settings, users, userId);
         });
+        onChanged();
     }
 
     private void updateEntireShouldFilterCacheInner(
@@ -1008,8 +984,7 @@
     private void updateEntireShouldFilterCacheAsync() {
         mBackgroundExecutor.execute(() -> {
             final ArrayMap<String, PackageStateInternal> settingsCopy = new ArrayMap<>();
-            final Collection<SharedUserSetting> sharedUserSettingsCopy =
-                    new ArraySet<SharedUserSetting>();
+            final Collection<SharedUserSetting> sharedUserSettingsCopy = new ArraySet<>();
             final ArrayMap<String, AndroidPackage> packagesCache = new ArrayMap<>();
             final UserInfo[][] usersRef = new UserInfo[1][];
             mStateProvider.runWithState((settings, sharedUserSettings, users) -> {
@@ -1049,6 +1024,7 @@
             } else {
                 updateEntireShouldFilterCacheInner(settingsCopy,
                         usersRef[0], USER_ALL);
+                onChanged();
             }
         });
     }
@@ -1058,7 +1034,6 @@
             return;
         }
         updateEntireShouldFilterCache(newUserId);
-        onChanged();
     }
 
     public void onUserDeleted(@UserIdInt int userId) {
@@ -1078,6 +1053,7 @@
                     settings.get(packageName), settings, users, USER_ALL,
                     settings.size() /*maxIndex*/);
         });
+        onChanged();
     }
 
     private void updateShouldFilterCacheForPackage(
@@ -1389,9 +1365,8 @@
                     }
                 }
             }
-
-            onChanged();
         });
+        onChanged();
     }
 
     private ArraySet<? extends PackageStateInternal> getSharedUserPackages(int sharedUserAppId,
@@ -1495,6 +1470,7 @@
                     mStateProvider.runWithState((settings, sharedUserSettings, users) ->
                             callingSharedPkgSettings.addAll(getSharedUserPackages(
                                     packageState.getSharedUserAppId(), sharedUserSettings)));
+
                 } else {
                     callingPkgSetting = packageState;
                 }
@@ -1624,9 +1600,12 @@
                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueriesViaComponent");
                 }
                 if (mQueriesViaComponentRequireRecompute) {
+                    final ArrayMap<String, PackageStateInternal> settingsCopy = new ArrayMap<>();
                     mStateProvider.runWithState((settings, sharedUserSettings, users) -> {
-                        recomputeComponentVisibility(settings);
+                        settingsCopy.putAll(settings);
                     });
+                    recomputeComponentVisibility(settingsCopy);
+                    onChanged();
                 }
                 synchronized (mLock) {
                     if (mQueriesViaComponent.contains(callingAppId, targetAppId)) {
diff --git a/services/core/java/com/android/server/pm/ChangedPackagesTracker.java b/services/core/java/com/android/server/pm/ChangedPackagesTracker.java
index bd12981..3802135 100644
--- a/services/core/java/com/android/server/pm/ChangedPackagesTracker.java
+++ b/services/core/java/com/android/server/pm/ChangedPackagesTracker.java
@@ -90,25 +90,27 @@
     }
 
     void updateSequenceNumber(@NonNull String packageName, int[] userList) {
-        for (int i = userList.length - 1; i >= 0; --i) {
-            final int userId = userList[i];
-            SparseArray<String> changedPackages = mUserIdToSequenceToPackage.get(userId);
-            if (changedPackages == null) {
-                changedPackages = new SparseArray<>();
-                mUserIdToSequenceToPackage.put(userId, changedPackages);
+        synchronized (mLock) {
+            for (int i = userList.length - 1; i >= 0; --i) {
+                final int userId = userList[i];
+                SparseArray<String> changedPackages = mUserIdToSequenceToPackage.get(userId);
+                if (changedPackages == null) {
+                    changedPackages = new SparseArray<>();
+                    mUserIdToSequenceToPackage.put(userId, changedPackages);
+                }
+                Map<String, Integer> sequenceNumbers = mChangedPackagesSequenceNumbers.get(userId);
+                if (sequenceNumbers == null) {
+                    sequenceNumbers = new HashMap<>();
+                    mChangedPackagesSequenceNumbers.put(userId, sequenceNumbers);
+                }
+                final Integer sequenceNumber = sequenceNumbers.get(packageName);
+                if (sequenceNumber != null) {
+                    changedPackages.remove(sequenceNumber);
+                }
+                changedPackages.put(mChangedPackagesSequenceNumber, packageName);
+                sequenceNumbers.put(packageName, mChangedPackagesSequenceNumber);
             }
-            Map<String, Integer> sequenceNumbers = mChangedPackagesSequenceNumbers.get(userId);
-            if (sequenceNumbers == null) {
-                sequenceNumbers = new HashMap<>();
-                mChangedPackagesSequenceNumbers.put(userId, sequenceNumbers);
-            }
-            final Integer sequenceNumber = sequenceNumbers.get(packageName);
-            if (sequenceNumber != null) {
-                changedPackages.remove(sequenceNumber);
-            }
-            changedPackages.put(mChangedPackagesSequenceNumber, packageName);
-            sequenceNumbers.put(packageName, mChangedPackagesSequenceNumber);
+            mChangedPackagesSequenceNumber++;
         }
-        mChangedPackagesSequenceNumber++;
     }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d5e2a63..ffd924e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1543,6 +1543,7 @@
     }
 
     // Link watchables to the class
+    @SuppressWarnings("GuardedBy")
     private void registerObservers(boolean verify) {
         // Null check to handle nullable test parameters
         if (mPackages != null) {
@@ -2256,7 +2257,7 @@
 
     @GuardedBy("mLock")
     void updateInstantAppInstallerLocked(String modifiedPackage) {
-        // we're only interested in updating the installer appliction when 1) it's not
+        // we're only interested in updating the installer application when 1) it's not
         // already set or 2) the modified package is the installer
         if (mInstantAppInstallerActivity != null
                 && !mInstantAppInstallerActivity.getComponentName().getPackageName()
@@ -2740,7 +2741,6 @@
         return mModuleInfoProvider.getModuleInfo(packageName, flags);
     }
 
-    @GuardedBy("mLock")
     void updateSequenceNumberLP(PackageSetting pkgSetting, int[] userList) {
         mChangedPackagesTracker.updateSequenceNumber(pkgSetting.getPackageName(), userList);
     }
@@ -3074,8 +3074,8 @@
                 userId);
     }
 
-    private void enforceCanSetDistractingPackageRestrictionsAsUser(@NonNull Computer snapshot,
-            int callingUid, int userId, String callingMethod) {
+    private void enforceCanSetDistractingPackageRestrictionsAsUser(int callingUid, int userId,
+            String callingMethod) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
                 callingMethod);
 
@@ -3159,6 +3159,7 @@
         }
     }
 
+    @SuppressWarnings("GuardedBy")
     VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) {
         if (pkg.isExternalStorage()) {
             if (TextUtils.isEmpty(pkg.getVolumeUuid())) {
@@ -3288,6 +3289,7 @@
      * Update component enabled settings to {@link PackageManager#COMPONENT_ENABLED_STATE_DEFAULT}
      * if the resetEnabledSettingsOnAppDataCleared is {@code true}.
      */
+    @GuardedBy("mLock")
     private void resetComponentEnabledSettingsIfNeededLPw(String packageName, int userId) {
         final AndroidPackage pkg = packageName != null ? mPackages.get(packageName) : null;
         if (pkg == null || !pkg.isResetEnabledSettingsOnAppDataCleared()) {
@@ -3879,6 +3881,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private boolean setEnabledSettingInternalLocked(@NonNull Computer computer,
             PackageSetting pkgSetting, ComponentEnabledSetting setting, @UserIdInt int userId,
             String callingPackage) {
@@ -4554,7 +4557,9 @@
                             final Computer snapshot = snapshotComputer();
                             unsuspendForSuspendingPackage(snapshot, packageName, userId);
                             removeAllDistractingPackageRestrictions(snapshot, userId);
-                            flushPackageRestrictionsAsUserInternalLocked(userId);
+                            synchronized (mLock) {
+                                flushPackageRestrictionsAsUserInternalLocked(userId);
+                            }
                         }
                     }
                     if (observer != null) {
@@ -4972,6 +4977,7 @@
         }
 
         @Override
+        @SuppressWarnings("GuardedBy")
         public int getRuntimePermissionsVersion(@UserIdInt int userId) {
             Preconditions.checkArgumentNonnegative(userId);
             enforceAdjustRuntimePermissionsPolicyOrUpgradeRuntimePermissions(
@@ -5576,7 +5582,7 @@
                 int restrictionFlags, int userId) {
             final int callingUid = Binder.getCallingUid();
             final Computer snapshot = snapshotComputer();
-            enforceCanSetDistractingPackageRestrictionsAsUser(snapshot, callingUid, userId,
+            enforceCanSetDistractingPackageRestrictionsAsUser(callingUid, userId,
                     "setDistractingPackageRestrictionsAsUser");
             Objects.requireNonNull(packageNames, "packageNames cannot be null");
             return mDistractingPackageHelper.setDistractingPackageRestrictionsAsUser(snapshot,
@@ -5845,6 +5851,7 @@
         }
 
         @Override
+        @SuppressWarnings("GuardedBy")
         public void setRuntimePermissionsVersion(int version, @UserIdInt int userId) {
             Preconditions.checkArgumentNonnegative(version);
             Preconditions.checkArgumentNonnegative(userId);
@@ -6363,6 +6370,7 @@
         }
 
         @Override
+        @SuppressWarnings("GuardedBy")
         public void updateRuntimePermissionsFingerprint(@UserIdInt int userId) {
             mSettings.updateRuntimePermissionsFingerprint(userId);
         }
@@ -6397,6 +6405,7 @@
         }
 
         @Override
+        @SuppressWarnings("GuardedBy")
         public boolean isPermissionUpgradeNeeded(int userId) {
             return mSettings.isPermissionUpgradeNeeded(userId);
         }
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 056f255..9627c43 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -105,6 +105,7 @@
 import android.util.Xml;
 import android.view.IWindowManager;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -455,6 +456,8 @@
 
     private final boolean mIsAppSearchEnabled;
 
+    private ComponentName mChooserActivity;
+
     static class InvalidFileFormatException extends Exception {
         public InvalidFileFormatException(String message, Throwable cause) {
             super(message, cause);
@@ -1646,6 +1649,26 @@
         return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
     }
 
+    @VisibleForTesting
+    ComponentName injectChooserActivity() {
+        if (mChooserActivity == null) {
+            mChooserActivity = ComponentName.unflattenFromString(
+                    mContext.getResources().getString(R.string.config_chooserActivity));
+        }
+        return mChooserActivity;
+    }
+
+    private boolean isCallerChooserActivity() {
+        // TODO(b/228975502): Migrate this check to a proper permission or role check
+        final int callingUid = injectBinderCallingUid();
+        ComponentName systemChooser = injectChooserActivity();
+        if (systemChooser == null) {
+            return false;
+        }
+        int uid = injectGetPackageUid(systemChooser.getPackageName(), UserHandle.USER_SYSTEM);
+        return uid == callingUid;
+    }
+
     private void enforceSystemOrShell() {
         if (!(isCallerSystem() || isCallerShell())) {
             throw new SecurityException("Caller must be system or shell");
@@ -2525,7 +2548,9 @@
             IntentFilter filter, @UserIdInt int userId) {
         Preconditions.checkStringNotEmpty(packageName, "packageName");
         Objects.requireNonNull(filter, "intentFilter");
-        verifyCaller(packageName, userId);
+        if (!isCallerChooserActivity()) {
+            verifyCaller(packageName, userId);
+        }
         enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APP_PREDICTIONS,
                 "getShareTargets");
         synchronized (mLock) {
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index 0e6d5e5..8dc9428 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -92,21 +92,6 @@
     public abstract void setDevicePolicyUserRestrictions(int originatingUserId,
             @Nullable Bundle global, @Nullable RestrictionsSet local, boolean isDeviceOwner);
 
-    /**
-     * Returns the "base" user restrictions.
-     *
-     * Used by {@link com.android.server.devicepolicy.DevicePolicyManagerService} for upgrading
-     * from MNC.
-     */
-    public abstract Bundle getBaseUserRestrictions(int userId);
-
-    /**
-     * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} for upgrading
-     * from MNC.
-     */
-    public abstract void setBaseUserRestrictionsByDpmsForMigration(int userId,
-            Bundle baseRestrictions);
-
     /** Return a user restriction. */
     public abstract boolean getUserRestriction(int userId, String key);
 
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index cb08c79..358e71a 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -5900,33 +5900,6 @@
         }
 
         @Override
-        public Bundle getBaseUserRestrictions(@UserIdInt int userId) {
-            synchronized (mRestrictionsLock) {
-                return mBaseUserRestrictions.getRestrictions(userId);
-            }
-        }
-
-        @Override
-        public void setBaseUserRestrictionsByDpmsForMigration(
-                @UserIdInt int userId, Bundle baseRestrictions) {
-            synchronized (mRestrictionsLock) {
-                if (mBaseUserRestrictions.updateRestrictions(userId,
-                        new Bundle(baseRestrictions))) {
-                    invalidateEffectiveUserRestrictionsLR(userId);
-                }
-            }
-
-            final UserData userData = getUserDataNoChecks(userId);
-            synchronized (mPackagesLock) {
-                if (userData != null) {
-                    writeUserLP(userData);
-                } else {
-                    Slog.w(LOG_TAG, "UserInfo not found for " + userId);
-                }
-            }
-        }
-
-        @Override
         public boolean getUserRestriction(@UserIdInt int userId, String key) {
             return getUserRestrictions(userId).getBoolean(key);
         }
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index aede4b1..685b744 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -64,6 +64,8 @@
 import com.android.server.statusbar.StatusBarManagerInternal;
 
 import java.io.PrintWriter;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Sends broadcasts about important power state changes.
@@ -133,6 +135,7 @@
     private final DisplayManagerInternal mDisplayManagerInternal;
 
     private final NotifierHandler mHandler;
+    private final Executor mBackgroundExecutor;
     private final Intent mScreenOnIntent;
     private final Intent mScreenOffIntent;
 
@@ -169,9 +172,12 @@
     // True if a user activity message should be sent.
     private boolean mUserActivityPending;
 
+    private final AtomicBoolean mIsPlayingChargingStartedFeedback = new AtomicBoolean(false);
+
     public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
             SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
-            FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
+            FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
+            Executor backgroundExecutor) {
         mContext = context;
         mBatteryStats = batteryStats;
         mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -188,6 +194,7 @@
         mVibrator = mContext.getSystemService(Vibrator.class);
 
         mHandler = new NotifierHandler(looper);
+        mBackgroundExecutor = backgroundExecutor;
         mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
         mScreenOnIntent.addFlags(
                 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND
@@ -824,25 +831,36 @@
             return;
         }
 
-        // vibrate
-        final boolean vibrate = Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                Settings.Secure.CHARGING_VIBRATION_ENABLED, 1, userId) != 0;
-        if (vibrate) {
-            mVibrator.vibrate(CHARGING_VIBRATION_EFFECT, HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES);
+        if (!mIsPlayingChargingStartedFeedback.compareAndSet(false, true)) {
+            // there's already a charging started feedback Runnable scheduled to run on the
+            // background thread, so let's not execute another
+            return;
         }
 
-        // play sound
-        final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
-                wireless ? Settings.Global.WIRELESS_CHARGING_STARTED_SOUND
-                        : Settings.Global.CHARGING_STARTED_SOUND);
-        final Uri soundUri = Uri.parse("file://" + soundPath);
-        if (soundUri != null) {
-            final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
-            if (sfx != null) {
-                sfx.setStreamType(AudioManager.STREAM_SYSTEM);
-                sfx.play();
+        // vibrate & play sound on a background thread
+        mBackgroundExecutor.execute(() -> {
+            // vibrate
+            final boolean vibrate = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.CHARGING_VIBRATION_ENABLED, 1, userId) != 0;
+            if (vibrate) {
+                mVibrator.vibrate(CHARGING_VIBRATION_EFFECT,
+                        HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES);
             }
-        }
+
+            // play sound
+            final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
+                    wireless ? Settings.Global.WIRELESS_CHARGING_STARTED_SOUND
+                            : Settings.Global.CHARGING_STARTED_SOUND);
+            final Uri soundUri = Uri.parse("file://" + soundPath);
+            if (soundUri != null) {
+                final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
+                if (sfx != null) {
+                    sfx.setStreamType(AudioManager.STREAM_SYSTEM);
+                    sfx.play();
+                }
+            }
+            mIsPlayingChargingStartedFeedback.set(false);
+        });
     }
 
     private void showWirelessChargingStarted(int batteryLevel, @UserIdInt int userId) {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 6e78ecb..e0da0e8 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -140,6 +140,7 @@
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Objects;
+import java.util.concurrent.Executor;
 
 /**
  * The power manager service is responsible for coordinating power management
@@ -905,10 +906,11 @@
     static class Injector {
         Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
                 SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
-                FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
+                FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
+                Executor backgroundExecutor) {
             return new Notifier(
                     looper, context, batteryStats, suspendBlocker, policy, faceDownDetector,
-                    screenUndimDetector);
+                    screenUndimDetector, backgroundExecutor);
         }
 
         SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
@@ -1227,7 +1229,8 @@
             mBatteryStats = BatteryStatsService.getService();
             mNotifier = mInjector.createNotifier(Looper.getMainLooper(), mContext, mBatteryStats,
                     mInjector.createSuspendBlocker(this, "PowerManagerService.Broadcasts"),
-                    mPolicy, mFaceDownDetector, mScreenUndimDetector);
+                    mPolicy, mFaceDownDetector, mScreenUndimDetector,
+                    BackgroundThread.getExecutor());
 
             mPowerGroups.append(Display.DEFAULT_DISPLAY_GROUP,
                     new PowerGroup(WAKEFULNESS_AWAKE, mPowerGroupWakefulnessChangeListener,
diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
index bce1cce..0834417 100644
--- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
@@ -560,7 +560,7 @@
                         + " sensors");
                 return;
             }
-            mContext.startActivityAsUser(dialogIntent, options.toBundle(), info.mUser);
+            mContext.startActivityAsUser(dialogIntent, options.toBundle(), UserHandle.SYSTEM);
         }
 
         /**
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
index ae52912..7173f60 100644
--- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
@@ -59,6 +59,8 @@
      */
     private static final Set<String> CONFIGURATION_INTERNAL_SERVER_FLAGS_KEYS_TO_WATCH = Set.of(
             ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
+            ServerFlags.KEY_PRIMARY_LTZP_MODE_OVERRIDE,
+            ServerFlags.KEY_SECONDARY_LTZP_MODE_OVERRIDE,
             ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_RUN_IN_BACKGROUND_ENABLED,
             ServerFlags.KEY_ENHANCED_METRICS_COLLECTION_ENABLED,
             ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
@@ -443,6 +445,9 @@
         mTestPrimaryLocationTimeZoneProviderMode =
                 mTestPrimaryLocationTimeZoneProviderPackageName == null
                         ? PROVIDER_MODE_DISABLED : PROVIDER_MODE_ENABLED;
+        // Changing this state can affect the content of ConfigurationInternal, so listeners need to
+        // be informed.
+        mContext.getMainThreadHandler().post(this::handleConfigurationInternalChangeOnMainThread);
     }
 
     @Override
@@ -469,6 +474,9 @@
         mTestSecondaryLocationTimeZoneProviderMode =
                 mTestSecondaryLocationTimeZoneProviderPackageName == null
                         ? PROVIDER_MODE_DISABLED : PROVIDER_MODE_ENABLED;
+        // Changing this state can affect the content of ConfigurationInternal, so listeners need to
+        // be informed.
+        mContext.getMainThreadHandler().post(this::handleConfigurationInternalChangeOnMainThread);
     }
 
     @Override
@@ -573,6 +581,10 @@
         mTestSecondaryLocationTimeZoneProviderPackageName = null;
         mTestSecondaryLocationTimeZoneProviderMode = null;
         mRecordStateChangesForTests = false;
+
+        // Changing LTZP config can affect the content of ConfigurationInternal, so listeners
+        // need to be informed.
+        mContext.getMainThreadHandler().post(this::handleConfigurationInternalChangeOnMainThread);
     }
 
     private boolean isTelephonyFallbackSupported() {
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index f75608e..898d02e 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -336,13 +336,13 @@
     boolean isTelephonyTimeZoneDetectionSupported() {
         enforceManageTimeZoneDetectorPermission();
 
-        return mServiceConfigAccessor.isTelephonyTimeZoneDetectionFeatureSupported();
+        return mTimeZoneDetectorStrategy.isTelephonyTimeZoneDetectionSupported();
     }
 
     boolean isGeoTimeZoneDetectionSupported() {
         enforceManageTimeZoneDetectorPermission();
 
-        return mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupported();
+        return mTimeZoneDetectorStrategy.isGeoTimeZoneDetectionSupported();
     }
 
     /**
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index 6b04adf..95ebd68 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -124,4 +124,10 @@
     /** Generates a state snapshot for metrics. */
     @NonNull
     MetricsTimeZoneDetectorState generateMetricsState();
+
+    /** Returns {@code true} if the device supports telephony time zone detection. */
+    boolean isTelephonyTimeZoneDetectionSupported();
+
+    /** Returns {@code true} if the device supports geolocation time zone detection. */
+    boolean isGeoTimeZoneDetectionSupported();
 }
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
index e21d0e4..66c23f5 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
@@ -396,6 +396,20 @@
                 getLatestGeolocationSuggestion());
     }
 
+    @Override
+    public boolean isTelephonyTimeZoneDetectionSupported() {
+        synchronized (this) {
+            return mCurrentConfigurationInternal.isTelephonyDetectionSupported();
+        }
+    }
+
+    @Override
+    public boolean isGeoTimeZoneDetectionSupported() {
+        synchronized (this) {
+            return mCurrentConfigurationInternal.isGeoDetectionSupported();
+        }
+    }
+
     private static int scoreTelephonySuggestion(@NonNull TelephonyTimeZoneSuggestion suggestion) {
         int score;
         if (suggestion.getZoneId() == null) {
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index c52a4e4..63619e5 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -446,20 +446,6 @@
         // Not relevant for the window observer.
     }
 
-    MagnificationSpec getMagnificationSpecForWindow(WindowState windowState) {
-        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
-            mAccessibilityTracing.logTrace(TAG + ".getMagnificationSpecForWindow",
-                    FLAGS_MAGNIFICATION_CALLBACK,
-                    "windowState={" + windowState + "}");
-        }
-        final int displayId = windowState.getDisplayId();
-        final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
-        if (displayMagnifier != null) {
-            return displayMagnifier.getMagnificationSpecForWindow(windowState);
-        }
-        return null;
-    }
-
     boolean hasCallbacks() {
         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
                 | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
index ca636b3..6e5011d 100644
--- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
+++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
@@ -596,8 +596,6 @@
      * surface flinger to the accessibility framework.
      */
     public static class AccessibilityWindow {
-        private static final Region TEMP_REGION = new Region();
-        private static final RectF TEMP_RECTF = new RectF();
         // Data
         private IWindow mWindow;
         private int mDisplayId;
@@ -615,15 +613,16 @@
         private final Region mLetterBoxBounds = new Region();
         private WindowInfo mWindowInfo;
 
+
         /**
          * Returns the instance after initializing the internal data.
          * @param service The window manager service.
          * @param inputWindowHandle The window from the surface flinger.
-         * @param inverseMatrix The magnification spec inverse matrix.
+         * @param magnificationInverseMatrix The magnification spec inverse matrix.
          */
         public static AccessibilityWindow initializeData(WindowManagerService service,
-                InputWindowHandle inputWindowHandle, Matrix inverseMatrix, IBinder pipIBinder,
-                Matrix displayMatrix) {
+                InputWindowHandle inputWindowHandle, Matrix magnificationInverseMatrix,
+                IBinder pipIBinder, Matrix displayMatrix) {
             final IWindow window = inputWindowHandle.getWindow();
             final WindowState windowState = window != null ? service.mWindowMap.get(
                     window.asBinder()) : null;
@@ -655,13 +654,35 @@
                     inputWindowHandle.frameTop, inputWindowHandle.frameRight,
                     inputWindowHandle.frameBottom);
             getTouchableRegionInWindow(instance.mShouldMagnify, inputWindowHandle.touchableRegion,
-                    instance.mTouchableRegionInWindow, windowFrame, inverseMatrix, displayMatrix);
+                    instance.mTouchableRegionInWindow, windowFrame, magnificationInverseMatrix,
+                    displayMatrix);
             getUnMagnifiedTouchableRegion(instance.mShouldMagnify,
                     inputWindowHandle.touchableRegion, instance.mTouchableRegionInScreen,
-                    inverseMatrix, displayMatrix);
+                    magnificationInverseMatrix, displayMatrix);
             instance.mWindowInfo = windowState != null
                     ? windowState.getWindowInfo() : getWindowInfoForWindowlessWindows(instance);
 
+            // Compute the transform matrix that will transform bounds from the window
+            // coordinates to screen coordinates.
+            final Matrix inverseTransform = new Matrix();
+            inputWindowHandle.transform.invert(inverseTransform);
+            inverseTransform.postConcat(displayMatrix);
+            inverseTransform.getValues(instance.mWindowInfo.mTransformMatrix);
+
+            // Compute the magnification spec matrix.
+            final Matrix magnificationSpecMatrix = new Matrix();
+            if (instance.shouldMagnify() && magnificationInverseMatrix != null
+                    && !magnificationInverseMatrix.isIdentity()) {
+                if (magnificationInverseMatrix.invert(magnificationSpecMatrix)) {
+                    magnificationSpecMatrix.getValues(sTempFloats);
+                    final MagnificationSpec spec = instance.mWindowInfo.mMagnificationSpec;
+                    spec.scale = sTempFloats[Matrix.MSCALE_X];
+                    spec.offsetX = sTempFloats[Matrix.MTRANS_X];
+                    spec.offsetY = sTempFloats[Matrix.MTRANS_Y];
+                } else {
+                    Slog.w(TAG, "can't find spec");
+                }
+            }
             return instance;
         }
 
@@ -779,7 +800,7 @@
             // for the consistency and match developers expectation.
             // So we need to make the intersection between the frame and touchable region to
             // obtain the real touch region in the screen.
-            Region touchRegion = TEMP_REGION;
+            Region touchRegion = new Region();
             touchRegion.set(inRegion);
             touchRegion.op(frame, Region.Op.INTERSECT);
 
@@ -807,8 +828,7 @@
 
             forEachRect(inRegion, rect -> {
                 // Move to origin as all transforms are captured by the matrix.
-                RectF windowFrame = TEMP_RECTF;
-                windowFrame.set(rect);
+                RectF windowFrame = new RectF(rect);
 
                 displayMatrix.mapRect(windowFrame);
                 inverseMatrix.mapRect(windowFrame);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 36a7c77..75d4621 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2644,14 +2644,16 @@
             Slog.w(TAG, "startActivity called from finishing " + mSourceRecord
                     + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
             mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
-            mNewTaskInfo = mSourceRecord.info;
 
-            // It is not guaranteed that the source record will have a task associated with it. For,
-            // example, if this method is being called for processing a pending activity launch, it
-            // is possible that the activity has been removed from the task after the launch was
-            // enqueued.
+            // It is not guaranteed that the source record will have a task associated with it.
+            // For example, if this method is being called for processing a pending activity
+            // launch, it is possible that the activity has been removed from the task after the
+            // launch was enqueued.
             final Task sourceTask = mSourceRecord.getTask();
-            mNewTaskIntent = sourceTask != null ? sourceTask.intent : null;
+            if (sourceTask == null || sourceTask.getTopNonFinishingActivity() == null) {
+                mNewTaskInfo = mSourceRecord.info;
+                mNewTaskIntent = sourceTask != null ? sourceTask.intent : null;
+            }
         }
         mSourceRecord = null;
         mSourceRootTask = null;
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index b37f980..0ed6718 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -167,6 +167,23 @@
                 currentActivity = window.mActivityRecord;
                 currentTask = window.getTask();
                 callbackInfo = window.getOnBackInvokedCallbackInfo();
+                final DisplayContent displayContent = window.getDisplayContent();
+
+                // When IME is shown, return the more prioritized callback between IME and app.
+                // Priority ordering follows: OVERLAY, IME, DEFAULT.
+                if (displayContent != null && displayContent.getImeContainer().isVisible()) {
+                    WindowState imeWindow = displayContent.getImeContainer().getWindow(
+                            windowState -> windowState.getOnBackInvokedCallbackInfo() != null);
+                    if (imeWindow != null) {
+                        OnBackInvokedCallbackInfo imeCallbackInfo =
+                                imeWindow.getOnBackInvokedCallbackInfo();
+                        if (imeCallbackInfo != null && (callbackInfo == null
+                                || callbackInfo.getPriority() <= imeCallbackInfo.getPriority())) {
+                            callbackInfo = imeCallbackInfo;
+                        }
+                    }
+                }
+
                 if (callbackInfo == null) {
                     Slog.e(TAG, "No callback registered, returning null.");
                     return null;
@@ -189,12 +206,10 @@
             // If we don't need to set up the animation, we return early. This is the case when
             // - We have an application callback.
             // - We don't have any ActivityRecord or Task to animate.
-            // - The IME is opened, and we just need to close it.
             // - The home activity is the focused activity.
             if (backType == BackNavigationInfo.TYPE_CALLBACK
                     || currentActivity == null
                     || currentTask == null
-                    || currentTask.getDisplayContent().getImeContainer().isVisible()
                     || currentActivity.isActivityTypeHome()) {
                 return infoBuilder
                         .setType(backType)
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index a7b3728..6162f12 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -289,6 +289,23 @@
         return adjustVisibilityForTransientTypes(originalState);
     }
 
+    /**
+     * @param type the internal type of the insets.
+     * @return {@code true} if the given type is controllable, {@code false} otherwise.
+     */
+    static boolean isInsetsTypeControllable(@InternalInsetsType int type) {
+        switch (type) {
+            case ITYPE_STATUS_BAR:
+            case ITYPE_NAVIGATION_BAR:
+            case ITYPE_IME:
+            case ITYPE_CLIMATE_BAR:
+            case ITYPE_EXTRA_NAVIGATION_BAR:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     private static @InternalInsetsType int getInsetsTypeForLayoutParams(
             WindowManager.LayoutParams attrs) {
         @WindowManager.LayoutParams.WindowType int type = attrs.type;
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index f3f08b2..e04644c 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -16,11 +16,7 @@
 
 package com.android.server.wm;
 
-import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_IME;
-import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_STATUS_BAR;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_INSETS;
 import static com.android.server.wm.InsetsSourceProviderProto.CAPTURED_LEASH;
@@ -128,18 +124,7 @@
         mStateController = stateController;
         mFakeControl = new InsetsSourceControl(
                 source.getType(), null /* leash */, new Point(), Insets.NONE);
-
-        switch (source.getType()) {
-            case ITYPE_STATUS_BAR:
-            case ITYPE_NAVIGATION_BAR:
-            case ITYPE_IME:
-            case ITYPE_CLIMATE_BAR:
-            case ITYPE_EXTRA_NAVIGATION_BAR:
-                mControllable = true;
-                break;
-            default:
-                mControllable = false;
-        }
+        mControllable = InsetsPolicy.isInsetsTypeControllable(source.getType());
     }
 
     InsetsSource getSource() {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index d460616..6f69e03 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2006,6 +2006,7 @@
             // of the activity entering PIP
             r.getDisplayContent().prepareAppTransition(TRANSIT_NONE);
 
+            final TaskFragment organizedTf = r.getOrganizedTaskFragment();
             // TODO: Does it make sense to only count non-finishing activities?
             final boolean singleActivity = task.getActivityCount() == 1;
             final Task rootTask;
@@ -2043,6 +2044,14 @@
                     task.clearLastRecentsAnimationTransaction(false /* forceRemoveOverlay */);
                 }
 
+                // The organized TaskFragment is becoming empty because this activity is reparented
+                // to a new PIP Task. In this case, we should notify the organizer about why the
+                // TaskFragment becomes empty.
+                if (organizedTf != null && organizedTf.getNonFinishingActivityCount() == 1
+                        && organizedTf.getTopNonFinishingActivity() == r) {
+                    organizedTf.mClearedTaskFragmentForPip = true;
+                }
+
                 // There are multiple activities in the task and moving the top activity should
                 // reveal/leave the other activities in their original task.
                 // On the other hand, ActivityRecord#onParentChanged takes care of setting the
@@ -2107,6 +2116,13 @@
             // Reset the state that indicates it can enter PiP while pausing after we've moved it
             // to the root pinned task
             r.supportsEnterPipOnTaskSwitch = false;
+
+            if (organizedTf != null && organizedTf.mClearedTaskFragmentForPip) {
+                // Dispatch the pending info to TaskFragmentOrganizer before PIP animation.
+                // Otherwise, it will keep waiting for the empty TaskFragment to be non-empty.
+                mService.mTaskFragmentOrganizerController.dispatchPendingInfoChangedEvent(
+                        organizedTf);
+            }
         } finally {
             mService.continueWindowLayout();
         }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index ac04843..bd078d8 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2043,7 +2043,7 @@
         Rect outOverrideBounds = getResolvedOverrideConfiguration().windowConfiguration.getBounds();
 
         if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
-            if (!mCreatedByOrganizer) {
+            if (!isOrganized()) {
                 // Use empty bounds to indicate "fill parent".
                 outOverrideBounds.setEmpty();
             }
@@ -2788,9 +2788,11 @@
         }
 
         final Rect visibleFrame = sTmpBounds;
+        final WindowManager.LayoutParams attrs = win.mAttrs;
         visibleFrame.set(win.getFrame());
         visibleFrame.inset(win.getInsetsStateWithVisibilityOverride().calculateVisibleInsets(
-                visibleFrame, win.mAttrs.softInputMode));
+                visibleFrame, attrs.type, win.getWindowingMode(), attrs.softInputMode,
+                attrs.flags));
         out.union(visibleFrame);
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 83bd979..4e0d84c 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -193,6 +193,12 @@
     boolean mClearedTaskForReuse;
 
     /**
+     * The last running activity of the TaskFragment was reparented to a different Task because it
+     * is entering PiP.
+     */
+    boolean mClearedTaskFragmentForPip;
+
+    /**
      * When we are in the process of pausing an activity, before starting the
      * next one, this variable holds the activity that is currently being paused.
      *
@@ -847,6 +853,16 @@
         return getActivity((r) -> r.canBeTopRunning() && r.getTask() == this.getTask());
     }
 
+    int getNonFinishingActivityCount() {
+        final int[] runningActivityCount = new int[1];
+        forAllActivities(a -> {
+            if (!a.finishing) {
+                runningActivityCount[0]++;
+            }
+        });
+        return runningActivityCount[0];
+    }
+
     boolean isTopActivityFocusable() {
         final ActivityRecord r = topRunningActivity();
         return r != null ? r.isFocusable()
@@ -1709,6 +1725,7 @@
     void addChild(WindowContainer child, int index) {
         ActivityRecord r = topRunningActivity();
         mClearedTaskForReuse = false;
+        mClearedTaskFragmentForPip = false;
 
         boolean isAddingActivity = child.asActivityRecord() != null;
         final Task task = isAddingActivity ? getTask() : null;
@@ -2253,22 +2270,16 @@
         }
         final Point positionInParent = new Point();
         getRelativePosition(positionInParent);
-        final int[] runningActivityCount = new int[1];
-        forAllActivities(a -> {
-            if (!a.finishing) {
-                runningActivityCount[0]++;
-            }
-        });
         return new TaskFragmentInfo(
                 mFragmentToken,
                 mRemoteToken.toWindowContainerToken(),
                 getConfiguration(),
-                runningActivityCount[0] == 0,
-                runningActivityCount[0],
+                getNonFinishingActivityCount(),
                 isVisible(),
                 childActivities,
                 positionInParent,
-                mClearedTaskForReuse);
+                mClearedTaskForReuse,
+                mClearedTaskFragmentForPip);
     }
 
     @Nullable
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 8a0ae65..9bf988f 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -38,6 +38,7 @@
 import android.os.RemoteException;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
+import android.view.Display;
 import android.view.SurfaceControl;
 import android.window.ITaskOrganizer;
 import android.window.ITaskOrganizerController;
@@ -526,17 +527,17 @@
         }
         final StartingWindowRemovalInfo removalInfo = new StartingWindowRemovalInfo();
         removalInfo.taskId = task.mTaskId;
-        removalInfo.playRevealAnimation = prepareAnimation;
+        removalInfo.playRevealAnimation = prepareAnimation
+                && task.getDisplayInfo().state == Display.STATE_ON;
         final boolean playShiftUpAnimation = !task.inMultiWindowMode();
         final ActivityRecord topActivity = task.topActivityContainsStartingWindow();
         if (topActivity != null) {
             removalInfo.deferRemoveForIme = topActivity.mDisplayContent
                     .mayImeShowOnLaunchingActivity(topActivity);
-            if (prepareAnimation && playShiftUpAnimation) {
+            if (removalInfo.playRevealAnimation && playShiftUpAnimation) {
                 final WindowState mainWindow =
                         topActivity.findMainWindow(false/* includeStartingApp */);
                 if (mainWindow != null) {
-                    final SurfaceControl.Transaction t = mainWindow.getPendingTransaction();
                     removalInfo.windowAnimationLeash = applyStartingWindowAnimation(mainWindow);
                     removalInfo.mainFrame = mainWindow.getRelativeFrame();
                 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index be74596..42fad6d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -409,21 +409,6 @@
     public abstract void getMagnificationRegion(int displayId, @NonNull Region magnificationRegion);
 
     /**
-     * Gets the magnification and translation applied to a window given its token.
-     * Not all windows are magnified and the window manager policy determines which
-     * windows are magnified. The returned result also takes into account the compat
-     * scale if necessary.
-     *
-     * @param windowToken The window's token.
-     *
-     * @return The magnification spec for the window.
-     *
-     * @see #setMagnificationCallbacks(int, MagnificationCallbacks)
-     */
-    public abstract MagnificationSpec getCompatibleMagnificationSpecForWindow(
-            IBinder windowToken);
-
-    /**
      * Sets a callback for observing which windows are touchable for the purposes
      * of accessibility on specified display.
      *
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4d262ef..2f4dc51 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1976,8 +1976,10 @@
         // We use the visible frame, because we want the animation to morph the window from what
         // was visible to the user to the final destination of the new window.
         final Rect frame = new Rect(replacedWindow.getFrame());
+        final WindowManager.LayoutParams attrs = replacedWindow.mAttrs;
         frame.inset(replacedWindow.getInsetsStateWithVisibilityOverride().calculateVisibleInsets(
-                frame, replacedWindow.mAttrs.softInputMode));
+                frame, attrs.type, replacedWindow.getWindowingMode(), attrs.softInputMode,
+                attrs.flags));
         // We treat this as if this activity was opening, so we can trigger the app transition
         // animation and piggy-back on existing transition animation infrastructure.
         final DisplayContent dc = activity.getDisplayContent();
@@ -7621,29 +7623,6 @@
         }
 
         @Override
-        public MagnificationSpec getCompatibleMagnificationSpecForWindow(IBinder windowToken) {
-            synchronized (mGlobalLock) {
-                WindowState windowState = mWindowMap.get(windowToken);
-                if (windowState == null) {
-                    return null;
-                }
-                MagnificationSpec spec = null;
-                if (mAccessibilityController.hasCallbacks()) {
-                    spec = mAccessibilityController.getMagnificationSpecForWindow(windowState);
-                }
-                if ((spec == null || spec.isNop()) && windowState.mGlobalScale == 1.0f) {
-                    return null;
-                }
-                MagnificationSpec result = new MagnificationSpec();
-                if (spec != null) {
-                    result.setTo(spec);
-                }
-                result.scale *= windowState.mGlobalScale;
-                return result;
-            }
-        }
-
-        @Override
         public boolean setMagnificationCallbacks(int displayId,
                 @Nullable MagnificationCallbacks callbacks) {
             synchronized (mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e7d4877..238f96f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1851,7 +1851,7 @@
 
         bounds.set(mWindowFrames.mFrame);
         bounds.inset(getInsetsStateWithVisibilityOverride().calculateVisibleInsets(
-                bounds, mAttrs.softInputMode));
+                bounds, mAttrs.type, getWindowingMode(), mAttrs.softInputMode, mAttrs.flags));
         if (intersectWithRootTaskBounds) {
             bounds.intersect(mTmpRect);
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 35dbb15..18bffeb 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -382,8 +382,6 @@
 import com.android.server.utils.Slogf;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
-import com.google.android.collect.Sets;
-
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.ByteArrayInputStream;
@@ -2002,7 +2000,6 @@
         synchronized (getLockObject()) {
             mOwners.load();
             setDeviceOwnershipSystemPropertyLocked();
-            findOwnerComponentIfNecessaryLocked();
         }
     }
 
@@ -2387,139 +2384,6 @@
         }
     }
 
-    private void findOwnerComponentIfNecessaryLocked() {
-        if (!mOwners.hasDeviceOwner()) {
-            return;
-        }
-        final ComponentName doComponentName = mOwners.getDeviceOwnerComponent();
-
-        if (!TextUtils.isEmpty(doComponentName.getClassName())) {
-            return; // Already a full component name.
-        }
-
-        final ComponentName doComponent = findAdminComponentWithPackageLocked(
-                doComponentName.getPackageName(),
-                mOwners.getDeviceOwnerUserId());
-        if (doComponent == null) {
-            Slogf.e(LOG_TAG, "Device-owner isn't registered as device-admin");
-        } else {
-            mOwners.setDeviceOwnerWithRestrictionsMigrated(
-                    doComponent,
-                    mOwners.getDeviceOwnerName(),
-                    mOwners.getDeviceOwnerUserId(),
-                    !mOwners.getDeviceOwnerUserRestrictionsNeedsMigration());
-            mOwners.writeDeviceOwner();
-            if (VERBOSE_LOG) {
-                Slogf.v(LOG_TAG, "Device owner component filled in");
-            }
-        }
-    }
-
-    /**
-     * We didn't use to persist user restrictions for each owners but only persisted in user
-     * manager.
-     */
-    private void migrateUserRestrictionsIfNecessaryLocked() {
-        boolean migrated = false;
-        // Migrate for the DO.  Basically all restrictions should be considered to be set by DO,
-        // except for the "system controlled" ones.
-        if (mOwners.getDeviceOwnerUserRestrictionsNeedsMigration()) {
-            if (VERBOSE_LOG) {
-                Slogf.v(LOG_TAG, "Migrating DO user restrictions");
-            }
-            migrated = true;
-
-            // Migrate user 0 restrictions to DO.
-            final ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked();
-
-            migrateUserRestrictionsForUser(UserHandle.SYSTEM, deviceOwnerAdmin,
-                    /* exceptionList =*/ null, /* isDeviceOwner =*/ true);
-
-            // Push DO user restrictions to user manager.
-            pushUserRestrictions(UserHandle.USER_SYSTEM);
-
-            mOwners.setDeviceOwnerUserRestrictionsMigrated();
-        }
-
-        // Migrate for POs.
-
-        // The following restrictions can be set on secondary users by the device owner, so we
-        // assume they're not from the PO.
-        final Set<String> secondaryUserExceptionList = Sets.newArraySet(
-                UserManager.DISALLOW_OUTGOING_CALLS,
-                UserManager.DISALLOW_SMS);
-
-        for (UserInfo ui : mUserManager.getUsers()) {
-            final int userId = ui.id;
-            if (mOwners.getProfileOwnerUserRestrictionsNeedsMigration(userId)) {
-                if (VERBOSE_LOG) {
-                    Slogf.v(LOG_TAG, "Migrating PO user restrictions for user %d", userId);
-                }
-                migrated = true;
-
-                final ActiveAdmin profileOwnerAdmin = getProfileOwnerAdminLocked(userId);
-
-                final Set<String> exceptionList =
-                        (userId == UserHandle.USER_SYSTEM) ? null : secondaryUserExceptionList;
-
-                migrateUserRestrictionsForUser(ui.getUserHandle(), profileOwnerAdmin,
-                        exceptionList, /* isDeviceOwner =*/ false);
-
-                // Note if a secondary user has no PO but has a DA that disables camera, we
-                // don't get here and won't push the camera user restriction to UserManager
-                // here.  That's okay because we'll push user restrictions anyway when a user
-                // starts.  But we still do it because we want to let user manager persist
-                // upon migration.
-                pushUserRestrictions(userId);
-
-                mOwners.setProfileOwnerUserRestrictionsMigrated(userId);
-            }
-        }
-        if (VERBOSE_LOG && migrated) {
-            Slogf.v(LOG_TAG, "User restrictions migrated.");
-        }
-    }
-
-    private void migrateUserRestrictionsForUser(UserHandle user, ActiveAdmin admin,
-            Set<String> exceptionList, boolean isDeviceOwner) {
-        final Bundle origRestrictions = mUserManagerInternal.getBaseUserRestrictions(
-                user.getIdentifier());
-
-        final Bundle newBaseRestrictions = new Bundle();
-        final Bundle newOwnerRestrictions = new Bundle();
-
-        for (String key : origRestrictions.keySet()) {
-            if (!origRestrictions.getBoolean(key)) {
-                continue;
-            }
-            final boolean canOwnerChange = isDeviceOwner
-                    ? UserRestrictionsUtils.canDeviceOwnerChange(key)
-                    : UserRestrictionsUtils.canProfileOwnerChange(key, user.getIdentifier());
-
-            if (!canOwnerChange || (exceptionList!= null && exceptionList.contains(key))) {
-                newBaseRestrictions.putBoolean(key, true);
-            } else {
-                newOwnerRestrictions.putBoolean(key, true);
-            }
-        }
-
-        if (VERBOSE_LOG) {
-            Slogf.v(LOG_TAG, "origRestrictions=%s", origRestrictions);
-            Slogf.v(LOG_TAG, "newBaseRestrictions=%s", newBaseRestrictions);
-            Slogf.v(LOG_TAG, "newOwnerRestrictions=%s", newOwnerRestrictions);
-        }
-        mUserManagerInternal.setBaseUserRestrictionsByDpmsForMigration(user.getIdentifier(),
-                newBaseRestrictions);
-
-        if (admin != null) {
-            admin.ensureUserRestrictions().clear();
-            admin.ensureUserRestrictions().putAll(newOwnerRestrictions);
-        } else {
-            Slogf.w(LOG_TAG, "ActiveAdmin for DO/PO not found. user=" + user.getIdentifier());
-        }
-        saveSettingsLocked(user.getIdentifier());
-    }
-
     /**
      * Fix left-over restrictions and auto-time policy during COMP -> COPE migration.
      *
@@ -2555,27 +2419,6 @@
         }
     }
 
-    private ComponentName findAdminComponentWithPackageLocked(String packageName, int userId) {
-        final DevicePolicyData policy = getUserData(userId);
-        final int n = policy.mAdminList.size();
-        ComponentName found = null;
-        int nFound = 0;
-        for (int i = 0; i < n; i++) {
-            final ActiveAdmin admin = policy.mAdminList.get(i);
-            if (packageName.equals(admin.info.getPackageName())) {
-                // Found!
-                if (nFound == 0) {
-                    found = admin.info.getComponent();
-                }
-                nFound++;
-            }
-        }
-        if (nFound > 1) {
-            Slogf.w(LOG_TAG, "Multiple DA found; assume the first one is DO.");
-        }
-        return found;
-    }
-
     /**
      * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
      * reminders.  Clears alarm if no expirations are configured.
@@ -3197,7 +3040,6 @@
 
     private void onLockSettingsReady() {
         synchronized (getLockObject()) {
-            migrateUserRestrictionsIfNecessaryLocked();
             fixupAutoTimeRestrictionDuringOrganizationOwnedDeviceMigration();
         }
         getUserData(UserHandle.USER_SYSTEM);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 37da7b4..859183c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -79,8 +79,6 @@
 
     private static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE
 
-    private static final String DEVICE_OWNER_XML_LEGACY = "device_owner.xml";
-
     // XML storing device owner info, system update policy and pending OTA update information.
     private static final String DEVICE_OWNER_XML = "device_owner_2.xml";
 
@@ -89,7 +87,6 @@
     private static final String TAG_ROOT = "root";
 
     private static final String TAG_DEVICE_OWNER = "device-owner";
-    private static final String TAG_DEVICE_INITIALIZER = "device-initializer";
     private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy";
     private static final String TAG_FREEZE_PERIOD_RECORD = "freeze-record";
     private static final String TAG_PENDING_OTA_INFO = "pending-ota-info";
@@ -107,7 +104,6 @@
     private static final String ATTR_REMOTE_BUGREPORT_URI = "remoteBugreportUri";
     private static final String ATTR_REMOTE_BUGREPORT_HASH = "remoteBugreportHash";
     private static final String ATTR_USERID = "userId";
-    private static final String ATTR_USER_RESTRICTIONS_MIGRATED = "userRestrictionsMigrated";
     private static final String ATTR_FREEZE_RECORD_START = "start";
     private static final String ATTR_FREEZE_RECORD_END = "end";
     // Legacy attribute, its presence would mean the profile owner associated with it is
@@ -180,35 +176,14 @@
      */
     void load() {
         synchronized (mLock) {
-            // First, try to read from the legacy file.
-            final File legacy = getLegacyConfigFile();
-
             final List<UserInfo> users = mUserManager.getAliveUsers();
 
-            if (readLegacyOwnerFileLocked(legacy)) {
-                if (DEBUG) {
-                    Log.d(TAG, "Legacy config file found.");
-                }
+            new DeviceOwnerReadWriter().readFromFileLocked();
 
-                // Legacy file exists, write to new files and remove the legacy one.
-                writeDeviceOwner();
-                for (int userId : getProfileOwnerKeys()) {
-                    writeProfileOwner(userId);
-                }
-                if (DEBUG) {
-                    Log.d(TAG, "Deleting legacy config file");
-                }
-                if (!legacy.delete()) {
-                    Slog.e(TAG, "Failed to remove the legacy setting file");
-                }
-            } else {
-                // No legacy file, read from the new format files.
-                new DeviceOwnerReadWriter().readFromFileLocked();
-
-                for (UserInfo ui : users) {
-                    new ProfileOwnerReadWriter(ui.id).readFromFileLocked();
-                }
+            for (UserInfo ui : users) {
+                new ProfileOwnerReadWriter(ui.id).readFromFileLocked();
             }
+
             mUserManagerInternal.setDeviceManaged(hasDeviceOwner());
             for (UserInfo ui : users) {
                 mUserManagerInternal.setUserManaged(ui.id, hasProfileOwner(ui.id));
@@ -338,23 +313,11 @@
             return;
         }
         synchronized (mLock) {
-            // For a newly set DO, there's no need for migration.
-            setDeviceOwnerWithRestrictionsMigrated(admin, ownerName, userId,
-                    /* userRestrictionsMigrated =*/ true);
-        }
-    }
-
-    // Note this should be only called during migration.  Normally when DO is set,
-    // userRestrictionsMigrated should always be true.
-    void setDeviceOwnerWithRestrictionsMigrated(ComponentName admin, String ownerName, int userId,
-            boolean userRestrictionsMigrated) {
-        synchronized (mLock) {
             // A device owner is allowed to access device identifiers. Even though this flag
             // is not currently checked for device owner, it is set to true here so that it is
             // semantically compatible with the meaning of this flag.
-            mDeviceOwner = new OwnerInfo(ownerName, admin, userRestrictionsMigrated,
-                    /* remoteBugreportUri =*/ null, /* remoteBugreportHash =*/
-                    null, /* isOrganizationOwnedDevice =*/true);
+            mDeviceOwner = new OwnerInfo(ownerName, admin, /* remoteBugreportUri =*/ null,
+                    /* remoteBugreportHash =*/ null, /* isOrganizationOwnedDevice =*/ true);
             mDeviceOwnerUserId = userId;
 
             mUserManagerInternal.setDeviceManaged(true);
@@ -385,8 +348,8 @@
         synchronized (mLock) {
             // For a newly set PO, there's no need for migration.
             mProfileOwners.put(userId, new OwnerInfo(ownerName, admin,
-                    /* userRestrictionsMigrated =*/ true, /* remoteBugreportUri =*/ null,
-                    /* remoteBugreportHash =*/ null, /* isOrganizationOwnedDevice =*/ false));
+                    /* remoteBugreportUri =*/ null, /* remoteBugreportHash =*/ null,
+                    /* isOrganizationOwnedDevice =*/ false));
             mUserManagerInternal.setUserManaged(userId, true);
             notifyChangeLocked();
         }
@@ -404,8 +367,7 @@
         synchronized (mLock) {
             final OwnerInfo ownerInfo = mProfileOwners.get(userId);
             final OwnerInfo newOwnerInfo = new OwnerInfo(target.getPackageName(), target,
-                    ownerInfo.userRestrictionsMigrated, ownerInfo.remoteBugreportUri,
-                    ownerInfo.remoteBugreportHash, /* isOrganizationOwnedDevice =*/
+                    ownerInfo.remoteBugreportUri, ownerInfo.remoteBugreportHash,
                     ownerInfo.isOrganizationOwnedDevice);
             mProfileOwners.put(userId, newOwnerInfo);
             notifyChangeLocked();
@@ -423,10 +385,8 @@
             }
             // We don't set a name because it's not used anyway.
             // See DevicePolicyManagerService#getDeviceOwnerName
-            mDeviceOwner = new OwnerInfo(null, target,
-                    mDeviceOwner.userRestrictionsMigrated, mDeviceOwner.remoteBugreportUri,
-                    mDeviceOwner.remoteBugreportHash, /* isOrganizationOwnedDevice =*/
-                    mDeviceOwner.isOrganizationOwnedDevice);
+            mDeviceOwner = new OwnerInfo(null, target, mDeviceOwner.remoteBugreportUri,
+                    mDeviceOwner.remoteBugreportHash, mDeviceOwner.isOrganizationOwnedDevice);
             if (previousDeviceOwnerType != null) {
                 mDeviceOwnerTypes.put(mDeviceOwner.packageName, previousDeviceOwnerType);
             }
@@ -570,35 +530,6 @@
         }
     }
 
-    /**
-     * @return true if user restrictions need to be migrated for DO.
-     */
-    boolean getDeviceOwnerUserRestrictionsNeedsMigration() {
-        synchronized (mLock) {
-            return mDeviceOwner != null && !mDeviceOwner.userRestrictionsMigrated;
-        }
-    }
-
-    /**
-     * @return true if user restrictions need to be migrated for PO.
-     */
-    boolean getProfileOwnerUserRestrictionsNeedsMigration(int userId) {
-        synchronized (mLock) {
-            OwnerInfo profileOwner = mProfileOwners.get(userId);
-            return profileOwner != null && !profileOwner.userRestrictionsMigrated;
-        }
-    }
-
-    /** Sets the user restrictions migrated flag, and also writes to the file. */
-    void setDeviceOwnerUserRestrictionsMigrated() {
-        synchronized (mLock) {
-            if (mDeviceOwner != null) {
-                mDeviceOwner.userRestrictionsMigrated = true;
-            }
-            writeDeviceOwner();
-        }
-    }
-
     /** Sets the remote bugreport uri and hash, and also writes to the file. */
     void setDeviceOwnerRemoteBugreportUriAndHash(String remoteBugreportUri,
             String remoteBugreportHash) {
@@ -611,17 +542,6 @@
         }
     }
 
-    /** Sets the user restrictions migrated flag, and also writes to the file. */
-    void setProfileOwnerUserRestrictionsMigrated(int userId) {
-        synchronized (mLock) {
-            OwnerInfo profileOwner = mProfileOwners.get(userId);
-            if (profileOwner != null) {
-                profileOwner.userRestrictionsMigrated = true;
-            }
-            writeProfileOwner(userId);
-        }
-    }
-
     /** Set whether the profile owner manages an organization-owned device, then write to file. */
     void setProfileOwnerOfOrganizationOwnedDevice(int userId, boolean isOrganizationOwnedDevice) {
         synchronized (mLock) {
@@ -696,72 +616,6 @@
         }
     }
 
-    private boolean readLegacyOwnerFileLocked(File file) {
-        if (!file.exists()) {
-            // Already migrated or the device has no owners.
-            return false;
-        }
-        try {
-            InputStream input = new AtomicFile(file).openRead();
-            TypedXmlPullParser parser = Xml.resolvePullParser(input);
-            int type;
-            while ((type = parser.next()) != TypedXmlPullParser.END_DOCUMENT) {
-                if (type != TypedXmlPullParser.START_TAG) {
-                    continue;
-                }
-
-                String tag = parser.getName();
-                if (tag.equals(TAG_DEVICE_OWNER)) {
-                    String name = parser.getAttributeValue(null, ATTR_NAME);
-                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
-                    mDeviceOwner = new OwnerInfo(name, packageName,
-                            /* userRestrictionsMigrated =*/ false, /* remoteBugreportUri =*/ null,
-                            /* remoteBugreportHash =*/ null, /* isOrganizationOwnedDevice =*/ true);
-                    mDeviceOwnerUserId = UserHandle.USER_SYSTEM;
-                } else if (tag.equals(TAG_DEVICE_INITIALIZER)) {
-                    // Deprecated tag
-                } else if (tag.equals(TAG_PROFILE_OWNER)) {
-                    String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
-                    String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
-                    String profileOwnerComponentStr =
-                            parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
-                    int userId = parser.getAttributeInt(null, ATTR_USERID);
-                    OwnerInfo profileOwnerInfo = null;
-                    if (profileOwnerComponentStr != null) {
-                        ComponentName admin = ComponentName.unflattenFromString(
-                                profileOwnerComponentStr);
-                        if (admin != null) {
-                            profileOwnerInfo = new OwnerInfo(profileOwnerName, admin,
-                                    /* userRestrictionsMigrated =*/ false, null,
-                                    null, /* isOrganizationOwnedDevice =*/ false);
-                        } else {
-                            // This shouldn't happen but switch from package name -> component name
-                            // might have written bad device owner files. b/17652534
-                            Slog.e(TAG, "Error parsing device-owner file. Bad component name " +
-                                    profileOwnerComponentStr);
-                        }
-                    }
-                    if (profileOwnerInfo == null) {
-                        profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName,
-                                /* userRestrictionsMigrated =*/ false,
-                                /* remoteBugreportUri =*/ null, /* remoteBugreportHash =*/
-                                null, /* isOrganizationOwnedDevice =*/ false);
-                    }
-                    mProfileOwners.put(userId, profileOwnerInfo);
-                } else if (TAG_SYSTEM_UPDATE_POLICY.equals(tag)) {
-                    mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser);
-                } else {
-                    throw new XmlPullParserException(
-                            "Unexpected tag in device owner file: " + tag);
-                }
-            }
-            input.close();
-        } catch (XmlPullParserException | IOException e) {
-            Slog.e(TAG, "Error parsing device-owner file", e);
-        }
-        return true;
-    }
-
     void writeDeviceOwner() {
         synchronized (mLock) {
             if (DEBUG) {
@@ -1047,9 +901,6 @@
                             mDeviceOwnerUserId);
                     break;
                 }
-                case TAG_DEVICE_INITIALIZER:
-                    // Deprecated tag
-                    break;
                 case TAG_SYSTEM_UPDATE_POLICY:
                     mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser);
                     break;
@@ -1087,7 +938,6 @@
                 default:
                     Slog.e(TAG, "Unexpected tag: " + tag);
                     return false;
-
             }
             return true;
         }
@@ -1136,30 +986,16 @@
         public final String name;
         public final String packageName;
         public final ComponentName admin;
-        public boolean userRestrictionsMigrated;
         public String remoteBugreportUri;
         public String remoteBugreportHash;
         public boolean isOrganizationOwnedDevice;
 
-        public OwnerInfo(String name, String packageName, boolean userRestrictionsMigrated,
-                String remoteBugreportUri, String remoteBugreportHash,
-                boolean isOrganizationOwnedDevice) {
-            this.name = name;
-            this.packageName = packageName;
-            this.admin = new ComponentName(packageName, "");
-            this.userRestrictionsMigrated = userRestrictionsMigrated;
-            this.remoteBugreportUri = remoteBugreportUri;
-            this.remoteBugreportHash = remoteBugreportHash;
-            this.isOrganizationOwnedDevice = isOrganizationOwnedDevice;
-        }
-
-        public OwnerInfo(String name, ComponentName admin, boolean userRestrictionsMigrated,
+        OwnerInfo(String name, ComponentName admin,
                 String remoteBugreportUri, String remoteBugreportHash,
                 boolean isOrganizationOwnedDevice) {
             this.name = name;
             this.admin = admin;
             this.packageName = admin.getPackageName();
-            this.userRestrictionsMigrated = userRestrictionsMigrated;
             this.remoteBugreportUri = remoteBugreportUri;
             this.remoteBugreportHash = remoteBugreportHash;
             this.isOrganizationOwnedDevice = isOrganizationOwnedDevice;
@@ -1167,14 +1003,12 @@
 
         public void writeToXml(TypedXmlSerializer out, String tag) throws IOException {
             out.startTag(null, tag);
-            out.attribute(null, ATTR_PACKAGE, packageName);
             if (name != null) {
                 out.attribute(null, ATTR_NAME, name);
             }
             if (admin != null) {
                 out.attribute(null, ATTR_COMPONENT_NAME, admin.flattenToString());
             }
-            out.attributeBoolean(null, ATTR_USER_RESTRICTIONS_MIGRATED, userRestrictionsMigrated);
             if (remoteBugreportUri != null) {
                 out.attribute(null, ATTR_REMOTE_BUGREPORT_URI, remoteBugreportUri);
             }
@@ -1189,14 +1023,9 @@
         }
 
         public static OwnerInfo readFromXml(TypedXmlPullParser parser) {
-            final String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
             final String name = parser.getAttributeValue(null, ATTR_NAME);
             final String componentName =
                     parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
-            final String userRestrictionsMigratedStr =
-                    parser.getAttributeValue(null, ATTR_USER_RESTRICTIONS_MIGRATED);
-            final boolean userRestrictionsMigrated =
-                    ("true".equals(userRestrictionsMigratedStr));
             final String remoteBugreportUri = parser.getAttributeValue(null,
                     ATTR_REMOTE_BUGREPORT_URI);
             final String remoteBugreportHash = parser.getAttributeValue(null,
@@ -1210,23 +1039,18 @@
             final boolean isOrgOwnedDevice =
                     ("true".equals(isOrgOwnedDeviceStr)) | canAccessDeviceIds;
 
-            // Has component name?  If so, return [name, component]
-            if (componentName != null) {
-                final ComponentName admin = ComponentName.unflattenFromString(componentName);
-                if (admin != null) {
-                    return new OwnerInfo(name, admin, userRestrictionsMigrated,
-                            remoteBugreportUri, remoteBugreportHash, isOrgOwnedDevice);
-                } else {
-                    // This shouldn't happen but switch from package name -> component name
-                    // might have written bad device owner files. b/17652534
-                    Slog.e(TAG, "Error parsing owner file. Bad component name " +
-                            componentName);
-                }
+            if (componentName == null) {
+                Slog.e(TAG, "Owner component not found");
+                return null;
+            }
+            final ComponentName admin = ComponentName.unflattenFromString(componentName);
+            if (admin == null) {
+                Slog.e(TAG, "Owner component not parsable: " + componentName);
+                return null;
             }
 
-            // Else, build with [name, package]
-            return new OwnerInfo(name, packageName, userRestrictionsMigrated, remoteBugreportUri,
-                    remoteBugreportHash, isOrgOwnedDevice);
+            return new OwnerInfo(
+                        name, admin, remoteBugreportUri, remoteBugreportHash, isOrgOwnedDevice);
         }
 
         public void dump(IndentingPrintWriter pw) {
@@ -1284,11 +1108,6 @@
     }
 
     @VisibleForTesting
-    File getLegacyConfigFile() {
-        return new File(mInjector.environmentGetDataSystemDirectory(), DEVICE_OWNER_XML_LEGACY);
-    }
-
-    @VisibleForTesting
     File getDeviceOwnerFile() {
         return new File(mInjector.environmentGetDataSystemDirectory(), DEVICE_OWNER_XML);
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index 6a27ecc..1753fc7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -737,6 +737,101 @@
         assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
     }
 
+    @Test
+    public void testGetRescheduleJobForPeriodic_outsideWindow_flex_failedJob_longPeriod() {
+        JobStatus job = createJobStatus(
+                "testGetRescheduleJobForPeriodic_outsideWindow_flex_failedJob_longPeriod",
+                createJobInfo().setPeriodic(7 * DAY_IN_MILLIS, 9 * HOUR_IN_MILLIS));
+        JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job);
+        // First window starts 6.625 days from now.
+        advanceElapsedClock(6 * DAY_IN_MILLIS + 15 * HOUR_IN_MILLIS);
+        long now = sElapsedRealtimeClock.millis();
+        long nextWindowStartTime = now + 7 * DAY_IN_MILLIS;
+        long nextWindowEndTime = nextWindowStartTime + 9 * HOUR_IN_MILLIS;
+
+        advanceElapsedClock(6 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS);
+        // Say the job ran at the very end of its previous window. The intended JSS behavior is to
+        // have consistent windows, so the new window should start as soon as the previous window
+        // ended and end PERIOD time after the previous window ended.
+        JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        advanceElapsedClock(DAY_IN_MILLIS);
+        // Say the job ran a day late. Since the period is massive compared to the flex, JSS should
+        // put the rescheduled job in the original window.
+        rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // 1 day before the start of the next window. Given the large period, respect the original
+        // next window.
+        advanceElapsedClock(nextWindowStartTime - sElapsedRealtimeClock.millis() - DAY_IN_MILLIS);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // 1 hour before the start of the next window. It's too close to the next window, so the
+        // returned job should be for the window after.
+        long oneHourBeforeNextWindow =
+                nextWindowStartTime - sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS;
+        long fiveMinsBeforeNextWindow =
+                nextWindowStartTime - sElapsedRealtimeClock.millis() - 5 * MINUTE_IN_MILLIS;
+        advanceElapsedClock(oneHourBeforeNextWindow);
+        nextWindowStartTime += 7 * DAY_IN_MILLIS;
+        nextWindowEndTime += 7 * DAY_IN_MILLIS;
+        rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // 5 minutes before the start of the next window. It's too close to the next window, so the
+        // returned job should be for the window after.
+        advanceElapsedClock(fiveMinsBeforeNextWindow);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        advanceElapsedClock(14 * DAY_IN_MILLIS);
+        // Say that the job ran at this point, probably because the phone was off the entire time.
+        // The next window should be consistent (start and end at the time it would have had the job
+        // run normally in previous windows).
+        nextWindowStartTime += 14 * DAY_IN_MILLIS;
+        nextWindowEndTime += 14 * DAY_IN_MILLIS;
+
+        rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // Test original job again but with a huge delay from the original execution window
+
+        // 1 day before the start of the next window. Given the large period, respect the original
+        // next window.
+        advanceElapsedClock(nextWindowStartTime - sElapsedRealtimeClock.millis() - DAY_IN_MILLIS);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // 1 hour before the start of the next window. It's too close to the next window, so the
+        // returned job should be for the window after.
+        oneHourBeforeNextWindow =
+                nextWindowStartTime - sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS;
+        fiveMinsBeforeNextWindow =
+                nextWindowStartTime - sElapsedRealtimeClock.millis() - 5 * MINUTE_IN_MILLIS;
+        advanceElapsedClock(oneHourBeforeNextWindow);
+        nextWindowStartTime += 7 * DAY_IN_MILLIS;
+        nextWindowEndTime += 7 * DAY_IN_MILLIS;
+        rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // 5 minutes before the start of the next window. It's too close to the next window, so the
+        // returned job should be for the window after.
+        advanceElapsedClock(fiveMinsBeforeNextWindow);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+    }
+
     /** Tests that rare job batching works as expected. */
     @Test
     public void testRareJobBatching() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/power/PowerManagerServiceMockingTest.java b/services/tests/mockingservicestests/src/com/android/server/power/PowerManagerServiceMockingTest.java
index 9cf6c03..5c4657f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/power/PowerManagerServiceMockingTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/power/PowerManagerServiceMockingTest.java
@@ -67,6 +67,8 @@
 import com.android.server.power.batterysaver.BatterySavingStats;
 import com.android.server.testutils.OffsettableClock;
 
+import java.util.concurrent.Executor;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -164,7 +166,8 @@
             @Override
             Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
                     SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
-                    FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
+                    FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
+                    Executor executor) {
                 return mNotifierMock;
             }
 
diff --git a/services/tests/servicestests/assets/OwnersTest/device_owner_1.xml b/services/tests/servicestests/assets/OwnersTest/device_owner_1.xml
new file mode 100644
index 0000000..d150b29
--- /dev/null
+++ b/services/tests/servicestests/assets/OwnersTest/device_owner_1.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<root>
+    <device-owner package="com.afwsamples.testdpc" name="" component="com.afwsamples.testdpc/com.afwsamples.testdpc.DeviceAdminReceiver" isPoOrganizationOwnedDevice="true" />
+    <device-owner-context userId="0" />
+    <system-update-policy policy_type="2" install_window_start="0" install_window_end="540" />
+</root>
\ No newline at end of file
diff --git a/services/tests/servicestests/assets/OwnersTest/profile_owner_1.xml b/services/tests/servicestests/assets/OwnersTest/profile_owner_1.xml
new file mode 100644
index 0000000..1f78b71
--- /dev/null
+++ b/services/tests/servicestests/assets/OwnersTest/profile_owner_1.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<root>
+    <profile-owner package="com.afwsamples.testdpc" name="com.afwsamples.testdpc" component="com.afwsamples.testdpc/com.afwsamples.testdpc.DeviceAdminReceiver" />
+</root>
\ No newline at end of file
diff --git a/services/tests/servicestests/assets/OwnersTest/test01/input.xml b/services/tests/servicestests/assets/OwnersTest/test01/input.xml
deleted file mode 100644
index db3e974..0000000
--- a/services/tests/servicestests/assets/OwnersTest/test01/input.xml
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
diff --git a/services/tests/servicestests/assets/OwnersTest/test02/input.xml b/services/tests/servicestests/assets/OwnersTest/test02/input.xml
deleted file mode 100644
index 321842b..0000000
--- a/services/tests/servicestests/assets/OwnersTest/test02/input.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
-<device-owner package="com.google.android.testdpc" />
diff --git a/services/tests/servicestests/assets/OwnersTest/test03/input.xml b/services/tests/servicestests/assets/OwnersTest/test03/input.xml
deleted file mode 100644
index 1bbfdadf..0000000
--- a/services/tests/servicestests/assets/OwnersTest/test03/input.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
-<profile-owner package="com.google.android.testdpc0" name="0" userId="10" component="com.google.android.testdpc/com.google.android.testdpc.DeviceAdminReceiver0" />
-<profile-owner package="com.google.android.testdpc1" name="1" userId="11" />
diff --git a/services/tests/servicestests/assets/OwnersTest/test04/input.xml b/services/tests/servicestests/assets/OwnersTest/test04/input.xml
deleted file mode 100644
index 8be51d9..0000000
--- a/services/tests/servicestests/assets/OwnersTest/test04/input.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
-<device-owner package="com.google.android.testdpc" />
-<profile-owner package="com.google.android.testdpc0" name="0" userId="10" component="com.google.android.testdpc/com.google.android.testdpc.DeviceAdminReceiver0" />
-<profile-owner package="com.google.android.testdpc1" name="1" userId="11" />
-<device-initializer package="com.google.android.testdpcx" name="di" component="com.google.android.testdpcx/receiver" />
-<system-update-policy policy_type="5" />
diff --git a/services/tests/servicestests/assets/OwnersTest/test05/input.xml b/services/tests/servicestests/assets/OwnersTest/test05/input.xml
deleted file mode 100644
index dbcb858..0000000
--- a/services/tests/servicestests/assets/OwnersTest/test05/input.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
-<device-initializer package="com.google.android.testdpcx" name="di" component="com.google.android.testdpcx/receiver" />
-
diff --git a/services/tests/servicestests/assets/OwnersTest/test06/input.xml b/services/tests/servicestests/assets/OwnersTest/test06/input.xml
deleted file mode 100644
index 794622b..0000000
--- a/services/tests/servicestests/assets/OwnersTest/test06/input.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
-<system-update-policy policy_type="5" />
diff --git a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
index 3d3c1ab..4e059b4 100644
--- a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
@@ -16,6 +16,9 @@
 
 package com.android.server;
 
+import static com.android.server.GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
+import static com.android.server.GestureLauncherService.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -248,7 +251,7 @@
         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
 
         long eventTime = INITIAL_EVENT_TIME_MILLIS +
-                GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+                CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                 IGNORED_REPEAT);
         boolean interactive = true;
@@ -296,7 +299,7 @@
         assertFalse(intercepted);
         assertFalse(outLaunched.value);
 
-        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
         eventTime += interval;
         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                 IGNORED_REPEAT);
@@ -341,7 +344,7 @@
         assertFalse(intercepted);
         assertFalse(outLaunched.value);
 
-        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
+        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
         eventTime += interval;
         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                 IGNORED_REPEAT);
@@ -435,7 +438,7 @@
         assertFalse(intercepted);
         assertFalse(outLaunched.value);
 
-        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
         eventTime += interval;
         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                 IGNORED_REPEAT);
@@ -489,7 +492,7 @@
         assertFalse(intercepted);
         assertFalse(outLaunched.value);
 
-        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
 
         // 2nd button triggers camera
         eventTime += interval;
@@ -578,7 +581,7 @@
         assertFalse(intercepted);
         assertFalse(outLaunched.value);
 
-        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
         // 3 more button presses which should not trigger any gesture (camera gesture disabled)
         for (int i = 0; i < 3; i++) {
             eventTime += interval;
@@ -632,7 +635,7 @@
         assertFalse(intercepted);
         assertFalse(outLaunched.value);
 
-        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
         // 3 more button presses which should not trigger any gesture, but intercepts action.
         for (int i = 0; i < 3; i++) {
             eventTime += interval;
@@ -735,7 +738,7 @@
                     interactive, outLaunched);
             assertTrue(intercepted);
             assertFalse(outLaunched.value);
-            interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+            interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
             eventTime += interval;
         }
     }
@@ -763,12 +766,33 @@
                     interactive, outLaunched);
             assertTrue(intercepted);
             assertFalse(outLaunched.value);
-            interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+            interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
             eventTime += interval;
         }
     }
 
     @Test
+    public void testInterceptPowerKeyDown_triggerEmergency_fiveFastTaps_gestureIgnored() {
+        // Trigger emergency by tapping button 5 times
+        long eventTime = triggerEmergencyGesture(/* tapIntervalMs= */ 1);
+
+        // Add 1 more millisecond and send the event again.
+        eventTime += 1;
+
+        // Subsequent long press is intercepted, but should not trigger any gesture
+        KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+                IGNORED_REPEAT, IGNORED_META_STATE, IGNORED_DEVICE_ID, IGNORED_SCANCODE,
+                KeyEvent.FLAG_LONG_PRESS);
+        MutableBoolean outLaunched = new MutableBoolean(true);
+        boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(
+                keyEvent,
+                /* interactive= */ true,
+                outLaunched);
+        assertFalse(intercepted);
+        assertFalse(outLaunched.value);
+    }
+
+    @Test
     public void testInterceptPowerKeyDown_triggerEmergency_longPress_cooldownTriggered() {
         // Enable power button cooldown
         withEmergencyGesturePowerButtonCooldownPeriodMsValue(3000);
@@ -890,7 +914,7 @@
         assertFalse(intercepted);
         assertFalse(outLaunched.value);
 
-        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
         eventTime += interval;
         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                 IGNORED_REPEAT, IGNORED_META_STATE, IGNORED_DEVICE_ID, IGNORED_SCANCODE,
@@ -936,7 +960,7 @@
         assertFalse(intercepted);
         assertFalse(outLaunched.value);
 
-        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
         eventTime += interval;
         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                 IGNORED_REPEAT);
@@ -983,7 +1007,7 @@
         assertFalse(intercepted);
         assertFalse(outLaunched.value);
 
-        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
+        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
         eventTime += interval;
         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                 IGNORED_REPEAT);
@@ -1075,7 +1099,7 @@
         assertFalse(intercepted);
         assertFalse(outLaunched.value);
 
-        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
         eventTime += interval;
         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                 IGNORED_REPEAT);
@@ -1120,7 +1144,7 @@
         assertFalse(intercepted);
         assertFalse(outLaunched.value);
 
-        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
+        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
         eventTime += interval;
         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                 IGNORED_REPEAT);
@@ -1212,7 +1236,7 @@
         assertFalse(intercepted);
         assertFalse(outLaunched.value);
 
-        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
         eventTime += interval;
         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                 IGNORED_REPEAT);
@@ -1261,7 +1285,7 @@
         assertFalse(intercepted);
         assertFalse(outLaunched.value);
 
-        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
         eventTime += interval;
         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                 IGNORED_REPEAT);
@@ -1306,7 +1330,7 @@
         assertFalse(intercepted);
         assertFalse(outLaunched.value);
 
-        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
+        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
         eventTime += interval;
         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                 IGNORED_REPEAT);
@@ -1384,9 +1408,20 @@
 
     /**
      * Helper method to trigger emergency gesture by pressing button for 5 times.
+     *
      * @return last event time.
      */
     private long triggerEmergencyGesture() {
+        return triggerEmergencyGesture(CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1);
+    }
+
+    /**
+     * Helper method to trigger emergency gesture by pressing button for 5 times with
+     * specified interval between each tap
+     *
+     * @return last event time.
+     */
+    private long triggerEmergencyGesture(long tapIntervalMs) {
         // Enable emergency power gesture
         withEmergencyGestureEnabledConfigValue(true);
         withEmergencyGestureEnabledSettingValue(true);
@@ -1402,8 +1437,7 @@
             keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                     IGNORED_REPEAT);
             mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive, outLaunched);
-            final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
-            eventTime += interval;
+            eventTime += tapIntervalMs;
         }
 
         // 5th button press should trigger the emergency flow
@@ -1412,12 +1446,22 @@
         outLaunched.value = false;
         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
                 outLaunched);
-        assertTrue(outLaunched.value);
+        long emergencyGestureTapDetectionMinTimeMs = Settings.Global.getInt(
+                mContext.getContentResolver(),
+                Settings.Global.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS,
+                EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS);
         assertTrue(intercepted);
-        verify(mUiEventLogger, times(1))
-                .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
-        verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();
-
+        if (tapIntervalMs * 4 > emergencyGestureTapDetectionMinTimeMs) {
+            assertTrue(outLaunched.value);
+            verify(mUiEventLogger, times(1))
+                    .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
+            verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();
+        } else {
+            assertFalse(outLaunched.value);
+            verify(mUiEventLogger, never())
+                    .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
+            verify(mStatusBarManagerInternal, never()).onEmergencyActionLaunchGestureDetected();
+        }
         return eventTime;
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
index 97ebdd4..08df438 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
@@ -58,6 +58,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -435,7 +436,7 @@
                 VIEWID_RESOURCE_NAME, INTERACTION_ID, mMockCallback, TID);
         verify(mMockIA11yInteractionConnection).findAccessibilityNodeInfosByViewId(
                 eq(ROOT_NODE_ID), eq(VIEWID_RESOURCE_NAME), any(), eq(INTERACTION_ID),
-                captor.capture(), anyInt(), eq(PID), eq(TID), any());
+                captor.capture(), anyInt(), eq(PID), eq(TID), any(), nullable(float[].class));
         verify(mMockSecurityPolicy).computeValidReportedPackages(any(), anyInt());
         verifyReplaceActions(captor.getValue());
     }
@@ -449,7 +450,7 @@
                 VIEW_TEXT, INTERACTION_ID, mMockCallback, TID);
         verify(mMockIA11yInteractionConnection).findAccessibilityNodeInfosByText(
                 eq(ROOT_NODE_ID), eq(VIEW_TEXT), any(), eq(INTERACTION_ID),
-                captor.capture(), anyInt(), eq(PID), eq(TID), any());
+                captor.capture(), anyInt(), eq(PID), eq(TID), any(), nullable(float[].class));
         verify(mMockSecurityPolicy).computeValidReportedPackages(any(), anyInt());
         verifyReplaceActions(captor.getValue());
     }
@@ -463,7 +464,7 @@
                 INTERACTION_ID, mMockCallback, 0, TID, null);
         verify(mMockIA11yInteractionConnection).findAccessibilityNodeInfoByAccessibilityId(
                 eq(ROOT_NODE_ID), any(), eq(INTERACTION_ID), captor.capture(), anyInt(),
-                eq(PID), eq(TID), any(), any());
+                eq(PID), eq(TID), any(),  nullable(float[].class), any());
         verify(mMockSecurityPolicy).computeValidReportedPackages(any(), anyInt());
         verifyReplaceActions(captor.getValue());
     }
@@ -476,7 +477,8 @@
         mServiceConnection.findFocus(PIP_WINDOWID, ROOT_NODE_ID, FOCUS_INPUT, INTERACTION_ID,
                 mMockCallback, TID);
         verify(mMockIA11yInteractionConnection).findFocus(eq(ROOT_NODE_ID), eq(FOCUS_INPUT),
-                any(), eq(INTERACTION_ID), captor.capture(), anyInt(), eq(PID), eq(TID), any());
+                any(), eq(INTERACTION_ID), captor.capture(), anyInt(), eq(PID), eq(TID), any(),
+                nullable(float[].class));
         verify(mMockSecurityPolicy).computeValidReportedPackages(any(), anyInt());
         verifyReplaceActions(captor.getValue());
     }
@@ -489,7 +491,8 @@
         mServiceConnection.focusSearch(PIP_WINDOWID, ROOT_NODE_ID, FOCUS_DOWN, INTERACTION_ID,
                 mMockCallback, TID);
         verify(mMockIA11yInteractionConnection).focusSearch(eq(ROOT_NODE_ID), eq(FOCUS_DOWN),
-                any(), eq(INTERACTION_ID), captor.capture(), anyInt(), eq(PID), eq(TID), any());
+                any(), eq(INTERACTION_ID), captor.capture(), anyInt(), eq(PID), eq(TID), any(),
+                nullable(float[].class));
         verify(mMockSecurityPolicy).computeValidReportedPackages(any(), anyInt());
         verifyReplaceActions(captor.getValue());
     }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java
index 022c137..842b23c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java
@@ -842,7 +842,7 @@
                 null, interactionId,
                 callback, prefetchFlags,
                 processAndThreadId,
-                processAndThreadId, null, null);
+                processAndThreadId, null, null, null);
 
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/ActionReplacingCallbackTest.java b/services/tests/servicestests/src/com/android/server/accessibility/ActionReplacingCallbackTest.java
index 72820f1..c16f3d3f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/ActionReplacingCallbackTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/ActionReplacingCallbackTest.java
@@ -16,6 +16,27 @@
 
 package com.android.server.accessibility;
 
+import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS;
+import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK;
+import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE;
+import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_CONTEXT_CLICK;
+import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND;
+
+import static junit.framework.TestCase.assertTrue;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.MockitoAnnotations.initMocks;
+
 import android.graphics.Region;
 import android.os.RemoteException;
 import android.view.MagnificationSpec;
@@ -35,28 +56,8 @@
 import org.mockito.Mock;
 
 import java.util.Arrays;
-import java.util.HashSet;
 import java.util.List;
 
-import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS;
-import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
-import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK;
-import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE;
-import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND;
-import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_CONTEXT_CLICK;
-import static junit.framework.TestCase.assertTrue;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.MockitoAnnotations.initMocks;
-
 /**
  * Tests for ActionReplacingCallback
  */
@@ -130,8 +131,8 @@
         verify(mMockReplacerConnection).findAccessibilityNodeInfoByAccessibilityId(
                 eq(AccessibilityNodeInfo.ROOT_NODE_ID), (Region) anyObject(),
                 mInteractionIdCaptor.capture(), eq(mActionReplacingCallback), eq(0),
-                eq(INTERROGATING_PID), eq(INTERROGATING_TID), (MagnificationSpec) anyObject(),
-                eq(null));
+                eq(INTERROGATING_PID), eq(INTERROGATING_TID), nullable(MagnificationSpec.class),
+                nullable(float[].class), eq(null));
         mReplacerInteractionId = mInteractionIdCaptor.getValue().intValue();
     }
 
@@ -247,7 +248,7 @@
                 .findAccessibilityNodeInfoByAccessibilityId(eq(AccessibilityNodeInfo.ROOT_NODE_ID),
                         (Region) anyObject(), anyInt(), (ActionReplacingCallback) anyObject(),
                         eq(0),  eq(INTERROGATING_PID), eq(INTERROGATING_TID),
-                        (MagnificationSpec) anyObject(), eq(null));
+                        (MagnificationSpec) anyObject(), nullable(float[].class), eq(null));
         ActionReplacingCallback actionReplacingCallback = new ActionReplacingCallback(
                 mMockServiceCallback, mMockReplacerConnection, INTERACTION_ID, INTERROGATING_PID,
                 INTERROGATING_TID);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
index 9ba7a9a..8bb619f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -27,7 +27,6 @@
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -37,7 +36,6 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.Build;
-import android.os.Bundle;
 import android.os.IpcDataCache;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -55,8 +53,6 @@
 import org.junit.runner.RunWith;
 
 import java.io.File;
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Set;
 
 @Presubmit
@@ -87,226 +83,9 @@
                 .thenReturn(true);
     }
 
-    @Test
-    public void testMigration() throws Exception {
-        final File user10dir = getServices().addUser(10, 0, USER_TYPE_EMPTY);
-        final File user11dir = getServices().addUser(11, 0,
-                UserManager.USER_TYPE_PROFILE_MANAGED);
-        getServices().addUser(12, 0, USER_TYPE_EMPTY);
-
-        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
-        setUpPackageManagerForAdmin(admin2, UserHandle.getUid(10, 123));
-        setUpPackageManagerForAdmin(admin3, UserHandle.getUid(11, 456));
-
-        // Create the legacy owners & policies file.
-        DpmTestUtils.writeToFile(
-                (new File(getServices().dataDir, "device_owner.xml")).getAbsoluteFile(),
-                DpmTestUtils.readAsset(mRealTestContext,
-                        "DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml"));
-
-        DpmTestUtils.writeToFile(
-                (new File(getServices().systemUserDataDir, "device_policies.xml")).getAbsoluteFile(),
-                DpmTestUtils.readAsset(mRealTestContext,
-                        "DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml"));
-
-        DpmTestUtils.writeToFile(
-                (new File(user10dir, "device_policies.xml")).getAbsoluteFile(),
-                DpmTestUtils.readAsset(mRealTestContext,
-                        "DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml"));
-        DpmTestUtils.writeToFile(
-                (new File(user11dir, "device_policies.xml")).getAbsoluteFile(),
-                DpmTestUtils.readAsset(mRealTestContext,
-                        "DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml"));
-
-        // Set up UserManager
-        when(getServices().userManagerInternal.getBaseUserRestrictions(
-                eq(USER_SYSTEM))).thenReturn(DpmTestUtils.newRestrictions(
-                UserManager.DISALLOW_ADD_USER,
-                UserManager.DISALLOW_RECORD_AUDIO));
-
-        when(getServices().userManagerInternal.getBaseUserRestrictions(
-                eq(10))).thenReturn(DpmTestUtils.newRestrictions(
-                UserManager.DISALLOW_REMOVE_USER,
-                UserManager.DISALLOW_ADD_USER,
-                UserManager.DISALLOW_SMS,
-                UserManager.DISALLOW_OUTGOING_CALLS,
-                UserManager.DISALLOW_WALLPAPER,
-                UserManager.DISALLOW_RECORD_AUDIO));
-
-        when(getServices().userManagerInternal.getBaseUserRestrictions(
-                eq(11))).thenReturn(DpmTestUtils.newRestrictions(
-                UserManager.DISALLOW_REMOVE_USER,
-                UserManager.DISALLOW_ADD_USER,
-                UserManager.DISALLOW_SMS,
-                UserManager.DISALLOW_OUTGOING_CALLS,
-                UserManager.DISALLOW_WALLPAPER,
-                UserManager.DISALLOW_RECORD_AUDIO));
-
-        final Map<Integer, Bundle> newBaseRestrictions = new HashMap<>();
-
-        doAnswer(invocation -> {
-            Integer userId = (Integer) invocation.getArguments()[0];
-            Bundle bundle = (Bundle) invocation.getArguments()[1];
-
-            newBaseRestrictions.put(userId, bundle);
-
-            return null;
-        }).when(getServices().userManagerInternal).setBaseUserRestrictionsByDpmsForMigration(
-                anyInt(), any(Bundle.class));
-
-        // Initialize DPM/DPMS and let it migrate the persisted information.
-        // (Need clearCallingIdentity() to pass permission checks.)
-
-        final DevicePolicyManagerServiceTestable dpms;
-
-        final long ident = mContext.binder.clearCallingIdentity();
-        try {
-            dpms = new DevicePolicyManagerServiceTestable(getServices(), mContext);
-
-            dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY);
-            dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED);
-        } finally {
-            mContext.binder.restoreCallingIdentity(ident);
-        }
-
-        assertThat(dpms.mOwners.hasDeviceOwner()).isTrue();
-        assertThat(dpms.mOwners.hasProfileOwner(USER_SYSTEM)).isFalse();
-        assertThat(dpms.mOwners.hasProfileOwner(10)).isTrue();
-        assertThat(dpms.mOwners.hasProfileOwner(11)).isTrue();
-        assertThat(dpms.mOwners.hasProfileOwner(12)).isFalse();
-
-        // Now all information should be migrated.
-        assertThat(dpms.mOwners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse();
-        assertThat(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(USER_SYSTEM))
-            .isFalse();
-        assertThat(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse();
-        assertThat(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse();
-        assertThat(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(12)).isFalse();
-
-        // Check the new base restrictions.
-        DpmTestUtils.assertRestrictions(
-                DpmTestUtils.newRestrictions(
-                        UserManager.DISALLOW_RECORD_AUDIO
-                ),
-                newBaseRestrictions.get(USER_SYSTEM));
-
-        DpmTestUtils.assertRestrictions(
-                DpmTestUtils.newRestrictions(
-                        UserManager.DISALLOW_ADD_USER,
-                        UserManager.DISALLOW_SMS,
-                        UserManager.DISALLOW_OUTGOING_CALLS,
-                        UserManager.DISALLOW_RECORD_AUDIO,
-                        UserManager.DISALLOW_WALLPAPER
-                ),
-                newBaseRestrictions.get(10));
-
-        DpmTestUtils.assertRestrictions(
-                DpmTestUtils.newRestrictions(
-                        UserManager.DISALLOW_ADD_USER,
-                        UserManager.DISALLOW_SMS,
-                        UserManager.DISALLOW_OUTGOING_CALLS,
-                        UserManager.DISALLOW_WALLPAPER,
-                        UserManager.DISALLOW_RECORD_AUDIO
-                ),
-                newBaseRestrictions.get(11));
-
-        // Check the new owner restrictions.
-        DpmTestUtils.assertRestrictions(
-                DpmTestUtils.newRestrictions(
-                        UserManager.DISALLOW_ADD_USER
-                ),
-                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions());
-
-        DpmTestUtils.assertRestrictions(
-                DpmTestUtils.newRestrictions(
-                        UserManager.DISALLOW_REMOVE_USER
-                ),
-                dpms.getProfileOwnerAdminLocked(10).ensureUserRestrictions());
-
-        DpmTestUtils.assertRestrictions(
-                DpmTestUtils.newRestrictions(
-                        UserManager.DISALLOW_REMOVE_USER
-                ),
-                dpms.getProfileOwnerAdminLocked(11).ensureUserRestrictions());
-    }
-
-    @Test
-    public void testMigration2_profileOwnerOnUser0() throws Exception {
-        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
-
-        // Create the legacy owners & policies file.
-        DpmTestUtils.writeToFile(
-                (new File(getServices().dataDir, "device_owner.xml")).getAbsoluteFile(),
-                DpmTestUtils.readAsset(mRealTestContext,
-                        "DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml"));
-
-        DpmTestUtils.writeToFile(
-                (new File(getServices().systemUserDataDir, "device_policies.xml")).getAbsoluteFile(),
-                DpmTestUtils.readAsset(mRealTestContext,
-                        "DevicePolicyManagerServiceMigrationTest2/legacy_device_policies.xml"));
-
-        // Set up UserManager
-        when(getServices().userManagerInternal.getBaseUserRestrictions(
-                eq(USER_SYSTEM))).thenReturn(DpmTestUtils.newRestrictions(
-                UserManager.DISALLOW_ADD_USER,
-                UserManager.DISALLOW_RECORD_AUDIO,
-                UserManager.DISALLOW_SMS,
-                UserManager.DISALLOW_OUTGOING_CALLS));
-
-        final Map<Integer, Bundle> newBaseRestrictions = new HashMap<>();
-
-        doAnswer(invocation -> {
-            Integer userId = (Integer) invocation.getArguments()[0];
-            Bundle bundle = (Bundle) invocation.getArguments()[1];
-
-            newBaseRestrictions.put(userId, bundle);
-
-            return null;
-        }).when(getServices().userManagerInternal).setBaseUserRestrictionsByDpmsForMigration(
-                anyInt(), any(Bundle.class));
-
-        // Initialize DPM/DPMS and let it migrate the persisted information.
-        // (Need clearCallingIdentity() to pass permission checks.)
-
-        final DevicePolicyManagerServiceTestable dpms;
-
-        final long ident = mContext.binder.clearCallingIdentity();
-        try {
-            dpms = new DevicePolicyManagerServiceTestable(getServices(), mContext);
-
-            dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY);
-            dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED);
-        } finally {
-            mContext.binder.restoreCallingIdentity(ident);
-        }
-        assertThat(dpms.mOwners.hasDeviceOwner()).isFalse();
-        assertThat(dpms.mOwners.hasProfileOwner(USER_SYSTEM)).isTrue();
-
-        // Now all information should be migrated.
-        assertThat(dpms.mOwners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse();
-        assertThat(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(USER_SYSTEM))
-            .isFalse();
-
-        // Check the new base restrictions.
-        DpmTestUtils.assertRestrictions(
-                DpmTestUtils.newRestrictions(
-                        UserManager.DISALLOW_RECORD_AUDIO
-                ),
-                newBaseRestrictions.get(USER_SYSTEM));
-
-        // Check the new owner restrictions.
-        DpmTestUtils.assertRestrictions(
-                DpmTestUtils.newRestrictions(
-                        UserManager.DISALLOW_ADD_USER,
-                        UserManager.DISALLOW_SMS,
-                        UserManager.DISALLOW_OUTGOING_CALLS
-                ),
-                dpms.getProfileOwnerAdminLocked(USER_SYSTEM).ensureUserRestrictions());
-    }
-
     // Test setting default restrictions for managed profile.
     @Test
-    public void testMigration3_managedProfileOwner() throws Exception {
+    public void testMigration_managedProfileOwner() throws Exception {
         // Create a managed profile user.
         final File user10dir = getServices().addUser(10, 0,
                 UserManager.USER_TYPE_PROFILE_MANAGED);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 7b11876d0..45d101a 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1665,39 +1665,6 @@
         assertThat(deviceOwner.getUid()).isEqualTo(DpmMockContext.CALLER_SYSTEM_USER_UID);
     }
 
-    /**
-     * This essentially tests
-     * {@code DevicePolicyManagerService.findOwnerComponentIfNecessaryLocked()}. (which is
-     * private.)
-     *
-     * We didn't use to persist the DO component class name, but now we do, and the above method
-     * finds the right component from a package name upon migration.
-     */
-    @Test
-    public void testDeviceOwnerMigration() throws Exception {
-        checkDeviceOwnerWithMultipleDeviceAdmins();
-
-        // Overwrite the device owner setting and clears the class name.
-        dpms.mOwners.setDeviceOwner(
-                new ComponentName(admin2.getPackageName(), ""),
-                "owner-name", CALLER_USER_HANDLE);
-        dpms.mOwners.writeDeviceOwner();
-
-        // Make sure the DO component name doesn't have a class name.
-        assertThat(dpms.getDeviceOwnerComponent(/* callingUserOnly= */ false).getClassName())
-                .isEmpty();
-
-        // Then create a new DPMS to have it load the settings from files.
-        when(getServices().userManager.getUserRestrictions(any(UserHandle.class)))
-                .thenReturn(new Bundle());
-        initializeDpms();
-
-        // Now the DO component name is a full name.
-        // *BUT* because both admin1 and admin2 belong to the same package, we think admin1 is the
-        // DO.
-        assertThat(dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false)).isEqualTo(admin1);
-    }
-
     @Test
     public void testSetGetApplicationRestriction() {
         setAsProfileOwner(admin1);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
index d1706f8..37ba8a4 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
@@ -18,29 +18,22 @@
 
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
+import static android.app.admin.SystemUpdatePolicy.TYPE_INSTALL_WINDOWED;
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.Mockito.verify;
-
 import android.content.ComponentName;
 import android.os.IpcDataCache;
-import android.os.UserHandle;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable;
 
-import com.google.android.collect.Lists;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * Tests for the DeviceOwner object that saves & loads device and policy owner information.
  *
@@ -52,8 +45,7 @@
 @RunWith(AndroidJUnit4.class)
 public class OwnersTest extends DpmTestBase {
 
-    private static final List<String> DEVICE_OWNER_PROTECTED_PACKAGES =
-            Lists.newArrayList("package_1", "package_2");
+    private static final String TESTDPC_PACKAGE = "com.afwsamples.testdpc";
 
     @Before
     public void setUp() throws Exception {
@@ -63,572 +55,66 @@
     }
 
     @Test
-    public void testUpgrade01() throws Exception {
-        getServices().addUsers(10, 11, 20, 21);
-
-        // First, migrate.
-        {
-            final OwnersTestable owners = new OwnersTestable(getServices());
-
-            DpmTestUtils.writeToFile(owners.getLegacyConfigFile(),
-                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test01/input.xml"));
-
-            owners.load();
-
-            // The legacy file should be removed.
-            assertThat(owners.getLegacyConfigFile().exists()).isFalse();
-
-            // File was empty, so no new files should be created.
-            assertThat(owners.getDeviceOwnerFile().exists()).isFalse();
-
-            assertThat(owners.getProfileOwnerFile(10).exists()).isFalse();
-            assertThat(owners.getProfileOwnerFile(11).exists()).isFalse();
-            assertThat(owners.getProfileOwnerFile(20).exists()).isFalse();
-            assertThat(owners.getProfileOwnerFile(21).exists()).isFalse();
-
-            assertThat(owners.hasDeviceOwner()).isFalse();
-            assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
-            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                    DEVICE_OWNER_TYPE_DEFAULT);
-            assertThat(owners.getDeviceOwnerProtectedPackages(owners.getDeviceOwnerPackageName()))
-                    .isEmpty();
-            assertThat(owners.getSystemUpdatePolicy()).isNull();
-            assertThat(owners.getProfileOwnerKeys()).isEmpty();
-
-            assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
-
-            owners.setDeviceOwnerType(owners.getDeviceOwnerPackageName(),
-                    DEVICE_OWNER_TYPE_FINANCED, /* isAdminTestOnly= */ false);
-            // There is no device owner, so the default owner type should be returned.
-            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                    DEVICE_OWNER_TYPE_DEFAULT);
-        }
-
-        // Then re-read and check.
-        {
-            final OwnersTestable owners = new OwnersTestable(getServices());
-            owners.load();
-
-            assertThat(owners.hasDeviceOwner()).isFalse();
-            assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
-            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                    DEVICE_OWNER_TYPE_DEFAULT);
-            assertThat(owners.getDeviceOwnerProtectedPackages(owners.getDeviceOwnerPackageName()))
-                    .isEmpty();
-            assertThat(owners.getSystemUpdatePolicy()).isNull();
-            assertThat(owners.getProfileOwnerKeys()).isEmpty();
-
-            assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
-        }
-    }
-
-    @Test
-    public void testUpgrade02() throws Exception {
-        getServices().addUsers(10, 11, 20, 21);
-
-        // First, migrate.
-        {
-            final OwnersTestable owners = new OwnersTestable(getServices());
-
-            DpmTestUtils.writeToFile(owners.getLegacyConfigFile(),
-                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test02/input.xml"));
-
-            owners.load();
-
-            // The legacy file should be removed.
-            assertThat(owners.getLegacyConfigFile().exists()).isFalse();
-
-            assertThat(owners.getDeviceOwnerFile().exists()).isTrue(); // TODO Check content
-
-            assertThat(owners.getProfileOwnerFile(10).exists()).isFalse();
-            assertThat(owners.getProfileOwnerFile(11).exists()).isFalse();
-            assertThat(owners.getProfileOwnerFile(20).exists()).isFalse();
-            assertThat(owners.getProfileOwnerFile(21).exists()).isFalse();
-
-            assertThat(owners.hasDeviceOwner()).isTrue();
-            assertThat(owners.getDeviceOwnerName()).isEqualTo(null);
-            assertThat(owners.getDeviceOwnerPackageName()).isEqualTo("com.google.android.testdpc");
-            assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);
-            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                    DEVICE_OWNER_TYPE_DEFAULT);
-            assertThat(owners.getDeviceOwnerProtectedPackages(owners.getDeviceOwnerPackageName()))
-                    .isEmpty();
-
-            assertThat(owners.getSystemUpdatePolicy()).isNull();
-            assertThat(owners.getProfileOwnerKeys()).isEmpty();
-
-            assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isTrue();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
-        }
-
-        // Then re-read and check.
-        {
-            final OwnersTestable owners = new OwnersTestable(getServices());
-            owners.load();
-
-            assertThat(owners.hasDeviceOwner()).isTrue();
-            assertThat(owners.getDeviceOwnerName()).isEqualTo(null);
-            assertThat(owners.getDeviceOwnerPackageName()).isEqualTo("com.google.android.testdpc");
-            assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);
-            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                    DEVICE_OWNER_TYPE_DEFAULT);
-            assertThat(owners.getDeviceOwnerProtectedPackages(owners.getDeviceOwnerPackageName()))
-                    .isEmpty();
-
-            assertThat(owners.getSystemUpdatePolicy()).isNull();
-            assertThat(owners.getProfileOwnerKeys()).isEmpty();
-
-            assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isTrue();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
-        }
-    }
-
-    @Test
-    public void testUpgrade03() throws Exception {
-        getServices().addUsers(10, 11, 20, 21);
-
-        // First, migrate.
-        {
-            final OwnersTestable owners = new OwnersTestable(getServices());
-
-            DpmTestUtils.writeToFile(owners.getLegacyConfigFile(),
-                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test03/input.xml"));
-
-            owners.load();
-
-            // The legacy file should be removed.
-            assertThat(owners.getLegacyConfigFile().exists()).isFalse();
-
-            assertThat(owners.getDeviceOwnerFile().exists()).isFalse();
-
-            assertThat(owners.getProfileOwnerFile(10).exists()).isTrue();
-            assertThat(owners.getProfileOwnerFile(11).exists()).isTrue();
-            assertThat(owners.getProfileOwnerFile(20).exists()).isFalse();
-            assertThat(owners.getProfileOwnerFile(21).exists()).isFalse();
-
-            assertThat(owners.hasDeviceOwner()).isFalse();
-            assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
-            assertThat(owners.getSystemUpdatePolicy()).isNull();
-            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                    DEVICE_OWNER_TYPE_DEFAULT);
-            assertThat(owners.getDeviceOwnerProtectedPackages(owners.getDeviceOwnerPackageName()))
-                    .isEmpty();
-
-            assertThat(owners.getProfileOwnerKeys()).hasSize(2);
-            assertThat(owners.getProfileOwnerComponent(10))
-                    .isEqualTo(new ComponentName("com.google.android.testdpc",
-                            "com.google.android.testdpc.DeviceAdminReceiver0"));
-            assertThat(owners.getProfileOwnerName(10)).isEqualTo("0");
-            assertThat(owners.getProfileOwnerPackage(10)).isEqualTo("com.google.android.testdpc");
-
-            assertThat(owners.getProfileOwnerComponent(11))
-                    .isEqualTo(new ComponentName("com.google.android.testdpc1", ""));
-            assertThat(owners.getProfileOwnerName(11)).isEqualTo("1");
-            assertThat(owners.getProfileOwnerPackage(11)).isEqualTo("com.google.android.testdpc1");
-
-            assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isTrue();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isTrue();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
-        }
-
-        // Then re-read and check.
-        {
-            final OwnersTestable owners = new OwnersTestable(getServices());
-            owners.load();
-
-            assertThat(owners.hasDeviceOwner()).isFalse();
-            assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
-            assertThat(owners.getSystemUpdatePolicy()).isNull();
-            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                    DEVICE_OWNER_TYPE_DEFAULT);
-            assertThat(owners.getDeviceOwnerProtectedPackages(owners.getDeviceOwnerPackageName()))
-                    .isEmpty();
-
-            assertThat(owners.getProfileOwnerKeys()).hasSize(2);
-            assertThat(owners.getProfileOwnerComponent(10))
-                    .isEqualTo(new ComponentName("com.google.android.testdpc",
-                            "com.google.android.testdpc.DeviceAdminReceiver0"));
-            assertThat(owners.getProfileOwnerName(10)).isEqualTo("0");
-            assertThat(owners.getProfileOwnerPackage(10)).isEqualTo("com.google.android.testdpc");
-
-            assertThat(owners.getProfileOwnerComponent(11))
-                    .isEqualTo(new ComponentName("com.google.android.testdpc1", ""));
-            assertThat(owners.getProfileOwnerName(11)).isEqualTo("1");
-            assertThat(owners.getProfileOwnerPackage(11)).isEqualTo("com.google.android.testdpc1");
-
-            assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isTrue();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isTrue();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
-        }
-    }
-
-    /**
-     * Note this also tests {@link Owners#setDeviceOwnerUserRestrictionsMigrated()}
-     * and {@link  Owners#setProfileOwnerUserRestrictionsMigrated(int)}.
-     */
-    @Test
-    public void testUpgrade04() throws Exception {
-        getServices().addUsers(10, 11, 20, 21);
-
-        // First, migrate.
-        {
-            final OwnersTestable owners = new OwnersTestable(getServices());
-
-            DpmTestUtils.writeToFile(owners.getLegacyConfigFile(),
-                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test04/input.xml"));
-
-            owners.load();
-
-            // The legacy file should be removed.
-            assertThat(owners.getLegacyConfigFile().exists()).isFalse();
-
-            assertThat(owners.getDeviceOwnerFile().exists()).isTrue();
-
-            assertThat(owners.getProfileOwnerFile(10).exists()).isTrue();
-            assertThat(owners.getProfileOwnerFile(11).exists()).isTrue();
-            assertThat(owners.getProfileOwnerFile(20).exists()).isFalse();
-            assertThat(owners.getProfileOwnerFile(21).exists()).isFalse();
-
-            assertThat(owners.hasDeviceOwner()).isTrue();
-            assertThat(owners.getDeviceOwnerName()).isEqualTo(null);
-            assertThat(owners.getDeviceOwnerPackageName()).isEqualTo("com.google.android.testdpc");
-            assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);
-            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                    DEVICE_OWNER_TYPE_DEFAULT);
-            assertThat(owners.getDeviceOwnerProtectedPackages(owners.getDeviceOwnerPackageName()))
-                    .isEmpty();
-
-            assertThat(owners.getSystemUpdatePolicy()).isNotNull();
-            assertThat(owners.getSystemUpdatePolicy().getPolicyType()).isEqualTo(5);
-
-            assertThat(owners.getProfileOwnerKeys()).hasSize(2);
-            assertThat(owners.getProfileOwnerComponent(10))
-                    .isEqualTo(new ComponentName("com.google.android.testdpc",
-                            "com.google.android.testdpc.DeviceAdminReceiver0"));
-            assertThat(owners.getProfileOwnerName(10)).isEqualTo("0");
-            assertThat(owners.getProfileOwnerPackage(10)).isEqualTo("com.google.android.testdpc");
-
-            assertThat(owners.getProfileOwnerComponent(11))
-                    .isEqualTo(new ComponentName("com.google.android.testdpc1", ""));
-            assertThat(owners.getProfileOwnerName(11)).isEqualTo("1");
-            assertThat(owners.getProfileOwnerPackage(11)).isEqualTo("com.google.android.testdpc1");
-
-            assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isTrue();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isTrue();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isTrue();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
-        }
-
-        // Then re-read and check.
-        {
-            final OwnersTestable owners = new OwnersTestable(getServices());
-            owners.load();
-
-            assertThat(owners.hasDeviceOwner()).isTrue();
-            assertThat(owners.getDeviceOwnerName()).isEqualTo(null);
-            assertThat(owners.getDeviceOwnerPackageName()).isEqualTo("com.google.android.testdpc");
-            assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);
-            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                    DEVICE_OWNER_TYPE_DEFAULT);
-            assertThat(owners.getDeviceOwnerProtectedPackages(owners.getDeviceOwnerPackageName()))
-                    .isEmpty();
-
-            assertThat(owners.getSystemUpdatePolicy()).isNotNull();
-            assertThat(owners.getSystemUpdatePolicy().getPolicyType()).isEqualTo(5);
-
-            assertThat(owners.getProfileOwnerKeys()).hasSize(2);
-            assertThat(owners.getProfileOwnerComponent(10))
-                    .isEqualTo(new ComponentName("com.google.android.testdpc",
-                            "com.google.android.testdpc.DeviceAdminReceiver0"));
-            assertThat(owners.getProfileOwnerName(10)).isEqualTo("0");
-            assertThat(owners.getProfileOwnerPackage(10)).isEqualTo("com.google.android.testdpc");
-
-            assertThat(owners.getProfileOwnerComponent(11))
-                    .isEqualTo(new ComponentName("com.google.android.testdpc1", ""));
-            assertThat(owners.getProfileOwnerName(11)).isEqualTo("1");
-            assertThat(owners.getProfileOwnerPackage(11)).isEqualTo("com.google.android.testdpc1");
-
-            assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isTrue();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isTrue();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isTrue();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
-
-            owners.setDeviceOwnerUserRestrictionsMigrated();
-
-            owners.setDeviceOwnerType(owners.getDeviceOwnerPackageName(),
-                    DEVICE_OWNER_TYPE_FINANCED, /* isAdminTestOnly= */ false);
-            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                    DEVICE_OWNER_TYPE_FINANCED);
-
-            owners.setDeviceOwnerProtectedPackages(
-                    owners.getDeviceOwnerPackageName(), DEVICE_OWNER_PROTECTED_PACKAGES);
-            assertThat(owners.getDeviceOwnerProtectedPackages(owners.getDeviceOwnerPackageName()))
-                    .isEqualTo(DEVICE_OWNER_PROTECTED_PACKAGES);
-            verify(getServices().packageManagerInternal)
-                    .setDeviceOwnerProtectedPackages(
-                            owners.getDeviceOwnerPackageName(), DEVICE_OWNER_PROTECTED_PACKAGES);
-        }
-
-        {
-            final OwnersTestable owners = new OwnersTestable(getServices());
-            owners.load();
-
-            assertThat(owners.hasDeviceOwner()).isTrue();
-            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                    DEVICE_OWNER_TYPE_FINANCED);
-            assertThat(owners.getDeviceOwnerProtectedPackages(owners.getDeviceOwnerPackageName()))
-                    .isEqualTo(DEVICE_OWNER_PROTECTED_PACKAGES);
-
-            assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isTrue();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isTrue();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
-
-            owners.setProfileOwnerUserRestrictionsMigrated(11);
-
-            owners.setDeviceOwnerType(owners.getDeviceOwnerPackageName(),
-                    DEVICE_OWNER_TYPE_DEFAULT, /* isAdminTestOnly= */ false);
-            // The previous device owner type should persist.
-            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                    DEVICE_OWNER_TYPE_FINANCED);
-
-            owners.setDeviceOwnerProtectedPackages(
-                    owners.getDeviceOwnerPackageName(), new ArrayList<>());
-            assertThat(owners.getDeviceOwnerProtectedPackages(owners.getDeviceOwnerPackageName()))
-                    .isEmpty();
-            verify(getServices().packageManagerInternal)
-                    .setDeviceOwnerProtectedPackages(
-                            owners.getDeviceOwnerPackageName(), new ArrayList<>());
-        }
-
-        {
-            final OwnersTestable owners = new OwnersTestable(getServices());
-            owners.load();
-
-            assertThat(owners.hasDeviceOwner()).isTrue();
-            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                    DEVICE_OWNER_TYPE_FINANCED);
-            assertThat(owners.getDeviceOwnerProtectedPackages(owners.getDeviceOwnerPackageName()))
-                    .isEmpty();
-
-            assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isTrue();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
-
-            owners.setProfileOwnerUserRestrictionsMigrated(11);
-        }
-    }
-
-    @Test
-    public void testUpgrade05() throws Exception {
-        getServices().addUsers(10, 11, 20, 21);
-
-        // First, migrate.
-        {
-            final OwnersTestable owners = new OwnersTestable(getServices());
-
-            DpmTestUtils.writeToFile(owners.getLegacyConfigFile(),
-                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test05/input.xml"));
-
-            owners.load();
-
-            // The legacy file should be removed.
-            assertThat(owners.getLegacyConfigFile().exists()).isFalse();
-
-            // Note device initializer is no longer supported.  No need to write the DO file.
-            assertThat(owners.getDeviceOwnerFile().exists()).isFalse();
-
-            assertThat(owners.getProfileOwnerFile(10).exists()).isFalse();
-            assertThat(owners.getProfileOwnerFile(11).exists()).isFalse();
-            assertThat(owners.getProfileOwnerFile(20).exists()).isFalse();
-
-            assertThat(owners.hasDeviceOwner()).isFalse();
-            assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
-            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                    DEVICE_OWNER_TYPE_DEFAULT);
-            assertThat(owners.getDeviceOwnerProtectedPackages(owners.getDeviceOwnerPackageName()))
-                    .isEmpty();
-
-
-            assertThat(owners.getSystemUpdatePolicy()).isNull();
-            assertThat(owners.getProfileOwnerKeys()).isEmpty();
-
-            assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
-        }
-
-        // Then re-read and check.
-        {
-            final OwnersTestable owners = new OwnersTestable(getServices());
-            owners.load();
-
-            assertThat(owners.hasDeviceOwner()).isFalse();
-            assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
-            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                    DEVICE_OWNER_TYPE_DEFAULT);
-            assertThat(owners.getDeviceOwnerProtectedPackages(owners.getDeviceOwnerPackageName()))
-                    .isEmpty();
-
-
-            assertThat(owners.getSystemUpdatePolicy()).isNull();
-            assertThat(owners.getProfileOwnerKeys()).isEmpty();
-
-            assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
-        }
-    }
-
-    @Test
-    public void testUpgrade06() throws Exception {
-        getServices().addUsers(10, 11, 20, 21);
-
-        // First, migrate.
-        {
-            final OwnersTestable owners = new OwnersTestable(getServices());
-
-            DpmTestUtils.writeToFile(owners.getLegacyConfigFile(),
-                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test06/input.xml"));
-
-            owners.load();
-
-            // The legacy file should be removed.
-            assertThat(owners.getLegacyConfigFile().exists()).isFalse();
-
-            assertThat(owners.getDeviceOwnerFile().exists()).isTrue();
-
-            assertThat(owners.getProfileOwnerFile(10).exists()).isFalse();
-            assertThat(owners.getProfileOwnerFile(11).exists()).isFalse();
-            assertThat(owners.getProfileOwnerFile(20).exists()).isFalse();
-
-            assertThat(owners.hasDeviceOwner()).isFalse();
-            assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
-            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                    DEVICE_OWNER_TYPE_DEFAULT);
-            assertThat(owners.getDeviceOwnerProtectedPackages(owners.getDeviceOwnerPackageName()))
-                    .isEmpty();
-            assertThat(owners.getProfileOwnerKeys()).isEmpty();
-
-            assertThat(owners.getSystemUpdatePolicy()).isNotNull();
-            assertThat(owners.getSystemUpdatePolicy().getPolicyType()).isEqualTo(5);
-
-            assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
-        }
-
-        // Then re-read and check.
-        {
-            final OwnersTestable owners = new OwnersTestable(getServices());
-            owners.load();
-
-            assertThat(owners.hasDeviceOwner()).isFalse();
-            assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
-            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                    DEVICE_OWNER_TYPE_DEFAULT);
-            assertThat(owners.getDeviceOwnerProtectedPackages(owners.getDeviceOwnerPackageName()))
-                    .isEmpty();
-            assertThat(owners.getProfileOwnerKeys()).isEmpty();
-
-            assertThat(owners.getSystemUpdatePolicy()).isNotNull();
-            assertThat(owners.getSystemUpdatePolicy().getPolicyType()).isEqualTo(5);
-
-            assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse();
-            assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
-        }
-    }
-
-    @Test
-    public void testRemoveExistingFiles() throws Exception {
-        getServices().addUsers(10, 11, 20, 21);
+    public void loadProfileOwner() throws Exception {
+        getServices().addUsers(10);
 
         final OwnersTestable owners = new OwnersTestable(getServices());
 
-        // First, migrate to create new-style config files.
-        DpmTestUtils.writeToFile(owners.getLegacyConfigFile(),
-                DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test04/input.xml"));
+        DpmTestUtils.writeToFile(owners.getProfileOwnerFile(10),
+                DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/profile_owner_1.xml"));
 
         owners.load();
 
-        assertThat(owners.getLegacyConfigFile().exists()).isFalse();
+        assertThat(owners.hasDeviceOwner()).isFalse();
+        assertThat(owners.getSystemUpdatePolicy()).isNull();
 
-        assertThat(owners.getDeviceOwnerFile().exists()).isTrue();
-        assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
-                DEVICE_OWNER_TYPE_DEFAULT);
-        assertThat(owners.getDeviceOwnerProtectedPackages(owners.getDeviceOwnerPackageName()))
-                .isEmpty();
-        assertThat(owners.getProfileOwnerFile(10).exists()).isTrue();
-        assertThat(owners.getProfileOwnerFile(11).exists()).isTrue();
+        assertThat(owners.getProfileOwnerKeys()).hasSize(1);
+        assertThat(owners.getProfileOwnerComponent(10))
+                .isEqualTo(new ComponentName(TESTDPC_PACKAGE,
+                        "com.afwsamples.testdpc.DeviceAdminReceiver"));
+    }
 
-        String previousDeviceOwnerPackageName = owners.getDeviceOwnerPackageName();
-        owners.setDeviceOwnerType(previousDeviceOwnerPackageName, DEVICE_OWNER_TYPE_FINANCED,
-                /* isAdminTestOnly= */ false);
-        assertThat(owners.getDeviceOwnerType(previousDeviceOwnerPackageName)).isEqualTo(
-                DEVICE_OWNER_TYPE_FINANCED);
-        owners.setDeviceOwnerProtectedPackages(
-                previousDeviceOwnerPackageName, DEVICE_OWNER_PROTECTED_PACKAGES);
-        assertThat(owners.getDeviceOwnerProtectedPackages(previousDeviceOwnerPackageName))
-                .isEqualTo(DEVICE_OWNER_PROTECTED_PACKAGES);
-        verify(getServices().packageManagerInternal)
-                .setDeviceOwnerProtectedPackages(
-                        owners.getDeviceOwnerPackageName(), DEVICE_OWNER_PROTECTED_PACKAGES);
+    @Test
+    public void loadDeviceOwner() throws Exception {
+        final OwnersTestable owners = new OwnersTestable(getServices());
 
-        // Then clear all information and save.
-        owners.clearDeviceOwner();
-        owners.clearSystemUpdatePolicy();
-        owners.removeProfileOwner(10);
-        owners.removeProfileOwner(11);
+        DpmTestUtils.writeToFile(owners.getDeviceOwnerFile(),
+                DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/device_owner_1.xml"));
 
-        owners.writeDeviceOwner();
-        owners.writeProfileOwner(10);
-        owners.writeProfileOwner(11);
-        owners.writeProfileOwner(20);
-        owners.writeProfileOwner(21);
+        owners.load();
 
-        // Now all files should be removed.
-        assertThat(owners.getDeviceOwnerFile().exists()).isFalse();
-        assertThat(owners.getProfileOwnerFile(10).exists()).isFalse();
-        assertThat(owners.getProfileOwnerFile(11).exists()).isFalse();
+        assertThat(owners.hasDeviceOwner()).isTrue();
 
-        assertThat(owners.getDeviceOwnerType(previousDeviceOwnerPackageName)).isEqualTo(
-                DEVICE_OWNER_TYPE_DEFAULT);
-        assertThat(owners.getDeviceOwnerProtectedPackages(previousDeviceOwnerPackageName))
-                .isEmpty();
-        verify(getServices().packageManagerInternal)
-                .setDeviceOwnerProtectedPackages(
-                        previousDeviceOwnerPackageName, new ArrayList<>());
+        assertThat(owners.getProfileOwnerKeys()).hasSize(0);
+        assertThat(owners.getDeviceOwnerComponent())
+                .isEqualTo(new ComponentName(TESTDPC_PACKAGE,
+                        "com.afwsamples.testdpc.DeviceAdminReceiver"));
+
+        assertThat(owners.getSystemUpdatePolicy().getPolicyType()).isEqualTo(TYPE_INSTALL_WINDOWED);
+    }
+
+    @Test
+    public void testDeviceOwnerType() throws Exception {
+        final OwnersTestable owners = new OwnersTestable(getServices());
+
+        DpmTestUtils.writeToFile(owners.getDeviceOwnerFile(),
+                DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/device_owner_1.xml"));
+
+        owners.load();
+
+        assertThat(owners.getDeviceOwnerType(TESTDPC_PACKAGE))
+                .isEqualTo(DEVICE_OWNER_TYPE_DEFAULT);
+
+        // Should be able to set DO type to "financed".
+        owners.setDeviceOwnerType(
+                TESTDPC_PACKAGE, DEVICE_OWNER_TYPE_FINANCED, /* isAdminTestOnly= */ false);
+        assertThat(owners.getDeviceOwnerType(TESTDPC_PACKAGE))
+                .isEqualTo(DEVICE_OWNER_TYPE_FINANCED);
+
+        // Once set, DO type cannot be changed.
+        owners.setDeviceOwnerType(
+                TESTDPC_PACKAGE, DEVICE_OWNER_TYPE_DEFAULT, /* isAdminTestOnly= */ false);
+        assertThat(owners.getDeviceOwnerType(TESTDPC_PACKAGE))
+                .isEqualTo(DEVICE_OWNER_TYPE_FINANCED);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index a79a52c..e4ee4d06 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -538,6 +538,11 @@
         }
 
         @Override
+        ComponentName injectChooserActivity() {
+            return mInjectedChooserActivity;
+        }
+
+        @Override
         void wtf(String message, Throwable th) {
             // During tests, WTF is fatal.
             fail(message + "  exception: " + th + "\n" + Log.getStackTraceString(th));
@@ -678,6 +683,7 @@
 
     protected int mInjectedCallingUid;
     protected String mInjectedClientPackage;
+    protected ComponentName mInjectedChooserActivity;
 
     protected Map<String, PackageInfo> mInjectedPackages;
 
@@ -723,6 +729,9 @@
     protected static final String LAUNCHER_4 = "com.android.launcher.4";
     protected static final int LAUNCHER_UID_4 = 10014;
 
+    protected static final String CHOOSER_ACTIVITY_PACKAGE = "com.android.intentresolver";
+    protected static final int CHOOSER_ACTIVITY_UID = 10015;
+
     protected static final int USER_0 = UserHandle.USER_SYSTEM;
     protected static final int USER_10 = 10;
     protected static final int USER_11 = 11;
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 a350dfb..867890f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -6901,6 +6901,9 @@
     }
 
     public void testGetShareTargets_permission() {
+        addPackage(CHOOSER_ACTIVITY_PACKAGE, CHOOSER_ACTIVITY_UID, 10, "sig1");
+        mInjectedChooserActivity =
+                ComponentName.createRelative(CHOOSER_ACTIVITY_PACKAGE, ".ChooserActivity");
         IntentFilter filter = new IntentFilter();
 
         assertExpectException(SecurityException.class, "Missing permission", () ->
@@ -6909,6 +6912,11 @@
         // Has permission, now it should pass.
         mCallerPermissions.add(permission.MANAGE_APP_PREDICTIONS);
         mManager.getShareTargets(filter);
+
+        runWithCaller(CHOOSER_ACTIVITY_PACKAGE, USER_0, () -> {
+            // Access is allowed when called from the configured system ChooserActivity
+            mManager.getShareTargets(filter);
+        });
     }
 
     public void testHasShareTargets_permission() {
diff --git a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
index a3223d6d..8f5f0e6 100644
--- a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.power;
 
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -56,6 +58,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.concurrent.Executor;
+
 /**
  * Tests for {@link com.android.server.power.Notifier}
  */
@@ -79,6 +83,7 @@
     private Context mContextSpy;
     private Resources mResourcesSpy;
     private TestLooper mTestLooper = new TestLooper();
+    private FakeExecutor mTestExecutor = new FakeExecutor();
     private Notifier mNotifier;
 
     @Before
@@ -107,6 +112,7 @@
         // WHEN wired charging starts
         mNotifier.onWiredChargingStarted(USER_ID);
         mTestLooper.dispatchAll();
+        mTestExecutor.simulateAsyncExecutionOfLastCommand();
 
         // THEN the device vibrates once
         verify(mVibrator, times(1)).vibrate(any(), any(VibrationAttributes.class));
@@ -122,6 +128,7 @@
         // WHEN wired charging starts
         mNotifier.onWiredChargingStarted(USER_ID);
         mTestLooper.dispatchAll();
+        mTestExecutor.simulateAsyncExecutionOfLastCommand();
 
         // THEN the device doesn't vibrate
         verify(mVibrator, never()).vibrate(any(), any(VibrationAttributes.class));
@@ -137,6 +144,7 @@
         // WHEN wireless charging starts
         mNotifier.onWirelessChargingStarted(5, USER_ID);
         mTestLooper.dispatchAll();
+        mTestExecutor.simulateAsyncExecutionOfLastCommand();
 
         // THEN the device vibrates once
         verify(mVibrator, times(1)).vibrate(any(), any(VibrationAttributes.class));
@@ -152,6 +160,7 @@
         // WHEN wireless charging starts
         mNotifier.onWirelessChargingStarted(5, USER_ID);
         mTestLooper.dispatchAll();
+        mTestExecutor.simulateAsyncExecutionOfLastCommand();
 
         // THEN the device doesn't vibrate
         verify(mVibrator, never()).vibrate(any(), any(VibrationAttributes.class));
@@ -170,6 +179,7 @@
         // WHEN wired charging starts
         mNotifier.onWiredChargingStarted(USER_ID);
         mTestLooper.dispatchAll();
+        mTestExecutor.simulateAsyncExecutionOfLastCommand();
 
         // THEN the device doesn't vibrate
         verify(mVibrator, never()).vibrate(any(), any(VibrationAttributes.class));
@@ -186,6 +196,7 @@
         // WHEN wireless charging starts
         mNotifier.onWirelessChargingStarted(5, USER_ID);
         mTestLooper.dispatchAll();
+        mTestExecutor.simulateAsyncExecutionOfLastCommand();
 
         // THEN the charging animation is triggered
         verify(mStatusBarManagerInternal, times(1)).showChargingAnimation(5);
@@ -202,6 +213,7 @@
         // WHEN wireless charging starts
         mNotifier.onWirelessChargingStarted(5, USER_ID);
         mTestLooper.dispatchAll();
+        mTestExecutor.simulateAsyncExecutionOfLastCommand();
 
         // THEN the charging animation never gets called
         verify(mStatusBarManagerInternal, never()).showChargingAnimation(anyInt());
@@ -211,7 +223,8 @@
         @Override
         Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
                 SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
-                FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
+                FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
+                Executor backgroundExecutor) {
             return mNotifierMock;
         }
 
@@ -300,6 +313,32 @@
                 mInjector.createSuspendBlocker(mService, "testBlocker"),
                 null,
                 null,
-                null);
+                null,
+                mTestExecutor);
     }
+
+    private static class FakeExecutor implements Executor {
+        private Runnable mLastCommand;
+
+        @Override
+        public void execute(Runnable command) {
+            assertNull(mLastCommand);
+            assertNotNull(command);
+            mLastCommand = command;
+        }
+
+        public Runnable getAndResetLastCommand() {
+            Runnable toReturn = mLastCommand;
+            mLastCommand = null;
+            return toReturn;
+        }
+
+        public void simulateAsyncExecutionOfLastCommand() {
+            Runnable toRun = getAndResetLastCommand();
+            if (toRun != null) {
+                toRun.run();
+            }
+        }
+    }
+
 }
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index c9721db..fbcad62 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -109,6 +109,7 @@
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
@@ -220,7 +221,8 @@
             @Override
             Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
                     SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
-                    FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
+                    FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
+                    Executor executor) {
                 return mNotifierMock;
             }
 
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
index 2d0dca2..c9fc033 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
@@ -61,6 +61,16 @@
     }
 
     @Override
+    public boolean isTelephonyTimeZoneDetectionSupported() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isGeoTimeZoneDetectionSupported() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public void dump(IndentingPrintWriter pw, String[] args) {
         mDumpCalled = true;
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index 49cd343..82e5411 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -20,6 +20,8 @@
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.window.BackNavigationInfo.typeToString;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
@@ -81,8 +83,8 @@
 
     @Test
     public void backNavInfo_HomeWhenBackToLauncher() {
-        Task task = createTopTaskWithActivity();
-        IOnBackInvokedCallback callback = withSystemCallback(task);
+        IOnBackInvokedCallback callback =
+                withCallback(createTopTaskWithActivity(), OnBackInvokedDispatcher.PRIORITY_SYSTEM);
 
         SurfaceControl.Transaction tx = mock(SurfaceControl.Transaction.class);
         BackNavigationInfo backNavigationInfo = mBackNavigationController.startBackNavigation(mWm,
@@ -103,7 +105,7 @@
     public void backTypeCrossTaskWhenBackToPreviousTask() {
         Task taskA = createTask(mDefaultDisplay);
         createActivityRecord(taskA);
-        withSystemCallback(createTopTaskWithActivity());
+        withCallback(createTopTaskWithActivity(), OnBackInvokedDispatcher.PRIORITY_SYSTEM);
         BackNavigationInfo backNavigationInfo = startBackNavigation();
         assertWithMessage("BackNavigationInfo").that(backNavigationInfo).isNotNull();
         assertThat(typeToString(backNavigationInfo.getType()))
@@ -155,7 +157,7 @@
     @Test
     public void preparesForBackToHome() {
         Task task = createTopTaskWithActivity();
-        withSystemCallback(task);
+        withCallback(task, OnBackInvokedDispatcher.PRIORITY_SYSTEM);
 
         BackNavigationInfo backNavigationInfo = startBackNavigation();
         assertThat(typeToString(backNavigationInfo.getType()))
@@ -165,7 +167,8 @@
     @Test
     public void backTypeCallback() {
         Task task = createTopTaskWithActivity();
-        IOnBackInvokedCallback appCallback = withAppCallback(task);
+        IOnBackInvokedCallback appCallback =
+                withCallback(task, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
 
         BackNavigationInfo backNavigationInfo = startBackNavigation();
         assertThat(typeToString(backNavigationInfo.getType()))
@@ -226,18 +229,61 @@
                 1, appLatch.getCount());
     }
 
-    private IOnBackInvokedCallback withSystemCallback(Task task) {
+    @Test
+    public void returnsImeCallback_imeVisible() {
+        // Set up a top activity with a default priority callback.
+        IOnBackInvokedCallback appCallback =
+                withCallback(createTopTaskWithActivity(), OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+        IOnBackInvokedCallback imeCallback = createOnBackInvokedCallback();
+
+        // Set up an IME window with also a default priority callback.
+        final DisplayArea.Tokens imeContainer = mDisplayContent.getImeContainer();
+        final WindowState imeWindow = createImeWindow();
+        imeWindow.setOnBackInvokedCallbackInfo(
+                new OnBackInvokedCallbackInfo(
+                        imeCallback, OnBackInvokedDispatcher.PRIORITY_DEFAULT));
+        spyOn(imeContainer);
+        // Simulate IME becoming visible.
+        doReturn(true).when(imeContainer).isVisible();
+        doReturn(imeWindow).when(imeContainer).getWindow(any());
+        BackNavigationInfo backNavigationInfo = startBackNavigation();
+
+        // Expect the IME callback to be selected.
+        assertThat(backNavigationInfo.getOnBackInvokedCallback()).isEqualTo(imeCallback);
+    }
+
+    @Test
+    public void returnsAppOverlayCallback_imeVisible() {
+        // Set up a top activity with an overlay priority callback.
+        IOnBackInvokedCallback appCallback =
+                withCallback(createTopTaskWithActivity(), OnBackInvokedDispatcher.PRIORITY_OVERLAY);
+        IOnBackInvokedCallback imeCallback = createOnBackInvokedCallback();
+
+        // Set up an IME window with a default priority callback.
+        final DisplayArea.Tokens imeContainer = mDisplayContent.getImeContainer();
+        final WindowState imeWindow = createImeWindow();
+        imeWindow.setOnBackInvokedCallbackInfo(
+                new OnBackInvokedCallbackInfo(
+                        imeCallback, OnBackInvokedDispatcher.PRIORITY_DEFAULT));
+        spyOn(imeContainer);
+        // Simulate IME becoming visible.
+        doReturn(true).when(imeContainer).isVisible();
+        doReturn(imeWindow).when(imeContainer).getWindow(any());
+        BackNavigationInfo backNavigationInfo = startBackNavigation();
+
+        // Expect the app callback to be selected.
+        assertThat(backNavigationInfo.getOnBackInvokedCallback()).isEqualTo(appCallback);
+    }
+
+    private IOnBackInvokedCallback withCallback(Task task, int priority) {
         IOnBackInvokedCallback callback = createOnBackInvokedCallback();
         task.getTopMostActivity().getTopChild().setOnBackInvokedCallbackInfo(
-                new OnBackInvokedCallbackInfo(callback, OnBackInvokedDispatcher.PRIORITY_SYSTEM));
+                new OnBackInvokedCallbackInfo(callback, priority));
         return callback;
     }
 
-    private IOnBackInvokedCallback withAppCallback(Task task) {
-        IOnBackInvokedCallback callback = createOnBackInvokedCallback();
-        task.getTopMostActivity().getTopChild().setOnBackInvokedCallbackInfo(
-                new OnBackInvokedCallbackInfo(callback, OnBackInvokedDispatcher.PRIORITY_DEFAULT));
-        return callback;
+    private WindowState createImeWindow() {
+        return createWindow(null, W_INPUT_METHOD, "mImeWindow", 12345 /* fake ime uide */);
     }
 
     @Nullable
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 30c2413..54fa4e4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -209,7 +209,7 @@
     }
 
     @Test
-    public void testEmbeddedTaskFragmentEnterPip_resetOrganizerOverrideConfig() {
+    public void testEmbeddedTaskFragmentEnterPip_singleActivity_resetOrganizerOverrideConfig() {
         final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
                 .setOrganizer(mOrganizer)
                 .setFragmentToken(new Binder())
@@ -242,6 +242,38 @@
     }
 
     @Test
+    public void testEmbeddedTaskFragmentEnterPip_multiActivities_notifyOrganizer() {
+        final Task task = createTask(mDisplayContent);
+        final TaskFragment taskFragment0 = new TaskFragmentBuilder(mAtm)
+                .setParentTask(task)
+                .setOrganizer(mOrganizer)
+                .setFragmentToken(new Binder())
+                .createActivityCount(1)
+                .build();
+        final TaskFragment taskFragment1 = new TaskFragmentBuilder(mAtm)
+                .setParentTask(task)
+                .setOrganizer(mOrganizer)
+                .setFragmentToken(new Binder())
+                .createActivityCount(1)
+                .build();
+        final ActivityRecord activity0 = taskFragment0.getTopMostActivity();
+        spyOn(mAtm.mTaskFragmentOrganizerController);
+
+        // Move activity to pinned.
+        mRootWindowContainer.moveActivityToPinnedRootTask(activity0,
+                null /* launchIntoPipHostActivity */, "test");
+
+        // Ensure taskFragment requested config is reset.
+        assertTrue(taskFragment0.mClearedTaskFragmentForPip);
+        assertFalse(taskFragment1.mClearedTaskFragmentForPip);
+        final TaskFragmentInfo info = taskFragment0.getTaskFragmentInfo();
+        assertTrue(info.isTaskFragmentClearedForPip());
+        assertTrue(info.isEmpty());
+        verify(mAtm.mTaskFragmentOrganizerController)
+                .dispatchPendingInfoChangedEvent(taskFragment0);
+    }
+
+    @Test
     public void testActivityHasOverlayOverUntrustedModeEmbedded() {
         final Task rootTask = createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW,
                 ACTIVITY_TYPE_STANDARD);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index a6a7c84..9c886aa 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -832,6 +832,17 @@
             "dial_string_replace_string_array";
 
     /**
+     * Specifies a map from dialstrings to replacements for international roaming network service
+     * numbers which cannot be replaced on the carrier side.
+     * <p>
+     * Individual entries have the format:
+     * [dialstring to replace]:[replacement]
+     * @hide
+     */
+    public static final String KEY_INTERNATIONAL_ROAMING_DIAL_STRING_REPLACE_STRING_ARRAY =
+            "international_roaming_dial_string_replace_string_array";
+
+    /**
      * Flag specifying whether WFC over IMS supports the "wifi only" option.  If false, the wifi
      * calling settings will not include an option for "wifi only".  If true, the wifi calling
      * settings will include an option for "wifi only"
@@ -8713,6 +8724,7 @@
         sDefaults.putStringArray(KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY, null);
         sDefaults.putStringArray(KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY, null);
         sDefaults.putStringArray(KEY_DIAL_STRING_REPLACE_STRING_ARRAY, null);
+        sDefaults.putStringArray(KEY_INTERNATIONAL_ROAMING_DIAL_STRING_REPLACE_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_FORCE_HOME_NETWORK_BOOL, false);
         sDefaults.putInt(KEY_GSM_DTMF_TONE_DELAY_INT, 0);
         sDefaults.putInt(KEY_IMS_DTMF_TONE_DELAY_INT, 0);
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
index 04fdda4..2f546b5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -63,8 +63,12 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Group4
 class TaskTransitionTest(val testSpec: FlickerTestParameter) {
-    val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
     private val mTestApp: NewTasksAppHelper = NewTasksAppHelper(instrumentation)
+    private val mWallpaper by lazy {
+        getWallpaperPackage(InstrumentationRegistry.getInstrumentation())
+            ?: error("Unable to obtain wallpaper")
+    }
 
     @FlickerBuilderProvider
     fun buildFlicker(): FlickerBuilder {
@@ -97,7 +101,7 @@
     @Test
     fun wallpaperWindowIsNeverVisible() {
         testSpec.assertWm {
-            this.isNonAppWindowInvisible(WALLPAPER)
+            this.isNonAppWindowInvisible(mWallpaper)
         }
     }
 
@@ -109,7 +113,7 @@
     @Test
     fun wallpaperLayerIsNeverVisible() {
         testSpec.assertLayers {
-            this.isInvisible(WALLPAPER)
+            this.isInvisible(mWallpaper)
             this.isInvisible(WALLPAPER_BBQ_WRAPPER)
         }
     }
@@ -229,15 +233,14 @@
     fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
 
     companion object {
-        private val WALLPAPER = getWallpaperPackage(InstrumentationRegistry.getInstrumentation())
         private val LAUNCH_NEW_TASK_ACTIVITY =
                 LAUNCH_NEW_TASK_ACTIVITY_COMPONENT_NAME.toFlickerComponent()
         private val SIMPLE_ACTIVITY = SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME.toFlickerComponent()
 
-        private fun getWallpaperPackage(instrumentation: Instrumentation): FlickerComponentName {
+        private fun getWallpaperPackage(instrumentation: Instrumentation): FlickerComponentName? {
             val wallpaperManager = WallpaperManager.getInstance(instrumentation.targetContext)
 
-            return wallpaperManager.wallpaperInfo.component.toFlickerComponent()
+            return wallpaperManager.wallpaperInfo?.component?.toFlickerComponent()
         }
 
         @Parameterized.Parameters(name = "{0}")
diff --git a/tools/aapt/SdkConstants.h b/tools/aapt/SdkConstants.h
index f57c4ee..a146466 100644
--- a/tools/aapt/SdkConstants.h
+++ b/tools/aapt/SdkConstants.h
@@ -48,6 +48,7 @@
     SDK_R = 30,
     SDK_S = 31,
     SDK_S_V2 = 32,
+    SDK_TIRAMISU = 33,
     SDK_CUR_DEVELOPMENT = 10000,
 };
 
diff --git a/tools/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h
index f2aaaf5..0bd61c0 100644
--- a/tools/aapt2/SdkConstants.h
+++ b/tools/aapt2/SdkConstants.h
@@ -58,6 +58,7 @@
   SDK_R = 30,
   SDK_S = 31,
   SDK_S_V2 = 32,
+  SDK_TIRAMISU = 33,
   SDK_CUR_DEVELOPMENT = 10000,
 };