Merge "Make TestableFlagResolver part of the 'testables' lib."
diff --git a/apct-tests/perftests/core/src/android/view/ViewPerfTest.java b/apct-tests/perftests/core/src/android/view/ViewPerfTest.java
index a2aeb31..67b33e5 100644
--- a/apct-tests/perftests/core/src/android/view/ViewPerfTest.java
+++ b/apct-tests/perftests/core/src/android/view/ViewPerfTest.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
 
 import android.content.Context;
 import android.perftests.utils.PerfTestActivity;
@@ -72,6 +73,15 @@
 
     @Test
     public void testPerformHapticFeedback() throws Throwable {
+        // performHapticFeedback is now asynchronous, so should be very fast. This benchmark
+        // is primarily a regression test for the re-introduction of blocking calls in the path.
+
+        // Can't run back-to-back performHapticFeedback, as it will just enqueue on the oneway
+        // thread and fill up that buffer. Instead, we invoke at a speed of a fairly high frame
+        // rate - and this is still too fast to fully vibrate in reality, but should be able to
+        // clear queues.
+        int waitPerCallMillis = 5;
+
         final BenchmarkState state = mBenchmarkRule.getState();
         mActivityRule.runOnUiThread(() -> {
             state.pauseTiming();
@@ -85,9 +95,17 @@
             int flags = HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
                     | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING;
 
-            while (state.keepRunning()) {
-                assertTrue("Call to performHapticFeedback was ignored",
-                        view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_PRESS, flags));
+            try {
+                while (state.keepRunning()) {
+                    assertTrue("Call to performHapticFeedback was ignored",
+                            view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_PRESS,
+                                    flags));
+                    state.pauseTiming();
+                    Thread.sleep(waitPerCallMillis);
+                    state.resumeTiming();
+                }
+            } catch (InterruptedException e) {
+                fail("Unexpectedly interrupted");
             }
         });
     }
diff --git a/api/Android.bp b/api/Android.bp
index 318748e..f49e6dd 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -100,7 +100,7 @@
         "framework-connectivity-t",
         "framework-devicelock",
         "framework-graphics",
-        "framework-healthconnect",
+        "framework-healthfitness",
         "framework-media",
         "framework-mediaprovider",
         "framework-ondevicepersonalization",
@@ -119,7 +119,7 @@
     system_server_classpath: [
         "service-art",
         "service-configinfrastructure",
-        "service-healthconnect",
+        "service-healthfitness",
         "service-media-s",
         "service-permission",
         "service-rkp",
diff --git a/boot/Android.bp b/boot/Android.bp
index d4a6500..83a46c5 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -88,8 +88,8 @@
             module: "com.android.devicelock-bootclasspath-fragment",
         },
         {
-            apex: "com.android.healthconnect",
-            module: "com.android.healthconnect-bootclasspath-fragment",
+            apex: "com.android.healthfitness",
+            module: "com.android.healthfitness-bootclasspath-fragment",
         },
         {
             apex: "com.android.i18n",
diff --git a/core/api/current.txt b/core/api/current.txt
index a57499b..d54290b 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -4319,6 +4319,7 @@
   @UiContext public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback {
     ctor public Activity();
     method public void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public void clearOverrideActivityTransition(int);
     method public void closeContextMenu();
     method public void closeOptionsMenu();
     method public android.app.PendingIntent createPendingResult(int, @NonNull android.content.Intent, int);
@@ -4487,6 +4488,8 @@
     method @Nullable public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
     method public void openContextMenu(android.view.View);
     method public void openOptionsMenu();
+    method public void overrideActivityTransition(int, @AnimRes int, @AnimRes int);
+    method public void overrideActivityTransition(int, @AnimRes int, @AnimRes int, @ColorInt int);
     method public void overridePendingTransition(int, int);
     method public void overridePendingTransition(int, int, int);
     method public void postponeEnterTransition();
@@ -4588,6 +4591,8 @@
     field protected static final int[] FOCUSED_STATE_SET;
     field public static final int FULLSCREEN_MODE_REQUEST_ENTER = 1; // 0x1
     field public static final int FULLSCREEN_MODE_REQUEST_EXIT = 0; // 0x0
+    field public static final int OVERRIDE_TRANSITION_CLOSE = 1; // 0x1
+    field public static final int OVERRIDE_TRANSITION_OPEN = 0; // 0x0
     field public static final int RESULT_CANCELED = 0; // 0x0
     field public static final int RESULT_FIRST_USER = 1; // 0x1
     field public static final int RESULT_OK = -1; // 0xffffffff
@@ -4614,6 +4619,7 @@
     method public java.util.List<android.app.ActivityManager.AppTask> getAppTasks();
     method public android.content.pm.ConfigurationInfo getDeviceConfigurationInfo();
     method @NonNull public java.util.List<android.app.ApplicationExitInfo> getHistoricalProcessExitReasons(@Nullable String, @IntRange(from=0) int, @IntRange(from=0) int);
+    method @NonNull public java.util.List<android.app.ApplicationStartInfo> getHistoricalProcessStartReasons(@IntRange(from=0) int);
     method public int getLargeMemoryClass();
     method public int getLauncherLargeIconDensity();
     method public int getLauncherLargeIconSize();
@@ -4639,7 +4645,9 @@
     method @RequiresPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES) public void killBackgroundProcesses(String);
     method @RequiresPermission(android.Manifest.permission.REORDER_TASKS) public void moveTaskToFront(int, int);
     method @RequiresPermission(android.Manifest.permission.REORDER_TASKS) public void moveTaskToFront(int, int, android.os.Bundle);
+    method public void removeApplicationStartInfoCompleteListener();
     method @Deprecated public void restartPackage(String);
+    method public void setApplicationStartInfoCompleteListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.ActivityManager.ApplicationStartInfoCompleteListener);
     method public void setProcessStateSummary(@Nullable byte[]);
     method public static void setVrThread(int);
     method public void setWatchHeapLimit(long);
@@ -4662,6 +4670,10 @@
     method public void startActivity(android.content.Context, android.content.Intent, android.os.Bundle);
   }
 
+  public static interface ActivityManager.ApplicationStartInfoCompleteListener {
+    method public void onApplicationStartInfoComplete(@NonNull android.app.ApplicationStartInfo);
+  }
+
   public static class ActivityManager.MemoryInfo implements android.os.Parcelable {
     ctor public ActivityManager.MemoryInfo();
     method public int describeContents();
@@ -5221,6 +5233,52 @@
     field public static final int REASON_USER_STOPPED = 11; // 0xb
   }
 
+  public final class ApplicationStartInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getDefiningUid();
+    method @Nullable public android.content.Intent getIntent();
+    method public int getLaunchMode();
+    method public int getPackageUid();
+    method public int getPid();
+    method @NonNull public String getProcessName();
+    method public int getRealUid();
+    method public int getReason();
+    method public int getStartType();
+    method public int getStartupState();
+    method @NonNull public java.util.Map<java.lang.Integer,java.lang.Long> getStartupTimestamps();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.ApplicationStartInfo> CREATOR;
+    field public static final int LAUNCH_MODE_SINGLE_INSTANCE = 2; // 0x2
+    field public static final int LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK = 4; // 0x4
+    field public static final int LAUNCH_MODE_SINGLE_TASK = 3; // 0x3
+    field public static final int LAUNCH_MODE_SINGLE_TOP = 1; // 0x1
+    field public static final int LAUNCH_MODE_STANDARD = 0; // 0x0
+    field public static final int STARTUP_STATE_ERROR = 1; // 0x1
+    field public static final int STARTUP_STATE_FIRST_FRAME_DRAWN = 2; // 0x2
+    field public static final int STARTUP_STATE_STARTED = 0; // 0x0
+    field public static final int START_REASON_ALARM = 0; // 0x0
+    field public static final int START_REASON_BACKUP = 1; // 0x1
+    field public static final int START_REASON_BOOT_COMPLETE = 2; // 0x2
+    field public static final int START_REASON_BROADCAST = 3; // 0x3
+    field public static final int START_REASON_CONTENT_PROVIDER = 4; // 0x4
+    field public static final int START_REASON_JOB = 5; // 0x5
+    field public static final int START_REASON_LAUNCHER = 6; // 0x6
+    field public static final int START_REASON_OTHER = 7; // 0x7
+    field public static final int START_REASON_PUSH = 8; // 0x8
+    field public static final int START_REASON_RESUMED_ACTIVITY = 9; // 0x9
+    field public static final int START_REASON_SERVICE = 10; // 0xa
+    field public static final int START_REASON_START_ACTIVITY = 11; // 0xb
+    field public static final int START_TIMESTAMP_APPLICATION_ONCREATE = 2; // 0x2
+    field public static final int START_TIMESTAMP_BIND_APPLICATION = 3; // 0x3
+    field public static final int START_TIMESTAMP_FIRST_FRAME = 4; // 0x4
+    field public static final int START_TIMESTAMP_FULLY_DRAWN = 5; // 0x5
+    field public static final int START_TIMESTAMP_JAVA_CLASSLOADING_COMPLETE = 1; // 0x1
+    field public static final int START_TIMESTAMP_LAUNCH = 0; // 0x0
+    field public static final int START_TYPE_COLD = 0; // 0x0
+    field public static final int START_TYPE_HOT = 2; // 0x2
+    field public static final int START_TYPE_WARM = 1; // 0x1
+  }
+
   public final class AsyncNotedAppOp implements android.os.Parcelable {
     method public int describeContents();
     method @Nullable public String getAttributionTag();
@@ -7697,6 +7755,26 @@
     method public final android.os.IBinder onBind(android.content.Intent);
   }
 
+  public final class DevicePolicyIdentifiers {
+    method @NonNull public static String getIdentifierForUserRestriction(@NonNull String);
+    field public static final String ACCOUNT_MANAGEMENT_DISABLED_POLICY = "accountManagementDisabled";
+    field public static final String APPLICATION_HIDDEN_POLICY = "applicationHidden";
+    field public static final String APPLICATION_RESTRICTIONS_POLICY = "applicationRestrictions";
+    field public static final String AUTO_TIMEZONE_POLICY = "autoTimezone";
+    field public static final String AUTO_TIME_POLICY = "autoTime";
+    field public static final String BACKUP_SERVICE_POLICY = "backupService";
+    field public static final String CAMERA_DISABLED_POLICY = "cameraDisabled";
+    field public static final String KEYGUARD_DISABLED_FEATURES_POLICY = "keyguardDisabledFeatures";
+    field public static final String LOCK_TASK_POLICY = "lockTask";
+    field public static final String PACKAGES_SUSPENDED_POLICY = "packagesSuspended";
+    field public static final String PACKAGE_UNINSTALL_BLOCKED_POLICY = "packageUninstallBlocked";
+    field public static final String PERMISSION_GRANT_POLICY = "permissionGrant";
+    field public static final String PERSISTENT_PREFERRED_ACTIVITY_POLICY = "persistentPreferredActivity";
+    field public static final String RESET_PASSWORD_TOKEN_POLICY = "resetPasswordToken";
+    field public static final String STATUS_BAR_DISABLED_POLICY = "statusBarDisabled";
+    field public static final String USER_CONTROL_DISABLED_PACKAGES_POLICY = "userControlDisabledPackages";
+  }
+
   public class DevicePolicyManager {
     method public void acknowledgeDeviceCompliant();
     method public void addCrossProfileIntentFilter(@NonNull android.content.ComponentName, android.content.IntentFilter, int);
@@ -7848,6 +7926,7 @@
     method public boolean isResetPasswordTokenActive(android.content.ComponentName);
     method public boolean isSafeOperation(int);
     method public boolean isSecurityLoggingEnabled(@Nullable android.content.ComponentName);
+    method public boolean isStatusBarDisabled();
     method public boolean isUninstallBlocked(@Nullable android.content.ComponentName, String);
     method public boolean isUniqueDeviceAttestationSupported();
     method public boolean isUsbDataSignalingEnabled();
@@ -7882,7 +7961,7 @@
     method @RequiresPermission(value=android.Manifest.permission.SET_TIME_ZONE, conditional=true) public void setAutoTimeZoneEnabled(@NonNull android.content.ComponentName, boolean);
     method public void setBackupServiceEnabled(@NonNull android.content.ComponentName, boolean);
     method public void setBluetoothContactSharingDisabled(@NonNull android.content.ComponentName, boolean);
-    method public void setCameraDisabled(@NonNull android.content.ComponentName, boolean);
+    method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA, conditional=true) public void setCameraDisabled(@Nullable android.content.ComponentName, boolean);
     method @Deprecated public void setCertInstallerPackage(@NonNull android.content.ComponentName, @Nullable String) throws java.lang.SecurityException;
     method public void setCommonCriteriaModeEnabled(@NonNull android.content.ComponentName, boolean);
     method public void setConfiguredNetworksLockdownState(@NonNull android.content.ComponentName, boolean);
@@ -8088,6 +8167,7 @@
     field @Deprecated public static final int KEYGUARD_DISABLE_REMOTE_INPUT = 64; // 0x40
     field public static final int KEYGUARD_DISABLE_SECURE_CAMERA = 2; // 0x2
     field public static final int KEYGUARD_DISABLE_SECURE_NOTIFICATIONS = 4; // 0x4
+    field public static final int KEYGUARD_DISABLE_SHORTCUTS_ALL = 512; // 0x200
     field public static final int KEYGUARD_DISABLE_TRUST_AGENTS = 16; // 0x10
     field public static final int KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS = 8; // 0x8
     field public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1; // 0x1
@@ -8249,6 +8329,8 @@
     ctor public PolicyUpdateResult(int);
     method public int getResultCode();
     field public static final int RESULT_FAILURE_CONFLICTING_ADMIN_POLICY = 1; // 0x1
+    field public static final int RESULT_FAILURE_HARDWARE_LIMITATION = 4; // 0x4
+    field public static final int RESULT_FAILURE_STORAGE_LIMIT_REACHED = 3; // 0x3
     field public static final int RESULT_FAILURE_UNKNOWN = -1; // 0xffffffff
     field public static final int RESULT_POLICY_CLEARED = 2; // 0x2
     field public static final int RESULT_SUCCESS = 0; // 0x0
@@ -8261,6 +8343,7 @@
     method public final void onReceive(android.content.Context, android.content.Intent);
     field public static final String ACTION_DEVICE_POLICY_CHANGED = "android.app.admin.action.DEVICE_POLICY_CHANGED";
     field public static final String ACTION_DEVICE_POLICY_SET_RESULT = "android.app.admin.action.DEVICE_POLICY_SET_RESULT";
+    field public static final String EXTRA_ACCOUNT_TYPE = "android.app.admin.extra.ACCOUNT_TYPE";
     field public static final String EXTRA_INTENT_FILTER = "android.app.admin.extra.INTENT_FILTER";
     field public static final String EXTRA_PACKAGE_NAME = "android.app.admin.extra.PACKAGE_NAME";
     field public static final String EXTRA_PERMISSION_NAME = "android.app.admin.extra.PERMISSION_NAME";
@@ -14850,6 +14933,7 @@
     method @Nullable public android.graphics.ColorSpace getColorSpace();
     method @NonNull public android.graphics.Bitmap.Config getConfig();
     method public int getDensity();
+    method @Nullable public android.graphics.Gainmap getGainmap();
     method public int getGenerationId();
     method @NonNull public android.hardware.HardwareBuffer getHardwareBuffer();
     method public int getHeight();
@@ -14865,6 +14949,7 @@
     method public int getScaledWidth(int);
     method public int getWidth();
     method public boolean hasAlpha();
+    method public boolean hasGainmap();
     method public boolean hasMipMap();
     method public boolean isMutable();
     method public boolean isPremultiplied();
@@ -14876,6 +14961,7 @@
     method public void setColorSpace(@NonNull android.graphics.ColorSpace);
     method public void setConfig(@NonNull android.graphics.Bitmap.Config);
     method public void setDensity(int);
+    method public void setGainmap(@Nullable android.graphics.Gainmap);
     method public void setHasAlpha(boolean);
     method public void setHasMipMap(boolean);
     method public void setHeight(int);
@@ -15411,6 +15497,26 @@
     ctor @Deprecated public EmbossMaskFilter(float[], float, float, float);
   }
 
+  public final class Gainmap {
+    ctor public Gainmap(@NonNull android.graphics.Bitmap);
+    method @NonNull public float getDisplayRatioForFullHdr();
+    method @NonNull public float[] getEpsilonHdr();
+    method @NonNull public float[] getEpsilonSdr();
+    method @NonNull public android.graphics.Bitmap getGainmapContents();
+    method @NonNull public float[] getGamma();
+    method @NonNull public float getMinDisplayRatioForHdrTransition();
+    method @NonNull public float[] getRatioMax();
+    method @NonNull public float[] getRatioMin();
+    method @NonNull public void setDisplayRatioForFullHdr(float);
+    method @NonNull public void setEpsilonHdr(float, float, float);
+    method @NonNull public void setEpsilonSdr(float, float, float);
+    method public void setGainmapContents(@NonNull android.graphics.Bitmap);
+    method @NonNull public void setGamma(float, float, float);
+    method @NonNull public void setMinDisplayRatioForHdrTransition(@FloatRange(from=1.0f) float);
+    method @NonNull public void setRatioMax(float, float, float);
+    method @NonNull public void setRatioMin(float, float, float);
+  }
+
   public class HardwareBufferRenderer implements java.lang.AutoCloseable {
     ctor public HardwareBufferRenderer(@NonNull android.hardware.HardwareBuffer);
     method public void close();
@@ -27310,6 +27416,7 @@
     method public void resumeRecording();
     method public void resumeRecording(@NonNull android.os.Bundle);
     method public void sendAppPrivateCommand(@NonNull String, android.os.Bundle);
+    method public void setTvInteractiveAppView(@Nullable android.media.tv.interactive.TvInteractiveAppView, @Nullable String);
     method public void startRecording(@Nullable android.net.Uri);
     method public void startRecording(@Nullable android.net.Uri, @NonNull android.os.Bundle);
     method public void stopRecording();
@@ -27598,8 +27705,13 @@
     method public boolean onKeyMultiple(int, int, @NonNull android.view.KeyEvent);
     method public boolean onKeyUp(int, @NonNull android.view.KeyEvent);
     method public void onMediaViewSizeChanged(@Px int, @Px int);
-    method public void onRecordingStarted(@NonNull String);
+    method public void onRecordingConnectionFailed(@NonNull String, @NonNull String);
+    method public void onRecordingDisconnected(@NonNull String, @NonNull String);
+    method public void onRecordingError(@NonNull String, int);
+    method public void onRecordingScheduled(@NonNull String, @Nullable String);
+    method public void onRecordingStarted(@NonNull String, @Nullable String);
     method public void onRecordingStopped(@NonNull String);
+    method public void onRecordingTuned(@NonNull String, @NonNull android.net.Uri);
     method public abstract void onRelease();
     method public void onResetInteractiveApp();
     method public abstract boolean onSetSurface(@Nullable android.view.Surface);
@@ -27634,8 +27746,10 @@
     method @CallSuper public void requestCurrentChannelUri();
     method @CallSuper public void requestCurrentTvInputId();
     method @CallSuper public void requestCurrentVideoBounds();
+    method @CallSuper public void requestScheduleRecording(@NonNull String, @NonNull String, @NonNull android.net.Uri, @NonNull android.net.Uri, @NonNull android.os.Bundle);
+    method @CallSuper public void requestScheduleRecording(@NonNull String, @NonNull String, @NonNull android.net.Uri, long, long, int, @NonNull android.os.Bundle);
     method @CallSuper public void requestSigning(@NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
-    method @CallSuper public void requestStartRecording(@Nullable android.net.Uri);
+    method @CallSuper public void requestStartRecording(@NonNull String, @Nullable android.net.Uri);
     method @CallSuper public void requestStopRecording(@NonNull String);
     method @CallSuper public void requestStreamVolume();
     method @CallSuper public void requestTimeShiftMode();
@@ -27676,7 +27790,8 @@
     method public boolean dispatchUnhandledInputEvent(@NonNull android.view.InputEvent);
     method @Nullable public android.media.tv.interactive.TvInteractiveAppView.OnUnhandledInputEventListener getOnUnhandledInputEventListener();
     method public void notifyError(@NonNull String, @NonNull android.os.Bundle);
-    method public void notifyRecordingStarted(@NonNull String);
+    method public void notifyRecordingScheduled(@NonNull String, @Nullable String);
+    method public void notifyRecordingStarted(@NonNull String, @Nullable String);
     method public void notifyRecordingStopped(@NonNull String);
     method public void notifyTimeShiftCurrentPositionChanged(@NonNull String, long);
     method public void notifyTimeShiftPlaybackParams(@NonNull android.media.PlaybackParams);
@@ -27730,8 +27845,10 @@
     method public void onRequestCurrentChannelUri(@NonNull String);
     method public void onRequestCurrentTvInputId(@NonNull String);
     method public void onRequestCurrentVideoBounds(@NonNull String);
+    method public void onRequestScheduleRecording(@NonNull String, @NonNull String, @NonNull String, @NonNull android.net.Uri, @NonNull android.net.Uri, @NonNull android.os.Bundle);
+    method public void onRequestScheduleRecording(@NonNull String, @NonNull String, @NonNull String, @NonNull android.net.Uri, long, long, int, @NonNull android.os.Bundle);
     method public void onRequestSigning(@NonNull String, @NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
-    method public void onRequestStartRecording(@NonNull String, @Nullable android.net.Uri);
+    method public void onRequestStartRecording(@NonNull String, @NonNull String, @Nullable android.net.Uri);
     method public void onRequestStopRecording(@NonNull String, @NonNull String);
     method public void onRequestStreamVolume(@NonNull String);
     method public void onRequestTimeShiftMode(@NonNull String);
@@ -33341,6 +33458,7 @@
     field public static final String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
     field public static final String ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED = "android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED";
     field public static final String ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED = "android.os.action.LOW_POWER_STANDBY_ENABLED_CHANGED";
+    field public static final String ACTION_LOW_POWER_STANDBY_POLICY_CHANGED = "android.os.action.LOW_POWER_STANDBY_POLICY_CHANGED";
     field public static final String ACTION_POWER_SAVE_MODE_CHANGED = "android.os.action.POWER_SAVE_MODE_CHANGED";
     field @Deprecated public static final int FULL_WAKE_LOCK = 26; // 0x1a
     field public static final int LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF = 2; // 0x2
@@ -41333,9 +41451,11 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method protected abstract void onCancel(android.speech.RecognitionService.Callback);
     method public void onCheckRecognitionSupport(@NonNull android.content.Intent, @NonNull android.speech.RecognitionService.SupportCallback);
+    method public void onCheckRecognitionSupport(@NonNull android.content.Intent, @NonNull android.content.AttributionSource, @NonNull android.speech.RecognitionService.SupportCallback);
     method protected abstract void onStartListening(android.content.Intent, android.speech.RecognitionService.Callback);
     method protected abstract void onStopListening(android.speech.RecognitionService.Callback);
     method public void onTriggerModelDownload(@NonNull android.content.Intent);
+    method public void onTriggerModelDownload(@NonNull android.content.Intent, @NonNull android.content.AttributionSource);
     field public static final String SERVICE_INTERFACE = "android.speech.RecognitionService";
     field public static final String SERVICE_META_DATA = "android.speech";
   }
@@ -53668,12 +53788,14 @@
     method public int getFitInsetsTypes();
     method public final CharSequence getTitle();
     method public boolean isFitInsetsIgnoringVisibility();
+    method public boolean isHdrConversionEnabled();
     method public static boolean mayUseInputMethod(int);
     method public void setBlurBehindRadius(@IntRange(from=0) int);
     method public void setColorMode(int);
     method public void setFitInsetsIgnoringVisibility(boolean);
     method public void setFitInsetsSides(int);
     method public void setFitInsetsTypes(int);
+    method public void setHdrConversionEnabled(boolean);
     method public final void setTitle(CharSequence);
     method public void setWallpaperTouchEventsEnabled(boolean);
     method public void writeToParcel(android.os.Parcel, int);
@@ -53684,6 +53806,7 @@
     field public static final float BRIGHTNESS_OVERRIDE_OFF = 0.0f;
     field @NonNull public static final android.os.Parcelable.Creator<android.view.WindowManager.LayoutParams> CREATOR;
     field public static final int DIM_AMOUNT_CHANGED = 32; // 0x20
+    field public static final int DISPLAY_FLAG_DISABLE_HDR_CONVERSION = 1; // 0x1
     field public static final int FIRST_APPLICATION_WINDOW = 1; // 0x1
     field public static final int FIRST_SUB_WINDOW = 1000; // 0x3e8
     field public static final int FIRST_SYSTEM_WINDOW = 2000; // 0x7d0
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 5406333..1e21c776 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -166,6 +166,7 @@
     method public void adjustSuggestedStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
     method @NonNull public java.util.List<android.bluetooth.BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp();
     method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio();
+    method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeBroadcast();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void handleBluetoothActiveDeviceChanged(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothDevice, @NonNull android.media.BluetoothProfileConnectionInfo);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void setA2dpSuspended(boolean);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void setBluetoothHeadsetProperties(@NonNull String, boolean, boolean);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 57759c6..67aa074 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -277,6 +277,7 @@
     field public static final String READ_PRINT_SERVICE_RECOMMENDATIONS = "android.permission.READ_PRINT_SERVICE_RECOMMENDATIONS";
     field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
     field public static final String READ_PROJECTION_STATE = "android.permission.READ_PROJECTION_STATE";
+    field public static final String READ_RESTRICTED_STATS = "android.permission.READ_RESTRICTED_STATS";
     field public static final String READ_RUNTIME_PROFILES = "android.permission.READ_RUNTIME_PROFILES";
     field public static final String READ_SAFETY_CENTER_STATUS = "android.permission.READ_SAFETY_CENTER_STATUS";
     field public static final String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES";
@@ -525,6 +526,7 @@
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
     method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void forceStopPackage(String);
     method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public static int getCurrentUser();
+    method @NonNull @RequiresPermission(android.Manifest.permission.DUMP) public java.util.List<android.app.ApplicationStartInfo> getExternalHistoricalProcessStartReasons(@NonNull String, @IntRange(from=0) int);
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String);
     method @NonNull public java.util.Collection<java.util.Locale> getSupportedLocales();
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidImportance(int);
@@ -1204,11 +1206,19 @@
 
 package android.app.admin {
 
+  public final class AccountTypePolicyKey extends android.app.admin.PolicyKey {
+    method public int describeContents();
+    method @NonNull public String getAccountType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.AccountTypePolicyKey> CREATOR;
+  }
+
   public abstract class Authority implements android.os.Parcelable {
     method public int describeContents();
   }
 
   public final class DeviceAdminAuthority extends android.app.admin.Authority {
+    ctor public DeviceAdminAuthority();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.DeviceAdminAuthority> CREATOR;
   }
@@ -1289,6 +1299,7 @@
     field public static final int EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION = 2; // 0x2
     field public static final int EXEMPT_FROM_APP_STANDBY = 0; // 0x0
     field public static final int EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS = 1; // 0x1
+    field public static final int EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION = 4; // 0x4
     field public static final int EXEMPT_FROM_HIBERNATION = 3; // 0x3
     field public static final String EXTRA_FORCE_UPDATE_ROLE_HOLDER = "android.app.extra.FORCE_UPDATE_ROLE_HOLDER";
     field public static final String EXTRA_LOST_MODE_LOCATION = "android.app.extra.LOST_MODE_LOCATION";
@@ -1392,11 +1403,13 @@
   }
 
   public final class DpcAuthority extends android.app.admin.Authority {
+    ctor public DpcAuthority();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.DpcAuthority> CREATOR;
   }
 
   public final class EnforcingAdmin implements android.os.Parcelable {
+    ctor public EnforcingAdmin(@NonNull String, @NonNull android.app.admin.Authority, @NonNull android.os.UserHandle);
     method public int describeContents();
     method @NonNull public android.app.admin.Authority getAuthority();
     method @NonNull public String getPackageName();
@@ -1520,6 +1533,7 @@
   }
 
   public final class RoleAuthority extends android.app.admin.Authority {
+    ctor public RoleAuthority(@NonNull java.util.Set<java.lang.String>);
     method @NonNull public java.util.Set<java.lang.String> getRoles();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.RoleAuthority> CREATOR;
@@ -1540,6 +1554,7 @@
   }
 
   public final class UnknownAuthority extends android.app.admin.Authority {
+    ctor public UnknownAuthority();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.UnknownAuthority> CREATOR;
   }
@@ -10646,7 +10661,6 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setPowerSaveModeEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void suppressAmbientDisplay(@NonNull String, boolean);
     method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.USER_ACTIVITY}) public void userActivity(long, int, int);
-    field @RequiresPermission(android.Manifest.permission.MANAGE_LOW_POWER_STANDBY) public static final String ACTION_LOW_POWER_STANDBY_POLICY_CHANGED = "android.os.action.LOW_POWER_STANDBY_POLICY_CHANGED";
     field public static final int POWER_SAVE_MODE_TRIGGER_DYNAMIC = 1; // 0x1
     field public static final int POWER_SAVE_MODE_TRIGGER_PERCENTAGE = 0; // 0x0
     field public static final String REBOOT_USERSPACE = "userspace";
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index f310d8d..bea2bfc 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -512,6 +512,10 @@
 
 package android.app.admin {
 
+  public final class DeviceAdminAuthority extends android.app.admin.Authority {
+    field @NonNull public static final android.app.admin.DeviceAdminAuthority DEVICE_ADMIN_AUTHORITY;
+  }
+
   public class DevicePolicyManager {
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void acknowledgeNewUserDisclaimer();
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void clearOrganizationId();
@@ -592,21 +596,28 @@
     field @Deprecated public static final int STATUS_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER = 14; // 0xe
   }
 
+  public final class DpcAuthority extends android.app.admin.Authority {
+    field @NonNull public static final android.app.admin.DpcAuthority DPC_AUTHORITY;
+  }
+
   public final class FlagUnion extends android.app.admin.ResolutionMechanism<java.lang.Integer> {
     method public int describeContents();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.FlagUnion> CREATOR;
+    field @NonNull public static final android.app.admin.FlagUnion FLAG_UNION;
   }
 
   public final class MostRecent<V> extends android.app.admin.ResolutionMechanism<V> {
     ctor public MostRecent();
     method public int describeContents();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.MostRecent> CREATOR;
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.MostRecent<?>> CREATOR;
+    field @NonNull public static final android.app.admin.MostRecent<?> MOST_RECENT;
   }
 
   public final class MostRestrictive<V> extends android.app.admin.ResolutionMechanism<V> {
     method public int describeContents();
+    method @NonNull public java.util.List<V> getMostToLeastRestrictiveValues();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.MostRestrictive<?>> CREATOR;
   }
@@ -627,14 +638,20 @@
     method public int describeContents();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.StringSetUnion> CREATOR;
+    field @NonNull public static final android.app.admin.StringSetUnion STRING_SET_UNION;
   }
 
   public final class TopPriority<V> extends android.app.admin.ResolutionMechanism<V> {
     method public int describeContents();
+    method @NonNull public java.util.List<android.app.admin.Authority> getHighestToLowestPriorityAuthorities();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.TopPriority<?>> CREATOR;
   }
 
+  public final class UnknownAuthority extends android.app.admin.Authority {
+    field @NonNull public static final android.app.admin.UnknownAuthority UNKNOWN_AUTHORITY;
+  }
+
   public final class UnsafeStateException extends java.lang.IllegalStateException implements android.os.Parcelable {
     ctor public UnsafeStateException(int, int);
     method public int getOperation();
@@ -1400,6 +1417,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE) public void clearGlobalUserPreferredDisplayMode();
     method @Nullable public android.view.Display.Mode getGlobalUserPreferredDisplayMode();
     method @NonNull public android.hardware.display.HdrConversionMode getHdrConversionMode();
+    method @NonNull public android.hardware.display.HdrConversionMode getHdrConversionModeSetting();
     method @NonNull public int[] getSupportedHdrOutputTypes();
     method @NonNull public int[] getUserDisabledHdrTypes();
     method public boolean isMinimalPostProcessingRequested(int);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 3c17a33..1d03d84 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -26,8 +26,10 @@
 
 import static java.lang.Character.MIN_VALUE;
 
+import android.annotation.AnimRes;
 import android.annotation.CallSuper;
 import android.annotation.CallbackExecutor;
+import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
 import android.annotation.IdRes;
 import android.annotation.IntDef;
@@ -108,6 +110,7 @@
 import android.util.Dumpable;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.Pair;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -1006,6 +1009,25 @@
      */
     public static final int FULLSCREEN_MODE_REQUEST_ENTER = 1;
 
+    /** @hide */
+    @IntDef(prefix = { "OVERRIDE_TRANSITION_" }, value = {
+            OVERRIDE_TRANSITION_OPEN,
+            OVERRIDE_TRANSITION_CLOSE
+    })
+    public @interface OverrideTransition {}
+
+    /**
+     * Request type of {@link #overrideActivityTransition(int, int, int)} or
+     * {@link #overrideActivityTransition(int, int, int, int)}, to override the
+     * opening transition.
+     */
+    public static final int OVERRIDE_TRANSITION_OPEN = 0;
+    /**
+     * Request type of {@link #overrideActivityTransition(int, int, int)} or
+     * {@link #overrideActivityTransition(int, int, int, int)}, to override the
+     * closing transition.
+     */
+    public static final int OVERRIDE_TRANSITION_CLOSE = 1;
     private boolean mShouldDockBigOverlays;
 
     private UiTranslationController mUiTranslationController;
@@ -6462,6 +6484,124 @@
     }
 
     /**
+     * Customizes the animation for the activity transition with this activity. This can be called
+     * at any time while the activity still alive.
+     *
+     * <p> This is a more robust method of overriding the transition animation at runtime without
+     * relying on {@link #overridePendingTransition(int, int)} which doesn't work for predictive
+     * back. However, the animation set from {@link #overridePendingTransition(int, int)} still
+     * has higher priority when the system is looking for the next transition animation.</p>
+     * <p> The animations resources set by this method will be chosen if and only if the activity is
+     * on top of the task while activity transitions are being played.
+     * For example, if we want to customize the opening transition when launching Activity B which
+     * gets started from Activity A, we should call this method inside B's onCreate with
+     * {@code overrideType = OVERRIDE_TRANSITION_OPEN} because the Activity B will on top of the
+     * task. And if we want to customize the closing transition when finishing Activity B and back
+     * to Activity A, since B is still is above A, we should call this method in Activity B with
+     * {@code overrideType = OVERRIDE_TRANSITION_CLOSE}. </p>
+     *
+     * <p> If an Activity has called this method, and it also set another activity animation
+     * by {@link Window#setWindowAnimations(int)}, the system will choose the animation set from
+     * this method.</p>
+     *
+     * <p> Note that {@link Window#setWindowAnimations},
+     * {@link #overridePendingTransition(int, int)} and this method will be ignored if the Activity
+     * is started with {@link ActivityOptions#makeSceneTransitionAnimation(Activity, Pair[])}. Also
+     * note that this method can only be used to customize cross-activity transitions but not
+     * cross-task transitions which are fully non-customizable as of Android 11.</p>
+     *
+     * @param overrideType {@code OVERRIDE_TRANSITION_OPEN} This animation will be used when
+     *                     starting/entering an activity. {@code OVERRIDE_TRANSITION_CLOSE} This
+     *                     animation will be used when finishing/closing an activity.
+     * @param enterAnim A resource ID of the animation resource to use for the incoming activity.
+     *                  Use 0 for no animation.
+     * @param exitAnim A resource ID of the animation resource to use for the outgoing activity.
+     *                 Use 0 for no animation.
+     *
+     * @see #overrideActivityTransition(int, int, int, int)
+     * @see #clearOverrideActivityTransition(int)
+     * @see OnBackInvokedCallback
+     * @see #overridePendingTransition(int, int)
+     * @see Window#setWindowAnimations(int)
+     * @see ActivityOptions#makeSceneTransitionAnimation(Activity, Pair[])
+     */
+    public void overrideActivityTransition(@OverrideTransition int overrideType,
+            @AnimRes int enterAnim, @AnimRes int exitAnim) {
+        overrideActivityTransition(overrideType, enterAnim, exitAnim, Color.TRANSPARENT);
+    }
+
+    /**
+     * Customizes the animation for the activity transition with this activity. This can be called
+     * at any time while the activity still alive.
+     *
+     * <p> This is a more robust method of overriding the transition animation at runtime without
+     * relying on {@link #overridePendingTransition(int, int)} which doesn't work for predictive
+     * back. However, the animation set from {@link #overridePendingTransition(int, int)} still
+     * has higher priority when the system is looking for the next transition animation.</p>
+     * <p> The animations resources set by this method will be chosen if and only if the activity is
+     * on top of the task while activity transitions are being played.
+     * For example, if we want to customize the opening transition when launching Activity B which
+     * gets started from Activity A, we should call this method inside B's onCreate with
+     * {@code overrideType = OVERRIDE_TRANSITION_OPEN} because the Activity B will on top of the
+     * task. And if we want to customize the closing transition when finishing Activity B and back
+     * to Activity A, since B is still is above A, we should call this method in Activity B with
+     * {@code overrideType = OVERRIDE_TRANSITION_CLOSE}. </p>
+     *
+     * <p> If an Activity has called this method, and it also set another activity animation
+     * by {@link Window#setWindowAnimations(int)}, the system will choose the animation set from
+     * this method.</p>
+     *
+     * <p> Note that {@link Window#setWindowAnimations},
+     * {@link #overridePendingTransition(int, int)} and this method will be ignored if the Activity
+     * is started with {@link ActivityOptions#makeSceneTransitionAnimation(Activity, Pair[])}. Also
+     * note that this method can only be used to customize cross-activity transitions but not
+     * cross-task transitions which are fully non-customizable as of Android 11.</p>
+     *
+     * @param overrideType {@code OVERRIDE_TRANSITION_OPEN} This animation will be used when
+     *                     starting/entering an activity. {@code OVERRIDE_TRANSITION_CLOSE} This
+     *                     animation will be used when finishing/closing an activity.
+     * @param enterAnim A resource ID of the animation resource to use for the incoming activity.
+     *                  Use 0 for no animation.
+     * @param exitAnim A resource ID of the animation resource to use for the outgoing activity.
+     *                 Use 0 for no animation.
+     * @param backgroundColor The background color to use for the background during the animation
+     *                        if the animation requires a background. Set to
+     *                        {@link Color#TRANSPARENT} to not override the default color.
+     * @see #overrideActivityTransition(int, int, int)
+     * @see #clearOverrideActivityTransition(int)
+     * @see OnBackInvokedCallback
+     * @see #overridePendingTransition(int, int)
+     * @see Window#setWindowAnimations(int)
+     * @see ActivityOptions#makeSceneTransitionAnimation(Activity, Pair[])
+     */
+    public void overrideActivityTransition(@OverrideTransition int overrideType,
+            @AnimRes int enterAnim, @AnimRes int exitAnim, @ColorInt int backgroundColor) {
+        if (overrideType != OVERRIDE_TRANSITION_OPEN && overrideType != OVERRIDE_TRANSITION_CLOSE) {
+            throw new IllegalArgumentException("Override type must be either open or close");
+        }
+
+        ActivityClient.getInstance().overrideActivityTransition(mToken,
+                overrideType == OVERRIDE_TRANSITION_OPEN, enterAnim, exitAnim, backgroundColor);
+    }
+
+    /**
+     * Clears the animations which are set from {@link #overrideActivityTransition}.
+     * @param overrideType {@code OVERRIDE_TRANSITION_OPEN} clear the animation set for starting a
+     *                     new activity. {@code OVERRIDE_TRANSITION_CLOSE} clear the animation set
+     *                     for finishing an activity.
+     *
+     * @see #overrideActivityTransition(int, int, int)
+     * @see #overrideActivityTransition(int, int, int, int)
+     */
+    public void clearOverrideActivityTransition(@OverrideTransition int overrideType) {
+        if (overrideType != OVERRIDE_TRANSITION_OPEN && overrideType != OVERRIDE_TRANSITION_CLOSE) {
+            throw new IllegalArgumentException("Override type must be either open or close");
+        }
+        ActivityClient.getInstance().clearOverrideActivityTransition(mToken,
+                overrideType == OVERRIDE_TRANSITION_OPEN);
+    }
+
+    /**
      * Call immediately after one of the flavors of {@link #startActivity(Intent)}
      * or {@link #finish} to specify an explicit transition animation to
      * perform next.
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index aa868a7..5354a44 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -486,6 +486,24 @@
         }
     }
 
+    void overrideActivityTransition(IBinder token, boolean open, int enterAnim, int exitAnim,
+            int backgroundColor) {
+        try {
+            getActivityClientController().overrideActivityTransition(
+                    token, open, enterAnim, exitAnim, backgroundColor);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    void clearOverrideActivityTransition(IBinder token, boolean open) {
+        try {
+            getActivityClientController().clearOverrideActivityTransition(token, open);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
     void overridePendingTransition(IBinder token, String packageName, int enterAnim, int exitAnim,
             int backgroundColor) {
         try {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f408916..42d056c 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3676,6 +3676,123 @@
     }
 
     /**
+     * Return a list of {@link ApplicationStartInfo} records containing the information about the
+     * most recent app startups.
+     *
+     * <p class="note"> Note: System stores this historical information in a ring buffer and only
+     * the most recent records will be returned. </p>
+     *
+     * @param maxNum      The maximum number of results to be returned; a value of 0
+     *                    means to ignore this parameter and return all matching records. If fewer
+     *                    records exist, all existing records will be returned.
+     *
+     * @return a list of {@link ApplicationStartInfo} records matching the criteria, sorted in
+     *         the order from most recent to least recent.
+     */
+    @NonNull
+    public List<ApplicationStartInfo> getHistoricalProcessStartReasons(
+            @IntRange(from = 0) int maxNum) {
+        try {
+            ParceledListSlice<ApplicationStartInfo> startInfos = getService()
+                    .getHistoricalProcessStartReasons(null, maxNum, mContext.getUserId());
+            return startInfos == null ? Collections.emptyList() : startInfos.getList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return a list of {@link ApplicationStartInfo} records containing the information about the
+     * most recent app startups.
+     *
+     * <p class="note"> Note: System stores this historical information in a ring buffer and only
+     * the most recent records will be returned. </p>
+     *
+     * @param packageName Package name for which app startups to receive.
+     * @param maxNum      The maximum number of results to be returned; a value of 0
+     *                    means to ignore this parameter and return all matching records. If fewer
+     *                    records exist, all existing records will be returned.
+     *
+     * @return a list of {@link ApplicationStartInfo} records matching the criteria, sorted in
+     *         the order from most recent to least recent.
+     *
+     * @hide
+     */
+    @NonNull
+    @SystemApi
+    @RequiresPermission(Manifest.permission.DUMP)
+    public List<ApplicationStartInfo> getExternalHistoricalProcessStartReasons(
+            @NonNull String packageName, @IntRange(from = 0) int maxNum) {
+        try {
+            ParceledListSlice<ApplicationStartInfo> startInfos = getService()
+                    .getHistoricalProcessStartReasons(packageName, maxNum, mContext.getUserId());
+            return startInfos == null ? Collections.emptyList() : startInfos.getList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Callback to receive {@link ApplicationStartInfo} object once recording of startup related
+     * metrics is complete.
+     * Use with {@link #setApplicationStartInfoCompleteListener}.
+     */
+    public interface ApplicationStartInfoCompleteListener {
+        /** {@link ApplicationStartInfo} is complete, no more info will be added. */
+        void onApplicationStartInfoComplete(@NonNull ApplicationStartInfo applicationStartInfo);
+    }
+
+    /**
+     * Sets a callback to be notified when the {@link ApplicationStartInfo} records of this startup
+     * are complete.
+     *
+     * <p class="note"> Note: callback will not wait for {@link Activity#reportFullyDrawn} to occur.
+     * Timestamp for fully drawn may be added after callback occurs. Set callback after invoking
+     * {@link Activity#reportFullyDrawn} if timestamp for fully drawn is required.</p>
+     *
+     * <p class="note"> Note: if start records have already been retrieved, the callback will be
+     * invoked immediately on the specified executor with the previously resolved AppStartInfo.</p>
+     *
+     * <p class="note"> Note: callback is asynchronous and should be made from a background thread.
+     * </p>
+     *
+     * @param executor    The executor on which the listener should be called.
+     * @param listener    Callback to be called when collection of {@link ApplicationStartInfo} is
+     *                    complete. Will replace existing listener if one is already attached.
+     *
+     * @throws IllegalArgumentException if executor or listener are null.
+     */
+    public void setApplicationStartInfoCompleteListener(@NonNull final Executor executor,
+            @NonNull final ApplicationStartInfoCompleteListener listener) {
+        Preconditions.checkNotNull(executor, "executor cannot be null");
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        IApplicationStartInfoCompleteListener callback =
+                new IApplicationStartInfoCompleteListener.Stub() {
+            @Override
+            public void onApplicationStartInfoComplete(ApplicationStartInfo applicationStartInfo) {
+                executor.execute(() ->
+                        listener.onApplicationStartInfoComplete(applicationStartInfo));
+            }
+        };
+        try {
+            getService().setApplicationStartInfoCompleteListener(callback, mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Removes the callback set by {@link #setApplicationStartInfoCompleteListener} if there is one.
+     */
+    public void removeApplicationStartInfoCompleteListener() {
+        try {
+            getService().removeApplicationStartInfoCompleteListener(mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Return a list of {@link ApplicationExitInfo} records containing the reasons for the most
      * recent app deaths.
      *
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 0fa1a37..2ad5c20 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -963,4 +963,12 @@
      * @hide
      */
     public abstract boolean canHoldWakeLocksInDeepDoze(int uid, int procstate);
+
+    /**
+     * Same as {@link android.app.IActivityManager#startProfile(int userId)}, but it would succeed
+     * even if the profile is disabled - it should only be called by
+     * {@link com.android.server.devicepolicy.DevicePolicyManagerService} when starting a profile
+     * while it's being created.
+     */
+    public abstract boolean startProfileEvenWhenDisabled(@UserIdInt int userId);
 }
diff --git a/core/java/android/app/ApplicationStartInfo.aidl b/core/java/android/app/ApplicationStartInfo.aidl
new file mode 100644
index 0000000..4322c7e
--- /dev/null
+++ b/core/java/android/app/ApplicationStartInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+parcelable ApplicationStartInfo;
diff --git a/core/java/android/app/ApplicationStartInfo.java b/core/java/android/app/ApplicationStartInfo.java
new file mode 100644
index 0000000..794c55e
--- /dev/null
+++ b/core/java/android/app/ApplicationStartInfo.java
@@ -0,0 +1,598 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.HashMap;
+import java.util.Map;
+
+/** Provide information related to a processes startup. */
+public final class ApplicationStartInfo implements Parcelable {
+
+    /**
+     * State indicating process startup has started. Some information is available in
+     * {@link ApplicationStartInfo} and more will be added.
+     */
+    public static final int STARTUP_STATE_STARTED = 0;
+
+    /**
+     * State indicating process startup has failed. Startup information in
+     * {@link ApplicationStartInfo} is incomplete, but no more will be added.
+     */
+    public static final int STARTUP_STATE_ERROR = 1;
+
+    /**
+     * State indicating process startup has made it to first frame draw. Startup
+     * information in {@link ApplicationStartInfo} is complete with potential exception
+     * of fully drawn timestamp which is not guaranteed to be set.
+     */
+    public static final int STARTUP_STATE_FIRST_FRAME_DRAWN = 2;
+
+    /** Process started due to alarm. */
+    public static final int START_REASON_ALARM = 0;
+
+    /** Process started to run backup. */
+    public static final int START_REASON_BACKUP = 1;
+
+    /** Process started due to boot complete. */
+    public static final int START_REASON_BOOT_COMPLETE = 2;
+
+    /**  Process started due to broadcast received. */
+    public static final int START_REASON_BROADCAST = 3;
+
+    /** Process started due to access of ContentProvider */
+    public static final int START_REASON_CONTENT_PROVIDER = 4;
+
+    /** * Process started to run scheduled job. */
+    public static final int START_REASON_JOB = 5;
+
+    /** Process started due to click app icon or widget from launcher. */
+    public static final int START_REASON_LAUNCHER = 6;
+
+    /** Process started not for any of the listed reasons. */
+    public static final int START_REASON_OTHER = 7;
+
+    /** Process started due to push message. */
+    public static final int START_REASON_PUSH = 8;
+
+    /** Process started to resume activity. */
+    public static final int START_REASON_RESUMED_ACTIVITY = 9;
+
+    /** Process service started. */
+    public static final int START_REASON_SERVICE = 10;
+
+    /** Process started due to Activity started for any reason not explicitly listed. */
+    public static final int START_REASON_START_ACTIVITY = 11;
+
+    /** Process started from scratch. */
+    public static final int START_TYPE_COLD = 0;
+
+    /** Process retained minimally SavedInstanceState. */
+    public static final int START_TYPE_WARM = 1;
+
+    /** Process brought back to foreground. */
+    public static final int START_TYPE_HOT = 2;
+
+    /**
+     * Default. The system always creates a new instance of the activity in the target task and
+     * routes the intent to it.
+     */
+    public static final int LAUNCH_MODE_STANDARD = 0;
+
+    /**
+     * If an instance of the activity already exists at the top of the target task, the system
+     * routes the intent to that instance through a call to its onNewIntent() method, rather than
+     * creating a new instance of the activity.
+     */
+    public static final int LAUNCH_MODE_SINGLE_TOP = 1;
+
+    /**
+     * The system creates the activity at the root of a new task or locates the activity on an
+     * existing task with the same affinity. If an instance of the activity already exists and is at
+     * the root of the task, the system routes the intent to existing instance through a call to its
+     * onNewIntent() method, rather than creating a new one.
+     */
+    public static final int LAUNCH_MODE_SINGLE_INSTANCE = 2;
+
+    /**
+     * Same as "singleTask", except that the system doesn't launch any other activities into the
+     * task holding the instance. The activity is always the single and only member of its task.
+     */
+    public static final int LAUNCH_MODE_SINGLE_TASK = 3;
+
+    /**
+     * The activity can only be running as the root activity of the task, the first activity that
+     * created the task, and therefore there will only be one instance of this activity in a task;
+     * but activity can be instantiated multiple times in different tasks.
+     */
+    public static final int LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK = 4;
+
+    /** Clock monotonic timestamp of launch started. */
+    public static final int START_TIMESTAMP_LAUNCH = 0;
+
+    /** Clock monotonic timestamp of finish java classloading. */
+    public static final int START_TIMESTAMP_JAVA_CLASSLOADING_COMPLETE = 1;
+
+    /** Clock monotonic timestamp of Application onCreate called. */
+    public static final int START_TIMESTAMP_APPLICATION_ONCREATE = 2;
+
+    /** Clock monotonic timestamp of bindApplication called. */
+    public static final int START_TIMESTAMP_BIND_APPLICATION = 3;
+
+    /** Clock monotonic timestamp of first frame drawn. */
+    public static final int START_TIMESTAMP_FIRST_FRAME = 4;
+
+    /** Clock monotonic timestamp of reportFullyDrawn called by application. */
+    public static final int START_TIMESTAMP_FULLY_DRAWN = 5;
+
+    /**
+     * @see #getStartupState
+     */
+    private @StartupState int mStartupState;
+
+    /**
+     * @see #getPid
+     */
+    private int mPid;
+
+    /**
+     * @see #getRealUid
+     */
+    private int mRealUid;
+
+    /**
+     * @see #getPackageUid
+     */
+    private int mPackageUid;
+
+    /**
+     * @see #getDefiningUid
+     */
+    private int mDefiningUid;
+
+    /**
+     * @see #getProcessName
+     */
+    private String mProcessName;
+
+    /**
+     * @see #getReason
+     */
+    private @StartReason int mReason;
+
+    /**
+     * @see #getStartupTimestamps
+     */
+    private Map<@StartupTimestamp Integer, Long> mStartupTimestampsNs;
+
+    /**
+     * @see #getStartType
+     */
+    private @StartType int mStartType;
+
+    /**
+     * @see #getStartIntent
+     */
+    private Intent mStartIntent;
+
+    /**
+     * @see #getLaunchMode
+     */
+    private @LaunchMode int mLaunchMode;
+
+    /**
+     * @hide *
+     */
+    @IntDef(
+            prefix = {"STARTUP_STATE_"},
+            value = {
+                STARTUP_STATE_STARTED,
+                STARTUP_STATE_ERROR,
+                STARTUP_STATE_FIRST_FRAME_DRAWN,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface StartupState {}
+
+    /**
+     * @hide *
+     */
+    @IntDef(
+            prefix = {"START_REASON_"},
+            value = {
+                START_REASON_ALARM,
+                START_REASON_BACKUP,
+                START_REASON_BOOT_COMPLETE,
+                START_REASON_BROADCAST,
+                START_REASON_CONTENT_PROVIDER,
+                START_REASON_JOB,
+                START_REASON_LAUNCHER,
+                START_REASON_OTHER,
+                START_REASON_PUSH,
+                START_REASON_RESUMED_ACTIVITY,
+                START_REASON_SERVICE,
+                START_REASON_START_ACTIVITY,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface StartReason {}
+
+    /**
+     * @hide *
+     */
+    @IntDef(
+            prefix = {"START_TYPE_"},
+            value = {
+                START_TYPE_COLD,
+                START_TYPE_WARM,
+                START_TYPE_HOT,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface StartType {}
+
+    /**
+     * @hide *
+     */
+    @IntDef(
+            prefix = {"LAUNCH_MODE_"},
+            value = {
+                LAUNCH_MODE_STANDARD,
+                LAUNCH_MODE_SINGLE_TOP,
+                LAUNCH_MODE_SINGLE_INSTANCE,
+                LAUNCH_MODE_SINGLE_TASK,
+                LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LaunchMode {}
+
+    /**
+     * @hide *
+     */
+    @IntDef(
+            prefix = {"START_TIMESTAMP_"},
+            value = {
+                START_TIMESTAMP_LAUNCH,
+                START_TIMESTAMP_JAVA_CLASSLOADING_COMPLETE,
+                START_TIMESTAMP_APPLICATION_ONCREATE,
+                START_TIMESTAMP_BIND_APPLICATION,
+                START_TIMESTAMP_FULLY_DRAWN,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+    public @interface StartupTimestamp {}
+
+    /**
+     * @see #getStartupState
+     * @hide
+     */
+    public void setStartupState(final @StartupState int startupState) {
+        mStartupState = startupState;
+    }
+
+    /**
+     * @see #getPid
+     * @hide
+     */
+    public void setPid(final int pid) {
+        mPid = pid;
+    }
+
+    /**
+     * @see #getRealUid
+     * @hide
+     */
+    public void setRealUid(final int uid) {
+        mRealUid = uid;
+    }
+
+    /**
+     * @see #getPackageUid
+     * @hide
+     */
+    public void setPackageUid(final int uid) {
+        mPackageUid = uid;
+    }
+
+    /**
+     * @see #getDefiningUid
+     * @hide
+     */
+    public void setDefiningUid(final int uid) {
+        mDefiningUid = uid;
+    }
+
+    /**
+     * @see #getProcessName
+     * @hide
+     */
+    public void setProcessName(final String processName) {
+        mProcessName = intern(processName);
+    }
+
+    /**
+     * @see #getReason
+     * @hide
+     */
+    public void setReason(@StartReason int reason) {
+        mReason = reason;
+    }
+
+    /**
+     * @see #getStartupTimestamps
+     * @hide
+     */
+    public void addStartupTimestamp(@StartupTimestamp int key, long timestampNs) {
+        if (mStartupTimestampsNs == null) {
+            mStartupTimestampsNs = new HashMap<@StartupTimestamp Integer, Long>();
+        }
+        mStartupTimestampsNs.put(key, timestampNs);
+    }
+
+    /**
+     * @see #getStartType
+     * @hide
+     */
+    public void setStartType(@StartType int startType) {
+        mStartType = startType;
+    }
+
+    /**
+     * @see #getStartIntent
+     * @hide
+     */
+    public void setIntent(Intent startIntent) {
+        mStartIntent = startIntent;
+    }
+
+    /**
+     * @see #getLaunchMode
+     * @hide
+     */
+    public void setLaunchMode(@LaunchMode int launchMode) {
+        mLaunchMode = launchMode;
+    }
+
+    /**
+     * Current state of startup.
+     *
+     * Can be used to determine whether the object will have additional fields added as it may be
+     * queried before all data is collected.
+     *
+     * <p class="note"> Note: field will always be set and available.</p>
+     */
+    public @StartupState int getStartupState() {
+        return mStartupState;
+    }
+
+    /**
+     * The process id.
+     *
+     * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+     */
+    public int getPid() {
+        return mPid;
+    }
+
+    /**
+     * The kernel user identifier of the process, most of the time the system uses this to do access
+     * control checks. It's typically the uid of the package where the component is running from,
+     * except the case of isolated process, where this field identifies the kernel user identifier
+     * that this process is actually running with, while the {@link #getPackageUid} identifies the
+     * kernel user identifier that is assigned at the package installation time.
+     *
+     * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+     */
+    public int getRealUid() {
+        return mRealUid;
+    }
+
+    /**
+     * Similar to {@link #getRealUid}, it's the kernel user identifier that is assigned at the
+     * package installation time.
+     *
+     * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+     */
+    public int getPackageUid() {
+        return mPackageUid;
+    }
+
+    /**
+     * Return the defining kernel user identifier, maybe different from {@link #getRealUid} and
+     * {@link #getPackageUid}, if an external service has the {@link
+     * android.R.styleable#AndroidManifestService_useAppZygote android:useAppZygote} set to <code>
+     * true</code> and was bound with the flag {@link android.content.Context#BIND_EXTERNAL_SERVICE}
+     * - in this case, this field here will be the kernel user identifier of the external service
+     * provider.
+     *
+     * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+     */
+    public int getDefiningUid() {
+        return mDefiningUid;
+    }
+
+    /**
+     * The actual process name it was running with.
+     *
+     * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+     */
+    public @NonNull String getProcessName() {
+        return mProcessName;
+    }
+
+    /**
+     * The reason code of what triggered the process's start.
+     *
+     * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+     */
+    public @StartReason int getReason() {
+        return mReason;
+    }
+
+    /**
+     * Various clock monotonic timestamps in nanoseconds throughout the startup process.
+     *
+     * <p class="note"> Note: different timestamps will be available for different values of
+     * {@link #getStartupState}:
+     *
+     * (Subsequent rows contain all timestamps of proceding states.)
+     *
+     * For {@link #STARTUP_STATE_STARTED}, timestamp {@link #START_TIMESTAMP_LAUNCH} will be
+     * available.
+     * For {@link #STARTUP_STATE_ERROR}, no additional timestamps are guaranteed available.
+     * For {@link #STARTUP_STATE_FIRST_FRAME_DRAWN}, timestamps
+     * {@link #START_TIMESTAMP_JAVA_CLASSLOADING_COMPLETE}, {@link #START_TIMESTAMP_APPLICATION_ONCREATE},
+     * {@link #START_TIMESTAMP_BIND_APPLICATION}, and {@link #START_TIMESTAMP_FIRST_FRAME} will
+     * additionally be available.
+     *
+     * Timestamp {@link #START_TIMESTAMP_FULLY_DRAWN} is never guaranteed to be available as it is
+     * dependant on devloper calling {@link Activity#reportFullyDrawn}.
+     * </p>
+     */
+    public @NonNull Map<@StartupTimestamp Integer, Long> getStartupTimestamps() {
+        if (mStartupTimestampsNs == null) {
+            mStartupTimestampsNs = new HashMap<@StartupTimestamp Integer, Long>();
+        }
+        return mStartupTimestampsNs;
+    }
+
+    /**
+     * The state of the app at startup.
+     *
+     * <p class="note"> Note: field will be set for {@link #getStartupState} value
+     * {@link #STARTUP_STATE_FIRST_FRAME_DRAWN}. Not guaranteed for other states.</p>
+     */
+    public @StartType int getStartType() {
+        return mStartType;
+    }
+
+    /**
+     * The intent used to launch the application.
+     *
+     * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+     */
+    @SuppressLint("IntentBuilderName")
+    @Nullable
+    public Intent getIntent() {
+        return mStartIntent;
+    }
+
+    /**
+     * An instruction on how the activity should be launched. There are five modes that work in
+     * conjunction with activity flags in Intent objects to determine what should happen when the
+     * activity is called upon to handle an intent.
+     *
+     * Modes:
+     * {@link #LAUNCH_MODE_STANDARD}
+     * {@link #LAUNCH_MODE_SINGLE_TOP}
+     * {@link #LAUNCH_MODE_SINGLE_INSTANCE}
+     * {@link #LAUNCH_MODE_SINGLE_TASK}
+     * {@link #LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK}
+     *
+     * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+     */
+    public @LaunchMode int getLaunchMode() {
+        return mLaunchMode;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mStartupState);
+        dest.writeInt(mPid);
+        dest.writeInt(mRealUid);
+        dest.writeInt(mPackageUid);
+        dest.writeInt(mDefiningUid);
+        dest.writeString(mProcessName);
+        dest.writeInt(mReason);
+        dest.writeInt(mStartupTimestampsNs.size());
+        for (@StartupTimestamp int key : mStartupTimestampsNs.keySet()) {
+            dest.writeInt(key);
+            dest.writeLong(mStartupTimestampsNs.get(key));
+        }
+        dest.writeInt(mStartType);
+        dest.writeParcelable(mStartIntent, flags);
+        dest.writeInt(mLaunchMode);
+    }
+
+    /** @hide */
+    public ApplicationStartInfo() {}
+
+    /** @hide */
+    public ApplicationStartInfo(ApplicationStartInfo other) {
+        mStartupState = other.mStartupState;
+        mPid = other.mPid;
+        mRealUid = other.mRealUid;
+        mPackageUid = other.mPackageUid;
+        mDefiningUid = other.mDefiningUid;
+        mProcessName = other.mProcessName;
+        mReason = other.mReason;
+        mStartupTimestampsNs = other.mStartupTimestampsNs;
+        mStartType = other.mStartType;
+        mStartIntent = other.mStartIntent;
+        mLaunchMode = other.mLaunchMode;
+    }
+
+    private ApplicationStartInfo(@NonNull Parcel in) {
+        mStartupState = in.readInt();
+        mPid = in.readInt();
+        mRealUid = in.readInt();
+        mPackageUid = in.readInt();
+        mDefiningUid = in.readInt();
+        mProcessName = intern(in.readString());
+        mReason = in.readInt();
+        int starupTimestampCount = in.readInt();
+        for (int i = 0; i < starupTimestampCount; i++) {
+            int key = in.readInt();
+            long val = in.readLong();
+            addStartupTimestamp(key, val);
+        }
+        mStartType = in.readInt();
+        mStartIntent =
+                in.readParcelable(Intent.class.getClassLoader(), android.content.Intent.class);
+        mLaunchMode = in.readInt();
+    }
+
+    private static String intern(@Nullable String source) {
+        return source != null ? source.intern() : null;
+    }
+
+    public @NonNull static final Creator<ApplicationStartInfo> CREATOR =
+            new Creator<ApplicationStartInfo>() {
+                @Override
+                public ApplicationStartInfo createFromParcel(Parcel in) {
+                    return new ApplicationStartInfo(in);
+                }
+
+                @Override
+                public ApplicationStartInfo[] newArray(int size) {
+                    return new ApplicationStartInfo[size];
+                }
+            };
+}
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index 03646c6..5e40399 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -121,6 +121,9 @@
     oneway void setInheritShowWhenLocked(in IBinder token, boolean setInheritShownWhenLocked);
     oneway void setTurnScreenOn(in IBinder token, boolean turnScreenOn);
     oneway void reportActivityFullyDrawn(in IBinder token, boolean restoredFromBundle);
+    oneway void overrideActivityTransition(IBinder token, boolean open, int enterAnim, int exitAnim,
+            int backgroundColor);
+    oneway void clearOverrideActivityTransition(IBinder token, boolean open);
     /**
      * Overrides the animation of activity pending transition. This call is not one-way because
      * the method is usually used after startActivity or Activity#finish. If this is non-blocking,
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index c5c3d30..29d80f8 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -19,10 +19,12 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.PendingIntentInfo;
 import android.app.ActivityTaskManager;
+import android.app.ApplicationStartInfo;
 import android.app.ApplicationErrorReport;
 import android.app.ApplicationExitInfo;
 import android.app.ContentProviderHolder;
 import android.app.GrantedUriPermission;
+import android.app.IApplicationStartInfoCompleteListener;
 import android.app.IApplicationThread;
 import android.app.IActivityController;
 import android.app.IAppTask;
@@ -93,7 +95,7 @@
     // below block of transactions.
 
     // Since these transactions are also called from native code, these must be kept in sync with
-    // the ones in frameworks/native/libs/binder/include/binder/IActivityManager.h
+    // the ones in frameworks/native/libs/binder/include_activitymanager/binder/ActivityManager.h
     // =============== Beginning of transactions used on native side as well ======================
     ParcelFileDescriptor openContentUri(in String uriString);
     void registerUidObserver(in IUidObserver observer, int which, int cutpoint,
@@ -485,8 +487,18 @@
 
     // Start of L transactions
     String getTagForIntentSender(in IIntentSender sender, in String prefix);
+
+    /**
+      * Starts a user in the background (i.e., while another user is running in the foreground).
+      *
+      * Notice that a background user is "invisible" and cannot launch activities. Starting on
+      * Android U, all users started with this method are invisible, even profiles (prior to Android
+      * U, profiles started with this method would be visible if its parent was the current user) -
+      * if you want to start a profile visible, you should call {@code startProfile()} instead.
+      */
     @UnsupportedAppUsage
     boolean startUserInBackground(int userid);
+
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
     boolean isInLockTaskMode();
     @UnsupportedAppUsage
@@ -634,6 +646,45 @@
     void appNotResponding(String reason);
 
     /**
+     * Return a list of {@link ApplicationStartInfo} records.
+     *
+     * <p class="note"> Note: System stores historical information in a ring buffer, older
+     * records would be overwritten by newer records. </p>
+     *
+     * @param packageName Optional, an empty value means match all packages belonging to the
+     *                    caller's UID. If this package belongs to another UID, you must hold
+     *                    {@link android.Manifest.permission#DUMP} in order to retrieve it.
+     * @param maxNum      Optional, the maximum number of results should be returned; A value of 0
+     *                    means to ignore this parameter and return all matching records
+     * @param userId      The userId in the multi-user environment.
+     *
+     * @return a list of {@link ApplicationStartInfo} records with the matching criteria, sorted in
+     *         the order from most recent to least recent.
+     */
+    ParceledListSlice<ApplicationStartInfo> getHistoricalProcessStartReasons(String packageName,
+            int maxNum, int userId);
+
+
+    /**
+     * Sets a callback for {@link ApplicationStartInfo} upon completion of collecting startup data.
+     *
+     * <p class="note"> Note: completion of startup is no guaranteed and as such this callback may not occur.</p>
+     *
+     * @param listener    A listener to for the callback upon completion of startup data collection.
+     * @param userId      The userId in the multi-user environment.
+     */
+    void setApplicationStartInfoCompleteListener(IApplicationStartInfoCompleteListener listener,
+            int userId);
+
+
+    /**
+     * Removes callback for {@link ApplicationStartInfo} upon completion of collecting startup data.
+     *
+     * @param userId      The userId in the multi-user environment.
+     */
+    void removeApplicationStartInfoCompleteListener(int userId);
+
+    /**
      * Return a list of {@link ApplicationExitInfo} records.
      *
      * <p class="note"> Note: System stores these historical information in a ring buffer, older
diff --git a/core/java/android/app/IApplicationStartInfoCompleteListener.aidl b/core/java/android/app/IApplicationStartInfoCompleteListener.aidl
new file mode 100644
index 0000000..0f0d919
--- /dev/null
+++ b/core/java/android/app/IApplicationStartInfoCompleteListener.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.app.ApplicationStartInfo;
+
+/**
+ * Notify the client when compilation of app start info is complete.
+ * Will not be called in case of an error that disrupts startup.
+ * @param applicationStartInfo the completed ApplicationStartInfo object.
+ *
+ * @hide
+ */
+interface IApplicationStartInfoCompleteListener {
+    void onApplicationStartInfoComplete(in ApplicationStartInfo applicationStartInfo);
+}
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 824c7cc..e72b141 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -4,7 +4,7 @@
 
 # ActivityManager
 per-file ActivityManager* = file:/services/core/java/com/android/server/am/OWNERS
-per-file ApplicationStartInfo* = file:/services/core/java/com/android/server/am/OWNERS
+per-file *ApplicationStartInfo* = file:/services/core/java/com/android/server/am/OWNERS
 per-file ApplicationErrorReport* = file:/services/core/java/com/android/server/am/OWNERS
 per-file ApplicationExitInfo* = file:/services/core/java/com/android/server/am/OWNERS
 per-file Application.java = file:/services/core/java/com/android/server/am/OWNERS
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 64538ec..6d80a44 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -1570,7 +1570,7 @@
                 new CachedServiceFetcher<SharedConnectivityManager>() {
                     @Override
                     public SharedConnectivityManager createService(ContextImpl ctx) {
-                        return new SharedConnectivityManager(ctx);
+                        return SharedConnectivityManager.create(ctx);
                     }
                 });
 
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index f133c8a..0bdc222 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -218,6 +218,23 @@
             "file_patterns": [
                 "(/|^)GameManager[^/]*", "(/|^)GameMode[^/]*"
             ]
+        },
+        {
+            "name": "HdmiCecTests",
+            "options": [
+                {
+                    "exclude-annotation": "androidx.test.filters.FlakyTest"
+                },
+                {
+                    "exclude-annotation": "org.junit.Ignore"
+                },
+                {
+                    "include-filter": "android.hardware.hdmi"
+                }
+            ],
+            "file_patterns": [
+                "(/|^)DeviceFeature[^/]*", "(/|^)Hdmi[^/]*"
+            ]
         }
     ],
     "presubmit-large": [
diff --git a/core/java/android/app/admin/AccountTypePolicyKey.java b/core/java/android/app/admin/AccountTypePolicyKey.java
new file mode 100644
index 0000000..14494d7
--- /dev/null
+++ b/core/java/android/app/admin/AccountTypePolicyKey.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_ACCOUNT_TYPE;
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_BUNDLE_KEY;
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_KEY;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * Class used to identify a policy that relates to a certain account type
+ * (e.g. {@link DevicePolicyManager#setAccountManagementDisabled}).
+ *
+ * @hide
+ */
+@SystemApi
+public final class AccountTypePolicyKey extends PolicyKey {
+    private static final String ATTR_ACCOUNT_TYPE = "account-type";
+
+    private final String mAccountType;
+
+    /**
+     * @hide
+     */
+    public AccountTypePolicyKey(@NonNull String key, @NonNull String accountType) {
+        super(key);
+        mAccountType = Objects.requireNonNull((accountType));
+    }
+
+    private AccountTypePolicyKey(Parcel source) {
+        super(source.readString());
+        mAccountType = source.readString();
+    }
+
+    /**
+     * @hide
+     */
+    public AccountTypePolicyKey(String key) {
+        super(key);
+        mAccountType = null;
+    }
+
+    /**
+     * Returns the account type this policy relates to.
+     */
+    @NonNull
+    public String getAccountType() {
+        return mAccountType;
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void saveToXml(TypedXmlSerializer serializer) throws IOException {
+        serializer.attribute(/* namespace= */ null, ATTR_POLICY_IDENTIFIER, getIdentifier());
+        serializer.attribute(/* namespace= */ null, ATTR_ACCOUNT_TYPE, mAccountType);
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public AccountTypePolicyKey readFromXml(TypedXmlPullParser parser)
+            throws XmlPullParserException, IOException {
+        String policyKey = parser.getAttributeValue(/* namespace= */ null,
+                ATTR_POLICY_IDENTIFIER);
+        String accountType = parser.getAttributeValue(/* namespace= */ null, ATTR_ACCOUNT_TYPE);
+        return new AccountTypePolicyKey(policyKey, accountType);
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void writeToBundle(Bundle bundle) {
+        bundle.putString(EXTRA_POLICY_KEY, getIdentifier());
+        Bundle extraPolicyParams = new Bundle();
+        extraPolicyParams.putString(EXTRA_ACCOUNT_TYPE, mAccountType);
+        bundle.putBundle(EXTRA_POLICY_BUNDLE_KEY, extraPolicyParams);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        AccountTypePolicyKey other = (AccountTypePolicyKey) o;
+        return Objects.equals(getIdentifier(), other.getIdentifier())
+                && Objects.equals(mAccountType, other.mAccountType);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(getIdentifier(), mAccountType);
+    }
+
+    @Override
+    public String toString() {
+        return "AccountTypePolicyKey{mPolicyKey= " + getIdentifier()
+                + "; mAccountType= " + mAccountType + "}";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(getIdentifier());
+        dest.writeString(mAccountType);
+    }
+
+    @NonNull
+    public static final Creator<AccountTypePolicyKey> CREATOR =
+            new Creator<AccountTypePolicyKey>() {
+                @Override
+                public AccountTypePolicyKey createFromParcel(Parcel source) {
+                    return new AccountTypePolicyKey(source);
+                }
+
+                @Override
+                public AccountTypePolicyKey[] newArray(int size) {
+                    return new AccountTypePolicyKey[size];
+                }
+            };
+}
diff --git a/core/java/android/app/admin/DeviceAdminAuthority.java b/core/java/android/app/admin/DeviceAdminAuthority.java
index 5d1ff11..d363147 100644
--- a/core/java/android/app/admin/DeviceAdminAuthority.java
+++ b/core/java/android/app/admin/DeviceAdminAuthority.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 
 /**
@@ -31,11 +32,18 @@
 public final class DeviceAdminAuthority extends Authority {
 
     /**
+     * Object representing a device admin authority.
+     *
      * @hide
      */
+    @TestApi
+    @NonNull
     public static final DeviceAdminAuthority DEVICE_ADMIN_AUTHORITY = new DeviceAdminAuthority();
 
-    private DeviceAdminAuthority() {}
+    /**
+     * Creates an authority that represents a device admin.
+     */
+    public DeviceAdminAuthority() {}
 
     @Override
     public String toString() {
@@ -44,12 +52,13 @@
 
     @Override
     public boolean equals(@Nullable Object o) {
-        return super.equals(o);
+        if (this == o) return true;
+        return o != null && getClass() == o.getClass();
     }
 
     @Override
     public int hashCode() {
-        return super.hashCode();
+        return 0;
     }
 
     @Override
@@ -65,7 +74,7 @@
             new Creator<DeviceAdminAuthority>() {
                 @Override
                 public DeviceAdminAuthority createFromParcel(Parcel source) {
-                    return new DeviceAdminAuthority();
+                    return DEVICE_ADMIN_AUTHORITY;
                 }
 
                 @Override
diff --git a/core/java/android/app/admin/DevicePolicyIdentifiers.java b/core/java/android/app/admin/DevicePolicyIdentifiers.java
new file mode 100644
index 0000000..f6b070a
--- /dev/null
+++ b/core/java/android/app/admin/DevicePolicyIdentifiers.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+import android.annotation.NonNull;
+import android.os.UserManager;
+
+import java.util.Objects;
+
+/**
+ * Class containing identifiers for policy APIs in {@link DevicePolicyManager}, for example they
+ * will be passed in {@link PolicyUpdatesReceiver#onPolicySetResult} and
+ * {@link PolicyUpdatesReceiver#onPolicyChanged} to communicate updates of a certain policy back
+ * to the admin.
+ */
+public final class DevicePolicyIdentifiers {
+
+    private DevicePolicyIdentifiers() {}
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setAutoTimeZoneEnabled}.
+     */
+    public static final String AUTO_TIMEZONE_POLICY = "autoTimezone";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setPermissionGrantState}.
+     */
+    public static final String PERMISSION_GRANT_POLICY = "permissionGrant";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setLockTaskPackages}.
+     */
+    public static final String LOCK_TASK_POLICY = "lockTask";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setUserControlDisabledPackages}.
+     */
+    public static final String USER_CONTROL_DISABLED_PACKAGES_POLICY =
+            "userControlDisabledPackages";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#addPersistentPreferredActivity}.
+     */
+    public static final String PERSISTENT_PREFERRED_ACTIVITY_POLICY =
+            "persistentPreferredActivity";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setUninstallBlocked}.
+     */
+    public static final String PACKAGE_UNINSTALL_BLOCKED_POLICY = "packageUninstallBlocked";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setApplicationRestrictions}.
+     */
+    public static final String APPLICATION_RESTRICTIONS_POLICY = "applicationRestrictions";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setResetPasswordToken}.
+     */
+    public static final String RESET_PASSWORD_TOKEN_POLICY = "resetPasswordToken";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setAccountManagementDisabled}.
+     */
+    public static final String ACCOUNT_MANAGEMENT_DISABLED_POLICY = "accountManagementDisabled";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setApplicationHidden}.
+     */
+    public static final String APPLICATION_HIDDEN_POLICY = "applicationHidden";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setCameraDisabled}.
+     */
+    public static final String CAMERA_DISABLED_POLICY = "cameraDisabled";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setStatusBarDisabled}.
+     */
+    public static final String STATUS_BAR_DISABLED_POLICY = "statusBarDisabled";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setPackagesSuspended}.
+     */
+    public static final String PACKAGES_SUSPENDED_POLICY = "packagesSuspended";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setKeyguardDisabledFeatures}.
+     */
+    public static final String KEYGUARD_DISABLED_FEATURES_POLICY = "keyguardDisabledFeatures";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setAutoTimeEnabled}.
+     */
+    public static final String AUTO_TIME_POLICY = "autoTime";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setBackupServiceEnabled}.
+     */
+    public static final String BACKUP_SERVICE_POLICY = "backupService";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setPermittedInputMethods}.
+     *
+     * @hide
+     */
+    public static final String PERMITTED_INPUT_METHODS_POLICY = "permittedInputMethods";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setPersonalAppsSuspended}.
+     *
+     * @hide
+     */
+    public static final String PERSONAL_APPS_SUSPENDED_POLICY = "personalAppsSuspended";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setScreenCaptureDisabled}.
+     *
+     * @hide
+     */
+    public static final String SCREEN_CAPTURE_DISABLED_POLICY = "screenCaptureDisabled";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#setTrustAgentConfiguration}.
+     *
+     * @hide
+     */
+    public static final String TRUST_AGENT_CONFIGURATION_POLICY = "trustAgentConfiguration";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#addCrossProfileIntentFilter}.
+     *
+     * @hide
+     */
+    public static final String CROSS_PROFILE_INTENT_FILTER_POLICY = "crossProfileIntentFilter";
+
+    /**
+     * String identifier for {@link DevicePolicyManager#addCrossProfileWidgetProvider}.
+     *
+     * @hide
+     */
+    public static final String CROSS_PROFILE_WIDGET_PROVIDER_POLICY = "crossProfileWidgetProvider";
+
+    /**
+     * @hide
+     */
+    public static final String USER_RESTRICTION_PREFIX = "userRestriction_";
+
+    /**
+     * Returns a string identifier for the provided user restrictions, see
+     * {@link DevicePolicyManager#addUserRestriction} and {@link UserManager} for the list of
+     * available restrictions.
+     */
+    @NonNull
+    public static String getIdentifierForUserRestriction(
+            @UserManager.UserRestrictionKey @NonNull String restriction) {
+        Objects.requireNonNull(restriction);
+        return USER_RESTRICTION_PREFIX + restriction;
+    }
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 409289c..ac65a6b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY;
 import static android.Manifest.permission.QUERY_ADMIN_POLICY;
 import static android.Manifest.permission.SET_TIME;
@@ -3904,6 +3905,15 @@
     public static final int EXEMPT_FROM_HIBERNATION =  3;
 
     /**
+     * Exempt an app from the start foreground service from background with while in user permission
+     * restriction.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION =  4;
+
+    /**
      * Exemptions to platform restrictions, given to an application through
      * {@link #setApplicationExemptions(String, Set)}.
      *
@@ -3913,7 +3923,8 @@
             EXEMPT_FROM_APP_STANDBY,
             EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS,
             EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION,
-            EXEMPT_FROM_HIBERNATION
+            EXEMPT_FROM_HIBERNATION,
+            EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ApplicationExemptionConstants {}
@@ -4029,58 +4040,6 @@
         return MTE_NOT_CONTROLLED_BY_POLICY;
     }
 
-    // TODO: Expose this as a public API
-    /**
-     * @hide
-     */
-    public static final String AUTO_TIMEZONE_POLICY = "autoTimezone";
-
-    // TODO: Expose this as a public API
-    /**
-     * @hide
-     */
-    public static final String PERMISSION_GRANT_POLICY = "permissionGrant";
-
-
-    // TODO: Expose this as a public API
-    /**
-     * @hide
-     */
-    public static final String LOCK_TASK_POLICY = "lockTask";
-
-    // TODO: Expose this as a public API
-    /**
-     * @hide
-     */
-    public static final String USER_CONTROL_DISABLED_PACKAGES_POLICY =
-            "userControlDisabledPackages";
-
-
-    // TODO: Expose this as a public API
-    /**
-     * @hide
-     */
-    public static final String PERSISTENT_PREFERRED_ACTIVITY_POLICY =
-            "persistentPreferredActivity";
-
-    // TODO: Expose this as a public API
-    /**
-     * @hide
-     */
-    public static final String PACKAGE_UNINSTALL_BLOCKED_POLICY = "packageUninstallBlocked";
-
-    // TODO: Expose this as a public API
-    /**
-     * @hide
-     */
-    public static final String APPLICATION_RESTRICTIONS_POLICY = "applicationRestrictions";
-
-    // TODO: Expose this as a public API
-    /**
-     * @hide
-     */
-    public static final String RESET_PASSWORD_TOKEN_POLICY = "resetPasswordToken";
-
     /**
      * This object is a single place to tack on invalidation and disable calls.  All
      * binder caches in this class derive from this Config, so all can be invalidated or
@@ -6900,6 +6859,11 @@
     public static final int KEYGUARD_DISABLE_IRIS = 1 << 8;
 
     /**
+     * Disable all keyguard shortcuts.
+     */
+    public static final int KEYGUARD_DISABLE_SHORTCUTS_ALL = 1 << 9;
+
+    /**
      * NOTE: Please remember to update the DevicePolicyManagerTest's testKeyguardDisabledFeatures
      * CTS test when adding to the list above.
      */
@@ -6942,7 +6906,8 @@
      */
     public static final int ORG_OWNED_PROFILE_KEYGUARD_FEATURES_PARENT_ONLY =
             DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA
-                    | DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS;
+                    | DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS
+                    | DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL;
 
     /**
      * Keyguard features that when set on a normal or organization-owned managed profile, have
@@ -8280,15 +8245,18 @@
      * legacy device admins targeting SDK version {@link android.os.Build.VERSION_CODES#P} or
      * below will be silently ignored.
      *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with or null if
+                     the caller is not a device admin
      * @param disabled Whether or not the camera should be disabled.
      * @throws SecurityException if {@code admin} is not an active administrator or does not use
      *             {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA}.
      */
-    public void setCameraDisabled(@NonNull ComponentName admin, boolean disabled) {
+    @RequiresPermission(value = MANAGE_DEVICE_POLICY_CAMERA, conditional = true)
+    public void setCameraDisabled(@Nullable ComponentName admin, boolean disabled) {
         if (mService != null) {
             try {
-                mService.setCameraDisabled(admin, disabled, mParentInstance);
+                mService.setCameraDisabled(admin, mContext.getPackageName(), disabled,
+                        mParentInstance);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -8759,7 +8727,8 @@
      *            {@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS},
      *            {@link #KEYGUARD_DISABLE_FINGERPRINT},
      *            {@link #KEYGUARD_DISABLE_FACE},
-     *            {@link #KEYGUARD_DISABLE_IRIS}.
+     *            {@link #KEYGUARD_DISABLE_IRIS},
+     *            {@link #KEYGUARD_DISABLE_SHORTCUTS_ALL}.
      * @throws SecurityException if {@code admin} is not an active administrator or does not user
      *             {@link DeviceAdminInfo#USES_POLICY_DISABLE_KEYGUARD_FEATURES}
      */
@@ -12586,6 +12555,33 @@
     }
 
     /**
+     * Returns whether the status bar is disabled/enabled, see {@link #setStatusBarDisabled}.
+     *
+     * <p>Callable by device owner or profile owner of secondary users that is affiliated with the
+     * device owner.
+     *
+     * <p>This policy has no effect in LockTask mode. The behavior of the
+     * status bar in LockTask mode can be configured with
+     * {@link #setLockTaskFeatures(ComponentName, int)}.
+     *
+     * <p>This policy also does not have any effect while on the lock screen, where the status bar
+     * will not be disabled.
+     *
+     * @throws SecurityException if the caller is not the device owner, or a profile owner of
+     * secondary user that is affiliated with the device.
+     * @see #isAffiliatedUser
+     * @see #getSecondaryUsers
+     */
+    public boolean isStatusBarDisabled() {
+        throwIfParentInstance("isStatusBarDisabled");
+        try {
+            return mService.isStatusBarDisabled(mContext.getPackageName());
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Called by the system update service to notify device and profile owners of pending system
      * updates.
      *
diff --git a/core/java/android/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java
index 11b840f..a498913 100644
--- a/core/java/android/app/admin/DevicePolicyResources.java
+++ b/core/java/android/app/admin/DevicePolicyResources.java
@@ -1836,6 +1836,27 @@
              */
             public static final String WORK_PROFILE_BADGED_LABEL =
                     PREFIX + "WORK_PROFILE_BADGED_LABEL";
+
+            /**
+             * Notification title. This notification lets the user know that they will be unable to
+             * receive phone calls or texts until the work profile is turned on.
+             */
+            public static final String WORK_PROFILE_TELEPHONY_PAUSED_TITLE =
+                    PREFIX + "WORK_PROFILE_TELEPHONY_UNAVAILABLE_TITLE";
+
+            /**
+             * Notification text. This notification lets the user know that they will be unable to
+             * receive phone calls or texts until the work profile is turned on.
+             */
+            public static final String WORK_PROFILE_TELEPHONY_PAUSED_BODY =
+                    PREFIX + "WORK_PROFILE_TELEPHONY_UNAVAILABLE_BODY";
+
+            /**
+             * Label for notification button. This button lets the user turn the work profile on.
+             */
+            public static final String WORK_PROFILE_TELEPHONY_PAUSED_TURN_ON_BUTTON =
+                    PREFIX + "TURN_ON_WORK_PROFILE_BUTTON_TEXT";
+
         }
 
         /**
diff --git a/core/java/android/app/admin/DevicePolicyState.java b/core/java/android/app/admin/DevicePolicyState.java
index ee33b00..6de5150 100644
--- a/core/java/android/app/admin/DevicePolicyState.java
+++ b/core/java/android/app/admin/DevicePolicyState.java
@@ -82,6 +82,11 @@
     }
 
     @Override
+    public String toString() {
+        return "DevicePolicyState { mPolicies= " + mPolicies + " }";
+    }
+
+    @Override
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/app/admin/DpcAuthority.java b/core/java/android/app/admin/DpcAuthority.java
index 72c16bc..cd9da9a 100644
--- a/core/java/android/app/admin/DpcAuthority.java
+++ b/core/java/android/app/admin/DpcAuthority.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 
 /**
@@ -31,11 +32,18 @@
 public final class DpcAuthority extends Authority {
 
     /**
+     * Object representing a DPC authority.
+     *
      * @hide
      */
+    @NonNull
+    @TestApi
     public static final DpcAuthority DPC_AUTHORITY = new DpcAuthority();
 
-    private DpcAuthority() {}
+    /**
+     * Creates an authority that represents a DPC admin.
+     */
+    public DpcAuthority() {}
 
     @Override
     public String toString() {
@@ -44,12 +52,13 @@
 
     @Override
     public boolean equals(@Nullable Object o) {
-        return super.equals(o);
+        if (this == o) return true;
+        return o != null && getClass() == o.getClass();
     }
 
     @Override
     public int hashCode() {
-        return super.hashCode();
+        return 0;
     }
 
     @Override
@@ -65,7 +74,7 @@
             new Creator<DpcAuthority>() {
                 @Override
                 public DpcAuthority createFromParcel(Parcel source) {
-                    return new DpcAuthority();
+                    return DPC_AUTHORITY;
                 }
 
                 @Override
diff --git a/core/java/android/app/admin/EnforcingAdmin.java b/core/java/android/app/admin/EnforcingAdmin.java
index 1786467..771794d 100644
--- a/core/java/android/app/admin/EnforcingAdmin.java
+++ b/core/java/android/app/admin/EnforcingAdmin.java
@@ -38,7 +38,7 @@
     private final UserHandle mUserHandle;
 
     /**
-     * @hide
+     * Creates an enforcing admin with the given params.
      */
     public EnforcingAdmin(
             @NonNull String packageName, @NonNull Authority authority,
diff --git a/core/java/android/app/admin/FlagUnion.java b/core/java/android/app/admin/FlagUnion.java
index be924d8..599373f 100644
--- a/core/java/android/app/admin/FlagUnion.java
+++ b/core/java/android/app/admin/FlagUnion.java
@@ -22,8 +22,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.Objects;
-
 /**
  * Class to identify a union resolution mechanism for flag policies, it's used to resolve the
  * enforced policy when being set by multiple admins (see
@@ -35,8 +33,10 @@
 public final class FlagUnion extends ResolutionMechanism<Integer> {
 
     /**
-     * @hide
+     * Union resolution for policies represented as int flags which resolves as the union of all
+     * flags.
      */
+    @NonNull
     public static final FlagUnion FLAG_UNION = new FlagUnion();
 
     private FlagUnion(){};
@@ -49,7 +49,7 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(this);
+        return 0;
     }
 
     @Override
@@ -70,7 +70,7 @@
             new Parcelable.Creator<FlagUnion>() {
                 @Override
                 public FlagUnion createFromParcel(Parcel source) {
-                    return new FlagUnion();
+                    return FLAG_UNION;
                 }
 
                 @Override
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index c86852a..3f66b45 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -141,7 +141,7 @@
 
     boolean requestBugreport(in ComponentName who);
 
-    void setCameraDisabled(in ComponentName who, boolean disabled, boolean parent);
+    void setCameraDisabled(in ComponentName who, String callerPackageName, boolean disabled, boolean parent);
     boolean getCameraDisabled(in ComponentName who, int userHandle, boolean parent);
 
     void setScreenCaptureDisabled(in ComponentName who, boolean disabled, boolean parent);
@@ -379,6 +379,7 @@
 
     boolean setKeyguardDisabled(in ComponentName admin, boolean disabled);
     boolean setStatusBarDisabled(in ComponentName who, boolean disabled);
+    boolean isStatusBarDisabled(in String callerPackage);
     boolean getDoNotAskCredentialsOnBoot();
 
     void notifyPendingSystemUpdate(in SystemUpdateInfo info);
diff --git a/core/java/android/app/admin/IntentFilterPolicyKey.java b/core/java/android/app/admin/IntentFilterPolicyKey.java
index d7eb101..f2f8aa4 100644
--- a/core/java/android/app/admin/IntentFilterPolicyKey.java
+++ b/core/java/android/app/admin/IntentFilterPolicyKey.java
@@ -117,7 +117,7 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(getIdentifier(), mFilter);
+        return Objects.hash(getIdentifier());
     }
 
     @Override
@@ -133,7 +133,7 @@
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeString(getIdentifier());
-        mFilter.writeToParcel(dest, flags);
+        dest.writeTypedObject(mFilter, flags);
     }
 
     @NonNull
diff --git a/core/java/android/app/admin/LockTaskPolicy.java b/core/java/android/app/admin/LockTaskPolicy.java
index 28757df..f5d1cb4 100644
--- a/core/java/android/app/admin/LockTaskPolicy.java
+++ b/core/java/android/app/admin/LockTaskPolicy.java
@@ -22,7 +22,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Objects;
 import java.util.Set;
@@ -67,7 +66,7 @@
     @Override
     @NonNull
     public LockTaskPolicy getValue() {
-        return super.getValue();
+        return this;
     }
 
     /**
@@ -76,6 +75,7 @@
     public LockTaskPolicy(@NonNull Set<String> packages) {
         Objects.requireNonNull(packages);
         mPackages.addAll(packages);
+        setValue(this);
     }
 
     /**
@@ -89,9 +89,13 @@
     }
 
     private LockTaskPolicy(Parcel source) {
-        String[] packages = Objects.requireNonNull(source.readStringArray());
-        mPackages = new HashSet<>(Arrays.stream(packages).toList());
+        int size = source.readInt();
+        mPackages = new HashSet<>();
+        for (int i = 0; i < size; i++) {
+            mPackages.add(source.readString());
+        }
         mFlags = source.readInt();
+        setValue(this);
     }
 
     /**
@@ -100,6 +104,7 @@
     public LockTaskPolicy(LockTaskPolicy policy) {
         mPackages = new HashSet<>(policy.mPackages);
         mFlags = policy.mFlags;
+        setValue(this);
     }
 
     /**
@@ -144,7 +149,10 @@
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeArray(mPackages.toArray(new String[0]));
+        dest.writeInt(mPackages.size());
+        for (String p : mPackages) {
+            dest.writeString(p);
+        }
         dest.writeInt(mFlags);
     }
 
diff --git a/core/java/android/app/admin/MostRecent.java b/core/java/android/app/admin/MostRecent.java
index ac1657189..9df4b53 100644
--- a/core/java/android/app/admin/MostRecent.java
+++ b/core/java/android/app/admin/MostRecent.java
@@ -18,6 +18,7 @@
 
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -32,6 +33,23 @@
 @TestApi
 public final class MostRecent<V> extends ResolutionMechanism<V> {
 
+    /**
+     * Indicates that the most recent setter of the policy wins the resolution.
+     */
+    @NonNull
+    public static final MostRecent<?> MOST_RECENT = new MostRecent<>();
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) return true;
+        return o != null && getClass() == o.getClass();
+    }
+
+    @Override
+    public int hashCode() {
+        return 0;
+    }
+
     @Override
     public String toString() {
         return "MostRecent {}";
@@ -46,15 +64,15 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {}
 
     @NonNull
-    public static final Parcelable.Creator<MostRecent> CREATOR =
-            new Parcelable.Creator<MostRecent>() {
+    public static final Parcelable.Creator<MostRecent<?>> CREATOR =
+            new Parcelable.Creator<MostRecent<?>>() {
                 @Override
-                public MostRecent createFromParcel(Parcel source) {
-                    return new MostRecent();
+                public MostRecent<?> createFromParcel(Parcel source) {
+                    return new MostRecent<>();
                 }
 
                 @Override
-                public MostRecent[] newArray(int size) {
+                public MostRecent<?>[] newArray(int size) {
                     return new MostRecent[size];
                 }
             };
diff --git a/core/java/android/app/admin/MostRestrictive.java b/core/java/android/app/admin/MostRestrictive.java
index adb4744..bbe6eb2 100644
--- a/core/java/android/app/admin/MostRestrictive.java
+++ b/core/java/android/app/admin/MostRestrictive.java
@@ -47,7 +47,8 @@
     /**
      * Returns an ordered list of most to least restrictive values for a certain policy.
      */
-    List<V> getMostToLeastRestrictiveValues() {
+    @NonNull
+    public List<V> getMostToLeastRestrictiveValues() {
         return mMostToLeastRestrictive.stream().map(PolicyValue::getValue).toList();
     }
 
@@ -55,13 +56,17 @@
     public boolean equals(@Nullable Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
-        MostRestrictive other = (MostRestrictive) o;
-        return Objects.equals(mMostToLeastRestrictive, other.mMostToLeastRestrictive);
+        try {
+            MostRestrictive<V> other = (MostRestrictive<V>) o;
+            return Objects.equals(mMostToLeastRestrictive, other.mMostToLeastRestrictive);
+        } catch (ClassCastException exception) {
+            return false;
+        }
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mMostToLeastRestrictive);
+        return mMostToLeastRestrictive.hashCode();
     }
 
     /**
diff --git a/core/java/android/app/admin/PolicyKey.java b/core/java/android/app/admin/PolicyKey.java
index a35f634..84cc66b 100644
--- a/core/java/android/app/admin/PolicyKey.java
+++ b/core/java/android/app/admin/PolicyKey.java
@@ -39,8 +39,7 @@
  *
  * @hide
  */
-// This is ok as the constructor is hidden and all subclasses have implemented
-// Parcelable.
+// This is ok as the constructor is hidden and all subclasses have implemented Parcelable.
 @SuppressLint({"ParcelNotFinal", "ParcelCreator"})
 @SystemApi
 public abstract class PolicyKey implements Parcelable {
diff --git a/core/java/android/app/admin/PolicyState.java b/core/java/android/app/admin/PolicyState.java
index da71bb1..fa76bfa 100644
--- a/core/java/android/app/admin/PolicyState.java
+++ b/core/java/android/app/admin/PolicyState.java
@@ -66,7 +66,7 @@
             PolicyValue<V> policyValue = source.readParcelable(PolicyValue.class.getClassLoader());
             mPoliciesSetByAdmins.put(admin, policyValue);
         }
-        mCurrentResolvedPolicy = source.readParcelable((PolicyValue.class.getClassLoader()));
+        mCurrentResolvedPolicy = source.readParcelable(PolicyValue.class.getClassLoader());
         mResolutionMechanism = source.readParcelable(ResolutionMechanism.class.getClassLoader());
     }
 
@@ -87,7 +87,7 @@
      */
     @Nullable
     public V getCurrentResolvedPolicy() {
-        return mCurrentResolvedPolicy.getValue();
+        return mCurrentResolvedPolicy == null ? null : mCurrentResolvedPolicy.getValue();
     }
 
     /**
diff --git a/core/java/android/app/admin/PolicyUpdateResult.java b/core/java/android/app/admin/PolicyUpdateResult.java
index a6d0ebf..79a76f2 100644
--- a/core/java/android/app/admin/PolicyUpdateResult.java
+++ b/core/java/android/app/admin/PolicyUpdateResult.java
@@ -44,6 +44,9 @@
     /**
      * Result code to indicate that the policy has not been enforced or has changed because another
      * admin has set a conflicting policy on the device.
+     *
+     * <p>The system will automatically try to enforce the policy when it can without additional
+     * calls from the admin.
      */
     public static final int RESULT_FAILURE_CONFLICTING_ADMIN_POLICY = 1;
 
@@ -56,6 +59,22 @@
     public static final int RESULT_POLICY_CLEARED = 2;
 
     /**
+     * Result code to indicate that the policy set by the admin has not been enforced because the
+     * local storage has reached its max limit.
+     *
+     * <p>The system will NOT try to automatically store and enforce this policy again.
+     */
+    public static final int RESULT_FAILURE_STORAGE_LIMIT_REACHED = 3;
+
+    /**
+     * Result code to indicate that the policy set by the admin has not been enforced because of a
+     * permanent hardware limitation/issue.
+     *
+     * <p>The system will NOT try to automatically store and enforce this policy again.
+     */
+    public static final int RESULT_FAILURE_HARDWARE_LIMITATION = 4;
+
+    /**
      * Reason codes for {@link #getResultCode()}.
      *
      * @hide
@@ -65,7 +84,9 @@
             RESULT_FAILURE_UNKNOWN,
             RESULT_SUCCESS,
             RESULT_FAILURE_CONFLICTING_ADMIN_POLICY,
-            RESULT_POLICY_CLEARED
+            RESULT_POLICY_CLEARED,
+            RESULT_FAILURE_STORAGE_LIMIT_REACHED,
+            RESULT_FAILURE_HARDWARE_LIMITATION
     })
     public @interface ResultCode {}
 
diff --git a/core/java/android/app/admin/PolicyUpdatesReceiver.java b/core/java/android/app/admin/PolicyUpdatesReceiver.java
index 67de04c..be32d83 100644
--- a/core/java/android/app/admin/PolicyUpdatesReceiver.java
+++ b/core/java/android/app/admin/PolicyUpdatesReceiver.java
@@ -104,6 +104,14 @@
             "android.app.admin.extra.INTENT_FILTER";
 
     /**
+     * A string extra holding the account type this policy applies to, (see
+     * {@link PolicyUpdatesReceiver#onPolicyChanged} and
+     * {@link PolicyUpdatesReceiver#onPolicySetResult})
+     */
+    public static final String EXTRA_ACCOUNT_TYPE =
+            "android.app.admin.extra.ACCOUNT_TYPE";
+
+    /**
      * @hide
      */
     public static final String EXTRA_POLICY_CHANGED_KEY =
@@ -214,7 +222,7 @@
      * send updates.
      *
      * @param context the running context as per {@link #onReceive}
-     * @param policyKey Key to identify which policy this callback relates to.
+     * @param policyIdentifier Key to identify which policy this callback relates to.
      * @param additionalPolicyParams Bundle containing additional params that may be required to
      *                               identify some of the policy
      *                               (e.g. {@link PolicyUpdatesReceiver#EXTRA_PACKAGE_NAME}
@@ -230,7 +238,7 @@
      */
     public void onPolicySetResult(
             @NonNull Context context,
-            @NonNull String policyKey,
+            @NonNull String policyIdentifier,
             @NonNull Bundle additionalPolicyParams,
             @NonNull TargetUser targetUser,
             @NonNull PolicyUpdateResult policyUpdateResult) {}
@@ -247,7 +255,7 @@
      * send updates.
      *
      * @param context the running context as per {@link #onReceive}
-     * @param policyKey Key to identify which policy this callback relates to.
+     * @param policyIdentifier Key to identify which policy this callback relates to.
      * @param additionalPolicyParams Bundle containing additional params that may be required to
      *                               identify some of the policy
      *                               (e.g. {@link PolicyUpdatesReceiver#EXTRA_PACKAGE_NAME}
@@ -264,7 +272,7 @@
      */
     public void onPolicyChanged(
             @NonNull Context context,
-            @NonNull String policyKey,
+            @NonNull String policyIdentifier,
             @NonNull Bundle additionalPolicyParams,
             @NonNull TargetUser targetUser,
             @NonNull PolicyUpdateResult policyUpdateResult) {}
diff --git a/core/java/android/app/admin/RoleAuthority.java b/core/java/android/app/admin/RoleAuthority.java
index 7fdd118..ccb41c3 100644
--- a/core/java/android/app/admin/RoleAuthority.java
+++ b/core/java/android/app/admin/RoleAuthority.java
@@ -22,7 +22,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Objects;
 import java.util.Set;
@@ -38,15 +37,18 @@
     private final Set<String> mRoles;
 
     /**
-     * @hide
+     * Constructor for a role authority that accepts the list of roles held by the admin.
      */
     public RoleAuthority(@NonNull Set<String> roles) {
         mRoles = new HashSet<>(Objects.requireNonNull(roles));
     }
 
     private RoleAuthority(Parcel source) {
-        String[] roles = source.readStringArray();
-        mRoles = roles == null ? new HashSet<>() : new HashSet<>(Arrays.stream(roles).toList());
+        mRoles = new HashSet<>();
+        int size = source.readInt();
+        for (int i = 0; i < size; i++) {
+            mRoles.add(source.readString());
+        }
     }
 
     /**
@@ -64,7 +66,10 @@
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeArray(mRoles.toArray());
+        dest.writeInt(mRoles.size());
+        for (String role : mRoles) {
+            dest.writeString(role);
+        }
     }
 
     @Override
diff --git a/core/java/android/app/admin/StringSetUnion.java b/core/java/android/app/admin/StringSetUnion.java
index 730e6a2..a95b51e 100644
--- a/core/java/android/app/admin/StringSetUnion.java
+++ b/core/java/android/app/admin/StringSetUnion.java
@@ -17,6 +17,7 @@
 package android.app.admin;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -33,6 +34,23 @@
 @TestApi
 public final class StringSetUnion extends ResolutionMechanism<Set<String>> {
 
+    /**
+     * Union resolution for policies represented {@code Set<String>} which resolves as the union of
+     * all sets.
+     */
+    @NonNull
+    public static final StringSetUnion STRING_SET_UNION = new StringSetUnion();
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) return true;
+        return o != null && getClass() == o.getClass();
+    }
+    @Override
+    public int hashCode() {
+        return 0;
+    }
+
     @Override
     public String toString() {
         return "StringSetUnion {}";
diff --git a/core/java/android/app/admin/TopPriority.java b/core/java/android/app/admin/TopPriority.java
index e712274..edb93b2 100644
--- a/core/java/android/app/admin/TopPriority.java
+++ b/core/java/android/app/admin/TopPriority.java
@@ -17,11 +17,12 @@
 package android.app.admin;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
@@ -36,26 +37,56 @@
 @TestApi
 public final class TopPriority<V> extends ResolutionMechanism<V> {
 
-    private final List<String> mHighestToLowestPriorityAuthorities;
+    private final List<Authority> mHighestToLowestPriorityAuthorities;
 
     /**
      * @hide
      */
-    public TopPriority(@NonNull List<String> highestToLowestPriorityAuthorities) {
+    public TopPriority(@NonNull List<Authority> highestToLowestPriorityAuthorities) {
         mHighestToLowestPriorityAuthorities = Objects.requireNonNull(
                 highestToLowestPriorityAuthorities);
     }
 
     /**
+     * Returns an object with the specified order of highest to lowest authorities.
+     */
+    private TopPriority(@NonNull Parcel source) {
+        mHighestToLowestPriorityAuthorities = new ArrayList<>();
+        int size = source.readInt();
+        for (int i = 0; i < size; i++) {
+            mHighestToLowestPriorityAuthorities.add(
+                    source.readParcelable(Authority.class.getClassLoader()));
+        }
+    }
+
+    /**
      * Returns an ordered list of authorities from highest priority to lowest priority for a
      * certain policy.
      */
     @NonNull
-    List<String> getHighestToLowestPriorityAuthorities() {
+    public List<Authority> getHighestToLowestPriorityAuthorities() {
         return mHighestToLowestPriorityAuthorities;
     }
 
     @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        try {
+            TopPriority<V> other = (TopPriority<V>) o;
+            return Objects.equals(
+                    mHighestToLowestPriorityAuthorities, other.mHighestToLowestPriorityAuthorities);
+        } catch (ClassCastException exception) {
+            return false;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return mHighestToLowestPriorityAuthorities.hashCode();
+    }
+
+    @Override
     public String toString() {
         return "TopPriority { mHighestToLowestPriorityAuthorities= "
                 + mHighestToLowestPriorityAuthorities + " }";
@@ -67,7 +98,10 @@
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeStringArray(mHighestToLowestPriorityAuthorities.toArray(new String[0]));
+        dest.writeInt(mHighestToLowestPriorityAuthorities.size());
+        for (Authority authority : mHighestToLowestPriorityAuthorities) {
+            dest.writeParcelable(authority, flags);
+        }
     }
 
     @NonNull
@@ -75,9 +109,7 @@
             new Parcelable.Creator<TopPriority<?>>() {
                 @Override
                 public TopPriority<?> createFromParcel(Parcel source) {
-                    String[] highestToLowestPriorityAuthorities = source.readStringArray();
-                    return new TopPriority<>(
-                            Arrays.stream(highestToLowestPriorityAuthorities).toList());
+                    return new TopPriority<>(source);
                 }
 
                 @Override
diff --git a/core/java/android/app/admin/UnknownAuthority.java b/core/java/android/app/admin/UnknownAuthority.java
index 4492b96..fdad898 100644
--- a/core/java/android/app/admin/UnknownAuthority.java
+++ b/core/java/android/app/admin/UnknownAuthority.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 
 /**
@@ -32,11 +33,19 @@
 public final class UnknownAuthority extends Authority {
 
     /**
+     * Object representing an unknown authority.
+     *
      * @hide
      */
+    @TestApi
+    @NonNull
     public static final UnknownAuthority UNKNOWN_AUTHORITY = new UnknownAuthority();
 
-    private UnknownAuthority() {}
+    /**
+     * Creates an authority that represents an admin that can set a policy but
+     * doesn't have a known authority (e.g. a system components).
+     */
+    public UnknownAuthority() {}
 
     @Override
     public String toString() {
@@ -45,12 +54,13 @@
 
     @Override
     public boolean equals(@Nullable Object o) {
-        return super.equals(o);
+        if (this == o) return true;
+        return o != null && getClass() == o.getClass();
     }
 
     @Override
     public int hashCode() {
-        return super.hashCode();
+        return 0;
     }
 
     @Override
@@ -66,7 +76,7 @@
             new Creator<UnknownAuthority>() {
                 @Override
                 public UnknownAuthority createFromParcel(Parcel source) {
-                    return new UnknownAuthority();
+                    return UNKNOWN_AUTHORITY;
                 }
 
                 @Override
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index ffe73d6..7be00a0 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -679,8 +679,9 @@
     public static final int PRIVATE_FLAG_PROFILEABLE_BY_SHELL = 1 << 23;
 
     /**
-     * Indicates whether this package requires access to non-SDK APIs.
-     * Only system apps and tests are allowed to use this property.
+     * Indicates whether this application has declared its user data as fragile,
+     * causing the system to prompt the user on whether to keep the user data
+     * on uninstall.
      * @hide
      */
     public static final int PRIVATE_FLAG_HAS_FRAGILE_USER_DATA = 1 << 24;
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 8f864f4..cfd291f 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -30,8 +30,6 @@
 import static android.content.pm.PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
 import static android.content.pm.PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL;
 
-import static com.android.internal.util.XmlUtils.writeStringAttribute;
-
 import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.CurrentTimeMillisLong;
@@ -84,7 +82,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.ExceptionUtils;
-import android.util.Log;
 
 import com.android.internal.content.InstallLocationUtils;
 import com.android.internal.util.ArrayUtils;
@@ -92,7 +89,6 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.modules.utils.TypedXmlSerializer;
 
 import java.io.Closeable;
 import java.io.File;
@@ -2313,11 +2309,6 @@
         private final ArrayMap<String, Integer> mPermissionStates;
 
         /**
-         * @see #getFinalPermissionStates()
-         */
-        private ArrayMap<String, Integer> mFinalPermissionStates;
-
-        /**
          * Construct parameters for a new package install session.
          *
          * @param mode one of {@link #MODE_FULL_INSTALL} or
@@ -2563,11 +2554,6 @@
                         + (permissionName == null ? "null" : "empty"));
             }
 
-            if (mFinalPermissionStates != null) {
-                Log.wtf(TAG, "Requested permission " + permissionName + " but final permissions"
-                        + " were already decided for this session: " + mFinalPermissionStates);
-            }
-
             switch (state) {
                 case PERMISSION_STATE_DEFAULT:
                     mPermissionStates.remove(permissionName);
@@ -3008,48 +2994,10 @@
             }
         }
 
-        /**
-         * This is only for use by system server. If you need the actual grant state, use
-         * {@link #getFinalPermissionStates()}.
-         * <p/>
-         * This is implemented here to avoid exposing the raw permission sets to external callers,
-         * so that enforcement done in the either of the final methods is the single source of truth
-         * for default grant/deny policy.
-         *
-         * @hide
-         */
-        public void writePermissionStateXml(@NonNull TypedXmlSerializer out,
-                @NonNull String grantTag, @NonNull String denyTag, @NonNull String attrName)
-                throws IOException {
-            for (int index = 0; index < mPermissionStates.size(); index++) {
-                var permissionName = mPermissionStates.keyAt(index);
-                var state = mPermissionStates.valueAt(index);
-                String tag = state == PERMISSION_STATE_GRANTED ? grantTag : denyTag;
-                out.startTag(null, tag);
-                writeStringAttribute(out, attrName, permissionName);
-                out.endTag(null, tag);
-            }
-        }
-
-        /**
-         * Snapshot of final permission states taken when this method is first called, to separate
-         * what the caller wanted and the effective state that should be applied to the session.
-         *
-         * This prevents someone from adding more permissions after the fact.
-         *
-         * @hide
-         */
+        /** @hide */
         @NonNull
-        public ArrayMap<String, Integer> getFinalPermissionStates() {
-            if (mFinalPermissionStates == null) {
-                mFinalPermissionStates = new ArrayMap<>(mPermissionStates);
-                if (!mFinalPermissionStates.containsKey(
-                        Manifest.permission.USE_FULL_SCREEN_INTENT)) {
-                    mFinalPermissionStates.put(Manifest.permission.USE_FULL_SCREEN_INTENT,
-                            PERMISSION_STATE_GRANTED);
-                }
-            }
-            return mFinalPermissionStates;
+        public ArrayMap<String, Integer> getPermissionStates() {
+            return mPermissionStates;
         }
 
         /** @hide */
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 7164dc3..17e81e5 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -1429,6 +1429,7 @@
      * hdrConversionMode.conversionMode is not {@link HdrConversionMode#HDR_CONVERSION_FORCE}.
      *
      * @see #getHdrConversionMode
+     * @see #getHdrConversionModeSetting
      * @see #getSupportedHdrOutputTypes
      * @hide
      */
@@ -1440,9 +1441,14 @@
 
     /**
      * Returns the {@link HdrConversionMode} of the device, which is set by the user.
+
+     * The HDR conversion mode chosen by user which considers the app override is returned. Apps can
+     * override HDR conversion using
+     * {@link android.view.WindowManager.LayoutParams#disableHdrConversion}.
      *
      * @see #setHdrConversionMode
      * @see #getSupportedHdrOutputTypes
+     * @see #getHdrConversionModeSetting()
      * @hide
      */
     @TestApi
@@ -1452,6 +1458,23 @@
     }
 
     /**
+     * Returns the {@link HdrConversionMode} of the device, which is set by the user.
+
+     * The HDR conversion mode chosen by user is returned irrespective of whether HDR conversion
+     * is disabled by an app.
+     *
+     * @see #setHdrConversionMode
+     * @see #getSupportedHdrOutputTypes
+     * @see #getHdrConversionMode()
+     * @hide
+     */
+    @TestApi
+    @NonNull
+    public HdrConversionMode getHdrConversionModeSetting() {
+        return mGlobal.getHdrConversionModeSetting();
+    }
+
+    /**
      * Returns the HDR output types supported by the device.
      *
      * @see #getHdrConversionMode
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index d9db177..4a992f3 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -990,6 +990,19 @@
     }
 
     /**
+     * Returns the {@link HdrConversionMode} of the device, which is set by the user.
+     * The HDR conversion mode chosen by user is returned irrespective of whether HDR conversion
+     * is disabled by an app.
+     */
+    public HdrConversionMode getHdrConversionModeSetting() {
+        try {
+            return mDm.getHdrConversionModeSetting();
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns the {@link HdrConversionMode} of the device.
      */
     public HdrConversionMode getHdrConversionMode() {
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 2bd0606..d6df033 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -234,13 +234,14 @@
      * @param requestedMinimalPostProcessing The preferred minimal post processing setting for the
      * display. This is true when there is at least one visible window that wants minimal post
      * processng on.
+     * @param disableHdrConversion The preferred HDR conversion setting for the window.
      * @param inTraversal True if called from WindowManagerService during a window traversal
      * prior to call to performTraversalInTransactionFromWindowManager.
      */
     public abstract void setDisplayProperties(int displayId, boolean hasContent,
             float requestedRefreshRate, int requestedModeId, float requestedMinRefreshRate,
             float requestedMaxRefreshRate, boolean requestedMinimalPostProcessing,
-            boolean inTraversal);
+            boolean disableHdrConversion, boolean inTraversal);
 
     /**
      * Applies an offset to the contents of a display, for example to avoid burn-in.
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 0a44f85..a3b7b51 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -180,6 +180,7 @@
     @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
                 + ".permission.MODIFY_HDR_CONVERSION_MODE)")
     void setHdrConversionMode(in HdrConversionMode hdrConversionMode);
+    HdrConversionMode getHdrConversionModeSetting();
     HdrConversionMode getHdrConversionMode();
     int[] getSupportedHdrOutputTypes();
 
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 13d54ef..c021cad 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -2968,15 +2968,13 @@
             "android.os.action.LOW_POWER_STANDBY_ENABLED_CHANGED";
 
     /**
-     * Intent that is broadcast when Low Power Standby is enabled or disabled.
+     * Intent that is broadcast when Low Power Standby policy is changed.
      * This broadcast is only sent to registered receivers.
      *
-     * @see #getLowPowerStandbyPolicy
-     * @see #setLowPowerStandbyPolicy
-     * @hide
+     * @see #isExemptFromLowPowerStandby()
+     * @see #isAllowedInLowPowerStandby(int)
+     * @see #isAllowedInLowPowerStandby(String)
      */
-    @SystemApi
-    @RequiresPermission(android.Manifest.permission.MANAGE_LOW_POWER_STANDBY)
     @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_LOW_POWER_STANDBY_POLICY_CHANGED =
             "android.os.action.LOW_POWER_STANDBY_POLICY_CHANGED";
diff --git a/core/java/android/speech/IRecognitionService.aidl b/core/java/android/speech/IRecognitionService.aidl
index ad3ad7a..cc64c45 100644
--- a/core/java/android/speech/IRecognitionService.aidl
+++ b/core/java/android/speech/IRecognitionService.aidl
@@ -67,12 +67,15 @@
      * given recognizerIntent. For more information see {@link #startListening} and
      * {@link RecognizerIntent}.
      */
-    void checkRecognitionSupport(in Intent recognizerIntent, in IRecognitionSupportCallback listener);
+    void checkRecognitionSupport(
+        in Intent recognizerIntent,
+        in AttributionSource attributionSource,
+        in IRecognitionSupportCallback listener);
 
     /**
      * Requests RecognitionService to download the support for the given recognizerIntent. For more
      * information see {@link #checkRecognitionSupport},  {@link #startListening} and
      * {@link RecognizerIntent}.
      */
-    void triggerModelDownload(in Intent recognizerIntent);
+    void triggerModelDownload(in Intent recognizerIntent, in AttributionSource attributionSource);
 }
diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
index a5dbdd7..0b0b3b56 100644
--- a/core/java/android/speech/RecognitionService.java
+++ b/core/java/android/speech/RecognitionService.java
@@ -110,13 +110,14 @@
                     dispatchClearCallback((IRecognitionListener) msg.obj);
                     break;
                 case MSG_CHECK_RECOGNITION_SUPPORT:
-                    Pair<Intent, IRecognitionSupportCallback> intentAndListener =
-                            (Pair<Intent, IRecognitionSupportCallback>) msg.obj;
+                    CheckRecognitionSupportArgs checkArgs = (CheckRecognitionSupportArgs) msg.obj;
                     dispatchCheckRecognitionSupport(
-                            intentAndListener.first, intentAndListener.second);
+                            checkArgs.mIntent, checkArgs.callback, checkArgs.mAttributionSource);
                     break;
                 case MSG_TRIGGER_MODEL_DOWNLOAD:
-                    dispatchTriggerModelDownload((Intent) msg.obj);
+                    Pair<Intent, AttributionSource> params =
+                            (Pair<Intent, AttributionSource>) msg.obj;
+                    dispatchTriggerModelDownload(params.first, params.second);
                     break;
             }
         }
@@ -211,12 +212,18 @@
     }
 
     private void dispatchCheckRecognitionSupport(
-            Intent intent, IRecognitionSupportCallback callback) {
-        RecognitionService.this.onCheckRecognitionSupport(intent, new SupportCallback(callback));
+            Intent intent, IRecognitionSupportCallback callback,
+            AttributionSource attributionSource) {
+        RecognitionService.this.onCheckRecognitionSupport(
+                intent,
+                attributionSource,
+                new SupportCallback(callback));
     }
 
-    private void dispatchTriggerModelDownload(Intent intent) {
-        RecognitionService.this.onTriggerModelDownload(intent);
+    private void dispatchTriggerModelDownload(
+            Intent intent,
+            AttributionSource attributionSource) {
+        RecognitionService.this.onTriggerModelDownload(intent, attributionSource);
     }
 
     private static class StartListeningArgs {
@@ -233,6 +240,21 @@
         }
     }
 
+    private static class CheckRecognitionSupportArgs {
+        public final Intent mIntent;
+        public final IRecognitionSupportCallback callback;
+        public final AttributionSource mAttributionSource;
+
+        private CheckRecognitionSupportArgs(
+                Intent intent,
+                IRecognitionSupportCallback callback,
+                AttributionSource attributionSource) {
+            this.mIntent = intent;
+            this.callback = callback;
+            this.mAttributionSource = attributionSource;
+        }
+    }
+
     /**
      * Notifies the service that it should start listening for speech.
      *
@@ -298,6 +320,26 @@
     }
 
     /**
+     * Queries the service on whether it would support a {@link #onStartListening(Intent, Callback)}
+     * for the same {@code recognizerIntent}.
+     *
+     * <p>The service will notify the caller about the level of support or error via
+     * {@link SupportCallback}.
+     *
+     * <p>If the service does not offer the support check it will notify the caller with
+     * {@link SpeechRecognizer#ERROR_CANNOT_CHECK_SUPPORT}.
+     *
+     * <p>Provides the calling AttributionSource to the service implementation so that permissions
+     * and bandwidth could be correctly blamed.</p>
+     */
+    public void onCheckRecognitionSupport(
+            @NonNull Intent recognizerIntent,
+            @NonNull AttributionSource attributionSource,
+            @NonNull SupportCallback supportCallback) {
+        onCheckRecognitionSupport(recognizerIntent, supportCallback);
+    }
+
+    /**
      * Requests the download of the recognizer support for {@code recognizerIntent}.
      */
     public void onTriggerModelDownload(@NonNull Intent recognizerIntent) {
@@ -306,6 +348,18 @@
         }
     }
 
+    /**
+     * Requests the download of the recognizer support for {@code recognizerIntent}.
+     *
+     * <p>Provides the calling AttributionSource to the service implementation so that permissions
+     * and bandwidth could be correctly blamed.</p>
+     */
+    public void onTriggerModelDownload(
+            @NonNull Intent recognizerIntent,
+            @NonNull AttributionSource attributionSource) {
+        onTriggerModelDownload(recognizerIntent);
+    }
+
     @Override
     @SuppressLint("MissingNullability")
     public Context createContext(@NonNull ContextParams contextParams) {
@@ -524,7 +578,8 @@
     public static class SupportCallback {
         private final IRecognitionSupportCallback mCallback;
 
-        private SupportCallback(IRecognitionSupportCallback callback) {
+        private SupportCallback(
+                IRecognitionSupportCallback callback) {
             this.mCallback = callback;
         }
 
@@ -596,22 +651,27 @@
 
         @Override
         public void checkRecognitionSupport(
-                Intent recognizerIntent, IRecognitionSupportCallback callback) {
+                Intent recognizerIntent,
+                @NonNull AttributionSource attributionSource,
+                IRecognitionSupportCallback callback) {
             final RecognitionService service = mServiceRef.get();
             if (service != null) {
                 service.mHandler.sendMessage(
                         Message.obtain(service.mHandler, MSG_CHECK_RECOGNITION_SUPPORT,
-                                Pair.create(recognizerIntent, callback)));
+                                new CheckRecognitionSupportArgs(
+                                        recognizerIntent, callback, attributionSource)));
             }
         }
 
         @Override
-        public void triggerModelDownload(Intent recognizerIntent) {
+        public void triggerModelDownload(
+                Intent recognizerIntent, @NonNull AttributionSource attributionSource) {
             final RecognitionService service = mServiceRef.get();
             if (service != null) {
                 service.mHandler.sendMessage(
                         Message.obtain(
-                                service.mHandler, MSG_TRIGGER_MODEL_DOWNLOAD, recognizerIntent));
+                                service.mHandler, MSG_TRIGGER_MODEL_DOWNLOAD,
+                                Pair.create(recognizerIntent, attributionSource)));
             }
         }
 
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index 33c5b5a..9c46e55 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -663,6 +663,7 @@
         try {
             mService.checkRecognitionSupport(
                     recognizerIntent,
+                    mContext.getAttributionSource(),
                     new InternalSupportCallback(callbackExecutor, recognitionSupportCallback));
             if (DBG) Log.d(TAG, "service support command succeeded");
         } catch (final RemoteException e) {
@@ -676,7 +677,7 @@
             return;
         }
         try {
-            mService.triggerModelDownload(recognizerIntent);
+            mService.triggerModelDownload(recognizerIntent, mContext.getAttributionSource());
         } catch (final RemoteException e) {
             Log.e(TAG, "downloadModel() failed", e);
             mListener.onError(ERROR_CLIENT);
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 680e8f7..a746dc6 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -96,12 +96,6 @@
     public static final String SETTINGS_NEW_KEYBOARD_UI = "settings_new_keyboard_ui";
 
     /**
-     * Enable new shortcut list UI
-     * @hide
-     */
-    public static final String SETTINGS_NEW_KEYBOARD_SHORTCUT = "settings_new_keyboard_shortcut";
-
-    /**
      * Enable new modifier key settings UI
      * @hide
      */
@@ -227,7 +221,6 @@
         DEFAULT_FLAGS.put(SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, "true");
         DEFAULT_FLAGS.put(SETTINGS_AUTO_TEXT_WRAPPING, "false");
         DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_UI, "false");
-        DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_SHORTCUT, "false");
         DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_MODIFIER_KEY, "false");
         DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD, "false");
         DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE, "false");
@@ -255,7 +248,6 @@
         PERSISTENT_FLAGS.add(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME);
         PERSISTENT_FLAGS.add(SETTINGS_AUTO_TEXT_WRAPPING);
         PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_UI);
-        PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_SHORTCUT);
         PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_MODIFIER_KEY);
         PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_TRACKPAD);
         PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE);
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 61582cd..1a5613e 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1351,7 +1351,7 @@
     private int mDeviceId;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int mSource;
-    private int mDisplayId;
+    private int mDisplayId = INVALID_DISPLAY;
     private @Nullable byte[] mHmac;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     private int mMetaState;
@@ -1602,7 +1602,6 @@
         mScanCode = scancode;
         mFlags = flags;
         mSource = source;
-        mDisplayId = INVALID_DISPLAY;
     }
 
     /**
@@ -1628,7 +1627,6 @@
         mDeviceId = deviceId;
         mFlags = flags;
         mSource = InputDevice.SOURCE_KEYBOARD;
-        mDisplayId = INVALID_DISPLAY;
     }
 
     /**
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 85365b3..a3c0d7e 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -742,13 +742,6 @@
      */
     public static final int POWER_MODE_ON_SUSPEND = 4;
 
-    /**
-     * internal representation of how to interpret pixel value, used only to convert to ColorSpace.
-     */
-    private static final int INTERNAL_DATASPACE_SRGB = 142671872;
-    private static final int INTERNAL_DATASPACE_DISPLAY_P3 = 143261696;
-    private static final int INTERNAL_DATASPACE_SCRGB = 411107328;
-
     private void assignNativeObject(long nativeObject, String callsite) {
         if (mNativeObject != 0) {
             release();
@@ -2195,18 +2188,9 @@
         ColorSpace[] colorSpaces = { srgb, srgb };
         if (dataspaces.length == 2) {
             for (int i = 0; i < 2; ++i) {
-                switch(dataspaces[i]) {
-                    case INTERNAL_DATASPACE_DISPLAY_P3:
-                        colorSpaces[i] = ColorSpace.get(ColorSpace.Named.DISPLAY_P3);
-                        break;
-                    case INTERNAL_DATASPACE_SCRGB:
-                        colorSpaces[i] = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB);
-                        break;
-                    case INTERNAL_DATASPACE_SRGB:
-                    // Other dataspace is not recognized, use SRGB color space instead,
-                    // the default value of the array is already SRGB, thus do nothing.
-                    default:
-                        break;
+                ColorSpace cs = ColorSpace.getFromDataSpace(dataspaces[i]);
+                if (cs != null) {
+                    colorSpaces[i] = cs;
                 }
             }
         }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d0f095c..480abe0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3741,7 +3741,7 @@
         }
 
         if (mAttachInfo.mContentCaptureEvents != null) {
-            notifyContentCatpureEvents();
+            notifyContentCaptureEvents();
         }
 
         mIsInTraversal = false;
@@ -3782,7 +3782,7 @@
         Trace.traceEnd(Trace.TRACE_TAG_VIEW);
     }
 
-    private void notifyContentCatpureEvents() {
+    private void notifyContentCaptureEvents() {
         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents");
         try {
             MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 0f68cd0..82b390e 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -3569,6 +3569,22 @@
          */
         public float preferredMaxDisplayRefreshRate;
 
+        /** Indicates whether this window wants the HDR conversion is disabled. */
+        public static final int DISPLAY_FLAG_DISABLE_HDR_CONVERSION =  1 << 0;
+
+        /**
+         * Flags that can be used to set display properties.
+         *
+         * @hide
+         */
+        @IntDef(flag = true, prefix = "DISPLAY_FLAG_", value = {
+                DISPLAY_FLAG_DISABLE_HDR_CONVERSION,
+        })
+        public @interface DisplayFlags {}
+
+        @DisplayFlags
+        private int mDisplayFlags;
+
         /**
          * An internal annotation for flags that can be specified to {@link #systemUiVisibility}
          * and {@link #subtreeSystemUiVisibility}.
@@ -4286,6 +4302,24 @@
             preservePreviousSurfaceInsets = preservePrevious;
         }
 
+        /** Returns whether the HDR conversion is enabled for the window */
+        public boolean isHdrConversionEnabled() {
+            return ((mDisplayFlags & DISPLAY_FLAG_DISABLE_HDR_CONVERSION) == 0);
+        }
+
+        /**
+         * Enables/disables the HDR conversion for the window.
+         *
+         * By default, the HDR conversion is enabled for the window.
+         */
+        public void setHdrConversionEnabled(boolean enabled) {
+            if (!enabled) {
+                mDisplayFlags |= DISPLAY_FLAG_DISABLE_HDR_CONVERSION;
+            } else {
+                mDisplayFlags &= ~DISPLAY_FLAG_DISABLE_HDR_CONVERSION;
+            }
+        }
+
         /**
          * <p>Set the color mode of the window. Setting the color mode might
          * override the window's pixel {@link WindowManager.LayoutParams#format format}.</p>
@@ -4460,6 +4494,7 @@
             out.writeTypedArray(providedInsets, 0 /* parcelableFlags */);
             checkNonRecursiveParams();
             out.writeTypedArray(paramsForRotation, 0 /* parcelableFlags */);
+            out.writeInt(mDisplayFlags);
         }
 
         public static final @android.annotation.NonNull Parcelable.Creator<LayoutParams> CREATOR
@@ -4530,6 +4565,7 @@
             mWallpaperTouchEventsEnabled = in.readBoolean();
             providedInsets = in.createTypedArray(InsetsFrameProvider.CREATOR);
             paramsForRotation = in.createTypedArray(LayoutParams.CREATOR);
+            mDisplayFlags = in.readInt();
         }
 
         @SuppressWarnings({"PointlessBitwiseExpression"})
@@ -4565,6 +4601,8 @@
         /** {@hide} */
         public static final int PREFERRED_REFRESH_RATE_CHANGED = 1 << 21;
         /** {@hide} */
+        public static final int DISPLAY_FLAGS_CHANGED = 1 << 22;
+        /** {@hide} */
         public static final int PREFERRED_DISPLAY_MODE_ID = 1 << 23;
         /** {@hide} */
         public static final int ACCESSIBILITY_ANCHOR_CHANGED = 1 << 24;
@@ -4724,6 +4762,11 @@
                 changes |= PREFERRED_MAX_DISPLAY_REFRESH_RATE;
             }
 
+            if (mDisplayFlags != o.mDisplayFlags) {
+                mDisplayFlags = o.mDisplayFlags;
+                changes |= DISPLAY_FLAGS_CHANGED;
+            }
+
             if (systemUiVisibility != o.systemUiVisibility
                     || subtreeSystemUiVisibility != o.subtreeSystemUiVisibility) {
                 systemUiVisibility = o.systemUiVisibility;
@@ -4979,6 +5022,10 @@
                 sb.append(" preferredMaxDisplayRefreshRate=");
                 sb.append(preferredMaxDisplayRefreshRate);
             }
+            if (mDisplayFlags != 0) {
+                sb.append(" displayFlags=0x");
+                sb.append(Integer.toHexString(mDisplayFlags));
+            }
             if (hasSystemUiListeners) {
                 sb.append(" sysuil=");
                 sb.append(hasSystemUiListeners);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index e87cd12..d1c4201 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -168,6 +168,9 @@
     private static final String TAG = "Editor";
     private static final boolean DEBUG_UNDO = false;
 
+    // TODO(nona): Make this configurable.
+    private static final boolean FLAG_USE_NEW_CONTEXT_MENU = false;
+
     // Specifies whether to use the magnifier when pressing the insertion or selection handles.
     private static final boolean FLAG_USE_MAGNIFIER = true;
 
@@ -198,16 +201,6 @@
     private static final int ACTION_MODE_MENU_ITEM_ORDER_SECONDARY_ASSIST_ACTIONS_START = 50;
     private static final int ACTION_MODE_MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 100;
 
-    // Ordering constants used to place the Context Menu items in their menu.
-    private static final int CONTEXT_MENU_ITEM_ORDER_UNDO = 2;
-    private static final int CONTEXT_MENU_ITEM_ORDER_REDO = 3;
-    private static final int CONTEXT_MENU_ITEM_ORDER_CUT = 4;
-    private static final int CONTEXT_MENU_ITEM_ORDER_COPY = 5;
-    private static final int CONTEXT_MENU_ITEM_ORDER_PASTE = 6;
-    private static final int CONTEXT_MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT = 7;
-    private static final int CONTEXT_MENU_ITEM_ORDER_SELECT_ALL = 8;
-    private static final int CONTEXT_MENU_ITEM_ORDER_SHARE = 9;
-    private static final int CONTEXT_MENU_ITEM_ORDER_AUTOFILL = 10;
     private static final int CONTEXT_MENU_ITEM_ORDER_REPLACE = 11;
 
     private static final int CONTEXT_MENU_GROUP_UNDO_REDO = Menu.FIRST;
@@ -3142,56 +3135,76 @@
             }
         }
 
-        menu.setOptionalIconsVisible(true);
+        final int menuItemOrderUndo = 2;
+        final int menuItemOrderRedo = 3;
+        final int menuItemOrderCut = 4;
+        final int menuItemOrderCopy = 5;
+        final int menuItemOrderPaste = 6;
+        final int menuItemOrderPasteAsPlainText;
+        final int menuItemOrderSelectAll;
+        final int menuItemOrderShare;
+        final int menuItemOrderAutofill;
+        if (FLAG_USE_NEW_CONTEXT_MENU) {
+            menuItemOrderPasteAsPlainText = 7;
+            menuItemOrderSelectAll = 8;
+            menuItemOrderShare = 9;
+            menuItemOrderAutofill = 10;
 
-        final int keyboard = mTextView.getResources().getConfiguration().keyboard;
-        menu.setQwertyMode(keyboard == Configuration.KEYBOARD_QWERTY);
+            menu.setOptionalIconsVisible(true);
+            menu.setGroupDividerEnabled(true);
 
-        menu.setGroupDividerEnabled(true);
+            final int keyboard = mTextView.getResources().getConfiguration().keyboard;
+            menu.setQwertyMode(keyboard == Configuration.KEYBOARD_QWERTY);
+        } else {
+            menuItemOrderShare = 7;
+            menuItemOrderSelectAll = 8;
+            menuItemOrderAutofill = 10;
+            menuItemOrderPasteAsPlainText = 11;
+        }
 
-        menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_UNDO, CONTEXT_MENU_ITEM_ORDER_UNDO,
+        menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_UNDO, menuItemOrderUndo,
                 com.android.internal.R.string.undo)
                 .setAlphabeticShortcut('z')
                 .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
                 .setEnabled(mTextView.canUndo());
-        menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_REDO, CONTEXT_MENU_ITEM_ORDER_REDO,
+        menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_REDO, menuItemOrderRedo,
                 com.android.internal.R.string.redo)
                 .setAlphabeticShortcut('z', KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)
                 .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
                 .setEnabled(mTextView.canRedo());
 
-        menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_CUT, CONTEXT_MENU_ITEM_ORDER_CUT,
+        menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_CUT, menuItemOrderCut,
                 com.android.internal.R.string.cut)
                 .setAlphabeticShortcut('x')
                 .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
                 .setEnabled(mTextView.canCut());
-        menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_COPY, CONTEXT_MENU_ITEM_ORDER_COPY,
+        menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_COPY, menuItemOrderCopy,
                 com.android.internal.R.string.copy)
                 .setAlphabeticShortcut('c')
                 .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
                 .setEnabled(mTextView.canCopy());
-        menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE, CONTEXT_MENU_ITEM_ORDER_PASTE,
+        menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE, menuItemOrderPaste,
                 com.android.internal.R.string.paste)
                 .setAlphabeticShortcut('v')
                 .setEnabled(mTextView.canPaste())
                 .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
         menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE_AS_PLAIN_TEXT,
-                        CONTEXT_MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT,
+                        menuItemOrderPasteAsPlainText,
                 com.android.internal.R.string.paste_as_plain_text)
                 .setAlphabeticShortcut('v', KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)
                 .setEnabled(mTextView.canPasteAsPlainText())
                 .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
         menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_SELECT_ALL,
-                        CONTEXT_MENU_ITEM_ORDER_SELECT_ALL, com.android.internal.R.string.selectAll)
+                        menuItemOrderSelectAll, com.android.internal.R.string.selectAll)
                 .setAlphabeticShortcut('a')
                 .setEnabled(mTextView.canSelectAllText())
                 .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
 
-        menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_SHARE, CONTEXT_MENU_ITEM_ORDER_SHARE,
+        menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_SHARE, menuItemOrderShare,
                 com.android.internal.R.string.share)
                 .setEnabled(mTextView.canShare())
                 .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
-        menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_AUTOFILL, CONTEXT_MENU_ITEM_ORDER_AUTOFILL,
+        menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_AUTOFILL, menuItemOrderAutofill,
                 android.R.string.autofill)
                 .setEnabled(mTextView.canRequestAutofill())
                 .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index e277b49..0b43eb5 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -846,6 +846,9 @@
         private HardwareBuffer mThumbnail;
         private int mAnimations;
         private @ColorInt int mBackgroundColor;
+        // Customize activity transition animation
+        private CustomActivityTransition mCustomActivityOpenTransition;
+        private CustomActivityTransition mCustomActivityCloseTransition;
 
         private AnimationOptions(int type) {
             mType = type;
@@ -861,6 +864,15 @@
             mTransitionBounds.readFromParcel(in);
             mThumbnail = in.readTypedObject(HardwareBuffer.CREATOR);
             mAnimations = in.readInt();
+            mCustomActivityOpenTransition = in.readTypedObject(CustomActivityTransition.CREATOR);
+            mCustomActivityCloseTransition = in.readTypedObject(CustomActivityTransition.CREATOR);
+        }
+
+        /** Make basic customized animation for a package */
+        public static AnimationOptions makeCommonAnimOptions(String packageName) {
+            AnimationOptions options = new AnimationOptions(ANIM_FROM_STYLE);
+            options.mPackageName = packageName;
+            return options;
         }
 
         public static AnimationOptions makeAnimOptionsFromLayoutParameters(
@@ -871,6 +883,27 @@
             return options;
         }
 
+        /** Add customized window animations */
+        public void addOptionsFromLayoutParameters(WindowManager.LayoutParams lp) {
+            mAnimations = lp.windowAnimations;
+        }
+
+        /** Add customized activity animation attributes */
+        public void addCustomActivityTransition(boolean isOpen,
+                int enterResId, int exitResId, int backgroundColor) {
+            CustomActivityTransition customTransition = isOpen
+                    ? mCustomActivityOpenTransition : mCustomActivityCloseTransition;
+            if (customTransition == null) {
+                customTransition = new CustomActivityTransition();
+                if (isOpen) {
+                    mCustomActivityOpenTransition = customTransition;
+                } else {
+                    mCustomActivityCloseTransition = customTransition;
+                }
+            }
+            customTransition.addCustomActivityTransition(enterResId, exitResId, backgroundColor);
+        }
+
         public static AnimationOptions makeCustomAnimOptions(String packageName, int enterResId,
                 int exitResId, @ColorInt int backgroundColor, boolean overrideTaskTransition) {
             AnimationOptions options = new AnimationOptions(ANIM_CUSTOM);
@@ -946,6 +979,11 @@
             return mAnimations;
         }
 
+        /** Return customized activity transition if existed. */
+        public CustomActivityTransition getCustomActivityTransition(boolean open) {
+            return open ? mCustomActivityOpenTransition : mCustomActivityCloseTransition;
+        }
+
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(mType);
@@ -957,6 +995,8 @@
             mTransitionBounds.writeToParcel(dest, flags);
             dest.writeTypedObject(mThumbnail, flags);
             dest.writeInt(mAnimations);
+            dest.writeTypedObject(mCustomActivityOpenTransition, flags);
+            dest.writeTypedObject(mCustomActivityCloseTransition, flags);
         }
 
         @NonNull
@@ -997,5 +1037,68 @@
             return "{ AnimationOptions type= " + typeToString(mType) + " package=" + mPackageName
                     + " override=" + mOverrideTaskTransition + " b=" + mTransitionBounds + "}";
         }
+
+        /** Customized activity transition. */
+        public static class CustomActivityTransition implements Parcelable {
+            private int mCustomEnterResId;
+            private int mCustomExitResId;
+            private int mCustomBackgroundColor;
+
+            /** Returns customize activity animation enter resource id */
+            public int getCustomEnterResId() {
+                return mCustomEnterResId;
+            }
+
+            /** Returns customize activity animation exit resource id */
+            public int getCustomExitResId() {
+                return mCustomExitResId;
+            }
+
+            /** Returns customize activity animation background color */
+            public int getCustomBackgroundColor() {
+                return mCustomBackgroundColor;
+            }
+            CustomActivityTransition() {}
+
+            CustomActivityTransition(Parcel in) {
+                mCustomEnterResId = in.readInt();
+                mCustomExitResId = in.readInt();
+                mCustomBackgroundColor = in.readInt();
+            }
+
+            /** Add customized activity animation attributes */
+            public void addCustomActivityTransition(
+                    int enterResId, int exitResId, int backgroundColor) {
+                mCustomEnterResId = enterResId;
+                mCustomExitResId = exitResId;
+                mCustomBackgroundColor = backgroundColor;
+            }
+
+            @Override
+            public int describeContents() {
+                return 0;
+            }
+
+            @Override
+            public void writeToParcel(Parcel dest, int flags) {
+                dest.writeInt(mCustomEnterResId);
+                dest.writeInt(mCustomExitResId);
+                dest.writeInt(mCustomBackgroundColor);
+            }
+
+            @NonNull
+            public static final Creator<CustomActivityTransition> CREATOR =
+                    new Creator<CustomActivityTransition>() {
+                        @Override
+                        public CustomActivityTransition createFromParcel(Parcel in) {
+                            return new CustomActivityTransition(in);
+                        }
+
+                        @Override
+                        public CustomActivityTransition[] newArray(int size) {
+                            return new CustomActivityTransition[size];
+                        }
+                    };
+        }
     }
 }
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index b0a4b54..8b41829 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -167,8 +167,9 @@
          */
         @UnsupportedAppUsage
         public String getFullNameInUiLanguage() {
+            Locale locale = mLocale.stripExtensions();
             // We don't cache the UI name because the default locale keeps changing
-            return LocaleHelper.getDisplayName(mLocale, true /* sentence case */);
+            return LocaleHelper.getDisplayName(locale, true /* sentence case */);
         }
 
         private String getLangScriptKey() {
diff --git a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
index 205c5fd..d2b612a 100644
--- a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
+++ b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
@@ -73,6 +73,23 @@
                 mOnPropertiesChangedListener);
     }
 
+    public void registerForCurrentUser() {
+        ContentResolver r = mContext.getContentResolver();
+        r.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT),
+                false, this);
+        r.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.BACK_GESTURE_INSET_SCALE_RIGHT),
+                false, this);
+        r.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE),
+                false, this);
+        DeviceConfig.addOnPropertiesChangedListener(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                runnable -> mMainHandler.post(runnable),
+                mOnPropertiesChangedListener);
+    }
+
     public void unregister() {
         mContext.getContentResolver().unregisterContentObserver(this);
         DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index bcb0da3..d2d87d6 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -427,7 +427,7 @@
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
         return 0;
     } else if (err != NO_ERROR) {
-        jniThrowException(env, OutOfResourcesException, NULL);
+        jniThrowException(env, OutOfResourcesException, statusToString(err).c_str());
         return 0;
     }
 
diff --git a/core/proto/android/app/OWNERS b/core/proto/android/app/OWNERS
index 4d76aee..a137ea9 100644
--- a/core/proto/android/app/OWNERS
+++ b/core/proto/android/app/OWNERS
@@ -1,2 +1,3 @@
+per-file appstartinfo.proto = file:/services/core/java/com/android/server/am/OWNERS
 per-file location_time_zone_manager.proto = file:platform/frameworks/base:/services/core/java/com/android/server/timezonedetector/OWNERS
 per-file time_zone_detector.proto = file:platform/frameworks/base:/services/core/java/com/android/server/timezonedetector/OWNERS
diff --git a/core/proto/android/server/OWNERS b/core/proto/android/server/OWNERS
index 72d39bf..c6d3cda 100644
--- a/core/proto/android/server/OWNERS
+++ b/core/proto/android/server/OWNERS
@@ -1 +1,2 @@
+per-file activitymanagerservice.proto = file:/services/core/java/com/android/server/am/OWNERS
 per-file window*.proto = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 52d6f55..a4818c7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -6091,6 +6091,11 @@
     <permission android:name="android.permission.REGISTER_STATS_PULL_ATOM"
                 android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi @hide Allows an application to read restricted stats from statsd.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.READ_RESTRICTED_STATS"
+                android:protectionLevel="internal|privileged" />
+
     <!-- @SystemApi Allows an application to control the backup and restore process.
     <p>Not for use by third-party applications.
          @hide pending API council -->
@@ -8110,7 +8115,7 @@
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
-        <service android:name="com.android.server.healthconnect.storage.AutoDeleteService"
+        <service android:name="com.android.server.healthconnect.HealthConnectDailyService"
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
diff --git a/core/res/res/drawable/ic_phone_disabled.xml b/core/res/res/drawable/ic_phone_disabled.xml
new file mode 100644
index 0000000..6e60912
--- /dev/null
+++ b/core/res/res/drawable/ic_phone_disabled.xml
@@ -0,0 +1,25 @@
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="48"
+        android:viewportHeight="48"
+        android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M40.65,45.15 L28.9,33.45Q23.55,37.8 18.5,39.925Q13.45,42.05 8.6,42.05Q7.45,42.05 6.7,41.4Q5.95,40.75 5.95,39.75V33Q5.95,32.2 6.45,31.6Q6.95,31 7.7,30.85L13.65,29.55Q14.3,29.4 14.95,29.625Q15.6,29.85 16.1,30.4L20.85,35.3Q22.3,34.6 23.9,33.45Q25.5,32.3 26.75,31.3L3.2,7.7L5.35,5.55L42.8,43.05ZM18.1,36.75 L14.15,32.6Q14.15,32.6 14.15,32.6Q14.15,32.6 14.15,32.6L9,33.65Q9,33.65 9,33.65Q9,33.65 9,33.65V39Q9,39 9,39Q9,39 9,39Q11.25,38.9 13.65,38.3Q16.05,37.7 18.1,36.75ZM33.15,29.15 L31,27Q32.05,25.75 33.125,24.175Q34.2,22.6 35.05,21.3L30.05,16.25Q29.65,15.85 29.5,15.275Q29.35,14.7 29.5,14L30.8,7.75Q30.95,6.95 31.475,6.475Q32,6 32.7,6H39.7Q40.65,6 41.325,6.65Q42,7.3 42,8.25Q42,13.35 39.6,18.975Q37.2,24.6 33.15,29.15ZM36.45,18.45Q37.75,15.45 38.35,13.2Q38.95,10.95 38.9,9Q38.9,9 38.9,9Q38.9,9 38.9,9H33.6Q33.6,9 33.6,9Q33.6,9 33.6,9L32.45,14.45Q32.45,14.45 32.45,14.45Q32.45,14.45 32.45,14.45ZM36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45ZM18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Z"/>
+</vector>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 26927f8..47d771f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -556,6 +556,16 @@
     <!-- Title for the button that turns work profile on. To be used in a notification
         [CHAR LIMIT=NONE] -->
     <string name="personal_apps_suspended_turn_profile_on">Turn on</string>
+    <!-- Notification title. This notification lets the user know that they will be unable to
+     receive phone calls or texts until the work profile is turned on. [CHAR LIMIT=40] -->
+    <string name="work_profile_telephony_paused_title">Calls and messages are off</string>
+    <!-- Notification text. This notification lets the user know that they will be unable to
+     receive phone calls or texts until the work profile is turned on. [CHAR LIMIT=NONE] -->
+    <string name="work_profile_telephony_paused_text">You have paused work apps.
+        You won\'t receive phone calls or text messages.</string>
+    <!-- Label for notification button. This button lets the user turn the work profile on.
+         [CHAR LIMIT=15]  -->
+    <string name="work_profile_telephony_paused_turn_on_button">Unpause work apps</string>
 
     <!-- Display name for any time a piece of data refers to the owner of the phone. For example, this could be used in place of the phone's phone number. -->
     <string name="me">Me</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 91d5692..dcd7a31 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1190,6 +1190,9 @@
   <java-symbol type="string" name="personal_apps_suspension_soon_text" />
   <java-symbol type="string" name="personal_apps_suspension_text" />
   <java-symbol type="string" name="personal_apps_suspended_turn_profile_on" />
+  <java-symbol type="string" name="work_profile_telephony_paused_title" />
+  <java-symbol type="string" name="work_profile_telephony_paused_text" />
+  <java-symbol type="string" name="work_profile_telephony_paused_turn_on_button" />
   <java-symbol type="string" name="notification_work_profile_content_description" />
   <java-symbol type="string" name="factory_reset_warning" />
   <java-symbol type="string" name="factory_reset_message" />
@@ -1410,6 +1413,7 @@
 
   <java-symbol type="drawable" name="btn_borderless_rect" />
   <java-symbol type="drawable" name="ic_phone" />
+  <java-symbol type="drawable" name="ic_phone_disabled" />
   <java-symbol type="drawable" name="ic_bt_headphones_a2dp" />
   <java-symbol type="drawable" name="ic_bt_headset_hfp" />
   <java-symbol type="drawable" name="ic_bt_hearing_aid" />
diff --git a/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java b/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
index d8799cb..34ca502 100644
--- a/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
+++ b/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
@@ -17,12 +17,15 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.platform.test.annotations.Presubmit;
+
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+@Presubmit
 @SmallTest
 @RunWith(JUnit4.class)
 /** Tests for {@link HdmiUtils} class. */
diff --git a/core/tests/coretests/src/android/view/KeyEventTest.java b/core/tests/coretests/src/android/view/KeyEventTest.java
index c10ef00..cbf11c4 100644
--- a/core/tests/coretests/src/android/view/KeyEventTest.java
+++ b/core/tests/coretests/src/android/view/KeyEventTest.java
@@ -170,8 +170,7 @@
                 DEVICE_ID, SCAN_CODE, FLAGS);
 
         assertKeyEventFields(key, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
-                DEVICE_ID, SCAN_CODE, FLAGS, /* source= */ 0, /* displayId= */ 0,
-                CHARACTERS);
+                DEVICE_ID, SCAN_CODE, FLAGS, /* source= */ 0, INVALID_DISPLAY, CHARACTERS);
     }
 
     @Test
@@ -180,7 +179,7 @@
                 DEVICE_ID, SCAN_CODE);
 
         assertKeyEventFields(key, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
-                DEVICE_ID, SCAN_CODE, /* flags= */ 0, /* source= */ 0, /* displayId= */ 0,
+                DEVICE_ID, SCAN_CODE, /* flags= */ 0, /* source= */ 0, INVALID_DISPLAY,
                 CHARACTERS);
     }
 
@@ -190,7 +189,7 @@
 
         assertKeyEventFields(key, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
                 KeyCharacterMap.VIRTUAL_KEYBOARD, /* scanCode= */ 0, /* flags= */ 0,
-                /* source= */ 0, /* displayId= */ 0, CHARACTERS);
+                /* source= */ 0, INVALID_DISPLAY, CHARACTERS);
     }
 
     @Test
@@ -199,7 +198,7 @@
 
         assertKeyEventFields(key, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
                 /* metaState= */ 0, KeyCharacterMap.VIRTUAL_KEYBOARD, /* scanCode= */ 0,
-                /* flags= */ 0, /* source= */ 0, /* displayId= */ 0, CHARACTERS);
+                /* flags= */ 0, /* source= */ 0, INVALID_DISPLAY, CHARACTERS);
     }
 
     @Test
@@ -217,7 +216,7 @@
 
         assertKeyEventFields(key, /* downTime= */ 0, /* eventTime= */ 0, ACTION, KEYCODE,
                 /* repeat= */ 0, /* metaState= */ 0, KeyCharacterMap.VIRTUAL_KEYBOARD,
-                /* scanCode= */ 0, FLAGS, /* source= */ 0, /* displayId= */ 0, CHARACTERS);
+                /* scanCode= */ 0, FLAGS, /* source= */ 0, INVALID_DISPLAY, CHARACTERS);
     }
 
     private static KeyEvent createKey() {
diff --git a/core/tests/hdmitests/Android.bp b/core/tests/hdmitests/Android.bp
index f49e053..3d04937 100644
--- a/core/tests/hdmitests/Android.bp
+++ b/core/tests/hdmitests/Android.bp
@@ -29,9 +29,11 @@
         "androidx.test.rules",
         "frameworks-base-testutils",
         "guava-android-testlib",
+        "platform-test-annotations",
         "truth-prebuilt",
     ],
     libs: ["android.test.runner"],
     platform_apis: true,
     certificate: "platform",
+    test_suites: ["device-tests"],
 }
diff --git a/core/tests/hdmitests/AndroidTest.xml b/core/tests/hdmitests/AndroidTest.xml
index 0c8da28..7376004 100644
--- a/core/tests/hdmitests/AndroidTest.xml
+++ b/core/tests/hdmitests/AndroidTest.xml
@@ -22,6 +22,9 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="HdmiCecTests.apk" />
     </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+        <option name="force-root" value="true" />
+    </target_preparer>
 
     <option name="test-suite-tag" value="apct"/>
     <option name="test-tag" value="HdmiTests"/>
@@ -30,5 +33,6 @@
         <option name="package" value="android.hardware.hdmi" />
         <option name="hidden-api-checks" value="false"/>
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
+        <option name="test-filter-dir" value="/data/data/android.hardware.hdmi" />
     </test>
 </configuration>
\ No newline at end of file
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/DeviceFeaturesTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/DeviceFeaturesTest.java
index 875ab38..9005afb 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/DeviceFeaturesTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/DeviceFeaturesTest.java
@@ -22,6 +22,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.platform.test.annotations.Presubmit;
+
 import androidx.test.filters.SmallTest;
 
 import com.google.common.testing.EqualsTester;
@@ -31,6 +33,7 @@
 import org.junit.runners.JUnit4;
 
 /** Tests for {@link DeviceFeatures} */
+@Presubmit
 @RunWith(JUnit4.class)
 @SmallTest
 public class DeviceFeaturesTest {
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index e16a2f8..bb3e768 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -18,6 +18,7 @@
 
 import android.os.Handler;
 import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
 import android.util.Log;
 
 import androidx.test.filters.SmallTest;
@@ -34,6 +35,7 @@
 /**
  * Tests for {@link HdmiAudioSystemClient}
  */
+@Presubmit
 @RunWith(JUnit4.class)
 @SmallTest
 public class HdmiAudioSystemClientTest {
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java
index 5f7468e..5039fe8 100755
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java
@@ -16,6 +16,8 @@
 
 package android.hardware.hdmi;
 
+import android.platform.test.annotations.Presubmit;
+
 import androidx.test.filters.SmallTest;
 
 import com.google.common.testing.EqualsTester;
@@ -25,6 +27,7 @@
 import org.junit.runners.JUnit4;
 
 /** Tests for {@link HdmiDeviceInfo} */
+@Presubmit
 @RunWith(JUnit4.class)
 @SmallTest
 public class HdmiDeviceInfoTest {
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java
index 2bce747..fde1122 100755
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java
@@ -16,6 +16,8 @@
 
 package android.hardware.hdmi;
 
+import android.platform.test.annotations.Presubmit;
+
 import androidx.test.filters.SmallTest;
 
 import com.google.common.testing.EqualsTester;
@@ -25,6 +27,7 @@
 import org.junit.runners.JUnit4;
 
 /** Tests for {@link HdmiPortInfo} */
+@Presubmit
 @RunWith(JUnit4.class)
 @SmallTest
 public class HdmiPortInfoTest {
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java
index fdc6b84..13212ce 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java
@@ -18,6 +18,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.platform.test.annotations.Presubmit;
+
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
@@ -26,6 +28,7 @@
 /**
  * Tests for {@link HdmiUtils}.
  */
+@Presubmit
 @RunWith(JUnit4.class)
 @SmallTest
 public class HdmiUtilsTest {
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 046373d..b1abc2a1 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1899,7 +1899,6 @@
 
     /**
      * Returns whether or not this Bitmap contains a Gainmap.
-     * @hide
      */
     public boolean hasGainmap() {
         checkRecycled("Bitmap is recycled");
@@ -1908,7 +1907,6 @@
 
     /**
      * Returns the gainmap or null if the bitmap doesn't contain a gainmap
-     * @hide
      */
     public @Nullable Gainmap getGainmap() {
         checkRecycled("Bitmap is recycled");
@@ -1919,6 +1917,14 @@
     }
 
     /**
+     * Sets a gainmap on this bitmap, or removes the gainmap if null
+     */
+    public void setGainmap(@Nullable Gainmap gainmap) {
+        checkRecycled("Bitmap is recycled");
+        nativeSetGainmap(mNativePtr, gainmap == null ? 0 : gainmap.mNativePtr);
+    }
+
+    /**
      * Fills the bitmap's pixels with the specified {@link Color}.
      *
      * @throws IllegalStateException if the bitmap is not mutable.
@@ -2403,6 +2409,7 @@
     private static native void nativeSetImmutable(long nativePtr);
 
     private static native Gainmap nativeExtractGainmap(long nativePtr);
+    private static native void nativeSetGainmap(long bitmapPtr, long gainmapPtr);
 
     // ---------------- @CriticalNative -------------------
 
diff --git a/graphics/java/android/graphics/Gainmap.java b/graphics/java/android/graphics/Gainmap.java
index a25a605..53f23c0 100644
--- a/graphics/java/android/graphics/Gainmap.java
+++ b/graphics/java/android/graphics/Gainmap.java
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import android.annotation.FloatRange;
 import android.annotation.NonNull;
 
 import libcore.util.NativeAllocationRegistry;
@@ -24,104 +25,288 @@
  * Gainmap represents a mechanism for augmenting an SDR image to produce an HDR one with variable
  * display adjustment capability.
  *
- * It is a combination of a set of metadata describing the gainmap, as well as either a 1 or 3
+ * It is a combination of a set of metadata describing how to apply the gainmap, as well as either
+ * a 1 (such as {@link android.graphics.Bitmap.Config#ALPHA_8} or 3
+ * (such as {@link android.graphics.Bitmap.Config#ARGB_8888} with the alpha channel ignored)
  * channel Bitmap that represents the gainmap data itself.
  *
- * @hide
+ * When rendering to an {@link android.content.pm.ActivityInfo#COLOR_MODE_HDR} activity, the
+ * hardware accelerated {@link Canvas} will automatically apply the gainmap when sufficient
+ * HDR headroom is available.
+ *
+ * <h3>Gainmap Structure</h3>
+ *
+ * The logical whole of a gainmap'd image consists of a base Bitmap that represents the original
+ * image as would be displayed without gainmap support in addition to a gainmap with a second
+ * enhancement image. In the case of a JPEG, the base image would be the typical 8-bit SDR image
+ * that the format is commonly associated with. The gainmap image is embedded alongside the base
+ * image, often at a lower resolution (such as 1/4th), along with some metadata to describe
+ * how to apply the gainmap. The gainmap image itself is then a greyscale image representing
+ * the transformation to apply onto the base image to reconstruct an HDR rendition of it.
+ *
+ * As such these "gainmap images" consist of 3 parts - a base {@link Bitmap} with a
+ * {@link Bitmap#getGainmap()} that returns an instance of this class which in turn contains
+ * the enhancement layer represented as another Bitmap, accessible via {@link #getGainmapContents()}
+ *
+ * <h3>Applying a gainmap manually</h3>
+ *
+ * When doing custom rendering such as to an OpenGL ES or Vulkan context, the gainmap is not
+ * automatically applied. In such situations, the following steps are appropriate to render the
+ * gainmap in combination with the base image.
+ *
+ * Suppose our display has HDR to SDR ratio of H, and we wish to display an image with gainmap on
+ * this display. Let B be the pixel value from the base image in a color space that has the
+ * primaries of the base image and a linear transfer function. Let G be the pixel value from the
+ * gainmap. Let D be the output pixel in the same color space as B. The value of D is computed
+ * as follows:
+ *
+ * First, let W be a weight parameter determining how much the gainmap will be applied.
+ *   W = clamp((log(H)               - log(displayRatioHdr)) /
+ *             (log(displayRatioHdr) - log(displayRatioSdr), 0, 1)
+ *
+ * Next, let L be the gainmap value in log space. We compute this from the value G that was
+ * sampled from the texture as follows:
+ *   L = mix(log(gainmapRatioMin), log(gainmapRatioMax), pow(G, gainmapGamma))
+ *
+ * Finally, apply the gainmap to compute D, the displayed pixel. If the base image is SDR then
+ * compute:
+ *   D = (B + epsilonSdr) * exp(L * W) - epsilonHdr
+ * If the base image is HDR then compute:
+ *   D = (B + epsilonHdr) * exp(L * (W - 1)) - epsilonSdr
+ *
+ * In the above math, log() is a natural logarithm and exp() is natural exponentiation.
  */
-public class Gainmap {
-    private final long mNativePtr;
-    private final Bitmap mGainmapImage;
+public final class Gainmap {
 
-    // called from JNI and Bitmap_Delegate.
-    private Gainmap(Bitmap gainmapImage, long nativeGainmap, int allocationByteCount,
-            boolean fromMalloc) {
+    // Use a Holder to allow static initialization of Gainmap in the boot image.
+    private static class NoImagePreloadHolder {
+        public static final NativeAllocationRegistry sRegistry =
+                NativeAllocationRegistry.createMalloced(
+                        Gainmap.class.getClassLoader(), nGetFinalizer());
+    }
+
+    final long mNativePtr;
+    private Bitmap mGainmapContents;
+
+    // called from JNI
+    private Gainmap(Bitmap gainmapContents, long nativeGainmap) {
         if (nativeGainmap == 0) {
             throw new RuntimeException("internal error: native gainmap is 0");
         }
 
-        mGainmapImage = gainmapImage;
+        mGainmapContents = gainmapContents;
         mNativePtr = nativeGainmap;
 
-        final NativeAllocationRegistry registry;
-        if (fromMalloc) {
-            registry = NativeAllocationRegistry.createMalloced(
-                    Bitmap.class.getClassLoader(), nGetFinalizer(), allocationByteCount);
-        } else {
-            registry = NativeAllocationRegistry.createNonmalloced(
-                    Bitmap.class.getClassLoader(), nGetFinalizer(), allocationByteCount);
-        }
-        registry.registerNativeAllocation(this, nativeGainmap);
+        NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, nativeGainmap);
     }
 
     /**
-     * Returns the image data of the gainmap represented as a Bitmap
-     * @return
+     * Creates a gainmap from a given Bitmap. The caller is responsible for setting the various
+     * fields to the desired values. The defaults are as follows:
+     * <ul>
+     *     <li>Ratio min is 1f, 1f, 1f</li>
+     *     <li>Ratio max is 2f, 2f, 2f</li>
+     *     <li>Gamma is 1f, 1f, 1f</li>
+     *     <li>Epsilon SDR is 0f, 0f, 0f</li>
+     *     <li>Epsilon HDR is 0f, 0f, 0f</li>
+     *     <li>Display ratio SDR is 1f</li>
+     *     <li>Display ratio HDR is 2f</li>
+     * </ul>
+     * It is strongly recommended that at least the ratio max and display ratio HDR are adjusted
+     * to better suit the given gainmap contents.
+     */
+    public Gainmap(@NonNull Bitmap gainmapContents) {
+        this(gainmapContents, nCreateEmpty());
+    }
+
+    /**
+     * @return Returns the image data of the gainmap represented as a Bitmap. This is represented
+     * as a Bitmap for broad API compatibility, however certain aspects of the Bitmap are ignored
+     * such as {@link Bitmap#getColorSpace()} or {@link Bitmap#getGainmap()} as they are not
+     * relevant to the gainmap's enhancement layer.
      */
     @NonNull
-    public Bitmap getGainmapImage() {
-        return mGainmapImage;
+    public Bitmap getGainmapContents() {
+        return mGainmapContents;
     }
 
     /**
-     * Sets the gainmap max metadata. For single-plane gainmaps, r, g, and b should be the same.
+     * Sets the image data of the gainmap. This is the 1 or 3 channel enhancement layer to apply
+     * to the base image. This is represented as a Bitmap for broad API compatibility, however
+     * certain aspects of the Bitmap are ignored such as {@link Bitmap#getColorSpace()} or
+     * {@link Bitmap#getGainmap()} as they are not relevant to the gainmap's enhancement layer.
+     *
+     * @param bitmap The non-null bitmap to set as the gainmap's contents
+     */
+    public void setGainmapContents(@NonNull Bitmap bitmap) {
+        // TODO: Validate here or leave native-side?
+        if (bitmap.isRecycled()) throw new IllegalArgumentException("Bitmap is recycled");
+        nSetBitmap(mNativePtr, bitmap);
+        mGainmapContents = bitmap;
+    }
+
+    /**
+     * Sets the gainmap ratio min. For single-plane gainmaps, r, g, and b should be the same.
      */
     @NonNull
-    public void setGainmapMax(float r, float g, float b) {
-        nSetGainmapMax(mNativePtr, r, g, b);
+    public void setRatioMin(float r, float g, float b) {
+        nSetRatioMin(mNativePtr, r, g, b);
     }
 
     /**
-     * Gets the gainmap max metadata. For single-plane gainmaps, all 3 components should be the
+     * Gets the gainmap ratio max. For single-plane gainmaps, all 3 components should be the
      * same. The components are in r, g, b order.
      */
     @NonNull
-    public float[] getGainmapMax() {
+    public float[] getRatioMin() {
         float[] ret = new float[3];
-        nGetGainmapMax(mNativePtr, ret);
+        nGetRatioMin(mNativePtr, ret);
         return ret;
     }
 
     /**
-     * Sets the maximum HDR ratio for the gainmap
+     * Sets the gainmap ratio max. For single-plane gainmaps, r, g, and b should be the same.
      */
     @NonNull
-    public void setHdrRatioMax(float max) {
-        nSetHdrRatioMax(mNativePtr, max);
+    public void setRatioMax(float r, float g, float b) {
+        nSetRatioMax(mNativePtr, r, g, b);
     }
 
     /**
-     * Gets the maximum HDR ratio for the gainmap
+     * Gets the gainmap ratio max. For single-plane gainmaps, all 3 components should be the
+     * same. The components are in r, g, b order.
      */
     @NonNull
-    public float getHdrRatioMax() {
-        return nGetHdrRatioMax(mNativePtr);
+    public float[] getRatioMax() {
+        float[] ret = new float[3];
+        nGetRatioMax(mNativePtr, ret);
+        return ret;
     }
 
     /**
-     * Sets the maximum HDR ratio for the gainmap
+     * Sets the gainmap gamma. For single-plane gainmaps, r, g, and b should be the same.
      */
     @NonNull
-    public void setHdrRatioMin(float min) {
-        nSetHdrRatioMin(mNativePtr, min);
+    public void setGamma(float r, float g, float b) {
+        nSetGamma(mNativePtr, r, g, b);
     }
 
     /**
-     * Gets the maximum HDR ratio for the gainmap
+     * Gets the gainmap gamma. For single-plane gainmaps, all 3 components should be the
+     * same. The components are in r, g, b order.
      */
     @NonNull
-    public float getHdrRatioMin() {
-        return nGetHdrRatioMin(mNativePtr);
+    public float[] getGamma() {
+        float[] ret = new float[3];
+        nGetGamma(mNativePtr, ret);
+        return ret;
+    }
+
+    /**
+     * Sets the sdr epsilon which is used to avoid numerical instability.
+     * For single-plane gainmaps, r, g, and b should be the same.
+     */
+    @NonNull
+    public void setEpsilonSdr(float r, float g, float b) {
+        nSetEpsilonSdr(mNativePtr, r, g, b);
+    }
+
+    /**
+     * Gets the sdr epsilon. For single-plane gainmaps, all 3 components should be the
+     * same. The components are in r, g, b order.
+     */
+    @NonNull
+    public float[] getEpsilonSdr() {
+        float[] ret = new float[3];
+        nGetEpsilonSdr(mNativePtr, ret);
+        return ret;
+    }
+
+    /**
+     * Sets the hdr epsilon which is used to avoid numerical instability.
+     * For single-plane gainmaps, r, g, and b should be the same.
+     */
+    @NonNull
+    public void setEpsilonHdr(float r, float g, float b) {
+        nSetEpsilonHdr(mNativePtr, r, g, b);
+    }
+
+    /**
+     * Gets the hdr epsilon. For single-plane gainmaps, all 3 components should be the
+     * same. The components are in r, g, b order.
+     */
+    @NonNull
+    public float[] getEpsilonHdr() {
+        float[] ret = new float[3];
+        nGetEpsilonHdr(mNativePtr, ret);
+        return ret;
+    }
+
+    /**
+     * Sets the hdr/sdr ratio at which point the gainmap is fully applied.
+     * @param max The hdr/sdr ratio at which the gainmap is fully applied. Must be >= 1.0f
+     */
+    @NonNull
+    public void setDisplayRatioForFullHdr(float max) {
+        if (!Float.isFinite(max) || max < 1f) {
+            throw new IllegalArgumentException(
+                    "setDisplayRatioForFullHdr must be >= 1.0f, got = " + max);
+        }
+        nSetDisplayRatioHdr(mNativePtr, max);
+    }
+
+    /**
+     * Gets the hdr/sdr ratio at which point the gainmap is fully applied.
+     */
+    @NonNull
+    public float getDisplayRatioForFullHdr() {
+        return nGetDisplayRatioHdr(mNativePtr);
+    }
+
+    /**
+     * Sets the hdr/sdr ratio below which only the SDR image is displayed.
+     * @param min The minimum hdr/sdr ratio at which to begin applying the gainmap. Must be >= 1.0f
+     */
+    @NonNull
+    public void setMinDisplayRatioForHdrTransition(@FloatRange(from = 1.0f) float min) {
+        if (!Float.isFinite(min) || min < 1f) {
+            throw new IllegalArgumentException(
+                    "setMinDisplayRatioForHdrTransition must be >= 1.0f, got = " + min);
+        }
+        nSetDisplayRatioSdr(mNativePtr, min);
+    }
+
+    /**
+     * Gets the hdr/sdr ratio below which only the SDR image is displayed.
+     */
+    @NonNull
+    public float getMinDisplayRatioForHdrTransition() {
+        return nGetDisplayRatioSdr(mNativePtr);
     }
 
     private static native long nGetFinalizer();
+    private static native long nCreateEmpty();
 
-    private static native void nSetGainmapMax(long ptr, float r, float g, float b);
-    private static native void nGetGainmapMax(long ptr, float[] components);
+    private static native void nSetBitmap(long ptr, Bitmap bitmap);
 
-    private static native void nSetHdrRatioMax(long ptr, float max);
-    private static native float nGetHdrRatioMax(long ptr);
+    private static native void nSetRatioMin(long ptr, float r, float g, float b);
+    private static native void nGetRatioMin(long ptr, float[] components);
 
-    private static native void nSetHdrRatioMin(long ptr, float min);
-    private static native float nGetHdrRatioMin(long ptr);
+    private static native void nSetRatioMax(long ptr, float r, float g, float b);
+    private static native void nGetRatioMax(long ptr, float[] components);
+
+    private static native void nSetGamma(long ptr, float r, float g, float b);
+    private static native void nGetGamma(long ptr, float[] components);
+
+    private static native void nSetEpsilonSdr(long ptr, float r, float g, float b);
+    private static native void nGetEpsilonSdr(long ptr, float[] components);
+
+    private static native void nSetEpsilonHdr(long ptr, float r, float g, float b);
+    private static native void nGetEpsilonHdr(long ptr, float[] components);
+
+    private static native void nSetDisplayRatioHdr(long ptr, float max);
+    private static native float nGetDisplayRatioHdr(long ptr);
+
+    private static native void nSetDisplayRatioSdr(long ptr, float min);
+    private static native float nGetDisplayRatioSdr(long ptr);
 }
diff --git a/libs/WindowManager/Shell/res/animator/tv_window_menu_action_button_animator.xml b/libs/WindowManager/Shell/res/animator/tv_window_menu_action_button_animator.xml
index 7475aba..b2d5939 100644
--- a/libs/WindowManager/Shell/res/animator/tv_window_menu_action_button_animator.xml
+++ b/libs/WindowManager/Shell/res/animator/tv_window_menu_action_button_animator.xml
@@ -18,6 +18,20 @@
 <selector
     xmlns:android="http://schemas.android.com/apk/res/android">
 
+    <item android:state_pressed="true">
+        <set>
+            <objectAnimator
+                android:duration="200"
+                android:propertyName="scaleX"
+                android:valueTo="1.0"
+                android:valueType="floatType"/>
+            <objectAnimator
+                android:duration="200"
+                android:propertyName="scaleY"
+                android:valueTo="1.0"
+                android:valueType="floatType"/>
+        </set>
+    </item>
     <item android:state_focused="true">
         <set>
             <objectAnimator
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 b8e8363..d6e1a82 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
@@ -25,7 +25,6 @@
 import static android.util.RotationUtils.rotateBounds;
 import static android.util.RotationUtils.rotateInsets;
 import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
@@ -46,9 +45,9 @@
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.Gravity;
-import android.view.InsetsSource;
 import android.view.InsetsState;
 import android.view.Surface;
+import android.view.WindowInsets;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -372,23 +371,20 @@
 
         // Only navigation bar
         if (hasNavigationBar) {
-            final InsetsSource extraNavBar = insetsState.peekSource(ITYPE_EXTRA_NAVIGATION_BAR);
-            final boolean hasExtraNav = extraNavBar != null && extraNavBar.isVisible();
+            final Insets insets = insetsState.calculateInsets(
+                    insetsState.getDisplayFrame(),
+                    WindowInsets.Type.navigationBars(),
+                    false /* ignoreVisibility */);
+            outInsets.set(insets.left, insets.top, insets.right, insets.bottom);
             int position = navigationBarPosition(res, displayWidth, displayHeight, displayRotation);
             int navBarSize =
                     getNavigationBarSize(res, position, displayWidth > displayHeight, uiMode);
             if (position == NAV_BAR_BOTTOM) {
-                outInsets.bottom = hasExtraNav
-                        ? Math.max(navBarSize, extraNavBar.getFrame().height())
-                        : navBarSize;
+                outInsets.bottom = Math.max(outInsets.bottom , navBarSize);
             } else if (position == NAV_BAR_RIGHT) {
-                outInsets.right = hasExtraNav
-                        ? Math.max(navBarSize, extraNavBar.getFrame().width())
-                        : navBarSize;
+                outInsets.right = Math.max(outInsets.right , navBarSize);
             } else if (position == NAV_BAR_LEFT) {
-                outInsets.left = hasExtraNav
-                        ? Math.max(navBarSize, extraNavBar.getFrame().width())
-                        : navBarSize;
+                outInsets.left = Math.max(outInsets.left , navBarSize);
             }
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index 02b9197..a437a3b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -740,7 +740,7 @@
             if (mRegistered) return;
 
             mContext.registerReceiverForAllUsers(this, mIntentFilter, SYSTEMUI_PERMISSION,
-                    mMainHandler);
+                    mMainHandler, Context.RECEIVER_NOT_EXPORTED);
             mRegistered = true;
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
index 1549355..5a5ceab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
@@ -142,9 +142,12 @@
         Animation a = null;
         if (animAttr != 0) {
             if (overrideType == ANIM_FROM_STYLE && !isTask) {
-                a = transitionAnimation
-                        .loadAnimationAttr(options.getPackageName(), options.getAnimations(),
-                                animAttr, translucent);
+                a = loadCustomActivityTransition(animAttr, options, enter, transitionAnimation);
+                if (a == null) {
+                    a = transitionAnimation
+                            .loadAnimationAttr(options.getPackageName(), options.getAnimations(),
+                                    animAttr, translucent);
+                }
             } else {
                 a = transitionAnimation.loadDefaultAnimationAttr(animAttr, translucent);
             }
@@ -157,6 +160,37 @@
         return a;
     }
 
+    static Animation loadCustomActivityTransition(int animAttr,
+            TransitionInfo.AnimationOptions options, boolean enter,
+            TransitionAnimation transitionAnimation) {
+        Animation a = null;
+        boolean isOpen = false;
+        switch (animAttr) {
+            case R.styleable.WindowAnimation_activityOpenEnterAnimation:
+            case R.styleable.WindowAnimation_activityOpenExitAnimation:
+                isOpen = true;
+                break;
+            case R.styleable.WindowAnimation_activityCloseEnterAnimation:
+            case R.styleable.WindowAnimation_activityCloseExitAnimation:
+                break;
+            default:
+                return null;
+        }
+
+        final TransitionInfo.AnimationOptions.CustomActivityTransition transitionAnim =
+                options.getCustomActivityTransition(isOpen);
+        if (transitionAnim != null) {
+            a = transitionAnimation.loadAppTransitionAnimation(options.getPackageName(),
+                    enter ? transitionAnim.getCustomEnterResId()
+                            : transitionAnim.getCustomExitResId());
+            if (a != null && transitionAnim.getCustomBackgroundColor() != 0) {
+                a.setBackdropColor(transitionAnim.getCustomBackgroundColor());
+            }
+        }
+
+        return a;
+    }
+
     /**
      * Gets the background {@link ColorInt} for the given transition animation if it is set.
      *
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
index 05fd889..e8784d7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
@@ -18,7 +18,6 @@
 
 import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
 import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
 import static android.view.WindowInsets.Type.navigationBars;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -333,7 +332,8 @@
         mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID,
                 /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener);
         InsetsState insetsState = new InsetsState();
-        InsetsSource insetsSource = new InsetsSource(ITYPE_EXTRA_NAVIGATION_BAR, navigationBars());
+        InsetsSource insetsSource = new InsetsSource(
+                InsetsSource.createId(null, 0, navigationBars()), navigationBars());
         insetsSource.setFrame(0, 0, 1000, 1000);
         insetsState.addSource(insetsSource);
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
index f3f615d9..4de5298 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
@@ -20,7 +20,6 @@
 import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
 import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
 import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
 import static android.view.WindowInsets.Type.navigationBars;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -338,8 +337,10 @@
         // Update if the insets change on the existing display layout
         clearInvocations(mWindowManager);
         InsetsState insetsState = new InsetsState();
-        InsetsSource insetsSource = new InsetsSource(ITYPE_EXTRA_NAVIGATION_BAR, navigationBars());
-        insetsSource.setFrame(0, 0, 1000, 1000);
+        insetsState.setDisplayFrame(new Rect(0, 0, 1000, 2000));
+        InsetsSource insetsSource = new InsetsSource(
+                InsetsSource.createId(null, 0, navigationBars()), navigationBars());
+        insetsSource.setFrame(0, 1800, 1000, 2000);
         insetsState.addSource(insetsSource);
         displayLayout.setInsets(mContext.getResources(), insetsState);
         mWindowManager.updateDisplayLayout(displayLayout);
diff --git a/libs/hwui/hwui/ImageDecoder.cpp b/libs/hwui/hwui/ImageDecoder.cpp
index 6d7c727..5bf53d0 100644
--- a/libs/hwui/hwui/ImageDecoder.cpp
+++ b/libs/hwui/hwui/ImageDecoder.cpp
@@ -506,6 +506,9 @@
     decoder.mOverrideOrigin.emplace(getOrigin());
     // Update mDecodeSize / mTargetSize for the overridden origin
     decoder.setTargetSize(decoder.width(), decoder.height());
+    if (decoder.gray()) {
+        decoder.setOutColorType(kGray_8_SkColorType);
+    }
 
     const bool isScaled = width() != mTargetSize.width() || height() != mTargetSize.height();
 
@@ -528,6 +531,9 @@
     }
 
     SkImageInfo bitmapInfo = decoder.getOutputInfo();
+    if (bitmapInfo.colorType() == kGray_8_SkColorType) {
+        bitmapInfo = bitmapInfo.makeColorType(kAlpha_8_SkColorType);
+    }
 
     SkBitmap bm;
     if (!bm.setInfo(bitmapInfo)) {
diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp
index 23a7520..e71a2a5 100644
--- a/libs/hwui/jni/Bitmap.cpp
+++ b/libs/hwui/jni/Bitmap.cpp
@@ -1300,6 +1300,13 @@
     return Gainmap_extractFromBitmap(env, bitmapHolder->bitmap());
 }
 
+static void Bitmap_setGainmap(JNIEnv*, jobject, jlong bitmapHandle, jlong gainmapPtr) {
+    LocalScopedBitmap bitmapHolder(bitmapHandle);
+    if (!bitmapHolder.valid()) return;
+    uirenderer::Gainmap* gainmap = reinterpret_cast<uirenderer::Gainmap*>(gainmapPtr);
+    bitmapHolder->bitmap().setGainmap(sp<uirenderer::Gainmap>::fromExisting(gainmap));
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static const JNINativeMethod gBitmapMethods[] = {
@@ -1351,6 +1358,7 @@
         {"nativeIsSRGBLinear", "(J)Z", (void*)Bitmap_isSRGBLinear},
         {"nativeSetImmutable", "(J)V", (void*)Bitmap_setImmutable},
         {"nativeExtractGainmap", "(J)Landroid/graphics/Gainmap;", (void*)Bitmap_extractGainmap},
+        {"nativeSetGainmap", "(JJ)V", (void*)Bitmap_setGainmap},
 
         // ------------ @CriticalNative ----------------
         {"nativeIsImmutable", "(J)Z", (void*)Bitmap_isImmutable},
diff --git a/libs/hwui/jni/Gainmap.cpp b/libs/hwui/jni/Gainmap.cpp
index f2efbc7..9cd3fb0 100644
--- a/libs/hwui/jni/Gainmap.cpp
+++ b/libs/hwui/jni/Gainmap.cpp
@@ -45,20 +45,18 @@
 jobject Gainmap_extractFromBitmap(JNIEnv* env, const Bitmap& bitmap) {
     auto gainmap = bitmap.gainmap();
     jobject jGainmapImage;
-    size_t allocationSize;
 
     {
         // Scope to guard the release of nativeBitmap
         auto nativeBitmap = gainmap->bitmap;
         const int createFlags = getCreateFlags(nativeBitmap);
-        allocationSize = nativeBitmap->getAllocationByteCount();
         jGainmapImage = bitmap::createBitmap(env, nativeBitmap.release(), createFlags);
     }
 
     // Grab a ref for the jobject
     gainmap->incStrong(0);
     jobject obj = env->NewObject(gGainmap_class, gGainmap_constructorMethodID, jGainmapImage,
-                                 gainmap.get(), allocationSize + sizeof(Gainmap), true);
+                                 gainmap.get());
 
     if (env->ExceptionCheck() != 0) {
         // sadtrombone
@@ -77,47 +75,109 @@
     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Gainmap_destructor));
 }
 
-static void Gainmap_setGainmapMax(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g,
-                                  jfloat b) {
-    fromJava(gainmapPtr)->info.fLogRatioMax = {r, g, b, 1.f};
+jlong Gainmap_createEmpty(JNIEnv*, jobject) {
+    Gainmap* gainmap = new Gainmap();
+    gainmap->incStrong(0);
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(gainmap));
 }
 
-static void Gainmap_getGainmapMax(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
-    const auto ratioMax = fromJava(gainmapPtr)->info.fLogRatioMax;
-    jfloat buf[3]{ratioMax.fR, ratioMax.fG, ratioMax.fB};
+static void Gainmap_setBitmap(JNIEnv* env, jobject, jlong gainmapPtr, jobject jBitmap) {
+    android::Bitmap* bitmap = GraphicsJNI::getNativeBitmap(env, jBitmap);
+    fromJava(gainmapPtr)->bitmap = sk_ref_sp(bitmap);
+}
+
+static void Gainmap_setRatioMin(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g, jfloat b) {
+    fromJava(gainmapPtr)->info.fGainmapRatioMin = {r, g, b, 1.f};
+}
+
+static void Gainmap_getRatioMin(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
+    const auto value = fromJava(gainmapPtr)->info.fGainmapRatioMin;
+    jfloat buf[3]{value.fR, value.fG, value.fB};
     env->SetFloatArrayRegion(components, 0, 3, buf);
 }
 
-static void Gainmap_setHdrRatioMax(JNIEnv*, jobject, jlong gainmapPtr, jfloat max) {
-    fromJava(gainmapPtr)->info.fHdrRatioMax = max;
+static void Gainmap_setRatioMax(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g, jfloat b) {
+    fromJava(gainmapPtr)->info.fGainmapRatioMax = {r, g, b, 1.f};
 }
 
-static jfloat Gainmap_getHdrRatioMax(JNIEnv*, jobject, jlong gainmapPtr) {
-    return fromJava(gainmapPtr)->info.fHdrRatioMax;
+static void Gainmap_getRatioMax(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
+    const auto value = fromJava(gainmapPtr)->info.fGainmapRatioMax;
+    jfloat buf[3]{value.fR, value.fG, value.fB};
+    env->SetFloatArrayRegion(components, 0, 3, buf);
 }
 
-static void Gainmap_setHdrRatioMin(JNIEnv*, jobject, jlong gainmapPtr, jfloat min) {
-    fromJava(gainmapPtr)->info.fHdrRatioMin = min;
+static void Gainmap_setGamma(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g, jfloat b) {
+    fromJava(gainmapPtr)->info.fGainmapGamma = {r, g, b, 1.f};
 }
 
-static jfloat Gainmap_getHdrRatioMin(JNIEnv*, jobject, jlong gainmapPtr) {
-    return fromJava(gainmapPtr)->info.fHdrRatioMin;
+static void Gainmap_getGamma(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
+    const auto value = fromJava(gainmapPtr)->info.fGainmapGamma;
+    jfloat buf[3]{value.fR, value.fG, value.fB};
+    env->SetFloatArrayRegion(components, 0, 3, buf);
+}
+
+static void Gainmap_setEpsilonSdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g,
+                                  jfloat b) {
+    fromJava(gainmapPtr)->info.fEpsilonSdr = {r, g, b, 1.f};
+}
+
+static void Gainmap_getEpsilonSdr(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
+    const auto value = fromJava(gainmapPtr)->info.fEpsilonSdr;
+    jfloat buf[3]{value.fR, value.fG, value.fB};
+    env->SetFloatArrayRegion(components, 0, 3, buf);
+}
+
+static void Gainmap_setEpsilonHdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g,
+                                  jfloat b) {
+    fromJava(gainmapPtr)->info.fEpsilonHdr = {r, g, b, 1.f};
+}
+
+static void Gainmap_getEpsilonHdr(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
+    const auto value = fromJava(gainmapPtr)->info.fEpsilonHdr;
+    jfloat buf[3]{value.fR, value.fG, value.fB};
+    env->SetFloatArrayRegion(components, 0, 3, buf);
+}
+
+static void Gainmap_setDisplayRatioHdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat max) {
+    fromJava(gainmapPtr)->info.fDisplayRatioHdr = max;
+}
+
+static jfloat Gainmap_getDisplayRatioHdr(JNIEnv*, jobject, jlong gainmapPtr) {
+    return fromJava(gainmapPtr)->info.fDisplayRatioHdr;
+}
+
+static void Gainmap_setDisplayRatioSdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat min) {
+    fromJava(gainmapPtr)->info.fDisplayRatioSdr = min;
+}
+
+static jfloat Gainmap_getDisplayRatioSdr(JNIEnv*, jobject, jlong gainmapPtr) {
+    return fromJava(gainmapPtr)->info.fDisplayRatioSdr;
 }
 
 static const JNINativeMethod gGainmapMethods[] = {
         {"nGetFinalizer", "()J", (void*)Gainmap_getNativeFinalizer},
-        {"nSetGainmapMax", "(JFFF)V", (void*)Gainmap_setGainmapMax},
-        {"nGetGainmapMax", "(J[F)V", (void*)Gainmap_getGainmapMax},
-        {"nSetHdrRatioMax", "(JF)V", (void*)Gainmap_setHdrRatioMax},
-        {"nGetHdrRatioMax", "(J)F", (void*)Gainmap_getHdrRatioMax},
-        {"nSetHdrRatioMin", "(JF)V", (void*)Gainmap_setHdrRatioMin},
-        {"nGetHdrRatioMin", "(J)F", (void*)Gainmap_getHdrRatioMin},
+        {"nCreateEmpty", "()J", (void*)Gainmap_createEmpty},
+        {"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*)Gainmap_setBitmap},
+        {"nSetRatioMin", "(JFFF)V", (void*)Gainmap_setRatioMin},
+        {"nGetRatioMin", "(J[F)V", (void*)Gainmap_getRatioMin},
+        {"nSetRatioMax", "(JFFF)V", (void*)Gainmap_setRatioMax},
+        {"nGetRatioMax", "(J[F)V", (void*)Gainmap_getRatioMax},
+        {"nSetGamma", "(JFFF)V", (void*)Gainmap_setGamma},
+        {"nGetGamma", "(J[F)V", (void*)Gainmap_getGamma},
+        {"nSetEpsilonSdr", "(JFFF)V", (void*)Gainmap_setEpsilonSdr},
+        {"nGetEpsilonSdr", "(J[F)V", (void*)Gainmap_getEpsilonSdr},
+        {"nSetEpsilonHdr", "(JFFF)V", (void*)Gainmap_setEpsilonHdr},
+        {"nGetEpsilonHdr", "(J[F)V", (void*)Gainmap_getEpsilonHdr},
+        {"nSetDisplayRatioHdr", "(JF)V", (void*)Gainmap_setDisplayRatioHdr},
+        {"nGetDisplayRatioHdr", "(J)F", (void*)Gainmap_getDisplayRatioHdr},
+        {"nSetDisplayRatioSdr", "(JF)V", (void*)Gainmap_setDisplayRatioSdr},
+        {"nGetDisplayRatioSdr", "(J)F", (void*)Gainmap_getDisplayRatioSdr},
 };
 
 int register_android_graphics_Gainmap(JNIEnv* env) {
     gGainmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Gainmap"));
     gGainmap_constructorMethodID =
-            GetMethodIDOrDie(env, gGainmap_class, "<init>", "(Landroid/graphics/Bitmap;JIZ)V");
+            GetMethodIDOrDie(env, gGainmap_class, "<init>", "(Landroid/graphics/Bitmap;J)V");
     return android::RegisterMethodsOrDie(env, "android/graphics/Gainmap", gGainmapMethods,
                                          NELEM(gGainmapMethods));
 }
diff --git a/libs/hwui/jni/YuvToJpegEncoder.cpp b/libs/hwui/jni/YuvToJpegEncoder.cpp
index 80bca1f..6c070fe 100644
--- a/libs/hwui/jni/YuvToJpegEncoder.cpp
+++ b/libs/hwui/jni/YuvToJpegEncoder.cpp
@@ -238,7 +238,7 @@
 }
 ///////////////////////////////////////////////////////////////////////////////
 
-using namespace android::recoverymap;
+using namespace android::jpegrecoverymap;
 
 jpegr_color_gamut P010Yuv420ToJpegREncoder::findColorGamut(JNIEnv* env, int aDataSpace) {
     switch (aDataSpace & ADataSpace::STANDARD_MASK) {
@@ -294,7 +294,7 @@
         return false;
     }
 
-    RecoveryMap recoveryMap;
+    JpegR jpegREncoder;
 
     jpegr_uncompressed_struct p010;
     p010.data = hdr;
@@ -314,7 +314,7 @@
     std::unique_ptr<uint8_t[]> jpegr_data = std::make_unique<uint8_t[]>(jpegR.maxLength);
     jpegR.data = jpegr_data.get();
 
-    if (int success = recoveryMap.encodeJPEGR(&p010, &yuv420,
+    if (int success = jpegREncoder.encodeJPEGR(&p010, &yuv420,
             hdrTransferFunction,
             &jpegR, jpegQuality, nullptr); success != android::OK) {
         ALOGW("Encode JPEG/R failed, error code: %d.", success);
diff --git a/libs/hwui/jni/YuvToJpegEncoder.h b/libs/hwui/jni/YuvToJpegEncoder.h
index 3d6d1f3..d22a26c 100644
--- a/libs/hwui/jni/YuvToJpegEncoder.h
+++ b/libs/hwui/jni/YuvToJpegEncoder.h
@@ -2,7 +2,7 @@
 #define _ANDROID_GRAPHICS_YUV_TO_JPEG_ENCODER_H_
 
 #include <android/data_space.h>
-#include <jpegrecoverymap/recoverymap.h>
+#include <jpegrecoverymap/jpegr.h>
 
 extern "C" {
     #include "jpeglib.h"
@@ -77,7 +77,7 @@
 class P010Yuv420ToJpegREncoder {
 public:
     /** Encode YUV data to jpeg/r,  which is output to a stream.
-     *  This method will call RecoveryMap::EncodeJPEGR() method. If encoding failed,
+     *  This method will call JpegR::EncodeJPEGR() method. If encoding failed,
      *  Corresponding error code (defined in jpegrerrorcode.h) will be printed and this
      *  method will be terminated and return false.
      *
@@ -103,7 +103,7 @@
      *  @param aDataSpace data space defined in data_space.h.
      *  @return color gamut for JPEG/R.
      */
-    static android::recoverymap::jpegr_color_gamut findColorGamut(JNIEnv* env, int aDataSpace);
+    static android::jpegrecoverymap::jpegr_color_gamut findColorGamut(JNIEnv* env, int aDataSpace);
 
     /** Map data space (defined in DataSpace.java and data_space.h) to the transfer function
      *  used in JPEG/R
@@ -112,7 +112,7 @@
      *  @param aDataSpace data space defined in data_space.h.
      *  @return color gamut for JPEG/R.
      */
-    static android::recoverymap::jpegr_transfer_function findHdrTransferFunction(
+    static android::jpegrecoverymap::jpegr_transfer_function findHdrTransferFunction(
             JNIEnv* env, int aDataSpace);
 };
 
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 7de3abc3..5a03ad3 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -7625,22 +7625,13 @@
         return codecConfigList;
     }
 
-    /**
-     * Returns a list of audio formats that corresponds to encoding formats
-     * supported on offload path for Le audio playback.
-     *
-     * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
-     * supported for offload Le Audio playback
-     * @hide
-     */
-    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-    @NonNull
-    public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() {
+    private List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio(
+            @AudioSystem.BtOffloadDeviceType int deviceType) {
         ArrayList<Integer> formatsList = new ArrayList<>();
         ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList = new ArrayList<>();
 
         int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
-                AudioSystem.DEVICE_OUT_BLE_HEADSET, formatsList);
+                deviceType, formatsList);
         if (status != AudioManager.SUCCESS) {
             Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForLeAudio failed:" + status);
             return leAudioCodecConfigList;
@@ -7657,6 +7648,34 @@
         return leAudioCodecConfigList;
     }
 
+    /**
+     * Returns a list of audio formats that corresponds to encoding formats
+     * supported on offload path for Le audio playback.
+     *
+     * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
+     * supported for offload Le Audio playback
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @NonNull
+    public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() {
+        return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_HEADSET);
+    }
+
+    /**
+     * Returns a list of audio formats that corresponds to encoding formats
+     * supported on offload path for Le Broadcast playback.
+     *
+     * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
+     * supported for offload Le Broadcast playback
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @NonNull
+    public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeBroadcast() {
+        return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_BROADCAST);
+    }
+
     // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
     // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list
     // of the ports that exist at the time of the last notification.
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 9339c3d..293d3d2 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -273,10 +273,11 @@
     /** @hide */
     @IntDef(flag = false, prefix = "DEVICE_", value = {
             DEVICE_OUT_BLUETOOTH_A2DP,
-            DEVICE_OUT_BLE_HEADSET}
+            DEVICE_OUT_BLE_HEADSET,
+            DEVICE_OUT_BLE_BROADCAST}
     )
     @Retention(RetentionPolicy.SOURCE)
-    public @interface DeviceType {}
+    public @interface BtOffloadDeviceType {}
 
     /**
      * @hide
@@ -1970,7 +1971,7 @@
      * Returns a list of audio formats (codec) supported on the A2DP and LE audio offload path.
      */
     public static native int getHwOffloadFormatsSupportedForBluetoothMedia(
-            @DeviceType int deviceType, ArrayList<Integer> formatList);
+            @BtOffloadDeviceType int deviceType, ArrayList<Integer> formatList);
 
     /** @hide */
     public static native int setSurroundFormatEnabled(int audioFormat, boolean enabled);
diff --git a/media/java/android/media/tv/TvRecordingClient.java b/media/java/android/media/tv/TvRecordingClient.java
index cdeef2b..9a995a0 100644
--- a/media/java/android/media/tv/TvRecordingClient.java
+++ b/media/java/android/media/tv/TvRecordingClient.java
@@ -78,18 +78,28 @@
      *
      * @param view The related {@link TvInteractiveAppView} instance that is linked to this TV
      *             recording client. {@code null} to unlink the view.
-     * @param recordingId The ID of the recording which is assigned by applications. {@code null} is
-     *                    valid only when the TvInteractiveAppView parameter is null.
-     * @hide
+     * @param recordingId The ID of the recording which is assigned by the TV application.
+     *                    {@code null} if and only if the TvInteractiveAppView parameter is
+     *                    {@code null}.
+     * @throws IllegalArgumentException when recording ID is {@code null} and the
+     *                                  TvInteractiveAppView is not {@code null}; or when recording
+     *                                  ID is not {@code null} and the TvInteractiveAppView is
+     *                                  {@code null}.
+     * @see TvInteractiveAppView#notifyRecordingScheduled(String, String)
+     * @see TvInteractiveAppView#notifyRecordingStarted(String, String)
      */
     public void setTvInteractiveAppView(
             @Nullable TvInteractiveAppView view, @Nullable String recordingId) {
         if (view != null && recordingId == null) {
             throw new IllegalArgumentException(
-                    "null recordingId is allowed only when the view is null");
+                    "null recordingId is not allowed only when the view is not null");
+        }
+        if (view == null && recordingId != null) {
+            throw new IllegalArgumentException(
+                    "recordingId should be null when the view is null");
         }
         mTvIAppView = view;
-        mRecordingId = view == null ? null : recordingId;
+        mRecordingId = recordingId;
     }
 
     /**
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
index aac2d61..36954ad 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
@@ -51,12 +51,12 @@
     void onRequestCurrentTvInputId(int seq);
     void onRequestTimeShiftMode(int seq);
     void onRequestAvailableSpeeds(int seq);
-    void onRequestStartRecording(in Uri programUri, int seq);
+    void onRequestStartRecording(in String requestId, in Uri programUri, int seq);
     void onRequestStopRecording(in String recordingId, int seq);
-    void onRequestScheduleRecording(in String inputId, in Uri channelUri, in Uri programUri,
-            in Bundle params, int seq);
-    void onRequestScheduleRecording2(in String inputId, in Uri channelUri, long start,
-            long duration, int repeat, in Bundle params, int seq);
+    void onRequestScheduleRecording(in String requestId, in String inputId, in Uri channelUri,
+            in Uri programUri, in Bundle params, int seq);
+    void onRequestScheduleRecording2(in String requestId, in String inputId, in Uri channelUri,
+            long start, long duration, int repeat, in Bundle params, int seq);
     void onSetTvRecordingInfo(in String recordingId, in TvRecordingInfo recordingInfo, int seq);
     void onRequestTvRecordingInfo(in String recordingId, int seq);
     void onRequestTvRecordingInfoList(in int type, int seq);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
index e362af2..89847a7 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
@@ -91,7 +91,8 @@
     void notifyContentAllowed(in IBinder sessionToken, int userId);
     void notifyContentBlocked(in IBinder sessionToken, in String rating, int userId);
     void notifySignalStrength(in IBinder sessionToken, int stength, int userId);
-    void notifyRecordingStarted(in IBinder sessionToken, in String recordingId, int userId);
+    void notifyRecordingStarted(in IBinder sessionToken, in String recordingId, String requestId,
+            int userId);
     void notifyRecordingStopped(in IBinder sessionToken, in String recordingId, int userId);
     void notifyTvMessage(in IBinder sessionToken, in String type, in Bundle data, int userId);
     void setSurface(in IBinder sessionToken, in Surface surface, int userId);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
index 8d77141..f17d1b7 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
@@ -70,7 +70,7 @@
     void notifyContentAllowed();
     void notifyContentBlocked(in String rating);
     void notifySignalStrength(int strength);
-    void notifyRecordingStarted(in String recordingId);
+    void notifyRecordingStarted(in String recordingId, in String requestId);
     void notifyRecordingStopped(in String recordingId);
     void notifyTvMessage(in String type, in Bundle data);
     void setSurface(in Surface surface);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
index b71f23c..7db8604 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
@@ -50,12 +50,12 @@
     void onRequestCurrentTvInputId();
     void onRequestTimeShiftMode();
     void onRequestAvailableSpeeds();
-    void onRequestStartRecording(in Uri programUri);
+    void onRequestStartRecording(in String requestId, in Uri programUri);
     void onRequestStopRecording(in String recordingId);
-    void onRequestScheduleRecording(in String inputId, in Uri channelUri, in Uri programUri,
-            in Bundle params);
-    void onRequestScheduleRecording2(in String inputId, in Uri channelUri, long start,
-            long duration, int repeat, in Bundle params);
+    void onRequestScheduleRecording(in String requestId, in String inputId, in Uri channelUri,
+            in Uri programUri, in Bundle params);
+    void onRequestScheduleRecording2(in String requestId, in String inputId, in Uri channelUri,
+            long start, long duration, int repeat, in Bundle params);
     void onSetTvRecordingInfo(in String recordingId, in TvRecordingInfo recordingInfo);
     void onRequestTvRecordingInfo(in String recordingId);
     void onRequestTvRecordingInfoList(in int type);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
index f009cea..ba30e79 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
@@ -206,7 +206,9 @@
                 break;
             }
             case DO_NOTIFY_RECORDING_STARTED: {
-                mSessionImpl.notifyRecordingStarted((String) msg.obj);
+                SomeArgs args = (SomeArgs) msg.obj;
+                mSessionImpl.notifyRecordingStarted((String) args.arg1, (String) args.arg2);
+                args.recycle();
                 break;
             }
             case DO_NOTIFY_RECORDING_STOPPED: {
@@ -555,9 +557,9 @@
     }
 
     @Override
-    public void notifyRecordingStarted(String recordingId) {
-        mCaller.executeOrSendMessage(mCaller.obtainMessageO(
-                DO_NOTIFY_RECORDING_STARTED, recordingId));
+    public void notifyRecordingStarted(String recordingId, String requestId) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageOO(
+                DO_NOTIFY_RECORDING_STARTED, recordingId, recordingId));
     }
 
     @Override
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index e6e8c8d..3e31bce3 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -542,14 +542,14 @@
             }
 
             @Override
-            public void onRequestStartRecording(Uri programUri, int seq) {
+            public void onRequestStartRecording(String requestId, Uri programUri, int seq) {
                 synchronized (mSessionCallbackRecordMap) {
                     SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
                     if (record == null) {
                         Log.e(TAG, "Callback not found for seq " + seq);
                         return;
                     }
-                    record.postRequestStartRecording(programUri);
+                    record.postRequestStartRecording(requestId, programUri);
                 }
             }
 
@@ -566,21 +566,8 @@
             }
 
             @Override
-            public void onRequestScheduleRecording(String inputId, Uri channelUri, Uri programUri,
-                    Bundle params, int seq) {
-                synchronized (mSessionCallbackRecordMap) {
-                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
-                    if (record == null) {
-                        Log.e(TAG, "Callback not found for seq " + seq);
-                        return;
-                    }
-                    record.postRequestScheduleRecording(inputId, channelUri, programUri, params);
-                }
-            }
-
-            @Override
-            public void onRequestScheduleRecording2(String inputId, Uri channelUri, long startTime,
-                    long duration, int repeatDays, Bundle params, int seq) {
+            public void onRequestScheduleRecording(String requestId, String inputId, Uri channelUri,
+                    Uri programUri, Bundle params, int seq) {
                 synchronized (mSessionCallbackRecordMap) {
                     SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
                     if (record == null) {
@@ -588,7 +575,22 @@
                         return;
                     }
                     record.postRequestScheduleRecording(
-                            inputId, channelUri, startTime, duration, repeatDays, params);
+                            requestId, inputId, channelUri, programUri, params);
+                }
+            }
+
+            @Override
+            public void onRequestScheduleRecording2(String requestId, String inputId,
+                    Uri channelUri, long startTime, long duration, int repeatDays, Bundle params,
+                    int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postRequestScheduleRecording(requestId, inputId, channelUri, startTime,
+                            duration, repeatDays, params);
                 }
             }
 
@@ -1267,13 +1269,13 @@
             }
         }
 
-        void notifyRecordingStarted(String recordingId) {
+        void notifyRecordingStarted(String recordingId, String requestId) {
             if (mToken == null) {
                 Log.w(TAG, "The session has been already released");
                 return;
             }
             try {
-                mService.notifyRecordingStarted(mToken, recordingId, mUserId);
+                mService.notifyRecordingStarted(mToken, recordingId, requestId, mUserId);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -2129,11 +2131,11 @@
             });
         }
 
-        void postRequestStartRecording(Uri programUri) {
+        void postRequestStartRecording(String requestId, Uri programUri) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    mSessionCallback.onRequestStartRecording(mSession, programUri);
+                    mSessionCallback.onRequestStartRecording(mSession, requestId, programUri);
                 }
             });
         }
@@ -2147,24 +2149,24 @@
             });
         }
 
-        void postRequestScheduleRecording(String inputId, Uri channelUri, Uri programUri,
-                Bundle params) {
+        void postRequestScheduleRecording(String requestId, String inputId, Uri channelUri,
+                Uri programUri, Bundle params) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
                     mSessionCallback.onRequestScheduleRecording(
-                            mSession, inputId, channelUri, programUri, params);
+                            mSession, requestId, inputId, channelUri, programUri, params);
                 }
             });
         }
 
-        void postRequestScheduleRecording(String inputId, Uri channelUri, long startTime,
-                long duration, int repeatDays, Bundle params) {
+        void postRequestScheduleRecording(String requestId, String inputId, Uri channelUri,
+                long startTime, long duration, int repeatDays, Bundle params) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    mSessionCallback.onRequestScheduleRecording(
-                            mSession, inputId, channelUri, startTime, duration, repeatDays, params);
+                    mSessionCallback.onRequestScheduleRecording(mSession, requestId, inputId,
+                            channelUri, startTime, duration, repeatDays, params);
                 }
             });
         }
@@ -2405,7 +2407,7 @@
          * @param session A {@link TvInteractiveAppService.Session} associated with this callback.
          * @param programUri The Uri of the program to be recorded.
          */
-        public void onRequestStartRecording(Session session, Uri programUri) {
+        public void onRequestStartRecording(Session session, String requestId, Uri programUri) {
         }
 
         /**
@@ -2420,7 +2422,7 @@
 
         /**
          * This is called when
-         * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, Uri, Uri, Bundle)}
+         * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, String, Uri, Uri, Bundle)}
          * is called.
          *
          * @param session A {@link TvInteractiveAppService.Session} associated with this callback.
@@ -2433,13 +2435,14 @@
          * @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
          * @see android.media.tv.TvRecordingClient#startRecording(Uri)
          */
-        public void onRequestScheduleRecording(Session session, @NonNull String inputId,
-                @NonNull Uri channelUri, @NonNull Uri programUri, @NonNull Bundle params) {
+        public void onRequestScheduleRecording(Session session, @NonNull String requestId,
+                @NonNull String inputId, @NonNull Uri channelUri, @NonNull Uri programUri,
+                @NonNull Bundle params) {
         }
 
         /**
          * This is called when
-         * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, Uri, long, long, int, Bundle)}
+         * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, String, Uri, long, long, int, Bundle)}
          * is called.
          *
          * @param session A {@link TvInteractiveAppService.Session} associated with this callback.
@@ -2454,9 +2457,9 @@
          * @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
          * @see android.media.tv.TvRecordingClient#startRecording(Uri)
          */
-        public void onRequestScheduleRecording(Session session, @NonNull String inputId,
-                @NonNull Uri channelUri, long startTime, long duration, int repeatDays,
-                @NonNull Bundle params) {
+        public void onRequestScheduleRecording(Session session, @NonNull String requestId,
+                @NonNull String inputId, @NonNull Uri channelUri, long startTime, long duration,
+                int repeatDays, @NonNull Bundle params) {
         }
 
         /**
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index 4be5523..1ae82f4 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -619,21 +619,28 @@
         public void onTvRecordingInfoList(@NonNull List<TvRecordingInfo> recordingInfoList) {}
 
         /**
-         * Receives started recording's ID.
+         * This is called when a recording has been started.
+         *
+         * <p>When a scheduled recording is started, this is also called, and the request ID in this
+         * case is {@code null}.
          *
          * @param recordingId The ID of the recording started. The TV app should provide and
          *                    maintain this ID to identify the recording in the future.
+         * @param requestId The ID of the request when
+         *                  {@link #requestStartRecording(String, Uri)} is called.
+         *                  {@code null} if the recording is not triggered by a
+         *                  {@link #requestStartRecording(String, Uri)} request.
          * @see #onRecordingStopped(String)
          */
-        public void onRecordingStarted(@NonNull String recordingId) {
+        public void onRecordingStarted(@NonNull String recordingId, @Nullable String requestId) {
         }
 
         /**
-         * Receives stopped recording's ID.
+         * This is called when the recording has been stopped.
          *
          * @param recordingId The ID of the recording stopped. This ID is created and maintained by
          *                    the TV app when the recording was started.
-         * @see #onRecordingStarted(String)
+         * @see #onRecordingStarted(String, String)
          */
         public void onRecordingStopped(@NonNull String recordingId) {
         }
@@ -643,10 +650,9 @@
          * session for the corresponding TV input.
          *
          * @param recordingId The ID of the related recording which is sent via
-         *                    {@link #notifyRecordingStarted(String)}
+         *                    {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
          * @param inputId The ID of the TV input bound to the current TvRecordingClient.
          * @see android.media.tv.TvRecordingClient.RecordingCallback#onConnectionFailed(String)
-         * @hide
          */
         public void onRecordingConnectionFailed(
                 @NonNull String recordingId, @NonNull String inputId) {
@@ -656,10 +662,9 @@
          * This is called when the connection to the current recording session is lost.
          *
          * @param recordingId The ID of the related recording which is sent via
-         *                    {@link #notifyRecordingStarted(String)}
+         *                    {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
          * @param inputId The ID of the TV input bound to the current TvRecordingClient.
          * @see android.media.tv.TvRecordingClient.RecordingCallback#onDisconnected(String)
-         * @hide
          */
         public void onRecordingDisconnected(@NonNull String recordingId, @NonNull String inputId) {
         }
@@ -669,10 +674,9 @@
          * ready to start recording.
          *
          * @param recordingId The ID of the related recording which is sent via
-         *                    {@link #notifyRecordingStarted(String)}
+         *                    {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
          * @param channelUri The URI of the tuned channel.
          * @see android.media.tv.TvRecordingClient.RecordingCallback#onTuned(Uri)
-         * @hide
          */
         public void onRecordingTuned(@NonNull String recordingId, @NonNull Uri channelUri) {
         }
@@ -682,7 +686,7 @@
          * recording session is created until it is released.
          *
          * @param recordingId The ID of the related recording which is sent via
-         *                    {@link #notifyRecordingStarted(String)}
+         *                    {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
          * @param err The error code. Should be one of the following.
          * <ul>
          * <li>{@link TvInputManager#RECORDING_ERROR_UNKNOWN}
@@ -690,7 +694,6 @@
          * <li>{@link TvInputManager#RECORDING_ERROR_RESOURCE_BUSY}
          * </ul>
          * @see android.media.tv.TvRecordingClient.RecordingCallback#onError(int)
-         * @hide
          */
         public void onRecordingError(
                 @NonNull String recordingId, @TvInputManager.RecordingError int err) {
@@ -702,9 +705,9 @@
          * @param recordingId The ID assigned to this recording by the app. It can be used to send
          *                    recording related requests such as
          *                    {@link #requestStopRecording(String)}.
-         * @param requestId The ID of the request when requestScheduleRecording is called.
+         * @param requestId The ID of the request when
+         *                  {@link #requestScheduleRecording}  is called.
          *                  {@code null} if the recording is not triggered by a request.
-         * @hide
          */
         public void onRecordingScheduled(@NonNull String recordingId, @Nullable String requestId) {
         }
@@ -1332,18 +1335,22 @@
          * program, whereas null {@code programUri} does not impose such a requirement and the
          * recording can span across multiple TV programs.
          *
+         * @param requestId The ID of this request which is used to match the corresponding
+         *                  response. The request ID in
+         *                  {@link #onRecordingStarted(String, String)} for this request is the
+         *                  same as the ID sent here.
          * @param programUri The URI for the TV program to record.
          * @see android.media.tv.TvRecordingClient#startRecording(Uri)
          */
         @CallSuper
-        public void requestStartRecording(@Nullable Uri programUri) {
+        public void requestStartRecording(@NonNull String requestId, @Nullable Uri programUri) {
             executeOrPostRunnableOnMainThread(() -> {
                 try {
                     if (DEBUG) {
                         Log.d(TAG, "requestStartRecording");
                     }
                     if (mSessionCallback != null) {
-                        mSessionCallback.onRequestStartRecording(programUri);
+                        mSessionCallback.onRequestStartRecording(requestId, programUri);
                     }
                 } catch (RemoteException e) {
                     Log.w(TAG, "error in requestStartRecording", e);
@@ -1358,7 +1365,7 @@
          * call {@link android.media.tv.TvRecordingClient#stopRecording()}.
          *
          * @param recordingId The ID of the recording to stop. This is provided by the TV app in
-         *                    {@link TvInteractiveAppView#notifyRecordingStarted(String)}
+         *                    {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
          * @see android.media.tv.TvRecordingClient#stopRecording()
          */
         @CallSuper
@@ -1380,6 +1387,10 @@
         /**
          * Requests scheduling of a recording.
          *
+         * @param requestId The ID of this request which is used to match the corresponding
+         *                  response. The request ID in
+         *                  {@link #onRecordingScheduled(String, String)} for this request is the
+         *                  same as the ID sent here.
          * @param inputId The ID of the TV input for the given channel.
          * @param channelUri The URI of a channel to be recorded.
          * @param programUri The URI of the TV program to be recorded.
@@ -1388,11 +1399,10 @@
          *            will not create conflicting keys.
          * @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
          * @see android.media.tv.TvRecordingClient#startRecording(Uri)
-         * @hide
          */
         @CallSuper
-        public void requestScheduleRecording(@NonNull String inputId, @NonNull Uri channelUri,
-                @NonNull Uri programUri, @NonNull Bundle params) {
+        public void requestScheduleRecording(@NonNull String requestId, @NonNull String inputId,
+                @NonNull Uri channelUri, @NonNull Uri programUri, @NonNull Bundle params) {
             executeOrPostRunnableOnMainThread(() -> {
                 try {
                     if (DEBUG) {
@@ -1400,7 +1410,7 @@
                     }
                     if (mSessionCallback != null) {
                         mSessionCallback.onRequestScheduleRecording(
-                                inputId, channelUri, programUri, params);
+                                requestId, inputId, channelUri, programUri, params);
                     }
                 } catch (RemoteException e) {
                     Log.w(TAG, "error in requestScheduleRecording", e);
@@ -1411,6 +1421,10 @@
         /**
          * Requests scheduling of a recording.
          *
+         * @param requestId The ID of this request which is used to match the corresponding
+         *                  response. The request ID in
+         *                  {@link #onRecordingScheduled(String, String)} for this request is the
+         *                  same as the ID sent here.
          * @param inputId The ID of the TV input for the given channel.
          * @param channelUri The URI of a channel to be recorded.
          * @param startTime The start time of the recording in milliseconds since epoch.
@@ -1421,19 +1435,19 @@
          *            will not create conflicting keys.
          * @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
          * @see android.media.tv.TvRecordingClient#startRecording(Uri)
-         * @hide
          */
         @CallSuper
-        public void requestScheduleRecording(@NonNull String inputId, @NonNull Uri channelUri,
-                long startTime, long duration, int repeatDays, @NonNull Bundle params) {
+        public void requestScheduleRecording(@NonNull String requestId, @NonNull String inputId,
+                @NonNull Uri channelUri, long startTime, long duration, int repeatDays,
+                @NonNull Bundle params) {
             executeOrPostRunnableOnMainThread(() -> {
                 try {
                     if (DEBUG) {
                         Log.d(TAG, "requestScheduleRecording");
                     }
                     if (mSessionCallback != null) {
-                        mSessionCallback.onRequestScheduleRecording2(
-                                inputId, channelUri, startTime, duration, repeatDays, params);
+                        mSessionCallback.onRequestScheduleRecording2(requestId, inputId, channelUri,
+                                startTime, duration, repeatDays, params);
                     }
                 } catch (RemoteException e) {
                     Log.w(TAG, "error in requestScheduleRecording", e);
@@ -1445,7 +1459,7 @@
          * Sets the recording info for the specified recording
          *
          * @param recordingId The ID of the recording to set the info for. This is provided by the
-         *     TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String)}
+         *     TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
          * @param recordingInfo The {@link TvRecordingInfo} to set to the recording.
          */
         @CallSuper
@@ -1468,7 +1482,8 @@
         /**
          * Gets the recording info for the specified recording
          * @param recordingId The ID of the recording to set the info for. This is provided by the
-         *                    TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String)}
+         *                    TV app in
+         *                    {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
          */
         @CallSuper
         public void requestTvRecordingInfo(@NonNull String recordingId) {
@@ -1757,10 +1772,10 @@
         }
 
         /**
-         * Calls {@link #onRecordingStarted(String)}.
+         * Calls {@link #onRecordingStarted(String, String)}.
          */
-        void notifyRecordingStarted(String recordingId) {
-            onRecordingStarted(recordingId);
+        void notifyRecordingStarted(String recordingId, String requestId) {
+            onRecordingStarted(recordingId, requestId);
         }
 
         /**
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index ca47c2c..0a8de12 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -667,19 +667,22 @@
     }
 
     /**
-     * Alerts the TV interactive app that a recording has been started.
+     * Alerts the related TV interactive app service that a recording has been started.
      *
      * @param recordingId The ID of the recording started. This ID is created and maintained by the
      *                    TV app and is used to identify the recording in the future.
+     *
+     * @param requestId The ID of the request when
+     *                  {@link TvInteractiveAppService.Session#requestStartRecording(String, Uri)}
+     *                  is called. {@code null} if the recording is not triggered by a request.
      * @see TvInteractiveAppView#notifyRecordingStopped(String)
      */
-    public void notifyRecordingStarted(@NonNull String recordingId) {
-        // TODO: add request ID to identify and map the corresponding request.
+    public void notifyRecordingStarted(@NonNull String recordingId, @Nullable String requestId) {
         if (DEBUG) {
             Log.d(TAG, "notifyRecordingStarted");
         }
         if (mSession != null) {
-            mSession.notifyRecordingStarted(recordingId);
+            mSession.notifyRecordingStarted(recordingId, recordingId);
         }
     }
 
@@ -688,7 +691,7 @@
      *
      * @param recordingId The ID of the recording stopped. This ID is created and maintained
      *                    by the TV app when a recording is started.
-     * @see TvInteractiveAppView#notifyRecordingStarted(String)
+     * @see TvInteractiveAppView#notifyRecordingStarted(String, String)
      */
     public void notifyRecordingStopped(@NonNull String recordingId) {
         if (DEBUG) {
@@ -824,7 +827,7 @@
      * while establishing a connection to the recording session for the corresponding TV input.
      *
      * @param recordingId The ID of the related recording which is sent via
-     *                    {@link #notifyRecordingStarted(String)}
+     *                    {@link #notifyRecordingStarted(String, String)}
      * @param inputId The ID of the TV input bound to the current TvRecordingClient.
      * @see android.media.tv.TvRecordingClient.RecordingCallback#onConnectionFailed(String)
      * @hide
@@ -845,7 +848,7 @@
      * the current recording session is lost.
      *
      * @param recordingId The ID of the related recording which is sent via
-     *                    {@link #notifyRecordingStarted(String)}
+     *                    {@link #notifyRecordingStarted(String, String)}
      * @param inputId The ID of the TV input bound to the current TvRecordingClient.
      * @see android.media.tv.TvRecordingClient.RecordingCallback#onDisconnected(String)
      * @hide
@@ -866,7 +869,7 @@
      * has been tuned to the given channel and is ready to start recording.
      *
      * @param recordingId The ID of the related recording which is sent via
-     *                    {@link #notifyRecordingStarted(String)}
+     *                    {@link #notifyRecordingStarted(String, String)}
      * @param channelUri The URI of the tuned channel.
      * @see android.media.tv.TvRecordingClient.RecordingCallback#onTuned(Uri)
      * @hide
@@ -888,7 +891,7 @@
      * it is released.
      *
      * @param recordingId The ID of the related recording which is sent via
-     *                    {@link #notifyRecordingStarted(String)}
+     *                    {@link #notifyRecordingStarted(String, String)}
      * @param err The error code. Should be one of the following.
      * <ul>
      * <li>{@link TvInputManager#RECORDING_ERROR_UNKNOWN}
@@ -916,9 +919,9 @@
      * @param recordingId The ID assigned to this recording by the app. It can be used to send
      *                    recording related requests such as
      *                    {@link TvInteractiveAppService.Session#requestStopRecording(String)}.
-     * @param requestId The ID of the request when requestScheduleRecording is called.
+     * @param requestId The ID of the request when
+     *                  {@link TvInteractiveAppService.Session#requestScheduleRecording} is called.
      *                  {@code null} if the recording is not triggered by a request.
-     * @hide
      */
     public void notifyRecordingScheduled(
             @NonNull String recordingId, @Nullable String requestId) {
@@ -1215,12 +1218,15 @@
          * is called.
          *
          * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+         * @param requestId The ID of this request which is used to match the corresponding
+         *                  response. The request ID in
+         *                  {@link #notifyRecordingStarted(String, String)}
+         *                  for this request should be the same as the ID received here.
          * @param programUri The URI of the program to record
          *
          */
-        public void onRequestStartRecording(
-                @NonNull String iAppServiceId,
-                @Nullable Uri programUri) {
+        public void onRequestStartRecording(@NonNull String iAppServiceId,
+                @NonNull String requestId, @Nullable Uri programUri) {
         }
 
         /**
@@ -1229,8 +1235,8 @@
          *
          * @param iAppServiceId The ID of the TV interactive app service bound to this view.
          * @param recordingId The ID of the recording to stop. This is provided by the TV app in
-         *                    {@link #notifyRecordingStarted(String)}
-         * @see #notifyRecordingStarted(String)
+         *                    {@link #notifyRecordingStarted(String, String)}
+         * @see #notifyRecordingStarted(String, String)
          * @see #notifyRecordingStopped(String)
          */
         public void onRequestStopRecording(
@@ -1240,10 +1246,14 @@
 
         /**
          * This is called when
-         * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, Uri, Uri, Bundle)}
+         * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, String, Uri, Uri, Bundle)}
          * is called.
          *
          * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+         * @param requestId The ID of this request which is used to match the corresponding
+         *                  response. The request ID in
+         *                  {@link #notifyRecordingScheduled(String, String)} for this request
+         *                  should be the same as the ID received here.
          * @param inputId The ID of the TV input for the given channel.
          * @param channelUri The URI of a channel to be recorded.
          * @param programUri The URI of the TV program to be recorded.
@@ -1252,19 +1262,22 @@
          *            will not create conflicting keys.
          * @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
          * @see android.media.tv.TvRecordingClient#startRecording(Uri)
-         * @hide
          */
         public void onRequestScheduleRecording(@NonNull String iAppServiceId,
-                @NonNull String inputId, @NonNull Uri channelUri, @NonNull Uri programUri,
-                @NonNull Bundle params) {
+                @NonNull String requestId, @NonNull String inputId, @NonNull Uri channelUri,
+                @NonNull Uri programUri, @NonNull Bundle params) {
         }
 
         /**
          * This is called when
-         * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, Uri, long, long, int, Bundle)}
+         * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, String, Uri, long, long, int, Bundle)}
          * is called.
          *
          * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+         * @param requestId The ID of this request which is used to match the corresponding
+         *                  response. The request ID in
+         *                  {@link #notifyRecordingScheduled(String, String)} for this request
+         *                  should be the same as the ID received here.
          * @param inputId The ID of the TV input for the given channel.
          * @param channelUri The URI of a channel to be recorded.
          * @param startTime The start time of the recording in milliseconds since epoch.
@@ -1275,11 +1288,10 @@
          *            will not create conflicting keys.
          * @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
          * @see android.media.tv.TvRecordingClient#startRecording(Uri)
-         * @hide
          */
         public void onRequestScheduleRecording(@NonNull String iAppServiceId,
-                @NonNull String inputId, @NonNull Uri channelUri, long startTime, long duration,
-                int repeatDays, @NonNull Bundle params) {
+                @NonNull String requestId, @NonNull String inputId, @NonNull Uri channelUri,
+                long startTime, long duration, int repeatDays, @NonNull Bundle params) {
         }
 
         /**
@@ -1304,7 +1316,7 @@
          *
          * @param iAppServiceId The ID of the TV interactive app service bound to this view.
          * @param recordingId The ID of the recording to set the info for. This is provided by the
-         *     TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String)}
+         *     TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
          * @param recordingInfo The {@link TvRecordingInfo} to set to the recording.
          */
         public void onSetTvRecordingInfo(
@@ -1320,7 +1332,8 @@
          *
          * @param iAppServiceId The ID of the TV interactive app service bound to this view.
          * @param recordingId The ID of the recording to get the info for. This is provided by the
-         *                    TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String)}
+         *                    TV app in
+         *                    {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
          */
         public void onRequestTvRecordingInfo(
                 @NonNull String iAppServiceId,
@@ -1724,7 +1737,7 @@
         }
 
         @Override
-        public void onRequestStartRecording(Session session, Uri programUri) {
+        public void onRequestStartRecording(Session session, String requestId, Uri programUri) {
             if (DEBUG) {
                 Log.d(TAG, "onRequestStartRecording");
             }
@@ -1733,7 +1746,7 @@
                 return;
             }
             if (mCallback != null) {
-                mCallback.onRequestStartRecording(mIAppServiceId, programUri);
+                mCallback.onRequestStartRecording(mIAppServiceId, requestId, programUri);
             }
         }
 
@@ -1767,8 +1780,9 @@
         }
 
         @Override
-        public void onRequestScheduleRecording(Session session, @NonNull String inputId,
-                @NonNull Uri channelUri, Uri progarmUri, @NonNull Bundle params) {
+        public void onRequestScheduleRecording(Session session, @NonNull String requestId,
+                @NonNull String inputId, @NonNull Uri channelUri, Uri programUri,
+                @NonNull Bundle params) {
             if (DEBUG) {
                 Log.d(TAG, "onRequestScheduleRecording");
             }
@@ -1777,8 +1791,24 @@
                 return;
             }
             if (mCallback != null) {
-                mCallback.onRequestScheduleRecording(mIAppServiceId, inputId, channelUri,
-                        progarmUri, params);
+                mCallback.onRequestScheduleRecording(mIAppServiceId, requestId, inputId, channelUri,
+                        programUri, params);
+            }
+        }
+
+        public void onRequestScheduleRecording(Session session, @NonNull String requestId,
+                @NonNull String inputId, @NonNull Uri channelUri, long startTime, long duration,
+                int repeatDays, @NonNull Bundle params) {
+            if (DEBUG) {
+                Log.d(TAG, "onRequestScheduleRecording");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onRequestScheduleRecording - session not created");
+                return;
+            }
+            if (mCallback != null) {
+                mCallback.onRequestScheduleRecording(mIAppServiceId, requestId, inputId, channelUri,
+                        startTime, duration, repeatDays, params);
             }
         }
 
@@ -1812,22 +1842,6 @@
             }
         }
 
-        public void onRequestScheduleRecording(Session session, @NonNull String inputId,
-                @NonNull Uri channelUri, long startTime, long duration, int repeatDays,
-                @NonNull Bundle params) {
-            if (DEBUG) {
-                Log.d(TAG, "onRequestScheduleRecording");
-            }
-            if (this != mSessionCallback) {
-                Log.w(TAG, "onRequestScheduleRecording - session not created");
-                return;
-            }
-            if (mCallback != null) {
-                mCallback.onRequestScheduleRecording(mIAppServiceId, inputId, channelUri, startTime,
-                        duration, repeatDays, params);
-            }
-        }
-
         @Override
         public void onRequestSigning(
                 Session session, String id, String algorithm, String alias, byte[] data) {
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 7d08b81..5a56945 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -805,6 +805,7 @@
         acquireTRMSLock("close()");
         try {
             releaseAll();
+            mTunerResourceManager.unregisterClientProfile(mClientId);
             TunerUtils.throwExceptionForResult(nativeClose(), "failed to close tuner");
         } finally {
             releaseTRMSLock();
@@ -968,7 +969,6 @@
         releaseDescramblers();
         releaseFilters();
         releaseDemux();
-        mTunerResourceManager.unregisterClientProfile(mClientId);
     }
 
     /**
diff --git a/packages/CompanionDeviceManager/res/drawable-night/ic_glasses.xml b/packages/CompanionDeviceManager/res/drawable-night/ic_glasses.xml
new file mode 100644
index 0000000..97d201d
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable-night/ic_glasses.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="@android:color/system_neutral1_200">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M6.85,15Q7.625,15 8.238,14.55Q8.85,14.1 9.1,13.375L9.475,12.225Q9.875,11.025 9.275,10.012Q8.675,9 7.55,9H4.025L4.5,12.925Q4.625,13.8 5.287,14.4Q5.95,15 6.85,15ZM17.15,15Q18.05,15 18.712,14.4Q19.375,13.8 19.5,12.925L19.975,9H16.475Q15.35,9 14.75,10.025Q14.15,11.05 14.55,12.25L14.9,13.375Q15.15,14.1 15.762,14.55Q16.375,15 17.15,15ZM6.85,17Q5.2,17 3.963,15.912Q2.725,14.825 2.525,13.175L2,9H1V7H7.55Q8.65,7 9.562,7.537Q10.475,8.075 11,9H13.025Q13.55,8.075 14.463,7.537Q15.375,7 16.475,7H23V9H22L21.475,13.175Q21.275,14.825 20.038,15.912Q18.8,17 17.15,17Q15.725,17 14.588,16.188Q13.45,15.375 13,14.025L12.625,12.9Q12.575,12.725 12.525,12.537Q12.475,12.35 12.425,12H11.575Q11.525,12.3 11.475,12.487Q11.425,12.675 11.375,12.85L11,14Q10.55,15.35 9.413,16.175Q8.275,17 6.85,17Z"/>
+</vector>
diff --git a/packages/CompanionDeviceManager/res/drawable-night/ic_permission_nearby_device_streaming.xml b/packages/CompanionDeviceManager/res/drawable-night/ic_permission_nearby_device_streaming.xml
new file mode 100644
index 0000000..af4fe4d
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable-night/ic_permission_nearby_device_streaming.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="@android:color/system_accent1_200">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M16,23V21H17Q17,21 17,21Q17,21 17,21V6H7V12H5V3Q5,2.175 5.588,1.587Q6.175,1 7,1H17Q17.825,1 18.413,1.587Q19,2.175 19,3V21Q19,21.825 18.413,22.413Q17.825,23 17,23ZM5,23V21Q5.825,21 6.412,21.587Q7,22.175 7,23ZM9,23Q9,21.35 7.825,20.175Q6.65,19 5,19V17Q7.5,17 9.25,18.75Q11,20.5 11,23ZM13,23Q13,19.65 10.675,17.325Q8.35,15 5,15V13Q7.075,13 8.9,13.787Q10.725,14.575 12.075,15.925Q13.425,17.275 14.213,19.1Q15,20.925 15,23ZM7,4H17V3Q17,3 17,3Q17,3 17,3H7Q7,3 7,3Q7,3 7,3ZM7,4V3Q7,3 7,3Q7,3 7,3Q7,3 7,3Q7,3 7,3V4Z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml b/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml
index 5f8d566..9065520 100644
--- a/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml
+++ b/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml
@@ -16,23 +16,12 @@
   -->
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-  android:height="24dp"
-  android:width="24dp"
-  android:viewportHeight="160"
-  android:viewportWidth="160" >
-  <path android:fillAlpha="0" android:fillColor="#000000"
-        android:pathData="M69.48,83.33A26.97,24.46 0,0 1,42.92 107.8,26.97 24.46,0 0,1 15.56,84.07 26.97,24.46 0,0 1,41.29 58.9,26.97 24.46,0 0,1 69.43,81.86"
-        android:strokeColor="#000000" android:strokeWidth="2.265"/>
-    <path android:fillAlpha="0" android:fillColor="#000000"
-        android:pathData="m143.73,83.58a26.97,24.46 0,0 1,-26.56 24.46,26.97 24.46,0 0,1 -27.36,-23.72 26.97,24.46 0,0 1,25.73 -25.18,26.97 24.46,0 0,1 28.14,22.96"
-        android:strokeColor="#000000" android:strokeWidth="2.265"/>
-    <path android:fillAlpha="0" android:fillColor="#000000"
-        android:pathData="m69.42,82.98c20.37,-0.25 20.37,-0.25 20.37,-0.25"
-        android:strokeColor="#000000" android:strokeWidth="2.265"/>
-    <path android:fillAlpha="0" android:fillColor="#000000"
-        android:pathData="M15.37,83.78 L1.9,56.83"
-        android:strokeColor="#000000" android:strokeWidth="2.265"/>
-    <path android:fillAlpha="0" android:fillColor="#000000"
-        android:pathData="M143.67,82.75C154.48,57.9 154.48,58.04 154.48,58.04"
-        android:strokeColor="#000000" android:strokeWidth="2.265"/>
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M6.85,15Q7.625,15 8.238,14.55Q8.85,14.1 9.1,13.375L9.475,12.225Q9.875,11.025 9.275,10.012Q8.675,9 7.55,9H4.025L4.5,12.925Q4.625,13.8 5.287,14.4Q5.95,15 6.85,15ZM17.15,15Q18.05,15 18.712,14.4Q19.375,13.8 19.5,12.925L19.975,9H16.475Q15.35,9 14.75,10.025Q14.15,11.05 14.55,12.25L14.9,13.375Q15.15,14.1 15.762,14.55Q16.375,15 17.15,15ZM6.85,17Q5.2,17 3.963,15.912Q2.725,14.825 2.525,13.175L2,9H1V7H7.55Q8.65,7 9.562,7.537Q10.475,8.075 11,9H13.025Q13.55,8.075 14.463,7.537Q15.375,7 16.475,7H23V9H22L21.475,13.175Q21.275,14.825 20.038,15.912Q18.8,17 17.15,17Q15.725,17 14.588,16.188Q13.45,15.375 13,14.025L12.625,12.9Q12.575,12.725 12.525,12.537Q12.475,12.35 12.425,12H11.575Q11.525,12.3 11.475,12.487Q11.425,12.675 11.375,12.85L11,14Q10.55,15.35 9.413,16.175Q8.275,17 6.85,17Z"/>
 </vector>
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_permission_nearby_device_streaming.xml b/packages/CompanionDeviceManager/res/drawable/ic_permission_nearby_device_streaming.xml
index 7295e78..d890afd 100644
--- a/packages/CompanionDeviceManager/res/drawable/ic_permission_nearby_device_streaming.xml
+++ b/packages/CompanionDeviceManager/res/drawable/ic_permission_nearby_device_streaming.xml
@@ -22,7 +22,6 @@
         android:viewportHeight="24"
         android:tint="@android:color/system_accent1_600">
     <path
-        android:pathData="M6.2529,18.5H16.2529V17.5H18.2529V21.5C18.2529,22.6 17.3529,23.5 16.2529,23.5H6.2529C5.1529,23.5 4.2529,22.6 4.2529,21.5V3.5C4.2529,2.4 5.1529,1.51 6.2529,1.51L16.2529,1.5C17.3529,1.5 18.2529,2.4 18.2529,3.5V7.5H16.2529V6.5H6.2529V18.5ZM16.2529,3.5H6.2529V4.5H16.2529V3.5ZM6.2529,21.5V20.5H16.2529V21.5H6.2529ZM12.6553,9.4049C12.6553,8.8526 13.103,8.4049 13.6553,8.4049H20.5254C21.0776,8.4049 21.5254,8.8526 21.5254,9.4049V14.6055C21.5254,15.1578 21.0776,15.6055 20.5254,15.6055H14.355L12.6553,17.0871V9.4049Z"
-        android:fillColor="#3C4043"
-        android:fillType="evenOdd"/>
+        android:fillColor="@android:color/white"
+        android:pathData="M16,23V21H17Q17,21 17,21Q17,21 17,21V6H7V12H5V3Q5,2.175 5.588,1.587Q6.175,1 7,1H17Q17.825,1 18.413,1.587Q19,2.175 19,3V21Q19,21.825 18.413,22.413Q17.825,23 17,23ZM5,23V21Q5.825,21 6.412,21.587Q7,22.175 7,23ZM9,23Q9,21.35 7.825,20.175Q6.65,19 5,19V17Q7.5,17 9.25,18.75Q11,20.5 11,23ZM13,23Q13,19.65 10.675,17.325Q8.35,15 5,15V13Q7.075,13 8.9,13.787Q10.725,14.575 12.075,15.925Q13.425,17.275 14.213,19.1Q15,20.925 15,23ZM7,4H17V3Q17,3 17,3Q17,3 17,3H7Q7,3 7,3Q7,3 7,3ZM7,4V3Q7,3 7,3Q7,3 7,3Q7,3 7,3Q7,3 7,3V4Z"/>
 </vector>
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index bf69ef4..f64a432 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -26,7 +26,6 @@
 import androidx.activity.ComponentActivity
 import androidx.activity.compose.rememberLauncherForActivityResult
 import androidx.activity.compose.setContent
-import androidx.activity.result.contract.ActivityResultContracts
 import androidx.activity.viewModels
 import androidx.compose.material.ExperimentalMaterialApi
 import androidx.compose.runtime.Composable
@@ -35,6 +34,7 @@
 import com.android.credentialmanager.common.Constants
 import com.android.credentialmanager.common.DialogState
 import com.android.credentialmanager.common.ProviderActivityResult
+import com.android.credentialmanager.common.StartBalIntentSenderForResultContract
 import com.android.credentialmanager.createflow.CreateCredentialScreen
 import com.android.credentialmanager.getflow.GetCredentialScreen
 import com.android.credentialmanager.ui.theme.CredentialSelectorTheme
@@ -84,7 +84,7 @@
             CredentialSelectorViewModel(credManRepo, userConfigRepo)
         }
         val launcher = rememberLauncherForActivityResult(
-            ActivityResultContracts.StartIntentSenderForResult()
+            StartBalIntentSenderForResultContract()
         ) {
             viewModel.onProviderActivityResult(ProviderActivityResult(it.resultCode, it.data))
         }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/StartBalIntentSenderForResultContract.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/StartBalIntentSenderForResultContract.kt
new file mode 100644
index 0000000..9952815
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/StartBalIntentSenderForResultContract.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.common
+
+import android.app.ActivityOptions
+import android.content.Context
+import android.content.Intent
+import androidx.activity.result.ActivityResult
+import androidx.activity.result.IntentSenderRequest
+import androidx.activity.result.contract.ActivityResultContract
+import androidx.activity.result.contract.ActivityResultContracts
+
+/**
+ * A custom StartIntentSenderForResult contract implementation that attaches an [ActivityOptions]
+ * that opts in for background activity launch.
+ */
+class StartBalIntentSenderForResultContract :
+    ActivityResultContract<IntentSenderRequest, ActivityResult>() {
+    override fun createIntent(context: Context, input: IntentSenderRequest): Intent {
+        val activityOptionBundle =
+            ActivityOptions.makeBasic().setPendingIntentBackgroundActivityStartMode(
+                ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+            ).toBundle()
+        return Intent(
+            ActivityResultContracts.StartIntentSenderForResult.ACTION_INTENT_SENDER_REQUEST
+        ).putExtra(
+            ActivityResultContracts.StartActivityForResult.EXTRA_ACTIVITY_OPTIONS_BUNDLE,
+            activityOptionBundle
+        ).putExtra(
+            ActivityResultContracts.StartIntentSenderForResult.EXTRA_INTENT_SENDER_REQUEST,
+            input
+        )
+    }
+
+    override fun parseResult(
+        resultCode: Int,
+        intent: Intent?
+    ): ActivityResult = ActivityResult(resultCode, intent)
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/ActivityEmbedding/Android.bp b/packages/SettingsLib/ActivityEmbedding/Android.bp
index 4b4cfb7..0cd9fe3 100644
--- a/packages/SettingsLib/ActivityEmbedding/Android.bp
+++ b/packages/SettingsLib/ActivityEmbedding/Android.bp
@@ -30,6 +30,6 @@
     apex_available: [
         "//apex_available:platform",
         "com.android.permission",
-        "com.android.healthconnect",
+        "com.android.healthfitness",
     ],
 }
diff --git a/packages/SettingsLib/AppPreference/Android.bp b/packages/SettingsLib/AppPreference/Android.bp
index af7b8b4..0ba47a8 100644
--- a/packages/SettingsLib/AppPreference/Android.bp
+++ b/packages/SettingsLib/AppPreference/Android.bp
@@ -23,6 +23,6 @@
     apex_available: [
         "//apex_available:platform",
         "com.android.permission",
-        "com.android.healthconnect",
+        "com.android.healthfitness",
     ],
 }
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
index 50f8e54..6330848f 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
@@ -28,6 +28,6 @@
         "com.android.adservices",
         "com.android.cellbroadcast",
         "com.android.permission",
-        "com.android.healthconnect",
+        "com.android.healthfitness",
     ],
 }
diff --git a/packages/SettingsLib/FooterPreference/Android.bp b/packages/SettingsLib/FooterPreference/Android.bp
index bcedf50..8b976bb 100644
--- a/packages/SettingsLib/FooterPreference/Android.bp
+++ b/packages/SettingsLib/FooterPreference/Android.bp
@@ -23,6 +23,6 @@
     apex_available: [
         "//apex_available:platform",
         "com.android.permission",
-        "com.android.healthconnect",
+        "com.android.healthfitness",
     ],
 }
diff --git a/packages/SettingsLib/HelpUtils/Android.bp b/packages/SettingsLib/HelpUtils/Android.bp
index 3ec4366a..13fcf8c 100644
--- a/packages/SettingsLib/HelpUtils/Android.bp
+++ b/packages/SettingsLib/HelpUtils/Android.bp
@@ -22,6 +22,6 @@
     apex_available: [
         "//apex_available:platform",
         "com.android.permission",
-        "com.android.healthconnect",
+        "com.android.healthfitness",
     ],
 }
diff --git a/packages/SettingsLib/MainSwitchPreference/Android.bp b/packages/SettingsLib/MainSwitchPreference/Android.bp
index 372a276..825e6ac 100644
--- a/packages/SettingsLib/MainSwitchPreference/Android.bp
+++ b/packages/SettingsLib/MainSwitchPreference/Android.bp
@@ -25,6 +25,6 @@
         "//apex_available:platform",
         "com.android.adservices",
         "com.android.cellbroadcast",
-        "com.android.healthconnect",
+        "com.android.healthfitness",
     ],
 }
diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp
index 939977f..09691f1 100644
--- a/packages/SettingsLib/SettingsTheme/Android.bp
+++ b/packages/SettingsLib/SettingsTheme/Android.bp
@@ -23,7 +23,7 @@
         "com.android.cellbroadcast",
         "com.android.permission",
         "com.android.adservices",
-        "com.android.healthconnect",
+        "com.android.healthfitness",
         "com.android.mediaprovider",
     ],
 }
diff --git a/packages/SettingsLib/SettingsTransition/Android.bp b/packages/SettingsLib/SettingsTransition/Android.bp
index be77845..7f9014c 100644
--- a/packages/SettingsLib/SettingsTransition/Android.bp
+++ b/packages/SettingsLib/SettingsTransition/Android.bp
@@ -23,6 +23,6 @@
         "com.android.adservices",
         "com.android.cellbroadcast",
         "com.android.permission",
-        "com.android.healthconnect",
+        "com.android.healthfitness",
     ],
 }
diff --git a/packages/SettingsLib/Spa/build.gradle b/packages/SettingsLib/Spa/build.gradle
index 9117524a..42af999 100644
--- a/packages/SettingsLib/Spa/build.gradle
+++ b/packages/SettingsLib/Spa/build.gradle
@@ -19,7 +19,7 @@
         BUILD_TOOLS_VERSION = "30.0.3"
         MIN_SDK = 21
         TARGET_SDK = 33
-        jetpack_compose_version = '1.4.0-alpha05'
+        jetpack_compose_version = '1.4.0-beta01'
         jetpack_compose_compiler_version = '1.4.0'
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemListPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemListPage.kt
index 08e6452..5f251b1 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemListPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemListPage.kt
@@ -64,7 +64,7 @@
 
         return SettingsEntryBuilder.createInject(
             owner = createSettingsPage(arguments),
-            displayName = "ItemList_$opParam",
+            label = "ItemList_$opParam",
         ).setUiLayoutFn {
             Preference(
                 object : PreferenceModel {
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemOperatePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemOperatePage.kt
index 8179356..98b27b7 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemOperatePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemOperatePage.kt
@@ -99,7 +99,7 @@
 
         return SettingsEntryBuilder.createInject(
             owner = createSettingsPage(arguments),
-            displayName = "ItemOp_$opParam",
+            label = "ItemOp_$opParam",
         ).setUiLayoutFn {
             // Item name is a runtime parameter, which needs to be read inside UiLayoutFn
             val itemName = parameter.getStringArg(ITEM_NAME_PARAM_NAME, it) ?: "NULL"
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
index eca47b6..f01ff38 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
@@ -87,7 +87,7 @@
 
         return SettingsEntryBuilder.createInject(
             owner = createSettingsPage(arguments),
-            displayName = "${name}_$stringParam",
+            label = "${name}_$stringParam",
         )
             .setSearchDataFn { ArgumentPageModel.genInjectSearchData() }
             .setUiLayoutFn {
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png
index 6bf20be..f513830 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png
index fa01348..73f2407 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png
index 7e57958..6e860d3 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/spa/build.gradle b/packages/SettingsLib/Spa/spa/build.gradle
index 6f1b41c..640aa01 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle
+++ b/packages/SettingsLib/Spa/spa/build.gradle
@@ -69,18 +69,16 @@
 }
 
 dependencies {
-    String jetpack_lifecycle_version = "2.6.0-alpha03"
-
-    api "androidx.appcompat:appcompat:1.7.0-alpha01"
+    api "androidx.appcompat:appcompat:1.7.0-alpha02"
     api "androidx.slice:slice-builders:1.1.0-alpha02"
     api "androidx.slice:slice-core:1.1.0-alpha02"
     api "androidx.slice:slice-view:1.1.0-alpha02"
-    api "androidx.compose.material3:material3:1.1.0-alpha05"
+    api "androidx.compose.material3:material3:1.1.0-alpha06"
     api "androidx.compose.material:material-icons-extended:$jetpack_compose_version"
-    api "androidx.compose.runtime:runtime-livedata:1.4.0-alpha04"
+    api "androidx.compose.runtime:runtime-livedata:$jetpack_compose_version"
     api "androidx.compose.ui:ui-tooling-preview:$jetpack_compose_version"
-    api "androidx.lifecycle:lifecycle-livedata-ktx:$jetpack_lifecycle_version"
-    api "androidx.lifecycle:lifecycle-runtime-compose:$jetpack_lifecycle_version"
+    api "androidx.lifecycle:lifecycle-livedata-ktx"
+    api "androidx.lifecycle:lifecycle-runtime-compose"
     api "androidx.navigation:navigation-compose:2.6.0-alpha04"
     api "com.github.PhilJay:MPAndroidChart:v3.1.0-alpha"
     api "com.google.android.material:material:1.7.0-alpha03"
@@ -108,7 +106,6 @@
 
                     // Excludes files forked from Accompanist.
                     "com/android/settingslib/spa/framework/compose/DrawablePainter*",
-                    "com/android/settingslib/spa/framework/compose/Pager*",
 
                     // Excludes inline functions, which is not covered in Jacoco reports.
                     "com/android/settingslib/spa/framework/util/Collections*",
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt
index d95ed05..444a3f0 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt
@@ -50,22 +50,22 @@
 }
 
 fun SettingsEntry.debugBrief(): String {
-    return "${owner.displayName}:$displayName"
+    return "${owner.displayName}:$label"
 }
 
 fun SettingsEntry.debugContent(entryRepository: SettingsEntryRepository): String {
     val searchData = getSearchData()
     val statusData = getStatusData()
-    val entryPathWithName = entryRepository.getEntryPathWithDisplayName(id)
+    val entryPathWithLabel = entryRepository.getEntryPathWithLabel(id)
     val entryPathWithTitle = entryRepository.getEntryPathWithTitle(id,
-        searchData?.title ?: displayName)
+        searchData?.title ?: label)
     val content = listOf(
         "------ STATIC ------",
         "id = $id",
         "owner = ${owner.debugBrief()} ${owner.debugArguments()}",
         "linkFrom = ${fromPage?.debugBrief()} ${fromPage?.debugArguments()}",
         "linkTo = ${toPage?.debugBrief()} ${toPage?.debugArguments()}",
-        "hierarchy_path = $entryPathWithName",
+        "hierarchy_path = $entryPathWithLabel",
         "------ ATTRIBUTION ------",
         "allowSearch = $isAllowSearch",
         "isSearchDynamic = $isSearchDataDynamic",
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt
index 494e3cc..1fcc888 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt
@@ -173,12 +173,12 @@
             val intent = entry.createIntent(SESSION_SEARCH) ?: Intent()
             cursor.newRow()
                 .add(ColumnEnum.ENTRY_ID.id, entry.id)
-                .add(ColumnEnum.ENTRY_NAME.id, entry.displayName)
+                .add(ColumnEnum.ENTRY_LABEL.id, entry.label)
                 .add(ColumnEnum.ENTRY_ROUTE.id, entry.containerPage().buildRoute())
                 .add(ColumnEnum.ENTRY_INTENT_URI.id, intent.toUri(URI_INTENT_SCHEME))
                 .add(
                     ColumnEnum.ENTRY_HIERARCHY_PATH.id,
-                    entryRepository.getEntryPathWithDisplayName(entry.id)
+                    entryRepository.getEntryPathWithLabel(entry.id)
                 )
         }
         return cursor
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/ProviderColumn.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/ProviderColumn.kt
index fc6160e..9b46ec2 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/ProviderColumn.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/ProviderColumn.kt
@@ -33,7 +33,7 @@
 
     // Columns related to entry
     ENTRY_ID("entryId"),
-    ENTRY_NAME("entryName"),
+    ENTRY_LABEL("entryLabel"),
     ENTRY_ROUTE("entryRoute"),
     ENTRY_INTENT_URI("entryIntent"),
     ENTRY_HIERARCHY_PATH("entryPath"),
@@ -76,7 +76,7 @@
         "entry_info", 200,
         listOf(
             ColumnEnum.ENTRY_ID,
-            ColumnEnum.ENTRY_NAME,
+            ColumnEnum.ENTRY_LABEL,
             ColumnEnum.ENTRY_ROUTE,
             ColumnEnum.ENTRY_INTENT_URI,
             ColumnEnum.ENTRY_HIERARCHY_PATH,
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
index b92729d..90581b9 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
@@ -51,11 +51,13 @@
     // The unique id of this entry, which is computed by name + owner + fromPage + toPage.
     val id: String,
 
-    // The name of the page, which is used to compute the unique id, and need to be stable.
+    // The name of the entry, which is used to compute the unique id, and need to be stable.
     private val name: String,
 
-    // The display name of the page, for better readability.
-    val displayName: String,
+    // The label of the entry, for better readability.
+    // For migration mapping, this should match the android:key field in the old architecture
+    // if applicable.
+    val label: String,
 
     // The owner page of this entry.
     val owner: SettingsPage,
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt
index 67f9ea5..97d8de3 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt
@@ -21,14 +21,14 @@
 import androidx.compose.runtime.remember
 import com.android.settingslib.spa.framework.util.genEntryId
 
-private const val INJECT_ENTRY_NAME = "INJECT"
-private const val ROOT_ENTRY_NAME = "ROOT"
+private const val INJECT_ENTRY_LABEL = "INJECT"
+private const val ROOT_ENTRY_LABEL = "ROOT"
 
 /**
  * The helper to build a Settings Entry instance.
  */
 class SettingsEntryBuilder(private val name: String, private val owner: SettingsPage) {
-    private var displayName = name
+    private var label = name
     private var fromPage: SettingsPage? = null
     private var toPage: SettingsPage? = null
 
@@ -51,7 +51,7 @@
             id = genEntryId(name, owner, fromPage, toPage),
             name = name,
             owner = owner,
-            displayName = displayName,
+            label = label,
 
             // linking data
             fromPage = fromPage,
@@ -72,8 +72,8 @@
         )
     }
 
-    fun setDisplayName(displayName: String): SettingsEntryBuilder {
-        this.displayName = displayName
+    fun setLabel(label: String): SettingsEntryBuilder {
+        this.label = label
         return this
     }
 
@@ -147,19 +147,19 @@
             return create(entryName, owner).setLink(toPage = owner)
         }
 
-        fun create(owner: SettingsPage, entryName: String, displayName: String? = null):
+        fun create(owner: SettingsPage, entryName: String, label: String? = null):
             SettingsEntryBuilder {
-            return SettingsEntryBuilder(entryName, owner).setDisplayName(displayName ?: entryName)
+            return SettingsEntryBuilder(entryName, owner).setLabel(label ?: entryName)
         }
 
-        fun createInject(owner: SettingsPage, displayName: String? = null): SettingsEntryBuilder {
-            val name = displayName ?: "${INJECT_ENTRY_NAME}_${owner.displayName}"
-            return createLinkTo(INJECT_ENTRY_NAME, owner).setDisplayName(name)
+        fun createInject(owner: SettingsPage, label: String? = null): SettingsEntryBuilder {
+            val label = label ?: "${INJECT_ENTRY_LABEL}_${owner.displayName}"
+            return createLinkTo(INJECT_ENTRY_LABEL, owner).setLabel(label)
         }
 
-        fun createRoot(owner: SettingsPage, displayName: String? = null): SettingsEntryBuilder {
-            val name = displayName ?: "${ROOT_ENTRY_NAME}_${owner.displayName}"
-            return createLinkTo(ROOT_ENTRY_NAME, owner).setDisplayName(name)
+        fun createRoot(owner: SettingsPage, label: String? = null): SettingsEntryBuilder {
+            val label = label ?: "${ROOT_ENTRY_LABEL}_${owner.displayName}"
+            return createLinkTo(ROOT_ENTRY_LABEL, owner).setLabel(label)
         }
     }
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
index 429f97b..8811b94 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
@@ -111,9 +111,9 @@
         return entryPath
     }
 
-    fun getEntryPathWithDisplayName(entryId: String): List<String> {
+    fun getEntryPathWithLabel(entryId: String): List<String> {
         val entryPath = getEntryPath(entryId)
-        return entryPath.map { it.displayName }
+        return entryPath.map { it.label }
     }
 
     fun getEntryPathWithTitle(entryId: String, defaultTitle: String): List<String> {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt
deleted file mode 100644
index 392089a..0000000
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.spa.framework.compose
-
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.wrapContentSize
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.LazyRow
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.Stable
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.snapshotFlow
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
-import androidx.compose.ui.input.nestedscroll.NestedScrollSource
-import androidx.compose.ui.input.nestedscroll.nestedScroll
-import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.Velocity
-import androidx.compose.ui.unit.dp
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.drop
-import kotlinx.coroutines.flow.filter
-
-/**
- * *************************************************************************************************
- * This file was forked from
- * https://github.com/google/accompanist/blob/main/pager/src/main/java/com/google/accompanist/pager/Pager.kt
- * and will be removed once it lands in AndroidX.
- */
-
-/**
- * A horizontally scrolling layout that allows users to flip between items to the left and right.
- *
- * @sample com.google.accompanist.sample.pager.HorizontalPagerSample
- *
- * @param count the number of pages.
- * @param modifier the modifier to apply to this layout.
- * @param state the state object to be used to control or observe the pager's state.
- * @param reverseLayout reverse the direction of scrolling and layout, when `true` items will be
- * composed from the end to the start and [PagerState.currentPage] == 0 will mean
- * the first item is located at the end.
- * @param itemSpacing horizontal spacing to add between items.
- * @param key the scroll position will be maintained based on the key, which means if you
- * add/remove items before the current visible item the item with the given key will be kept as the
- * first visible one.
- * @param content a block which describes the content. Inside this block you can reference
- * [PagerScope.currentPage] and other properties in [PagerScope].
- */
-@Composable
-fun HorizontalPager(
-    count: Int,
-    modifier: Modifier = Modifier,
-    state: PagerState = rememberPagerState(),
-    reverseLayout: Boolean = false,
-    itemSpacing: Dp = 0.dp,
-    contentPadding: PaddingValues = PaddingValues(0.dp),
-    verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
-    key: ((page: Int) -> Any)? = null,
-    content: @Composable PagerScope.(page: Int) -> Unit,
-) {
-    Pager(
-        count = count,
-        state = state,
-        modifier = modifier,
-        isVertical = false,
-        reverseLayout = reverseLayout,
-        itemSpacing = itemSpacing,
-        verticalAlignment = verticalAlignment,
-        key = key,
-        contentPadding = contentPadding,
-        content = content
-    )
-}
-
-/**
- * A vertically scrolling layout that allows users to flip between items to the top and bottom.
- *
- * @sample com.google.accompanist.sample.pager.VerticalPagerSample
- *
- * @param count the number of pages.
- * @param modifier the modifier to apply to this layout.
- * @param state the state object to be used to control or observe the pager's state.
- * @param reverseLayout reverse the direction of scrolling and layout, when `true` items will be
- * composed from the bottom to the top and [PagerState.currentPage] == 0 will mean
- * the first item is located at the bottom.
- * @param itemSpacing vertical spacing to add between items.
- * @param key the scroll position will be maintained based on the key, which means if you
- * add/remove items before the current visible item the item with the given key will be kept as the
- * first visible one.
- * @param content a block which describes the content. Inside this block you can reference
- * [PagerScope.currentPage] and other properties in [PagerScope].
- */
-@Composable
-fun VerticalPager(
-    count: Int,
-    modifier: Modifier = Modifier,
-    state: PagerState = rememberPagerState(),
-    reverseLayout: Boolean = false,
-    itemSpacing: Dp = 0.dp,
-    contentPadding: PaddingValues = PaddingValues(0.dp),
-    horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
-    key: ((page: Int) -> Any)? = null,
-    content: @Composable PagerScope.(page: Int) -> Unit,
-) {
-    Pager(
-        count = count,
-        state = state,
-        modifier = modifier,
-        isVertical = true,
-        reverseLayout = reverseLayout,
-        itemSpacing = itemSpacing,
-        horizontalAlignment = horizontalAlignment,
-        key = key,
-        contentPadding = contentPadding,
-        content = content
-    )
-}
-
-@Composable
-internal fun Pager(
-    count: Int,
-    modifier: Modifier,
-    state: PagerState,
-    reverseLayout: Boolean,
-    itemSpacing: Dp,
-    isVertical: Boolean,
-    key: ((page: Int) -> Any)?,
-    contentPadding: PaddingValues,
-    verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
-    horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
-    content: @Composable PagerScope.(page: Int) -> Unit,
-) {
-    require(count >= 0) { "pageCount must be >= 0" }
-
-    LaunchedEffect(count) {
-        state.currentPage = minOf(count - 1, state.currentPage).coerceAtLeast(0)
-    }
-
-    // Once a fling (scroll) has finished, notify the state
-    LaunchedEffect(state) {
-        // When a 'scroll' has finished, notify the state
-        snapshotFlow { state.isScrollInProgress }
-            .filter { !it }
-            // initially isScrollInProgress is false as well and we want to start receiving
-            // the events only after the real scroll happens.
-            .drop(1)
-            .collect { state.onScrollFinished() }
-    }
-    LaunchedEffect(state) {
-        snapshotFlow { state.mostVisiblePageLayoutInfo?.index }
-            .distinctUntilChanged()
-            .collect { state.updateCurrentPageBasedOnLazyListState() }
-    }
-    val density = LocalDensity.current
-    LaunchedEffect(density, state, itemSpacing) {
-        with(density) { state.itemSpacing = itemSpacing.roundToPx() }
-    }
-
-    val pagerScope = remember(state) { PagerScopeImpl(state) }
-
-    // We only consume nested flings in the main-axis, allowing cross-axis flings to propagate
-    // as normal
-    val consumeFlingNestedScrollConnection = remember(isVertical) {
-        ConsumeFlingNestedScrollConnection(
-            consumeHorizontal = !isVertical,
-            consumeVertical = isVertical,
-            pagerState = state,
-        )
-    }
-
-    if (isVertical) {
-        LazyColumn(
-            state = state.lazyListState,
-            verticalArrangement = Arrangement.spacedBy(itemSpacing, verticalAlignment),
-            horizontalAlignment = horizontalAlignment,
-            reverseLayout = reverseLayout,
-            contentPadding = contentPadding,
-            userScrollEnabled = false,
-            modifier = modifier,
-        ) {
-            items(
-                count = count,
-                key = key,
-            ) { page ->
-                Box(
-                    Modifier
-                        // We don't any nested flings to continue in the pager, so we add a
-                        // connection which consumes them.
-                        // See: https://github.com/google/accompanist/issues/347
-                        .nestedScroll(connection = consumeFlingNestedScrollConnection)
-                        // Constraint the content height to be <= than the height of the pager.
-                        .fillParentMaxHeight()
-                        .wrapContentSize()
-                ) {
-                    pagerScope.content(page)
-                }
-            }
-        }
-    } else {
-        LazyRow(
-            state = state.lazyListState,
-            verticalAlignment = verticalAlignment,
-            horizontalArrangement = Arrangement.spacedBy(itemSpacing, horizontalAlignment),
-            reverseLayout = reverseLayout,
-            contentPadding = contentPadding,
-            userScrollEnabled = false,
-            modifier = modifier,
-        ) {
-            items(
-                count = count,
-                key = key,
-            ) { page ->
-                Box(
-                    Modifier
-                        // We don't any nested flings to continue in the pager, so we add a
-                        // connection which consumes them.
-                        // See: https://github.com/google/accompanist/issues/347
-                        .nestedScroll(connection = consumeFlingNestedScrollConnection)
-                        // Constraint the content width to be <= than the width of the pager.
-                        .fillParentMaxWidth()
-                        .wrapContentSize()
-                ) {
-                    pagerScope.content(page)
-                }
-            }
-        }
-    }
-}
-
-private class ConsumeFlingNestedScrollConnection(
-    private val consumeHorizontal: Boolean,
-    private val consumeVertical: Boolean,
-    private val pagerState: PagerState,
-) : NestedScrollConnection {
-    override fun onPostScroll(
-        consumed: Offset,
-        available: Offset,
-        source: NestedScrollSource
-    ): Offset = when (source) {
-        // We can consume all resting fling scrolls so that they don't propagate up to the
-        // Pager
-        NestedScrollSource.Fling -> available.consume(consumeHorizontal, consumeVertical)
-        else -> Offset.Zero
-    }
-
-    override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
-        return if (pagerState.currentPageOffset != 0f) {
-            // The Pager is already scrolling. This means that a nested scroll child was
-            // scrolled to end, and the Pager can use this fling
-            Velocity.Zero
-        } else {
-            // A nested scroll child is still scrolling. We can consume all post fling
-            // velocity on the main-axis so that it doesn't propagate up to the Pager
-            available.consume(consumeHorizontal, consumeVertical)
-        }
-    }
-}
-
-private fun Offset.consume(
-    consumeHorizontal: Boolean,
-    consumeVertical: Boolean,
-): Offset = Offset(
-    x = if (consumeHorizontal) this.x else 0f,
-    y = if (consumeVertical) this.y else 0f,
-)
-
-private fun Velocity.consume(
-    consumeHorizontal: Boolean,
-    consumeVertical: Boolean,
-): Velocity = Velocity(
-    x = if (consumeHorizontal) this.x else 0f,
-    y = if (consumeVertical) this.y else 0f,
-)
-
-/**
- * Scope for [HorizontalPager] content.
- */
-@Stable
-interface PagerScope {
-    /**
-     * Returns the current selected page
-     */
-    val currentPage: Int
-
-    /**
-     * The current offset from the start of [currentPage], as a ratio of the page width.
-     */
-    val currentPageOffset: Float
-}
-
-private class PagerScopeImpl(
-    private val state: PagerState,
-) : PagerScope {
-    override val currentPage: Int get() = state.currentPage
-    override val currentPageOffset: Float get() = state.currentPageOffset
-}
-
-/**
- * Calculate the offset for the given [page] from the current scroll position. This is useful
- * when using the scroll position to apply effects or animations to items.
- *
- * The returned offset can positive or negative, depending on whether which direction the [page] is
- * compared to the current scroll position.
- *
- * @sample com.google.accompanist.sample.pager.HorizontalPagerWithOffsetTransition
- */
-fun PagerScope.calculateCurrentOffsetForPage(page: Int): Float {
-    return (currentPage - page) + currentPageOffset
-}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/PagerState.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/PagerState.kt
deleted file mode 100644
index 480335d..0000000
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/PagerState.kt
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.spa.framework.compose
-
-import androidx.annotation.FloatRange
-import androidx.annotation.IntRange
-import androidx.compose.foundation.MutatePriority
-import androidx.compose.foundation.gestures.ScrollScope
-import androidx.compose.foundation.gestures.ScrollableState
-import androidx.compose.foundation.interaction.InteractionSource
-import androidx.compose.foundation.lazy.LazyListItemInfo
-import androidx.compose.foundation.lazy.LazyListState
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.Stable
-import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.saveable.Saver
-import androidx.compose.runtime.saveable.listSaver
-import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
-import kotlin.math.abs
-import kotlin.math.absoluteValue
-import kotlin.math.roundToInt
-
-/**
- * *************************************************************************************************
- * This file was forked from
- * https://github.com/google/accompanist/blob/main/pager/src/main/java/com/google/accompanist/pager/PagerState.kt
- * and will be removed once it lands in AndroidX.
- */
-
-/**
- * Creates a [PagerState] that is remembered across compositions.
- *
- * Changes to the provided values for [initialPage] will **not** result in the state being
- * recreated or changed in any way if it has already
- * been created.
- *
- * @param initialPage the initial value for [PagerState.currentPage]
- */
-@Composable
-fun rememberPagerState(
-    @IntRange(from = 0) initialPage: Int = 0,
-): PagerState = rememberSaveable(saver = PagerState.Saver) {
-    PagerState(
-        currentPage = initialPage,
-    )
-}
-
-/**
- * A state object that can be hoisted to control and observe scrolling for [HorizontalPager].
- *
- * In most cases, this will be created via [rememberPagerState].
- *
- * @param currentPage the initial value for [PagerState.currentPage]
- */
-@Stable
-class PagerState(
-    @IntRange(from = 0) currentPage: Int = 0,
-) : ScrollableState {
-    // Should this be public?
-    internal val lazyListState = LazyListState(firstVisibleItemIndex = currentPage)
-
-    private var _currentPage by mutableStateOf(currentPage)
-
-    // finds the page which has larger visible area within the viewport not including paddings
-    internal val mostVisiblePageLayoutInfo: LazyListItemInfo?
-        get() {
-            val layoutInfo = lazyListState.layoutInfo
-            return layoutInfo.visibleItemsInfo.maxByOrNull {
-                val start = maxOf(it.offset, 0)
-                val end = minOf(
-                    it.offset + it.size,
-                    layoutInfo.viewportEndOffset - layoutInfo.afterContentPadding
-                )
-                end - start
-            }
-        }
-
-    internal var itemSpacing by mutableStateOf(0)
-
-    private val currentPageLayoutInfo: LazyListItemInfo?
-        get() = lazyListState.layoutInfo.visibleItemsInfo.lastOrNull {
-            it.index == currentPage
-        }
-
-    /**
-     * [InteractionSource] that will be used to dispatch drag events when this
-     * list is being dragged. If you want to know whether the fling (or animated scroll) is in
-     * progress, use [isScrollInProgress].
-     */
-    val interactionSource: InteractionSource
-        get() = lazyListState.interactionSource
-
-    /**
-     * The number of pages to display.
-     */
-    @get:IntRange(from = 0)
-    val pageCount: Int by derivedStateOf {
-        lazyListState.layoutInfo.totalItemsCount
-    }
-
-    /**
-     * The index of the currently selected page. This may not be the page which is
-     * currently displayed on screen.
-     *
-     * To update the scroll position, use [scrollToPage] or [animateScrollToPage].
-     */
-    @get:IntRange(from = 0)
-    var currentPage: Int
-        get() = _currentPage
-        internal set(value) {
-            if (value != _currentPage) {
-                _currentPage = value
-            }
-        }
-
-    /**
-     * The current offset from the start of [currentPage], as a ratio of the page width.
-     *
-     * To update the scroll position, use [scrollToPage] or [animateScrollToPage].
-     */
-    val currentPageOffset: Float by derivedStateOf {
-        currentPageLayoutInfo?.let {
-            (-it.offset / (it.size + itemSpacing).toFloat()).coerceIn(-0.5f, 0.5f)
-        } ?: 0f
-    }
-
-    /**
-     * The target page for any on-going animations.
-     */
-    private var animationTargetPage: Int? by mutableStateOf(null)
-
-    /**
-     * Animate (smooth scroll) to the given page to the middle of the viewport.
-     *
-     * Cancels the currently running scroll, if any, and suspends until the cancellation is
-     * complete.
-     *
-     * @param page the page to animate to. Must be >= 0.
-     * @param pageOffset the percentage of the page size to offset, from the start of [page].
-     * Must be in the range -1f..1f.
-     */
-    suspend fun animateScrollToPage(
-        @IntRange(from = 0) page: Int,
-        @FloatRange(from = -1.0, to = 1.0) pageOffset: Float = 0f,
-    ) {
-        requireCurrentPage(page, "page")
-        requireCurrentPageOffset(pageOffset, "pageOffset")
-        try {
-            animationTargetPage = page
-
-            // pre-jump to nearby item for long jumps as an optimization
-            // the same trick is done in ViewPager2
-            val oldPage = lazyListState.firstVisibleItemIndex
-            if (abs(page - oldPage) > 3) {
-                lazyListState.scrollToItem(if (page > oldPage) page - 3 else page + 3)
-            }
-
-            if (pageOffset.absoluteValue <= 0.005f) {
-                // If the offset is (close to) zero, just call animateScrollToItem and we're done
-                lazyListState.animateScrollToItem(index = page)
-            } else {
-                // Else we need to figure out what the offset is in pixels...
-                lazyListState.scroll { } // this will await for the first layout.
-                val layoutInfo = lazyListState.layoutInfo
-                var target = layoutInfo.visibleItemsInfo
-                    .firstOrNull { it.index == page }
-
-                if (target != null) {
-                    // If we have access to the target page layout, we can calculate the pixel
-                    // offset from the size
-                    lazyListState.animateScrollToItem(
-                        index = page,
-                        scrollOffset = ((target.size + itemSpacing) * pageOffset).roundToInt()
-                    )
-                } else if (layoutInfo.visibleItemsInfo.isNotEmpty()) {
-                    // If we don't, we use the current page size as a guide
-                    val currentSize = layoutInfo.visibleItemsInfo.first().size + itemSpacing
-                    lazyListState.animateScrollToItem(
-                        index = page,
-                        scrollOffset = (currentSize * pageOffset).roundToInt()
-                    )
-
-                    // The target should be visible now
-                    target = layoutInfo.visibleItemsInfo.firstOrNull { it.index == page }
-
-                    if (target != null && target.size + itemSpacing != currentSize) {
-                        // If the size we used for calculating the offset differs from the actual
-                        // target page size, we need to scroll again. This doesn't look great,
-                        // but there's not much else we can do.
-                        lazyListState.animateScrollToItem(
-                            index = page,
-                            scrollOffset = ((target.size + itemSpacing) * pageOffset).roundToInt()
-                        )
-                    }
-                }
-            }
-        } finally {
-            // We need to manually call this, as the `animateScrollToItem` call above will happen
-            // in 1 frame, which is usually too fast for the LaunchedEffect in Pager to detect
-            // the change. This is especially true when running unit tests.
-            onScrollFinished()
-        }
-    }
-
-    /**
-     * Instantly brings the item at [page] to the middle of the viewport.
-     *
-     * Cancels the currently running scroll, if any, and suspends until the cancellation is
-     * complete.
-     *
-     * @param page the page to snap to. Must be >= 0.
-     * @param pageOffset the percentage of the page size to offset, from the start of [page].
-     * Must be in the range -1f..1f.
-     */
-    suspend fun scrollToPage(
-        @IntRange(from = 0) page: Int,
-        @FloatRange(from = -1.0, to = 1.0) pageOffset: Float = 0f,
-    ) {
-        requireCurrentPage(page, "page")
-        requireCurrentPageOffset(pageOffset, "pageOffset")
-        try {
-            animationTargetPage = page
-
-            // First scroll to the given page. It will now be laid out at offset 0
-            lazyListState.scrollToItem(index = page)
-            updateCurrentPageBasedOnLazyListState()
-
-            // If we have a start spacing, we need to offset (scroll) by that too
-            if (pageOffset.absoluteValue > 0.0001f) {
-                currentPageLayoutInfo?.let {
-                    scroll {
-                        scrollBy((it.size + itemSpacing) * pageOffset)
-                    }
-                }
-            }
-        } finally {
-            // We need to manually call this, as the `scroll` call above will happen in 1 frame,
-            // which is usually too fast for the LaunchedEffect in Pager to detect the change.
-            // This is especially true when running unit tests.
-            onScrollFinished()
-        }
-    }
-
-    internal fun updateCurrentPageBasedOnLazyListState() {
-        // Then update the current page to our layout page
-        mostVisiblePageLayoutInfo?.let {
-            currentPage = it.index
-        }
-    }
-
-    internal fun onScrollFinished() {
-        // Clear the animation target page
-        animationTargetPage = null
-    }
-
-    override suspend fun scroll(
-        scrollPriority: MutatePriority,
-        block: suspend ScrollScope.() -> Unit
-    ) = lazyListState.scroll(scrollPriority, block)
-
-    override fun dispatchRawDelta(delta: Float): Float {
-        return lazyListState.dispatchRawDelta(delta)
-    }
-
-    override val isScrollInProgress: Boolean
-        get() = lazyListState.isScrollInProgress
-
-    override fun toString(): String = "PagerState(" +
-        "pageCount=$pageCount, " +
-        "currentPage=$currentPage, " +
-        "currentPageOffset=$currentPageOffset" +
-        ")"
-
-    private fun requireCurrentPage(value: Int, name: String) {
-        require(value >= 0) { "$name[$value] must be >= 0" }
-    }
-
-    private fun requireCurrentPageOffset(value: Float, name: String) {
-        require(value in -1f..1f) { "$name must be >= -1 and <= 1" }
-    }
-
-    companion object {
-        /**
-         * The default [Saver] implementation for [PagerState].
-         */
-        val Saver: Saver<PagerState, *> = listSaver(
-            save = {
-                listOf<Any>(
-                    it.currentPage,
-                )
-            },
-            restore = {
-                PagerState(
-                    currentPage = it[0] as Int,
-                )
-            }
-        )
-    }
-}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt
index e6fa74e..26372b6 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt
@@ -17,6 +17,9 @@
 package com.android.settingslib.spa.framework.theme
 
 import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material.ripple.LocalRippleTheme
+import androidx.compose.material.ripple.RippleAlpha
+import androidx.compose.material.ripple.RippleTheme
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
@@ -33,8 +36,11 @@
         background = settingsColorScheme.background,
     )
 
-    CompositionLocalProvider(LocalColorScheme provides settingsColorScheme(isDarkTheme)) {
-        MaterialTheme(colorScheme = colorScheme, typography = rememberSettingsTypography()) {
+    MaterialTheme(colorScheme = colorScheme, typography = rememberSettingsTypography()) {
+        CompositionLocalProvider(
+            LocalColorScheme provides settingsColorScheme(isDarkTheme),
+            LocalRippleTheme provides SettingsRippleTheme,
+        ) {
             content()
         }
     }
@@ -46,3 +52,19 @@
         @ReadOnlyComposable
         get() = LocalColorScheme.current
 }
+
+private object SettingsRippleTheme : RippleTheme {
+    @Composable
+    override fun defaultColor() = MaterialTheme.colorScheme.onSurface
+
+    @Composable
+    override fun rippleAlpha() = RippleAlpha
+}
+
+/** Alpha levels for all content. */
+private val RippleAlpha = RippleAlpha(
+    pressedAlpha = 0.48f,
+    focusedAlpha = 0.48f,
+    draggedAlpha = 0.32f,
+    hoveredAlpha = 0.16f,
+)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt
index 83dcd13..780933d3c 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt
@@ -43,6 +43,7 @@
 /** Enum to define all column names in provider. */
 enum class ColumnEnum(val id: String) {
     ENTRY_ID("entryId"),
+    ENTRY_LABEL("entryLabel"),
     SEARCH_TITLE("searchTitle"),
     SEARCH_KEYWORD("searchKw"),
     SEARCH_PATH("searchPath"),
@@ -50,7 +51,6 @@
     INTENT_TARGET_CLASS("intentTargetClass"),
     INTENT_EXTRAS("intentExtras"),
     SLICE_URI("sliceUri"),
-    LEGACY_KEY("legacyKey"),
     ENTRY_DISABLED("entryDisabled"),
 }
 
@@ -64,6 +64,7 @@
         SEARCH_STATIC_DATA,
         listOf(
             ColumnEnum.ENTRY_ID,
+            ColumnEnum.ENTRY_LABEL,
             ColumnEnum.SEARCH_TITLE,
             ColumnEnum.SEARCH_KEYWORD,
             ColumnEnum.SEARCH_PATH,
@@ -71,13 +72,13 @@
             ColumnEnum.INTENT_TARGET_CLASS,
             ColumnEnum.INTENT_EXTRAS,
             ColumnEnum.SLICE_URI,
-            ColumnEnum.LEGACY_KEY
         )
     ),
     SEARCH_DYNAMIC_DATA_QUERY(
         SEARCH_DYNAMIC_DATA,
         listOf(
             ColumnEnum.ENTRY_ID,
+            ColumnEnum.ENTRY_LABEL,
             ColumnEnum.SEARCH_TITLE,
             ColumnEnum.SEARCH_KEYWORD,
             ColumnEnum.SEARCH_PATH,
@@ -85,13 +86,13 @@
             ColumnEnum.INTENT_TARGET_CLASS,
             ColumnEnum.INTENT_EXTRAS,
             ColumnEnum.SLICE_URI,
-            ColumnEnum.LEGACY_KEY
         )
     ),
     SEARCH_IMMUTABLE_STATUS_DATA_QUERY(
         SEARCH_IMMUTABLE_STATUS,
         listOf(
             ColumnEnum.ENTRY_ID,
+            ColumnEnum.ENTRY_LABEL,
             ColumnEnum.ENTRY_DISABLED,
         )
     ),
@@ -99,6 +100,7 @@
         SEARCH_MUTABLE_STATUS,
         listOf(
             ColumnEnum.ENTRY_ID,
+            ColumnEnum.ENTRY_LABEL,
             ColumnEnum.ENTRY_DISABLED,
         )
     ),
@@ -106,6 +108,7 @@
         SEARCH_STATIC_ROW,
         listOf(
             ColumnEnum.ENTRY_ID,
+            ColumnEnum.ENTRY_LABEL,
             ColumnEnum.SEARCH_TITLE,
             ColumnEnum.SEARCH_KEYWORD,
             ColumnEnum.SEARCH_PATH,
@@ -113,7 +116,6 @@
             ColumnEnum.INTENT_TARGET_CLASS,
             ColumnEnum.INTENT_EXTRAS,
             ColumnEnum.SLICE_URI,
-            ColumnEnum.LEGACY_KEY,
             ColumnEnum.ENTRY_DISABLED,
         )
     ),
@@ -121,6 +123,7 @@
         SEARCH_DYNAMIC_ROW,
         listOf(
             ColumnEnum.ENTRY_ID,
+            ColumnEnum.ENTRY_LABEL,
             ColumnEnum.SEARCH_TITLE,
             ColumnEnum.SEARCH_KEYWORD,
             ColumnEnum.SEARCH_PATH,
@@ -128,7 +131,6 @@
             ColumnEnum.INTENT_TARGET_CLASS,
             ColumnEnum.INTENT_EXTRAS,
             ColumnEnum.SLICE_URI,
-            ColumnEnum.LEGACY_KEY,
             ColumnEnum.ENTRY_DISABLED,
         )
     ),
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
index 057f13f..eacb28c 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
@@ -42,7 +42,7 @@
  * One can query the provider result by:
  *   $ adb shell content query --uri content://<AuthorityPath>/<QueryPath>
  * For gallery, AuthorityPath = com.android.spa.gallery.search.provider
- * For Settings, AuthorityPath = com.android.settings.spa.search.provider"
+ * For Settings, AuthorityPath = com.android.settings.spa.search.provider
  * Some examples:
  *   $ adb shell content query --uri content://<AuthorityPath>/search_static_data
  *   $ adb shell content query --uri content://<AuthorityPath>/search_dynamic_data
@@ -205,6 +205,7 @@
         val searchData = entry.getSearchData() ?: return
         val intent = entry.createIntent(SESSION_SEARCH)
         val row = cursor.newRow().add(ColumnEnum.ENTRY_ID.id, entry.id)
+            .add(ColumnEnum.ENTRY_LABEL.id, entry.label)
             .add(ColumnEnum.SEARCH_TITLE.id, searchData.title)
             .add(ColumnEnum.SEARCH_KEYWORD.id, searchData.keyword)
             .add(
@@ -221,7 +222,6 @@
                 ColumnEnum.SLICE_URI.id, Uri.Builder()
                     .fromEntry(entry, spaEnvironment.sliceProviderAuthorities)
             )
-        // TODO: support legacy key
     }
 
     private fun fetchStatusData(entry: SettingsEntry, cursor: MatrixCursor) {
@@ -229,6 +229,7 @@
         val statusData = entry.getStatusData() ?: return
         cursor.newRow()
             .add(ColumnEnum.ENTRY_ID.id, entry.id)
+            .add(ColumnEnum.ENTRY_LABEL.id, entry.label)
             .add(ColumnEnum.ENTRY_DISABLED.id, statusData.isDisabled)
     }
 
@@ -239,6 +240,7 @@
         val searchData = entry.getSearchData() ?: return
         val intent = entry.createIntent(SESSION_SEARCH)
         val row = cursor.newRow().add(ColumnEnum.ENTRY_ID.id, entry.id)
+            .add(ColumnEnum.ENTRY_LABEL.id, entry.label)
             .add(ColumnEnum.SEARCH_TITLE.id, searchData.title)
             .add(ColumnEnum.SEARCH_KEYWORD.id, searchData.keyword)
             .add(
@@ -255,8 +257,6 @@
                 ColumnEnum.SLICE_URI.id, Uri.Builder()
                     .fromEntry(entry, spaEnvironment.sliceProviderAuthorities)
             )
-        // TODO: support legacy key
-
         // Fetch status data. We can add runtime arguments later if necessary
         val statusData = entry.getStatusData() ?: return
         row.add(ColumnEnum.ENTRY_DISABLED.id, statusData.isDisabled)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ProgressBarPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ProgressBarPreference.kt
index b8c59ad..7f7088a 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ProgressBarPreference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ProgressBarPreference.kt
@@ -163,7 +163,7 @@
             Text(
                 text = data,
                 color = MaterialTheme.colorScheme.onSurfaceVariant,
-                style = MaterialTheme.typography.titleMedium,
+                style = MaterialTheme.typography.titleSmall,
             )
         }
         subTitle()
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
index e0e9b95..c6e13a1 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
@@ -16,19 +16,21 @@
 
 package com.android.settingslib.spa.widget.scaffold
 
+import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.pager.HorizontalPager
+import androidx.compose.foundation.pager.rememberPagerState
 import androidx.compose.material3.TabRow
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
-import com.android.settingslib.spa.framework.compose.HorizontalPager
-import com.android.settingslib.spa.framework.compose.rememberPagerState
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import kotlin.math.absoluteValue
 import kotlinx.coroutines.launch
 
+@OptIn(ExperimentalFoundationApi::class)
 @Composable
 fun SettingsPager(titles: List<String>, content: @Composable (page: Int) -> Unit) {
     check(titles.isNotEmpty())
@@ -52,7 +54,7 @@
                 SettingsTab(
                     title = title,
                     selected = pagerState.currentPage == page,
-                    currentPageOffset = pagerState.currentPageOffset.absoluteValue,
+                    currentPageOffset = pagerState.currentPageOffsetFraction.absoluteValue,
                     onClick = {
                         coroutineScope.launch {
                             pagerState.animateScrollToPage(page)
@@ -62,7 +64,7 @@
             }
         }
 
-        HorizontalPager(count = titles.size, state = pagerState) { page ->
+        HorizontalPager(pageCount = titles.size, state = pagerState) { page ->
             content(page)
         }
     }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
index 64a9c73..f0df9a6 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
@@ -23,8 +23,8 @@
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.selection.selectableGroup
 import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.outlined.ArrowDropDown
-import androidx.compose.material.icons.outlined.ArrowDropUp
+import androidx.compose.material.icons.outlined.ExpandLess
+import androidx.compose.material.icons.outlined.ExpandMore
 import androidx.compose.material3.Button
 import androidx.compose.material3.ButtonDefaults
 import androidx.compose.material3.DropdownMenu
@@ -76,8 +76,8 @@
             SpinnerText(options.find { it.id == selectedId })
             Icon(
                 imageVector = when {
-                    expanded -> Icons.Outlined.ArrowDropUp
-                    else -> Icons.Outlined.ArrowDropDown
+                    expanded -> Icons.Outlined.ExpandLess
+                    else -> Icons.Outlined.ExpandMore
                 },
                 contentDescription = null,
             )
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt
index 379b9a7..b139f28 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt
@@ -115,7 +115,7 @@
     fun testGetEntryPath() {
         SpaEnvironmentFactory.reset(spaEnvironment)
         assertThat(
-            entryRepository.getEntryPathWithDisplayName(
+            entryRepository.getEntryPathWithLabel(
                 genEntryId("Layer2Entry1", SppLayer2.createSettingsPage())
             )
         ).containsExactly("Layer2Entry1", "INJECT_SppLayer2", "INJECT_SppLayer1", "ROOT_SppHome")
@@ -129,7 +129,7 @@
         ).containsExactly("entryTitle", "SppLayer2", "TitleLayer1", "TitleHome").inOrder()
 
         assertThat(
-            entryRepository.getEntryPathWithDisplayName(
+            entryRepository.getEntryPathWithLabel(
                 genEntryId(
                     "INJECT",
                     SppLayer1.createSettingsPage(),
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
index 5754c9b..ce34979 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
@@ -68,7 +68,7 @@
         val owner = createSettingsPage("mySpp")
         val entry = SettingsEntryBuilder.create(owner, "myEntry").build()
         assertThat(entry.id).isEqualTo(genEntryId("myEntry", owner))
-        assertThat(entry.displayName).isEqualTo("myEntry")
+        assertThat(entry.label).isEqualTo("myEntry")
         assertThat(entry.owner.sppName).isEqualTo("mySpp")
         assertThat(entry.owner.displayName).isEqualTo("mySpp")
         assertThat(entry.fromPage).isNull()
@@ -87,14 +87,14 @@
         val entryFrom =
             SettingsEntryBuilder.createLinkFrom("myEntry", owner).setLink(toPage = toPage).build()
         assertThat(entryFrom.id).isEqualTo(genEntryId("myEntry", owner, owner, toPage))
-        assertThat(entryFrom.displayName).isEqualTo("myEntry")
+        assertThat(entryFrom.label).isEqualTo("myEntry")
         assertThat(entryFrom.fromPage!!.sppName).isEqualTo("mySpp")
         assertThat(entryFrom.toPage!!.sppName).isEqualTo("toSpp")
 
         val entryTo =
             SettingsEntryBuilder.createLinkTo("myEntry", owner).setLink(fromPage = fromPage).build()
         assertThat(entryTo.id).isEqualTo(genEntryId("myEntry", owner, fromPage, owner))
-        assertThat(entryTo.displayName).isEqualTo("myEntry")
+        assertThat(entryTo.label).isEqualTo("myEntry")
         assertThat(entryTo.fromPage!!.sppName).isEqualTo("fromSpp")
         assertThat(entryTo.toPage!!.sppName).isEqualTo("mySpp")
     }
@@ -108,7 +108,7 @@
                 INJECT_ENTRY_NAME_TEST, owner, toPage = owner
             )
         )
-        assertThat(entryInject.displayName).isEqualTo("${INJECT_ENTRY_NAME_TEST}_mySpp")
+        assertThat(entryInject.label).isEqualTo("${INJECT_ENTRY_NAME_TEST}_mySpp")
         assertThat(entryInject.fromPage).isNull()
         assertThat(entryInject.toPage).isNotNull()
     }
@@ -122,7 +122,7 @@
                 ROOT_ENTRY_NAME_TEST, owner, toPage = owner
             )
         )
-        assertThat(entryInject.displayName).isEqualTo("myRootEntry")
+        assertThat(entryInject.label).isEqualTo("myRootEntry")
         assertThat(entryInject.fromPage).isNull()
         assertThat(entryInject.toPage).isNotNull()
     }
@@ -133,14 +133,14 @@
         val owner = createSettingsPage("SppHome")
         val entryBuilder =
             SettingsEntryBuilder.create(owner, "myEntry")
-                .setDisplayName("myEntryDisplay")
+                .setLabel("myEntryDisplay")
                 .setIsSearchDataDynamic(false)
                 .setHasMutableStatus(true)
                 .setSearchDataFn { null }
                 .setSliceDataFn { _, _ -> null }
         val entry = entryBuilder.build()
         assertThat(entry.id).isEqualTo(genEntryId("myEntry", owner))
-        assertThat(entry.displayName).isEqualTo("myEntryDisplay")
+        assertThat(entry.label).isEqualTo("myEntryDisplay")
         assertThat(entry.fromPage).isNull()
         assertThat(entry.toPage).isNull()
         assertThat(entry.isAllowSearch).isTrue()
@@ -152,14 +152,14 @@
         val ownerDisabled = createSettingsPage("SppDisabled")
         val entryBuilderDisabled =
             SettingsEntryBuilder.create(ownerDisabled, "myEntry")
-                .setDisplayName("myEntryDisplay")
+                .setLabel("myEntryDisplay")
                 .setIsSearchDataDynamic(false)
                 .setHasMutableStatus(true)
                 .setSearchDataFn { null }
                 .setSliceDataFn { _, _ -> null }
         val entryDisabled = entryBuilderDisabled.build()
         assertThat(entryDisabled.id).isEqualTo(genEntryId("myEntry", ownerDisabled))
-        assertThat(entryDisabled.displayName).isEqualTo("myEntryDisplay")
+        assertThat(entryDisabled.label).isEqualTo("myEntryDisplay")
         assertThat(entryDisabled.fromPage).isNull()
         assertThat(entryDisabled.toPage).isNull()
         assertThat(entryDisabled.isAllowSearch).isFalse()
@@ -175,7 +175,7 @@
         SpaEnvironmentFactory.reset()
         val entry3 = entryBuilder.build()
         assertThat(entry3.id).isEqualTo(genEntryId("myEntry", owner))
-        assertThat(entry3.displayName).isEqualTo("myEntryDisplay")
+        assertThat(entry3.label).isEqualTo("myEntryDisplay")
         assertThat(entry3.fromPage).isNull()
         assertThat(entry3.toPage).isNull()
         assertThat(entry3.isAllowSearch).isFalse()
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt
index 007d08b..00d2314 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt
@@ -63,6 +63,11 @@
             pageOwner.getEntryId("SearchDynamicWithImmutableStatus")
         )
         immutableStatus.checkValue(
+            QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY,
+            ColumnEnum.ENTRY_LABEL,
+            pageOwner.getEntryLabel("SearchDynamicWithImmutableStatus")
+        )
+        immutableStatus.checkValue(
             QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY, ColumnEnum.ENTRY_DISABLED, true.toString()
         )
 
@@ -75,6 +80,11 @@
             pageOwner.getEntryId("SearchStaticWithMutableStatus")
         )
         mutableStatus.checkValue(
+            QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY,
+            ColumnEnum.ENTRY_LABEL,
+            pageOwner.getEntryLabel("SearchStaticWithMutableStatus")
+        )
+        mutableStatus.checkValue(
             QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY, ColumnEnum.ENTRY_DISABLED, false.toString()
         )
 
@@ -85,6 +95,11 @@
             pageOwner.getEntryId("SearchDynamicWithMutableStatus")
         )
         mutableStatus.checkValue(
+            QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY,
+            ColumnEnum.ENTRY_LABEL,
+            pageOwner.getEntryLabel("SearchDynamicWithMutableStatus")
+        )
+        mutableStatus.checkValue(
             QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY, ColumnEnum.ENTRY_DISABLED, true.toString()
         )
     }
@@ -102,6 +117,11 @@
             pageOwner.getEntryId("SearchStaticWithNoStatus")
         )
         staticData.checkValue(
+            QueryEnum.SEARCH_STATIC_DATA_QUERY,
+            ColumnEnum.ENTRY_LABEL,
+            pageOwner.getEntryLabel("SearchStaticWithNoStatus")
+        )
+        staticData.checkValue(
             QueryEnum.SEARCH_STATIC_DATA_QUERY, ColumnEnum.SEARCH_TITLE, "SearchStaticWithNoStatus"
         )
         staticData.checkValue(
@@ -139,6 +159,11 @@
             ColumnEnum.ENTRY_ID,
             pageOwner.getEntryId("SearchStaticWithMutableStatus")
         )
+        staticData.checkValue(
+            QueryEnum.SEARCH_STATIC_DATA_QUERY,
+            ColumnEnum.ENTRY_LABEL,
+            pageOwner.getEntryLabel("SearchStaticWithMutableStatus")
+        )
 
         val dynamicData = searchProvider.querySearchDynamicData()
         Truth.assertThat(dynamicData.count).isEqualTo(2)
@@ -148,6 +173,11 @@
             ColumnEnum.ENTRY_ID,
             pageOwner.getEntryId("SearchDynamicWithMutableStatus")
         )
+        dynamicData.checkValue(
+            QueryEnum.SEARCH_DYNAMIC_DATA_QUERY,
+            ColumnEnum.ENTRY_LABEL,
+            pageOwner.getEntryLabel("SearchDynamicWithMutableStatus")
+        )
 
         dynamicData.moveToNext()
         dynamicData.checkValue(
@@ -157,6 +187,11 @@
         )
         dynamicData.checkValue(
             QueryEnum.SEARCH_DYNAMIC_DATA_QUERY,
+            ColumnEnum.ENTRY_LABEL,
+            pageOwner.getEntryLabel("SearchDynamicWithImmutableStatus")
+        )
+        dynamicData.checkValue(
+            QueryEnum.SEARCH_DYNAMIC_DATA_QUERY,
             ColumnEnum.SEARCH_KEYWORD,
             listOf("kw1", "kw2").toString()
         )
@@ -175,6 +210,11 @@
             pageOwner.getEntryId("SearchStaticWithNoStatus")
         )
         staticRow.checkValue(
+            QueryEnum.SEARCH_STATIC_ROW_QUERY,
+            ColumnEnum.ENTRY_LABEL,
+            pageOwner.getEntryLabel("SearchStaticWithNoStatus")
+        )
+        staticRow.checkValue(
             QueryEnum.SEARCH_STATIC_ROW_QUERY, ColumnEnum.SEARCH_TITLE, "SearchStaticWithNoStatus"
         )
         staticRow.checkValue(
@@ -223,6 +263,11 @@
             pageOwner.getEntryId("SearchStaticWithMutableStatus")
         )
         dynamicRow.checkValue(
+            QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
+            ColumnEnum.ENTRY_LABEL,
+            pageOwner.getEntryLabel("SearchStaticWithMutableStatus")
+        )
+        dynamicRow.checkValue(
             QueryEnum.SEARCH_DYNAMIC_ROW_QUERY, ColumnEnum.ENTRY_DISABLED, false.toString()
         )
 
@@ -233,6 +278,11 @@
             pageOwner.getEntryId("SearchDynamicWithMutableStatus")
         )
         dynamicRow.checkValue(
+            QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
+            ColumnEnum.ENTRY_LABEL,
+            pageOwner.getEntryLabel("SearchDynamicWithMutableStatus")
+        )
+        dynamicRow.checkValue(
             QueryEnum.SEARCH_DYNAMIC_ROW_QUERY, ColumnEnum.ENTRY_DISABLED, true.toString()
         )
 
@@ -245,6 +295,11 @@
         )
         dynamicRow.checkValue(
             QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
+            ColumnEnum.ENTRY_LABEL,
+            pageOwner.getEntryLabel("SearchDynamicWithImmutableStatus")
+        )
+        dynamicRow.checkValue(
+            QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
             ColumnEnum.SEARCH_KEYWORD,
             listOf("kw1", "kw2").toString()
         )
@@ -271,3 +326,7 @@
 private fun SettingsPage.getEntryId(name: String): String {
     return SettingsEntryBuilder.create(this, name).build().id
 }
+
+private fun SettingsPage.getEntryLabel(name: String): String {
+    return SettingsEntryBuilder.create(this, name).build().label
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
index 14cb698f..e37288ab 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
@@ -81,7 +81,7 @@
         val entryList = appInfoPageProvider.buildEntry(null)
 
         assertThat(entryList).hasSize(1)
-        assertThat(entryList[0].displayName).isEqualTo("AllowControl")
+        assertThat(entryList[0].label).isEqualTo("AllowControl")
     }
 
     @Test
diff --git a/packages/SettingsLib/TopIntroPreference/Android.bp b/packages/SettingsLib/TopIntroPreference/Android.bp
index 9e86567..eca1165 100644
--- a/packages/SettingsLib/TopIntroPreference/Android.bp
+++ b/packages/SettingsLib/TopIntroPreference/Android.bp
@@ -23,6 +23,6 @@
     apex_available: [
         "//apex_available:platform",
         "com.android.cellbroadcast",
-        "com.android.healthconnect",
+        "com.android.healthfitness",
     ],
 }
diff --git a/packages/SettingsLib/TwoTargetPreference/Android.bp b/packages/SettingsLib/TwoTargetPreference/Android.bp
index e9c6aed..a3e50a9 100644
--- a/packages/SettingsLib/TwoTargetPreference/Android.bp
+++ b/packages/SettingsLib/TwoTargetPreference/Android.bp
@@ -23,6 +23,6 @@
     apex_available: [
         "//apex_available:platform",
         "com.android.permission",
-        "com.android.healthconnect",
+        "com.android.healthfitness",
     ],
 }
diff --git a/packages/SettingsLib/Utils/Android.bp b/packages/SettingsLib/Utils/Android.bp
index dc88304..644e990 100644
--- a/packages/SettingsLib/Utils/Android.bp
+++ b/packages/SettingsLib/Utils/Android.bp
@@ -26,6 +26,6 @@
         "com.android.adservices",
         "com.android.permission",
         "com.android.cellbroadcast",
-        "com.android.healthconnect",
+        "com.android.healthfitness",
     ],
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 6641db1..91b852a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -235,7 +235,7 @@
     /**
      * @return whether high quality audio is enabled or not
      */
-    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
     public boolean isHighQualityAudioEnabled(BluetoothDevice device) {
         BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
         if (bluetoothDevice == null) {
@@ -287,7 +287,7 @@
      * @param device to get codec label from
      * @return the label associated with the device codec
      */
-    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
     public String getHighQualityAudioOptionLabel(BluetoothDevice device) {
         BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
         int unknownCodecId = R.string.bluetooth_profile_a2dp_high_quality_unknown_codec;
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
index e0588ee..2555e2b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
@@ -34,6 +34,8 @@
 
 import com.android.settingslib.R;
 
+import java.util.Optional;
+
 /**
  * Stores and computes some battery information.
  */
@@ -52,11 +54,12 @@
     public final int health;
     public final int maxChargingWattage;
     public final boolean present;
+    public final Optional<Boolean> incompatibleCharger;
 
-    public static BatteryStatus create(Context context) {
+    public static BatteryStatus create(Context context, boolean incompatibleCharger) {
         final Intent batteryChangedIntent = BatteryUtils.getBatteryIntent(context);
         return batteryChangedIntent == null
-                ? null : new BatteryStatus(batteryChangedIntent);
+                ? null : new BatteryStatus(batteryChangedIntent, incompatibleCharger);
     }
 
     public BatteryStatus(int status, int level, int plugged, int health,
@@ -67,14 +70,25 @@
         this.health = health;
         this.maxChargingWattage = maxChargingWattage;
         this.present = present;
+        this.incompatibleCharger = Optional.empty();
     }
 
+
     public BatteryStatus(Intent batteryChangedIntent) {
+        this(batteryChangedIntent, Optional.empty());
+    }
+
+    public BatteryStatus(Intent batteryChangedIntent, boolean incompatibleCharger) {
+        this(batteryChangedIntent, Optional.of(incompatibleCharger));
+    }
+
+    private BatteryStatus(Intent batteryChangedIntent, Optional<Boolean> incompatibleCharger) {
         status = batteryChangedIntent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN);
         plugged = batteryChangedIntent.getIntExtra(EXTRA_PLUGGED, 0);
         level = getBatteryLevel(batteryChangedIntent);
         health = batteryChangedIntent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN);
         present = batteryChangedIntent.getBooleanExtra(EXTRA_PRESENT, true);
+        this.incompatibleCharger = incompatibleCharger;
 
         final int maxChargingMicroAmp = batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_CURRENT,
                 -1);
@@ -95,10 +109,7 @@
 
     /** Determine whether the device is plugged. */
     public boolean isPluggedIn() {
-        return plugged == BatteryManager.BATTERY_PLUGGED_AC
-                || plugged == BatteryManager.BATTERY_PLUGGED_USB
-                || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS
-                || plugged == BatteryManager.BATTERY_PLUGGED_DOCK;
+        return isPluggedIn(plugged);
     }
 
     /** Determine whether the device is plugged in (USB, power). */
@@ -190,4 +201,17 @@
                 ? -1 /*invalid battery level*/
                 : Math.round((level / (float) scale) * 100f);
     }
+
+    /** Whether the device is plugged or not. */
+    public static boolean isPluggedIn(Intent batteryChangedIntent) {
+        return isPluggedIn(batteryChangedIntent.getIntExtra(EXTRA_PLUGGED, 0));
+    }
+
+    /** Whether the device is plugged or not. */
+    public static boolean isPluggedIn(int plugged) {
+        return plugged == BatteryManager.BATTERY_PLUGGED_AC
+                || plugged == BatteryManager.BATTERY_PLUGGED_USB
+                || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS
+                || plugged == BatteryManager.BATTERY_PLUGGED_DOCK;
+    }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index f1413e5..7abace03 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -97,7 +97,6 @@
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
 import android.provider.Settings.SetAllResult;
-import android.provider.UpdatableDeviceConfigServiceReadiness;
 import android.provider.settings.validators.SystemSettingsValidators;
 import android.provider.settings.validators.Validator;
 import android.text.TextUtils;
@@ -419,16 +418,10 @@
             startWatchingUserRestrictionChanges();
         });
         ServiceManager.addService("settings", new SettingsService(this));
-        addDeviceConfigServiceIfNeeded();
+        ServiceManager.addService("device_config", new DeviceConfigService(this));
         return true;
     }
 
-    private void addDeviceConfigServiceIfNeeded() {
-        if (!UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService()) {
-            ServiceManager.addService("device_config", new DeviceConfigService(this));
-        }
-    }
-
     @Override
     public Bundle call(String method, String name, Bundle args) {
         final int requestingUserId = getRequestingUserId(args);
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index f4cef84..51f507c 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -55,6 +55,9 @@
     <!-- When the lock screen is showing and the phone plugged in, and the defend mode is triggered, say that charging is temporarily limited.  -->
     <string name="keyguard_plugged_in_charging_limited"><xliff:g id="percentage">%s</xliff:g> • Charging optimized to protect battery</string>
 
+    <!-- When the lock screen is showing and the phone plugged in with incompatible charger. -->
+    <string name="keyguard_plugged_in_incompatible_charger"><xliff:g id="percentage">%s</xliff:g> • Incompatible charging</string>
+
     <!-- On the keyguard screen, when pattern lock is disabled, only tell them to press menu to unlock.  This is shown in small font at the bottom. -->
     <string name="keyguard_instructions_when_pattern_disabled">Press Menu to unlock.</string>
 
diff --git a/packages/SystemUI/res/drawable/ic_shortcutlist_search.xml b/packages/SystemUI/res/drawable/ic_shortcutlist_search.xml
new file mode 100644
index 0000000..1b12e74
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_shortcutlist_search.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="48"
+        android:viewportHeight="48"
+        android:tint="?android:attr/textColorSecondary">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M39.8,41.95 L26.65,28.8Q25.15,30.1 23.15,30.825Q21.15,31.55 18.9,31.55Q13.5,31.55 9.75,27.8Q6,24.05 6,18.75Q6,13.45 9.75,9.7Q13.5,5.95 18.85,5.95Q24.15,5.95 27.875,9.7Q31.6,13.45 31.6,18.75Q31.6,20.9 30.9,22.9Q30.2,24.9 28.8,26.65L42,39.75ZM18.85,28.55Q22.9,28.55 25.75,25.675Q28.6,22.8 28.6,18.75Q28.6,14.7 25.75,11.825Q22.9,8.95 18.85,8.95Q14.75,8.95 11.875,11.825Q9,14.7 9,18.75Q9,22.8 11.875,25.675Q14.75,28.55 18.85,28.55Z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_shortcutlist_search_button_cancel.xml b/packages/SystemUI/res/drawable/ic_shortcutlist_search_button_cancel.xml
new file mode 100644
index 0000000..e3b1ab2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_shortcutlist_search_button_cancel.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/textColorSecondary">
+    <path
+        android:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z"
+        android:fillColor="@android:color/white"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/shortcut_button_colored.xml b/packages/SystemUI/res/drawable/shortcut_button_colored.xml
new file mode 100644
index 0000000..a21489c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/shortcut_button_colored.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+
+<inset
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+    <ripple
+        android:color="?android:attr/colorControlHighlight">
+        <item>
+            <shape android:shape="rectangle">
+                <corners android:radius="16dp"/>
+                <solid android:color="?androidprv:attr/colorSurface"/>
+            </shape>
+        </item>
+    </ripple>
+</inset>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml b/packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml
new file mode 100644
index 0000000..2ff32b6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+
+<inset
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+    <ripple
+        android:color="?android:attr/colorControlHighlight">
+        <item>
+            <shape android:shape="rectangle">
+                <corners android:radius="16dp"/>
+                <solid android:color="?androidprv:attr/colorAccentPrimary"/>
+            </shape>
+        </item>
+    </ripple>
+</inset>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/shortcut_dialog_bg.xml b/packages/SystemUI/res/drawable/shortcut_dialog_bg.xml
new file mode 100644
index 0000000..6ce3eae
--- /dev/null
+++ b/packages/SystemUI/res/drawable/shortcut_dialog_bg.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="?android:attr/colorBackground"/>
+    <corners android:topLeftRadius="16dp"
+             android:topRightRadius="16dp"
+             android:bottomLeftRadius="0dp"
+             android:bottomRightRadius="0dp"/>
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/shortcut_search_background.xml b/packages/SystemUI/res/drawable/shortcut_search_background.xml
new file mode 100644
index 0000000..66fc191
--- /dev/null
+++ b/packages/SystemUI/res/drawable/shortcut_search_background.xml
@@ -0,0 +1,26 @@
+<?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
+  -->
+<layer-list
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+    <item>
+        <shape android:shape="rectangle">
+            <solid android:color="?androidprv:attr/colorSurface" />
+            <corners android:radius="24dp" />
+        </shape>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/font_scaling_dialog.xml b/packages/SystemUI/res/layout/font_scaling_dialog.xml
new file mode 100644
index 0000000..27c1e9d
--- /dev/null
+++ b/packages/SystemUI/res/layout/font_scaling_dialog.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/font_scaling_slider"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    app:max="6"
+    app:progress="0"
+    app:iconStartContentDescription="@string/font_scaling_smaller"
+    app:iconEndContentDescription="@string/font_scaling_larger"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_category_short_separator.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_category_short_separator.xml
new file mode 100644
index 0000000..530e46e
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_category_short_separator.xml
@@ -0,0 +1,20 @@
+<?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
+  -->
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+      android:layout_marginTop="8dp"
+      android:layout_marginBottom="0dp"
+      style="@style/ShortcutHorizontalDivider" />
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_icon_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_icon_view.xml
new file mode 100644
index 0000000..a037cb2
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_icon_view.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+           android:layout_width="wrap_content"
+           android:layout_height="wrap_content"
+           android:padding="@dimen/ksh_item_padding"
+           android:layout_marginLeft="0dp"
+           android:layout_marginRight="0dp"
+           android:scaleType="fitXY"
+           android:tint="?android:attr/textColorPrimary"
+           style="@style/ShortcutItemBackground" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_view.xml
new file mode 100644
index 0000000..12b4e15
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_view.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:padding="@dimen/ksh_item_padding"
+          android:layout_marginStart="@dimen/ksh_item_margin_start"
+          style="@style/ShortcutItemBackground"
+          android:textColor="?android:attr/textColorPrimary"
+          android:singleLine="false"
+          android:gravity="center"
+          android:textSize="@dimen/ksh_item_text_size"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_plus_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_plus_view.xml
new file mode 100644
index 0000000..727f2c1
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_plus_view.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:padding="@dimen/ksh_item_padding"
+          android:layout_marginLeft="0dp"
+          android:layout_marginRight="0dp"
+          android:text="+"
+          style="@style/ShortcutItemBackground"
+          android:textColor="?android:attr/textColorPrimary"
+          android:singleLine="true"
+          android:gravity="center"
+          android:textSize="@dimen/ksh_item_text_size"
+          android:textAllCaps="true"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_vertical_bar_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_vertical_bar_view.xml
new file mode 100644
index 0000000..00ef947
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_vertical_bar_view.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:padding="@dimen/ksh_item_padding"
+          android:layout_marginLeft="0dp"
+          android:layout_marginRight="0dp"
+          android:text="|"
+          style="@style/ShortcutItemBackground"
+          android:textColor="?android:attr/textColorPrimary"
+          android:singleLine="true"
+          android:gravity="center"
+          android:textSize="@dimen/ksh_item_text_size"
+          android:textAllCaps="true"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml
new file mode 100644
index 0000000..8a66f50
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml
@@ -0,0 +1,139 @@
+<?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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:background="@drawable/shortcut_dialog_bg"
+    android:layout_width="@dimen/ksh_layout_width"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+    <TextView
+        android:id="@+id/shortcut_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="40dp"
+        android:layout_gravity="center_horizontal"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:textColor="?android:attr/textColorPrimary"
+        android:text="@string/keyboard_shortcut_search_list_title"/>
+
+    <FrameLayout android:layout_width="match_parent"
+                 android:layout_height="wrap_content">
+        <EditText
+            android:id="@+id/keyboard_shortcuts_search"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="24dp"
+            android:layout_marginBottom="24dp"
+            android:layout_marginStart="49dp"
+            android:layout_marginEnd="49dp"
+            android:padding="16dp"
+            android:background="@drawable/shortcut_search_background"
+            android:drawableStart="@drawable/ic_shortcutlist_search"
+            android:drawablePadding="15dp"
+            android:singleLine="true"
+            android:textColor="?android:attr/textColorPrimary"
+            android:inputType="text"
+            android:textDirection="locale"
+            android:textAlignment="viewStart"
+            android:hint="@string/keyboard_shortcut_search_list_hint"
+            android:textColorHint="?android:attr/textColorTertiary" />
+
+        <ImageView
+            android:id="@+id/keyboard_shortcuts_search_cancel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="end"
+            android:layout_marginTop="24dp"
+            android:layout_marginBottom="24dp"
+            android:layout_marginEnd="49dp"
+            android:padding="16dp"
+            android:contentDescription="@string/keyboard_shortcut_clear_text"
+            android:src="@drawable/ic_shortcutlist_search_button_cancel" />
+    </FrameLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <View
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginStart="37dp"/>
+
+        <Button
+            android:id="@+id/shortcut_system"
+            android:layout_width="120dp"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="12dp"
+            style="@style/ShortCutButton"
+            android:text="@string/keyboard_shortcut_search_category_system"/>
+
+        <Button
+            android:id="@+id/shortcut_input"
+            android:layout_width="120dp"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="12dp"
+            style="@style/ShortCutButton"
+            android:text="@string/keyboard_shortcut_search_category_input"/>
+
+        <Button
+            android:id="@+id/shortcut_open_apps"
+            android:layout_width="120dp"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="12dp"
+            style="@style/ShortCutButton"
+            android:text="@string/keyboard_shortcut_search_category_open_apps"/>
+
+        <Button
+            android:id="@+id/shortcut_specific_app"
+            android:layout_width="120dp"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="12dp"
+            style="@style/ShortCutButton"
+            android:text="@string/keyboard_shortcut_search_category_current_app"/>
+    </LinearLayout>
+
+    <TextView
+        android:id="@+id/shortcut_search_no_result"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="50dp"
+        android:layout_gravity="center_horizontal"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textColor="?android:attr/textColorPrimary"
+        android:text="@string/keyboard_shortcut_search_list_no_result"/>
+
+    <ScrollView
+        android:id="@+id/keyboard_shortcuts_scroll_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:layout_marginStart="25dp"
+        android:layout_marginEnd="25dp">
+        <LinearLayout
+            android:id="@+id/keyboard_shortcuts_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"/>
+    </ScrollView>
+    <!-- Required for stretching to full available height when the items in the scroll view
+         occupy less space then the full height -->
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"/>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/seekbar_with_icon_buttons.xml b/packages/SystemUI/res/layout/seekbar_with_icon_buttons.xml
index f20b582..52d1d4f 100644
--- a/packages/SystemUI/res/layout/seekbar_with_icon_buttons.xml
+++ b/packages/SystemUI/res/layout/seekbar_with_icon_buttons.xml
@@ -1,41 +1,47 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2023 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
+   Copyright (C) 2023 The Android Open Source Project
 
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+  -->
 <merge xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
-              android:id="@+id/seekbar_frame"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:clipChildren="false"
-              android:gravity="center_vertical"
-              android:orientation="horizontal"
-              tools:parentTag="android.widget.LinearLayout">
+       android:id="@+id/seekbar_frame"
+       android:layout_width="match_parent"
+       android:layout_height="wrap_content"
+       android:clipChildren="false"
+       android:gravity="center_vertical"
+       android:orientation="horizontal"
+       tools:parentTag="android.widget.LinearLayout">
 
-    <ImageView
-        android:id="@+id/icon_start"
-        android:layout_width="@dimen/magnification_setting_seekbar_icon_size"
-        android:layout_height="@dimen/magnification_setting_seekbar_icon_size"
-        android:layout_gravity="center"
-        android:background="?android:attr/selectableItemBackgroundBorderless"
-        android:adjustViewBounds="true"
-        android:focusable="true"
-        android:src="@drawable/ic_remove"
-        android:tint="?android:attr/textColorPrimary"
-        android:tintMode="src_in" />
+    <FrameLayout
+        android:id="@+id/icon_start_frame"
+        android:layout_width="@dimen/min_clickable_item_size"
+        android:layout_height="@dimen/min_clickable_item_size"
+        android:clipChildren="false"
+        android:focusable="true" >
+        <ImageView
+            android:id="@+id/icon_start"
+            android:layout_width="@dimen/seekbar_icon_size"
+            android:layout_height="@dimen/seekbar_icon_size"
+            android:layout_gravity="center"
+            android:background="?android:attr/selectableItemBackgroundBorderless"
+            android:adjustViewBounds="true"
+            android:focusable="false"
+            android:src="@drawable/ic_remove"
+            android:tint="?android:attr/textColorPrimary"
+            android:tintMode="src_in" />
+    </FrameLayout>
 
     <SeekBar
         android:id="@+id/seekbar"
@@ -45,16 +51,23 @@
         android:layout_gravity="center_vertical"
         android:layout_weight="1" />
 
-    <ImageView
-        android:id="@+id/icon_end"
-        android:layout_width="@dimen/magnification_setting_seekbar_icon_size"
-        android:layout_height="@dimen/magnification_setting_seekbar_icon_size"
-        android:layout_gravity="center"
-        android:background="?android:attr/selectableItemBackgroundBorderless"
-        android:adjustViewBounds="true"
-        android:focusable="true"
-        android:src="@drawable/ic_add"
-        android:tint="?android:attr/textColorPrimary"
-        android:tintMode="src_in" />
+    <FrameLayout
+        android:id="@+id/icon_end_frame"
+        android:layout_width="@dimen/min_clickable_item_size"
+        android:layout_height="@dimen/min_clickable_item_size"
+        android:clipChildren="false"
+        android:focusable="true" >
+        <ImageView
+            android:id="@+id/icon_end"
+            android:layout_width="@dimen/seekbar_icon_size"
+            android:layout_height="@dimen/seekbar_icon_size"
+            android:layout_gravity="center"
+            android:background="?android:attr/selectableItemBackgroundBorderless"
+            android:adjustViewBounds="true"
+            android:focusable="false"
+            android:src="@drawable/ic_add"
+            android:tint="?android:attr/textColorPrimary"
+            android:tintMode="src_in" />
+    </FrameLayout>
 
 </merge>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index e2fdf16..c6cc0bc 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -118,6 +118,7 @@
     <color name="ksh_application_group_color">#fff44336</color>
     <color name="ksh_key_item_color">@color/material_grey_600</color>
     <color name="ksh_key_item_background">@color/material_grey_100</color>
+    <color name="ksh_key_item_new_background">@color/transparent</color>
 
     <color name="instant_apps_color">#ff4d5a64</color>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 36172ca..4afe9d5 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1183,8 +1183,9 @@
     <dimen name="magnification_setting_image_button_padding_horizontal">24dp</dimen>
     <dimen name="magnification_setting_image_button_open_in_full_padding_vertical">16dp</dimen>
     <dimen name="magnification_setting_image_button_open_in_full_padding_horizontal">28dp</dimen>
-    <dimen name="magnification_setting_seekbar_icon_size">24dp</dimen>
 
+    <!-- Seekbar with icon buttons -->
+    <dimen name="seekbar_icon_size">24dp</dimen>
 
     <!-- How far from the right edge of the screen you need to drag the window before the button
          repositions to the other side. -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 85edbec..435a866 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1700,34 +1700,105 @@
     <string name="keyboard_shortcut_group_system">System</string>
     <!-- User visible title for the keyboard shortcut that takes the user to the home screen. -->
     <string name="keyboard_shortcut_group_system_home">Home</string>
-    <!-- User visible title for the the keyboard shortcut that takes the user to the recents screen. -->
+    <!-- User visible title for the keyboard shortcut that takes the user to the recents screen. -->
     <string name="keyboard_shortcut_group_system_recents">Recents</string>
-    <!-- User visible title for the the keyboard shortcut that triggers the back action. -->
+    <!-- User visible title for the keyboard shortcut that triggers the back action. -->
     <string name="keyboard_shortcut_group_system_back">Back</string>
-    <!-- User visible title for the the keyboard shortcut that triggers the notification shade. -->
+    <!-- User visible title for the keyboard shortcut that triggers the notification shade. -->
     <string name="keyboard_shortcut_group_system_notifications">Notifications</string>
-    <!-- User visible title for the the keyboard shortcut that triggers the keyboard shortcuts helper. -->
+    <!-- User visible title for the keyboard shortcut that triggers the keyboard shortcuts helper. -->
     <string name="keyboard_shortcut_group_system_shortcuts_helper">Keyboard Shortcuts</string>
-    <!-- User visible title for the the keyboard shortcut that switches to the next hardware keyboard layout. [CHAR LIMIT=30] -->
+    <!-- User visible title for the keyboard shortcut that switches to the next hardware keyboard layout. -->
     <string name="keyboard_shortcut_group_system_switch_input">Switch keyboard layout</string>
 
-    <!-- User visible title for the system-wide applications keyboard shortcuts list. -->
+    <!-- Content description for the clear text button in shortcut search list. [CHAR LIMIT=NONE] -->
+    <string name="keyboard_shortcut_clear_text">Clear text</string>
+    <!-- The title for keyboard shortcut search list [CHAR LIMIT=25] -->
+    <string name="keyboard_shortcut_search_list_title">Shortcuts</string>
+    <!-- The hint for keyboard shortcut search list [CHAR LIMIT=25] -->
+    <string name="keyboard_shortcut_search_list_hint">Search shortcuts</string>
+    <!-- The description for no shortcuts results [CHAR LIMIT=25] -->
+    <string name="keyboard_shortcut_search_list_no_result">No shortcuts found</string>
+    <!-- The title of system category in shortcut search list. [CHAR LIMIT=15] -->
+    <string name="keyboard_shortcut_search_category_system">System</string>
+    <!-- The title of input category in shortcut search list. [CHAR LIMIT=15] -->
+    <string name="keyboard_shortcut_search_category_input">Input</string>
+    <!-- The title of open apps category in shortcut search list. [CHAR LIMIT=15] -->
+    <string name="keyboard_shortcut_search_category_open_apps">Open apps</string>
+    <!-- The title of current app category in shortcut search list. [CHAR LIMIT=15] -->
+    <string name="keyboard_shortcut_search_category_current_app">Current app</string>
+
+    <!-- User visible title for the keyboard shortcut that triggers the notification shade. [CHAR LIMIT=70] -->
+    <string name="group_system_access_notification_shade">Access notification shade</string>
+    <!-- User visible title for the keyboard shortcut that takes a full screenshot. [CHAR LIMIT=70] -->
+    <string name="group_system_full_screenshot">Take a full screenshot</string>
+    <!-- User visible title for the keyboard shortcut that access list of system / apps shortcuts. [CHAR LIMIT=70] -->
+    <string name="group_system_access_system_app_shortcuts">Access list of system / apps shortcuts</string>
+    <!-- User visible title for the keyboard shortcut that goes back to previous state. [CHAR LIMIT=70] -->
+    <string name="group_system_go_back">Back: go back to previous state (back button)</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the home screen. [CHAR LIMIT=70] -->
+    <string name="group_system_access_home_screen">Access home screen</string>
+    <!-- User visible title for the keyboard shortcut that triggers overview of open apps. [CHAR LIMIT=70] -->
+    <string name="group_system_overview_open_apps">Overview of open apps</string>
+    <!-- User visible title for the keyboard shortcut that cycles through recent apps (forward). [CHAR LIMIT=70] -->
+    <string name="group_system_cycle_forward">Cycle through recent apps (forward)</string>
+    <!-- User visible title for the keyboard shortcut that cycles through recent apps (back). [CHAR LIMIT=70] -->
+    <string name="group_system_cycle_back">Cycle through recent apps (back)</string>
+    <!-- User visible title for the keyboard shortcut that accesses list of all apps and search. [CHAR LIMIT=70] -->
+    <string name="group_system_access_all_apps_search">Access list of all apps and search (i.e. Search/Launcher)</string>
+    <!-- User visible title for the keyboard shortcut that hides and (re)showes taskbar. [CHAR LIMIT=70] -->
+    <string name="group_system_hide_reshow_taskbar">Hide and (re)show taskbar</string>
+    <!-- User visible title for the keyboard shortcut that accesses system settings. [CHAR LIMIT=70] -->
+    <string name="group_system_access_system_settings">Access system settings</string>
+    <!-- User visible title for the keyboard shortcut that accesses Google Assistant. [CHAR LIMIT=70] -->
+    <string name="group_system_access_google_assistant">Access Google Assistant</string>
+    <!-- User visible title for the keyboard shortcut that locks screen. [CHAR LIMIT=70] -->
+    <string name="group_system_lock_screen">Lock screen</string>
+    <!-- User visible title for the keyboard shortcut that pulls up Notes app for quick memo. [CHAR LIMIT=70] -->
+    <string name="group_system_quick_memo">Pull up Notes app for quick memo</string>
+
+    <!-- User visible title for the system multitasking keyboard shortcuts list. [CHAR LIMIT=70] -->
+    <string name="keyboard_shortcut_group_system_multitasking">System multitasking</string>
+    <!-- User visible title for the keyboard shortcut that enters split screen with current app to RHS [CHAR LIMIT=70] -->
+    <string name="system_multitasking_rhs">Enter Split screen with current app to RHS</string>
+    <!-- User visible title for the keyboard shortcut that enters split screen with current app to LHS [CHAR LIMIT=70] -->
+    <string name="system_multitasking_lhs">Enter Split screen with current app to LHS</string>
+    <!-- User visible title for the keyboard shortcut that switches from split screen to full screen [CHAR LIMIT=70] -->
+    <string name="system_multitasking_full_screen">Switch from Split screen to full screen</string>
+    <!-- User visible title for the keyboard shortcut that replaces an app from one to another during split screen [CHAR LIMIT=70] -->
+    <string name="system_multitasking_replace">During Split screen: replace an app from one to another</string>
+
+    <!-- User visible title for the input keyboard shortcuts list. [CHAR LIMIT=70] -->
+    <string name="keyboard_shortcut_group_input">Input</string>
+    <!-- User visible title for the keyboard shortcut that switches input language (next language). [CHAR LIMIT=70] -->
+    <string name="input_switch_input_language_next">Switch input language (next language)</string>
+    <!-- User visible title for the keyboard shortcut that switches input language (previous language). [CHAR LIMIT=70] -->
+    <string name="input_switch_input_language_previous">Switch input language (previous language)</string>
+    <!-- User visible title for the keyboard shortcut that accesses emoji. [CHAR LIMIT=70] -->
+    <string name="input_access_emoji">Access emoji</string>
+    <!-- User visible title for the keyboard shortcut that accesses voice typing. [CHAR LIMIT=70] -->
+    <string name="input_access_voice_typing">Access voice typing</string>
+
+    <!-- User visible title for the system-wide applications keyboard shortcuts list. [CHAR LIMIT=70] -->
     <string name="keyboard_shortcut_group_applications">Applications</string>
-    <!-- User visible title for the keyboard shortcut that takes the user to the assist app. -->
+    <!-- User visible title for the keyboard shortcut that takes the user to the assist app. [CHAR LIMIT=70] -->
     <string name="keyboard_shortcut_group_applications_assist">Assist</string>
-    <!-- User visible title for the keyboard shortcut that takes the user to the browser app. -->
-    <string name="keyboard_shortcut_group_applications_browser">Browser</string>
-    <!-- User visible title for the keyboard shortcut that takes the user to the contacts app. -->
+    <!-- User visible title for the keyboard shortcut that takes the user to the browser app. [CHAR LIMIT=70] -->
+    <string name="keyboard_shortcut_group_applications_browser">Browser (Chrome as default)</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the contacts app. [CHAR LIMIT=70] -->
     <string name="keyboard_shortcut_group_applications_contacts">Contacts</string>
-    <!-- User visible title for the keyboard shortcut that takes the user to the email app. -->
-    <string name="keyboard_shortcut_group_applications_email">Email</string>
-    <!-- User visible title for the keyboard shortcut that takes the user to the SMS messaging app. -->
+    <!-- User visible title for the keyboard shortcut that takes the user to the email app. [CHAR LIMIT=70] -->
+    <string name="keyboard_shortcut_group_applications_email">Email (Gmail as default)</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the SMS messaging app. [CHAR LIMIT=70] -->
     <string name="keyboard_shortcut_group_applications_sms">SMS</string>
-    <!-- User visible title for the keyboard shortcut that takes the user to the music app. -->
+    <!-- User visible title for the keyboard shortcut that takes the user to the music app. [CHAR LIMIT=70] -->
     <string name="keyboard_shortcut_group_applications_music">Music</string>
-    <!-- User visible title for the keyboard shortcut that takes the user to the YouTube app. -->
-    <!-- User visible title for the keyboard shortcut that takes the user to the calendar app. -->
+    <!-- User visible title for the keyboard shortcut that takes the user to the calendar app. [CHAR LIMIT=70] -->
     <string name="keyboard_shortcut_group_applications_calendar">Calendar</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the calculator app. [CHAR LIMIT=70] -->
+    <string name="keyboard_shortcut_group_applications_calculator">Calculator</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the maps app. [CHAR LIMIT=70] -->
+    <string name="keyboard_shortcut_group_applications_maps">Maps</string>
 
     <!-- SysUI Tuner: Label for screen about do not disturb settings [CHAR LIMIT=60] -->
     <string name="volume_and_do_not_disturb">Do Not Disturb</string>
@@ -2233,6 +2304,14 @@
     <!-- Title of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=25] -->
     <string name="inattentive_sleep_warning_title">Standby</string>
 
+    <!-- Font scaling -->
+    <!-- Font scaling: Quick Settings dialog title [CHAR LIMIT=30] -->
+    <string name="font_scaling_dialog_title">Font Size</string>
+    <!-- Content Description for the icon button to make fonts smaller. [CHAR LIMIT=30] -->
+    <string name="font_scaling_smaller">Make smaller</string>
+    <!-- Content Description for the icon button to make fonts larger. [CHAR LIMIT=30] -->
+    <string name="font_scaling_larger">Make larger</string>
+
     <!-- Window Magnification strings -->
     <!-- Title for Magnification Window [CHAR LIMIT=NONE] -->
     <string name="magnification_window_title">Magnification Window</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 9398c89..2cd2173 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -1375,4 +1375,23 @@
         <item name="android:lineHeight">@dimen/magnification_setting_button_line_height</item>
         <item name="android:textAlignment">center</item>
     </style>
+
+    <style name="ShortCutButton" parent="@android:style/Widget.Material.Button">
+        <item name="android:background">@drawable/shortcut_button_colored</item>
+        <item name="android:stateListAnimator">@null</item>
+        <item name="android:textSize">16sp</item>
+        <item name="android:padding">4dp</item>
+        <item name="android:textColor">?androidprv:attr/textColorSecondary</item>
+    </style>
+
+    <style name="ShortcutHorizontalDivider">
+        <item name="android:layout_width">120dp</item>
+        <item name="android:layout_height">1dp</item>
+        <item name="android:layout_gravity">center_horizontal</item>
+        <item name="android:background">?android:attr/dividerHorizontal</item>
+    </style>
+
+    <style name="ShortcutItemBackground">
+        <item name="android:background">@color/ksh_key_item_new_background</item>
+    </style>
 </resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 9f1c382..5b628f8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -102,6 +102,7 @@
 import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
 import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.hardware.usb.UsbManager;
 import android.nfc.NfcAdapter;
 import android.os.CancellationSignal;
 import android.os.Handler;
@@ -138,6 +139,7 @@
 import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
 import com.android.settingslib.WirelessUtils;
 import com.android.settingslib.fuelgauge.BatteryStatus;
+import com.android.settingslib.Utils;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.biometrics.AuthController;
@@ -329,6 +331,8 @@
     // Battery status
     @VisibleForTesting
     BatteryStatus mBatteryStatus;
+    @VisibleForTesting
+    boolean mIncompatibleCharger;
 
     private StrongAuthTracker mStrongAuthTracker;
 
@@ -1572,10 +1576,20 @@
                         MSG_TIMEZONE_UPDATE, intent.getStringExtra(Intent.EXTRA_TIMEZONE));
                 mHandler.sendMessage(msg);
             } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
-
+                // Clear incompatible charger state when device is unplugged.
+                if (!BatteryStatus.isPluggedIn(intent)) {
+                    mIncompatibleCharger = false;
+                }
                 final Message msg = mHandler.obtainMessage(
-                        MSG_BATTERY_UPDATE, new BatteryStatus(intent));
+                        MSG_BATTERY_UPDATE, new BatteryStatus(intent, mIncompatibleCharger));
                 mHandler.sendMessage(msg);
+            } else if (UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED.equals(action)) {
+                mIncompatibleCharger = Utils.containsIncompatibleChargers(context, TAG);
+                BatteryStatus batteryStatus = BatteryStatus.create(context, mIncompatibleCharger);
+                if (batteryStatus != null) {
+                    mHandler.sendMessage(
+                            mHandler.obtainMessage(MSG_BATTERY_UPDATE, batteryStatus));
+                }
             } else if (Intent.ACTION_SIM_STATE_CHANGED.equals(action)) {
                 SimData args = SimData.fromIntent(intent);
                 // ACTION_SIM_STATE_CHANGED is rebroadcast after unlocking the device to
@@ -2251,6 +2265,7 @@
         filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+        filter.addAction(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED);
         mBroadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter, mHandler);
         // Since ACTION_SERVICE_STATE is being moved to a non-sticky broadcast, trigger the
         // listener now with the service state from the default sub.
@@ -3527,8 +3542,6 @@
         final boolean wasPluggedIn = old.isPluggedIn();
         final boolean stateChangedWhilePluggedIn = wasPluggedIn && nowPluggedIn
                 && (old.status != current.status);
-        final boolean nowPresent = current.present;
-        final boolean wasPresent = old.present;
 
         // change in plug state is always interesting
         if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) {
@@ -3545,8 +3558,13 @@
             return true;
         }
 
-        // Battery either showed up or disappeared
-        if (wasPresent != nowPresent) {
+        // change in battery is present or not
+        if (old.present != current.present) {
+            return true;
+        }
+
+        // change in the incompatible charger
+        if (!old.incompatibleCharger.equals(current.incompatibleCharger)) {
             return true;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
new file mode 100644
index 0000000..54f933a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.accessibility.fontscaling
+
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.content.res.Configuration
+import android.os.Bundle
+import android.provider.Settings
+import android.view.LayoutInflater
+import android.widget.Button
+import android.widget.SeekBar
+import android.widget.SeekBar.OnSeekBarChangeListener
+import android.widget.TextView
+import com.android.systemui.R
+import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.settings.SystemSettings
+
+/** The Dialog that contains a seekbar for changing the font size. */
+class FontScalingDialog(context: Context, private val systemSettings: SystemSettings) :
+    SystemUIDialog(context) {
+    private val strEntryValues: Array<String> =
+        context.resources.getStringArray(com.android.settingslib.R.array.entryvalues_font_size)
+    private lateinit var title: TextView
+    private lateinit var doneButton: Button
+    private lateinit var seekBarWithIconButtonsView: SeekBarWithIconButtonsView
+
+    private val configuration: Configuration =
+        Configuration(context.getResources().getConfiguration())
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        setTitle(R.string.font_scaling_dialog_title)
+        setView(LayoutInflater.from(context).inflate(R.layout.font_scaling_dialog, null))
+        setPositiveButton(
+            R.string.quick_settings_done,
+            /* onClick = */ null,
+            /* dismissOnClick = */ true
+        )
+        super.onCreate(savedInstanceState)
+
+        title = requireViewById(com.android.internal.R.id.alertTitle)
+        doneButton = requireViewById(com.android.internal.R.id.button1)
+        seekBarWithIconButtonsView = requireViewById(R.id.font_scaling_slider)
+
+        seekBarWithIconButtonsView.setMax((strEntryValues).size - 1)
+
+        val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, 1.0f)
+        seekBarWithIconButtonsView.setProgress(fontSizeValueToIndex(currentScale))
+
+        seekBarWithIconButtonsView.setOnSeekBarChangeListener(
+            object : OnSeekBarChangeListener {
+                override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
+                    systemSettings.putString(Settings.System.FONT_SCALE, strEntryValues[progress])
+                }
+
+                override fun onStartTrackingTouch(seekBar: SeekBar) {
+                    // Do nothing
+                }
+
+                override fun onStopTrackingTouch(seekBar: SeekBar) {
+                    // Do nothing
+                }
+            }
+        )
+        doneButton.setOnClickListener { dismiss() }
+    }
+
+    private fun fontSizeValueToIndex(value: Float): Int {
+        var lastValue = strEntryValues[0].toFloat()
+        for (i in 1 until strEntryValues.size) {
+            val thisValue = strEntryValues[i].toFloat()
+            if (value < lastValue + (thisValue - lastValue) * .5f) {
+                return i - 1
+            }
+            lastValue = thisValue
+        }
+        return strEntryValues.size - 1
+    }
+
+    override fun onConfigurationChanged(configuration: Configuration) {
+        super.onConfigurationChanged(configuration)
+
+        val configDiff = configuration.diff(this.configuration)
+        this.configuration.setTo(configuration)
+
+        if (configDiff and ActivityInfo.CONFIG_FONT_SCALE != 0) {
+            title.post {
+                title.setTextAppearance(R.style.TextAppearance_Dialog_Title)
+                doneButton.setTextAppearance(R.style.Widget_Dialog_Button)
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java b/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
index ae6a08f..a2077a3 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
@@ -22,6 +22,7 @@
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.SeekBar;
@@ -37,6 +38,8 @@
     private static final int DEFAULT_SEEKBAR_MAX = 6;
     private static final int DEFAULT_SEEKBAR_PROGRESS = 0;
 
+    private ViewGroup mIconStartFrame;
+    private ViewGroup mIconEndFrame;
     private ImageView mIconStart;
     private ImageView mIconEnd;
     private SeekBar mSeekbar;
@@ -62,6 +65,8 @@
         LayoutInflater.from(context).inflate(
                 R.layout.seekbar_with_icon_buttons, this, /* attachToRoot= */ true);
 
+        mIconStartFrame = findViewById(R.id.icon_start_frame);
+        mIconEndFrame = findViewById(R.id.icon_end_frame);
         mIconStart = findViewById(R.id.icon_start);
         mIconEnd = findViewById(R.id.icon_end);
         mSeekbar = findViewById(R.id.seekbar);
@@ -80,24 +85,22 @@
             mSeekbar.setMax(max);
             setProgress(progress);
 
-            int iconStartContentDescriptionId = typedArray.getResourceId(
+            int iconStartFrameContentDescriptionId = typedArray.getResourceId(
                     R.styleable.SeekBarWithIconButtonsView_Layout_iconStartContentDescription,
                     /* defValue= */ 0);
-            int iconEndContentDescriptionId = typedArray.getResourceId(
+            int iconEndFrameContentDescriptionId = typedArray.getResourceId(
                     R.styleable.SeekBarWithIconButtonsView_Layout_iconEndContentDescription,
                     /* defValue= */ 0);
-            if (iconStartContentDescriptionId != 0) {
+            if (iconStartFrameContentDescriptionId != 0) {
                 final String contentDescription =
-                        context.getString(iconStartContentDescriptionId);
-                mIconStart.setContentDescription(contentDescription);
+                        context.getString(iconStartFrameContentDescriptionId);
+                mIconStartFrame.setContentDescription(contentDescription);
             }
-            if (iconEndContentDescriptionId != 0) {
+            if (iconEndFrameContentDescriptionId != 0) {
                 final String contentDescription =
-                        context.getString(iconEndContentDescriptionId);
-                mIconEnd.setContentDescription(contentDescription);
+                        context.getString(iconEndFrameContentDescriptionId);
+                mIconEndFrame.setContentDescription(contentDescription);
             }
-
-            typedArray.recycle();
         } else {
             mSeekbar.setMax(DEFAULT_SEEKBAR_MAX);
             setProgress(DEFAULT_SEEKBAR_PROGRESS);
@@ -109,7 +112,7 @@
             final int progress = mSeekbar.getProgress();
             if (progress > 0) {
                 mSeekbar.setProgress(progress - 1);
-                setIconViewEnabled(mIconStart, mSeekbar.getProgress() > 0);
+                setIconViewAndFrameEnabled(mIconStart, mSeekbar.getProgress() > 0);
             }
         });
 
@@ -117,13 +120,15 @@
             final int progress = mSeekbar.getProgress();
             if (progress < mSeekbar.getMax()) {
                 mSeekbar.setProgress(progress + 1);
-                setIconViewEnabled(mIconEnd, mSeekbar.getProgress() < mSeekbar.getMax());
+                setIconViewAndFrameEnabled(mIconEnd, mSeekbar.getProgress() < mSeekbar.getMax());
             }
         });
     }
 
-    private static void setIconViewEnabled(View iconView, boolean enabled) {
+    private static void setIconViewAndFrameEnabled(View iconView, boolean enabled) {
         iconView.setEnabled(enabled);
+        final ViewGroup iconFrame = (ViewGroup) iconView.getParent();
+        iconFrame.setEnabled(enabled);
     }
 
     /**
@@ -141,12 +146,22 @@
      * Icon End will need to be enabled when the seekbar progress is less than Max.
      */
     private void updateIconViewIfNeeded(int progress) {
-        setIconViewEnabled(mIconStart, progress > 0);
-        setIconViewEnabled(mIconEnd, progress < mSeekbar.getMax());
+        setIconViewAndFrameEnabled(mIconStart, progress > 0);
+        setIconViewAndFrameEnabled(mIconEnd, progress < mSeekbar.getMax());
+    }
+
+    /**
+     * Sets max to the seekbar in the layout.
+     */
+    public void setMax(int max) {
+        mSeekbar.setMax(max);
     }
 
     /**
      * Sets progress to the seekbar in the layout.
+     * If the progress is smaller than or equals to 0, the IconStart will be disabled. If the
+     * progress is larger than or equals to Max, the IconEnd will be disabled. The seekbar progress
+     * will be constrained in {@link SeekBar}.
      */
     public void setProgress(int progress) {
         mSeekbar.setProgress(progress);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index d0c5007..fadabb4 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -47,6 +47,7 @@
 import com.android.systemui.shade.ShadeControllerImpl;
 import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.KeyboardShortcutsModule;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -100,7 +101,8 @@
         QSModule.class,
         ReferenceScreenshotModule.class,
         StartCentralSurfacesModule.class,
-        VolumeModule.class
+        VolumeModule.class,
+        KeyboardShortcutsModule.class
 })
 public abstract class ReferenceSystemUIModule {
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
index 4d8f89e..b9cd535 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
@@ -19,8 +19,12 @@
 import android.os.Handler
 import android.os.Looper
 import android.view.View
+import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.logging.MetricsLogger
 import com.android.systemui.R
+import com.android.systemui.accessibility.fontscaling.FontScalingDialog
+import com.android.systemui.animation.DialogCuj
+import com.android.systemui.animation.DialogLaunchAnimator
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.ActivityStarter
@@ -30,6 +34,8 @@
 import com.android.systemui.qs.QSHost
 import com.android.systemui.qs.logging.QSLogger
 import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.settings.SystemSettings
 import javax.inject.Inject
 
 class FontScalingTile
@@ -42,7 +48,9 @@
     metricsLogger: MetricsLogger,
     statusBarStateController: StatusBarStateController,
     activityStarter: ActivityStarter,
-    qsLogger: QSLogger
+    qsLogger: QSLogger,
+    private val dialogLaunchAnimator: DialogLaunchAnimator,
+    private val systemSettings: SystemSettings
 ) :
     QSTileImpl<QSTile.State?>(
         host,
@@ -54,7 +62,7 @@
         activityStarter,
         qsLogger
     ) {
-    private val mIcon = ResourceIcon.get(R.drawable.ic_qs_font_scaling)
+    private val icon = ResourceIcon.get(R.drawable.ic_qs_font_scaling)
 
     override fun isAvailable(): Boolean {
         return false
@@ -66,11 +74,24 @@
         return state
     }
 
-    override fun handleClick(view: View?) {}
+    override fun handleClick(view: View?) {
+        mUiHandler.post {
+            val dialog: SystemUIDialog = FontScalingDialog(mContext, systemSettings)
+            if (view != null) {
+                dialogLaunchAnimator.showFromView(
+                    dialog,
+                    view,
+                    DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, INTERACTION_JANK_TAG)
+                )
+            } else {
+                dialog.show()
+            }
+        }
+    }
 
     override fun handleUpdateState(state: QSTile.State?, arg: Any?) {
         state?.label = mContext.getString(R.string.quick_settings_font_scaling_label)
-        state?.icon = mIcon
+        state?.icon = icon
     }
 
     override fun getLongClickIntent(): Intent? {
@@ -80,4 +101,8 @@
     override fun getTileLabel(): CharSequence {
         return mContext.getString(R.string.quick_settings_font_scaling_label)
     }
+
+    companion object {
+        private const val INTERACTION_JANK_TAG = "font_scaling"
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
new file mode 100644
index 0000000..01e042b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
@@ -0,0 +1,1382 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.hardware.input.InputManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.util.Pair;
+import android.util.SparseArray;
+import android.view.ContextThemeWrapper;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
+import android.view.KeyboardShortcutInfo;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.AccessibilityDelegate;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.WindowManager.KeyboardShortcutsReceiver;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.AssistUtils;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settingslib.Utils;
+import com.android.systemui.R;
+
+import com.google.android.material.bottomsheet.BottomSheetBehavior;
+import com.google.android.material.bottomsheet.BottomSheetDialog;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Contains functionality for handling keyboard shortcuts.
+ */
+public final class KeyboardShortcutListSearch {
+    private static final String TAG = KeyboardShortcutListSearch.class.getSimpleName();
+    private static final Object sLock = new Object();
+    @VisibleForTesting static KeyboardShortcutListSearch sInstance;
+
+    private static int SHORTCUT_SYSTEM_INDEX = 0;
+    private static int SHORTCUT_INPUT_INDEX = 1;
+    private static int SHORTCUT_OPENAPPS_INDEX = 2;
+    private static int SHORTCUT_SPECIFICAPP_INDEX = 3;
+
+    private WindowManager mWindowManager;
+    private EditText mSearchEditText;
+    private String mQueryString;
+    private int mCurrentCategoryIndex = 0;
+    private Map<Integer, Boolean> mKeySearchResultMap = new HashMap<>();
+
+    private List<List<KeyboardShortcutMultiMappingGroup>> mFullShortsGroup = new ArrayList<>();
+    private List<KeyboardShortcutMultiMappingGroup> mSpecificAppGroup = new ArrayList<>();
+    private List<KeyboardShortcutMultiMappingGroup> mSystemGroup = new ArrayList<>();
+    private List<KeyboardShortcutMultiMappingGroup> mInputGroup = new ArrayList<>();
+    private List<KeyboardShortcutMultiMappingGroup> mOpenAppsGroup = new ArrayList<>();
+
+    private ArrayList<Button> mFullButtonList = new ArrayList<>();
+    private Button mButtonSystem;
+    private Button mButtonInput;
+    private Button mButtonOpenApps;
+    private Button mButtonSpecificApp;
+    private ImageView mEditTextCancel;
+    private TextView mNoSearchResults;
+
+    private final SparseArray<String> mSpecialCharacterNames = new SparseArray<>();
+    private final SparseArray<String> mModifierNames = new SparseArray<>();
+    private final SparseArray<Drawable> mSpecialCharacterDrawables = new SparseArray<>();
+    private final SparseArray<Drawable> mModifierDrawables = new SparseArray<>();
+    // Ordered list of modifiers that are supported. All values in this array must exist in
+    // mModifierNames.
+    private final int[] mModifierList = new int[] {
+            KeyEvent.META_META_ON, KeyEvent.META_CTRL_ON, KeyEvent.META_ALT_ON,
+            KeyEvent.META_SHIFT_ON, KeyEvent.META_SYM_ON, KeyEvent.META_FUNCTION_ON
+    };
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+    @VisibleForTesting Context mContext;
+    private final IPackageManager mPackageManager;
+
+    @VisibleForTesting BottomSheetDialog mKeyboardShortcutsBottomSheetDialog;
+    private KeyCharacterMap mKeyCharacterMap;
+    private KeyCharacterMap mBackupKeyCharacterMap;
+
+    @VisibleForTesting
+    KeyboardShortcutListSearch(Context context, WindowManager windowManager) {
+        this.mContext = new ContextThemeWrapper(
+                context, android.R.style.Theme_DeviceDefault_Settings);
+        this.mPackageManager = AppGlobals.getPackageManager();
+        if (windowManager != null) {
+            this.mWindowManager = windowManager;
+        } else {
+            this.mWindowManager = mContext.getSystemService(WindowManager.class);
+        }
+        loadResources(context);
+        createHardcodedShortcuts();
+    }
+
+    private static KeyboardShortcutListSearch getInstance(Context context) {
+        if (sInstance == null) {
+            sInstance = new KeyboardShortcutListSearch(context, null);
+        }
+        return sInstance;
+    }
+
+    public static void show(Context context, int deviceId) {
+        MetricsLogger.visible(context,
+                MetricsProto.MetricsEvent.KEYBOARD_SHORTCUTS_HELPER);
+        synchronized (sLock) {
+            if (sInstance != null && !sInstance.mContext.equals(context)) {
+                dismiss();
+            }
+            getInstance(context).showKeyboardShortcuts(deviceId);
+        }
+    }
+
+    public static void toggle(Context context, int deviceId) {
+        synchronized (sLock) {
+            if (isShowing()) {
+                dismiss();
+            } else {
+                show(context, deviceId);
+            }
+        }
+    }
+
+    public static void dismiss() {
+        synchronized (sLock) {
+            if (sInstance != null) {
+                MetricsLogger.hidden(sInstance.mContext,
+                        MetricsProto.MetricsEvent.KEYBOARD_SHORTCUTS_HELPER);
+                sInstance.dismissKeyboardShortcuts();
+                sInstance = null;
+            }
+        }
+    }
+
+    private static boolean isShowing() {
+        return sInstance != null && sInstance.mKeyboardShortcutsBottomSheetDialog != null
+                && sInstance.mKeyboardShortcutsBottomSheetDialog.isShowing();
+    }
+
+    private void loadResources(Context context) {
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_HOME, context.getString(R.string.keyboard_key_home));
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_BACK, context.getString(R.string.keyboard_key_back));
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_DPAD_UP, context.getString(R.string.keyboard_key_dpad_up));
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_DPAD_DOWN, context.getString(R.string.keyboard_key_dpad_down));
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_DPAD_LEFT, context.getString(R.string.keyboard_key_dpad_left));
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_DPAD_RIGHT, context.getString(R.string.keyboard_key_dpad_right));
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_DPAD_CENTER, context.getString(R.string.keyboard_key_dpad_center));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_PERIOD, ".");
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_TAB, context.getString(R.string.keyboard_key_tab));
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_SPACE, context.getString(R.string.keyboard_key_space));
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_ENTER, context.getString(R.string.keyboard_key_enter));
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_DEL, context.getString(R.string.keyboard_key_backspace));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE,
+                context.getString(R.string.keyboard_key_media_play_pause));
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_MEDIA_STOP, context.getString(R.string.keyboard_key_media_stop));
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_MEDIA_NEXT, context.getString(R.string.keyboard_key_media_next));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_MEDIA_PREVIOUS,
+                context.getString(R.string.keyboard_key_media_previous));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_MEDIA_REWIND,
+                context.getString(R.string.keyboard_key_media_rewind));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD,
+                context.getString(R.string.keyboard_key_media_fast_forward));
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_PAGE_UP, context.getString(R.string.keyboard_key_page_up));
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_PAGE_DOWN, context.getString(R.string.keyboard_key_page_down));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_A,
+                context.getString(R.string.keyboard_key_button_template, "A"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_B,
+                context.getString(R.string.keyboard_key_button_template, "B"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_C,
+                context.getString(R.string.keyboard_key_button_template, "C"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_X,
+                context.getString(R.string.keyboard_key_button_template, "X"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_Y,
+                context.getString(R.string.keyboard_key_button_template, "Y"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_Z,
+                context.getString(R.string.keyboard_key_button_template, "Z"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_L1,
+                context.getString(R.string.keyboard_key_button_template, "L1"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_R1,
+                context.getString(R.string.keyboard_key_button_template, "R1"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_L2,
+                context.getString(R.string.keyboard_key_button_template, "L2"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_R2,
+                context.getString(R.string.keyboard_key_button_template, "R2"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_START,
+                context.getString(R.string.keyboard_key_button_template, "Start"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_SELECT,
+                context.getString(R.string.keyboard_key_button_template, "Select"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_MODE,
+                context.getString(R.string.keyboard_key_button_template, "Mode"));
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_FORWARD_DEL, context.getString(R.string.keyboard_key_forward_del));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_ESCAPE, "Esc");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_SYSRQ, "SysRq");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_BREAK, "Break");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_SCROLL_LOCK, "Scroll Lock");
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_MOVE_HOME, context.getString(R.string.keyboard_key_move_home));
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_MOVE_END, context.getString(R.string.keyboard_key_move_end));
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_INSERT, context.getString(R.string.keyboard_key_insert));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_F1, "F1");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_F2, "F2");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_F3, "F3");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_F4, "F4");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_F5, "F5");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_F6, "F6");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_F7, "F7");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_F8, "F8");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_F9, "F9");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_F10, "F10");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_F11, "F11");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_F12, "F12");
+        mSpecialCharacterNames.put(
+                KeyEvent.KEYCODE_NUM_LOCK, context.getString(R.string.keyboard_key_num_lock));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_MINUS, "-");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_GRAVE, "~");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_EQUALS, "=");
+
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_0,
+                context.getString(R.string.keyboard_key_numpad_template, "0"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_1,
+                context.getString(R.string.keyboard_key_numpad_template, "1"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_2,
+                context.getString(R.string.keyboard_key_numpad_template, "2"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_3,
+                context.getString(R.string.keyboard_key_numpad_template, "3"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_4,
+                context.getString(R.string.keyboard_key_numpad_template, "4"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_5,
+                context.getString(R.string.keyboard_key_numpad_template, "5"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_6,
+                context.getString(R.string.keyboard_key_numpad_template, "6"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_7,
+                context.getString(R.string.keyboard_key_numpad_template, "7"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_8,
+                context.getString(R.string.keyboard_key_numpad_template, "8"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_9,
+                context.getString(R.string.keyboard_key_numpad_template, "9"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_DIVIDE,
+                context.getString(R.string.keyboard_key_numpad_template, "/"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_MULTIPLY,
+                context.getString(R.string.keyboard_key_numpad_template, "*"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_SUBTRACT,
+                context.getString(R.string.keyboard_key_numpad_template, "-"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_ADD,
+                context.getString(R.string.keyboard_key_numpad_template, "+"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_DOT,
+                context.getString(R.string.keyboard_key_numpad_template, "."));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_COMMA,
+                context.getString(R.string.keyboard_key_numpad_template, ","));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_ENTER,
+                context.getString(R.string.keyboard_key_numpad_template,
+                        context.getString(R.string.keyboard_key_enter)));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_EQUALS,
+                context.getString(R.string.keyboard_key_numpad_template, "="));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_LEFT_PAREN,
+                context.getString(R.string.keyboard_key_numpad_template, "("));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_RIGHT_PAREN,
+                context.getString(R.string.keyboard_key_numpad_template, ")"));
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_ZENKAKU_HANKAKU, "半角/全角");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_EISU, "英数");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_MUHENKAN, "無変換");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_HENKAN, "変換");
+        mSpecialCharacterNames.put(KeyEvent.KEYCODE_KATAKANA_HIRAGANA, "かな");
+
+        mModifierNames.put(KeyEvent.META_META_ON, "Meta");
+        mModifierNames.put(KeyEvent.META_CTRL_ON, "Ctrl");
+        mModifierNames.put(KeyEvent.META_ALT_ON, "Alt");
+        mModifierNames.put(KeyEvent.META_SHIFT_ON, "Shift");
+        mModifierNames.put(KeyEvent.META_SYM_ON, "Sym");
+        mModifierNames.put(KeyEvent.META_FUNCTION_ON, "Fn");
+
+        mSpecialCharacterDrawables.put(
+                KeyEvent.KEYCODE_DEL, context.getDrawable(R.drawable.ic_ksh_key_backspace));
+        mSpecialCharacterDrawables.put(
+                KeyEvent.KEYCODE_ENTER, context.getDrawable(R.drawable.ic_ksh_key_enter));
+        mSpecialCharacterDrawables.put(
+                KeyEvent.KEYCODE_DPAD_UP, context.getDrawable(R.drawable.ic_ksh_key_up));
+        mSpecialCharacterDrawables.put(
+                KeyEvent.KEYCODE_DPAD_RIGHT, context.getDrawable(R.drawable.ic_ksh_key_right));
+        mSpecialCharacterDrawables.put(
+                KeyEvent.KEYCODE_DPAD_DOWN, context.getDrawable(R.drawable.ic_ksh_key_down));
+        mSpecialCharacterDrawables.put(
+                KeyEvent.KEYCODE_DPAD_LEFT, context.getDrawable(R.drawable.ic_ksh_key_left));
+
+        mModifierDrawables.put(
+                KeyEvent.META_META_ON, context.getDrawable(R.drawable.ic_ksh_key_meta));
+    }
+
+    private void createHardcodedShortcuts() {
+        // Add system shortcuts
+        mKeySearchResultMap.put(SHORTCUT_SYSTEM_INDEX, true);
+        mSystemGroup.add(getMultiMappingSystemShortcuts(mContext));
+        mSystemGroup.add(getSystemMultitaskingShortcuts(mContext));
+        // Add input shortcuts
+        mKeySearchResultMap.put(SHORTCUT_INPUT_INDEX, true);
+        mInputGroup.add(getMultiMappingInputShortcuts(mContext));
+        // Add open apps shortcuts
+        final List<KeyboardShortcutMultiMappingGroup> appShortcuts =
+                Arrays.asList(getDefaultMultiMappingApplicationShortcuts());
+        if (appShortcuts != null && !appShortcuts.isEmpty()) {
+            mOpenAppsGroup = appShortcuts;
+            mKeySearchResultMap.put(SHORTCUT_OPENAPPS_INDEX, true);
+        } else {
+            mKeySearchResultMap.put(SHORTCUT_OPENAPPS_INDEX, false);
+        }
+    }
+
+    /**
+     * Retrieves a {@link KeyCharacterMap} and assigns it to mKeyCharacterMap. If the given id is an
+     * existing device, that device's map is used. Otherwise, it checks first all available devices
+     * and if there is a full keyboard it uses that map, otherwise falls back to the Virtual
+     * Keyboard with its default map.
+     */
+    private void retrieveKeyCharacterMap(int deviceId) {
+        final InputManager inputManager = InputManager.getInstance();
+        mBackupKeyCharacterMap = inputManager.getInputDevice(-1).getKeyCharacterMap();
+        if (deviceId != -1) {
+            final InputDevice inputDevice = inputManager.getInputDevice(deviceId);
+            if (inputDevice != null) {
+                mKeyCharacterMap = inputDevice.getKeyCharacterMap();
+                return;
+            }
+        }
+        final int[] deviceIds = inputManager.getInputDeviceIds();
+        for (int id : deviceIds) {
+            final InputDevice inputDevice = inputManager.getInputDevice(id);
+            // -1 is the Virtual Keyboard, with the default key map. Use that one only as last
+            // resort.
+            if (inputDevice.getId() != -1 && inputDevice.isFullKeyboard()) {
+                mKeyCharacterMap = inputDevice.getKeyCharacterMap();
+                return;
+            }
+        }
+        // Fall back to -1, the virtual keyboard.
+        mKeyCharacterMap = mBackupKeyCharacterMap;
+    }
+
+    @VisibleForTesting
+    void showKeyboardShortcuts(int deviceId) {
+        retrieveKeyCharacterMap(deviceId);
+        mWindowManager.requestAppKeyboardShortcuts(new KeyboardShortcutsReceiver() {
+            @Override
+            public void onKeyboardShortcutsReceived(
+                    final List<KeyboardShortcutGroup> result) {
+                // Add specific app shortcuts
+                if (result.isEmpty()) {
+                    mKeySearchResultMap.put(SHORTCUT_SPECIFICAPP_INDEX, false);
+                } else {
+                    mSpecificAppGroup = reMapToKeyboardShortcutMultiMappingGroup(result);
+                    mKeySearchResultMap.put(SHORTCUT_SPECIFICAPP_INDEX, true);
+                }
+                mFullShortsGroup.add(SHORTCUT_SYSTEM_INDEX, mSystemGroup);
+                mFullShortsGroup.add(SHORTCUT_INPUT_INDEX, mInputGroup);
+                mFullShortsGroup.add(SHORTCUT_OPENAPPS_INDEX, mOpenAppsGroup);
+                mFullShortsGroup.add(SHORTCUT_SPECIFICAPP_INDEX, mSpecificAppGroup);
+                showKeyboardShortcutSearchList(mFullShortsGroup);
+            }
+        }, deviceId);
+    }
+
+    // The original data structure is only for 1-to-1 shortcut mapping, so remap the old
+    // data structure to the new data structure for handling the N-to-1 key mapping and other
+    // complex case.
+    private List<KeyboardShortcutMultiMappingGroup> reMapToKeyboardShortcutMultiMappingGroup(
+            List<KeyboardShortcutGroup> keyboardShortcutGroups) {
+        List<KeyboardShortcutMultiMappingGroup> keyboardShortcutMultiMappingGroups =
+                new ArrayList<>();
+        for (KeyboardShortcutGroup group : keyboardShortcutGroups) {
+            CharSequence categoryTitle = group.getLabel();
+            List<ShortcutMultiMappingInfo> shortcutMultiMappingInfos = new ArrayList<>();
+            for (KeyboardShortcutInfo info : group.getItems()) {
+                shortcutMultiMappingInfos.add(new ShortcutMultiMappingInfo(info));
+            }
+            keyboardShortcutMultiMappingGroups.add(
+                    new KeyboardShortcutMultiMappingGroup(
+                            categoryTitle, shortcutMultiMappingInfos));
+        }
+        return keyboardShortcutMultiMappingGroups;
+    }
+
+    private void dismissKeyboardShortcuts() {
+        if (mKeyboardShortcutsBottomSheetDialog != null) {
+            mKeyboardShortcutsBottomSheetDialog.dismiss();
+            mKeyboardShortcutsBottomSheetDialog = null;
+        }
+    }
+
+    private KeyboardShortcutMultiMappingGroup getMultiMappingSystemShortcuts(Context context) {
+        KeyboardShortcutMultiMappingGroup systemGroup =
+                new KeyboardShortcutMultiMappingGroup(
+                        context.getString(R.string.keyboard_shortcut_group_system),
+                        new ArrayList<>());
+        List<ShortcutKeyGroupMultiMappingInfo> infoList = Arrays.asList(
+                /* Access notification shade: Meta + N */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_access_notification_shade),
+                        Arrays.asList(
+                                Pair.create(KeyEvent.KEYCODE_N, KeyEvent.META_META_ON))),
+                /* Take a full screenshot: Meta + Ctrl + S */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_full_screenshot),
+                        Arrays.asList(
+                                Pair.create(
+                                        KeyEvent.KEYCODE_S,
+                                        KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON))),
+                /* Access list of system / apps shortcuts: Meta + / */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_access_system_app_shortcuts),
+                        Arrays.asList(
+                                Pair.create(KeyEvent.KEYCODE_SLASH, KeyEvent.META_META_ON))),
+                /* Back: go back to previous state (back button) */
+                /* Meta + ~, Meta + backspace, Meta + left arrow */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_go_back),
+                        Arrays.asList(
+                                Pair.create(KeyEvent.KEYCODE_GRAVE, KeyEvent.META_META_ON),
+                                Pair.create(KeyEvent.KEYCODE_DEL, KeyEvent.META_META_ON),
+                                Pair.create(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.META_META_ON))),
+                /* Access home screen: Meta + H, Meta + Enter */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_access_home_screen),
+                        Arrays.asList(
+                                Pair.create(KeyEvent.KEYCODE_H, KeyEvent.META_META_ON),
+                                Pair.create(KeyEvent.KEYCODE_ENTER, KeyEvent.META_META_ON))),
+                /* Overview of open apps: Meta + Tab */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_overview_open_apps),
+                        Arrays.asList(
+                                Pair.create(KeyEvent.KEYCODE_TAB, KeyEvent.META_META_ON))),
+                /* Cycle through recent apps (forward): Alt + Tab */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_cycle_forward),
+                        Arrays.asList(
+                                Pair.create(KeyEvent.KEYCODE_TAB, KeyEvent.META_ALT_ON))),
+                /* Cycle through recent apps (back): Shift + Alt + Tab */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_cycle_back),
+                        Arrays.asList(
+                                Pair.create(
+                                        KeyEvent.KEYCODE_TAB,
+                                        KeyEvent.META_SHIFT_ON | KeyEvent.META_ALT_ON))),
+                /* Access list of all apps and search (i.e. Search/Launcher): Meta */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_access_all_apps_search),
+                        Arrays.asList(
+                                Pair.create(KeyEvent.KEYCODE_UNKNOWN, KeyEvent.META_META_ON))),
+                /* Hide and (re)show taskbar: Meta + T */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_hide_reshow_taskbar),
+                        Arrays.asList(
+                                Pair.create(KeyEvent.KEYCODE_T, KeyEvent.META_META_ON))),
+                /* Access system settings: Meta + I */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_access_system_settings),
+                        Arrays.asList(
+                                Pair.create(KeyEvent.KEYCODE_I, KeyEvent.META_META_ON))),
+                /* Access Google Assistant: Meta + A */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_access_google_assistant),
+                        Arrays.asList(
+                                Pair.create(KeyEvent.KEYCODE_A, KeyEvent.META_META_ON))),
+                /*  Lock screen: Meta + L */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_lock_screen),
+                        Arrays.asList(
+                                Pair.create(KeyEvent.KEYCODE_L, KeyEvent.META_META_ON))),
+                /* Pull up Notes app for quick memo: Meta + Ctrl + N */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_quick_memo),
+                        Arrays.asList(
+                                Pair.create(
+                                        KeyEvent.KEYCODE_N,
+                                        KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON)))
+        );
+        for (ShortcutKeyGroupMultiMappingInfo info : infoList) {
+            systemGroup.addItem(info.getShortcutMultiMappingInfo());
+        }
+        return systemGroup;
+    }
+
+    private static class ShortcutKeyGroupMultiMappingInfo {
+        private String mLabel;
+        private List<Pair<Integer, Integer>> mKeycodeGroupList;
+
+        ShortcutKeyGroupMultiMappingInfo(
+                String label, List<Pair<Integer, Integer>> keycodeGroupList) {
+            mLabel = label;
+            mKeycodeGroupList = keycodeGroupList;
+        }
+
+        ShortcutMultiMappingInfo getShortcutMultiMappingInfo() {
+            List<ShortcutKeyGroup> shortcutKeyGroups = new ArrayList<>();
+            for (Pair<Integer, Integer> keycodeGroup : mKeycodeGroupList) {
+                shortcutKeyGroups.add(new ShortcutKeyGroup(
+                        new KeyboardShortcutInfo(
+                                mLabel,
+                                keycodeGroup.first /* keycode */,
+                                keycodeGroup.second /* modifiers*/),
+                        null));
+            }
+            ShortcutMultiMappingInfo shortcutMultiMappingInfo =
+                    new ShortcutMultiMappingInfo(mLabel, null, shortcutKeyGroups);
+            return shortcutMultiMappingInfo;
+        }
+    }
+
+    private static KeyboardShortcutMultiMappingGroup getSystemMultitaskingShortcuts(
+            Context context) {
+        KeyboardShortcutMultiMappingGroup systemMultitaskingGroup =
+                new KeyboardShortcutMultiMappingGroup(
+                        context.getString(R.string.keyboard_shortcut_group_system_multitasking),
+                        new ArrayList<>());
+
+        // System multitasking shortcuts:
+        //    Enter Split screen with current app to RHS: Meta + Ctrl + Right arrow
+        //    Enter Split screen with current app to LHS: Meta + Ctrl + Left arrow
+        //    Switch from Split screen to full screen: Meta + Ctrl + Up arrow
+        //    During Split screen: replace an app from one to another: Meta + Ctrl + Down arrow
+        String[] shortcutLabels = {
+                context.getString(R.string.system_multitasking_rhs),
+                context.getString(R.string.system_multitasking_lhs),
+                context.getString(R.string.system_multitasking_full_screen),
+                context.getString(R.string.system_multitasking_replace)
+        };
+        int[] keyCodes = {
+                KeyEvent.KEYCODE_DPAD_RIGHT,
+                KeyEvent.KEYCODE_DPAD_LEFT,
+                KeyEvent.KEYCODE_DPAD_UP,
+                KeyEvent.KEYCODE_DPAD_DOWN
+        };
+
+        for (int i = 0; i < shortcutLabels.length; i++) {
+            List<ShortcutKeyGroup> shortcutKeyGroups = Arrays.asList(new ShortcutKeyGroup(
+                    new KeyboardShortcutInfo(
+                            shortcutLabels[i],
+                            keyCodes[i],
+                            KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON),
+                    null));
+            ShortcutMultiMappingInfo shortcutMultiMappingInfo =
+                    new ShortcutMultiMappingInfo(
+                            shortcutLabels[i],
+                            null,
+                            shortcutKeyGroups);
+            systemMultitaskingGroup.addItem(shortcutMultiMappingInfo);
+        }
+        return systemMultitaskingGroup;
+    }
+
+    private static KeyboardShortcutMultiMappingGroup getMultiMappingInputShortcuts(
+            Context context) {
+        List<ShortcutMultiMappingInfo> shortcutMultiMappingInfoList = Arrays.asList(
+                /* Switch input language (next language): Ctrl + Space or Meta + Space */
+                new ShortcutMultiMappingInfo(
+                        context.getString(R.string.input_switch_input_language_next),
+                        null,
+                        Arrays.asList(
+                                new ShortcutKeyGroup(new KeyboardShortcutInfo(
+                                        context.getString(
+                                                R.string.input_switch_input_language_next),
+                                        KeyEvent.KEYCODE_SPACE, KeyEvent.META_CTRL_ON),
+                                        null),
+                                new ShortcutKeyGroup(new KeyboardShortcutInfo(
+                                        context.getString(
+                                                R.string.input_switch_input_language_next),
+                                        KeyEvent.KEYCODE_SPACE, KeyEvent.META_META_ON),
+                                        null))),
+                /* Switch input language (previous language): */
+                /* Ctrl + Shift + Space or Meta + Shift + Space */
+                new ShortcutMultiMappingInfo(
+                        context.getString(R.string.input_switch_input_language_previous),
+                        null,
+                        Arrays.asList(
+                                new ShortcutKeyGroup(new KeyboardShortcutInfo(
+                                        context.getString(
+                                                R.string.input_switch_input_language_previous),
+                                        KeyEvent.KEYCODE_SPACE,
+                                        KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON),
+                                        null),
+                                new ShortcutKeyGroup(new KeyboardShortcutInfo(
+                                        context.getString(
+                                                R.string.input_switch_input_language_previous),
+                                        KeyEvent.KEYCODE_SPACE,
+                                        KeyEvent.META_META_ON | KeyEvent.META_SHIFT_ON),
+                                        null))),
+                /* Access emoji: Meta + . */
+                new ShortcutMultiMappingInfo(
+                        context.getString(R.string.input_access_emoji),
+                        null,
+                        Arrays.asList(
+                                new ShortcutKeyGroup(new KeyboardShortcutInfo(
+                                        context.getString(R.string.input_access_emoji),
+                                        KeyEvent.KEYCODE_PERIOD,
+                                        KeyEvent.META_META_ON),
+                                        null))),
+                /* Access voice typing: Meta + V */
+                new ShortcutMultiMappingInfo(
+                        context.getString(R.string.input_access_voice_typing),
+                        null,
+                        Arrays.asList(
+                                new ShortcutKeyGroup(new KeyboardShortcutInfo(
+                                        context.getString(R.string.input_access_voice_typing),
+                                        KeyEvent.KEYCODE_V, KeyEvent.META_META_ON),
+                                        null)))
+        );
+        return new KeyboardShortcutMultiMappingGroup(
+                context.getString(R.string.keyboard_shortcut_group_input),
+                shortcutMultiMappingInfoList);
+    }
+
+    private KeyboardShortcutMultiMappingGroup getDefaultMultiMappingApplicationShortcuts() {
+        final int userId = mContext.getUserId();
+        PackageInfo assistPackageInfo = getAssistPackageInfo(mContext, mPackageManager, userId);
+        CharSequence categoryTitle =
+                mContext.getString(R.string.keyboard_shortcut_group_applications);
+        List<ShortcutMultiMappingInfo> shortcutMultiMappingInfos = new ArrayList<>();
+
+        String[] intentCategories = {
+                Intent.CATEGORY_APP_BROWSER,
+                Intent.CATEGORY_APP_CONTACTS,
+                Intent.CATEGORY_APP_EMAIL,
+                Intent.CATEGORY_APP_CALENDAR,
+                Intent.CATEGORY_APP_MAPS,
+                Intent.CATEGORY_APP_MUSIC,
+                Intent.CATEGORY_APP_MESSAGING,
+                Intent.CATEGORY_APP_CALCULATOR,
+
+        };
+        String[] shortcutLabels = {
+                mContext.getString(R.string.keyboard_shortcut_group_applications_browser),
+                mContext.getString(R.string.keyboard_shortcut_group_applications_contacts),
+                mContext.getString(R.string.keyboard_shortcut_group_applications_email),
+                mContext.getString(R.string.keyboard_shortcut_group_applications_calendar),
+                mContext.getString(R.string.keyboard_shortcut_group_applications_maps),
+                mContext.getString(R.string.keyboard_shortcut_group_applications_music),
+                mContext.getString(R.string.keyboard_shortcut_group_applications_sms),
+                mContext.getString(R.string.keyboard_shortcut_group_applications_calculator)
+        };
+        int[] keyCodes = {
+                KeyEvent.KEYCODE_B,
+                KeyEvent.KEYCODE_C,
+                KeyEvent.KEYCODE_E,
+                KeyEvent.KEYCODE_K,
+                KeyEvent.KEYCODE_M,
+                KeyEvent.KEYCODE_P,
+                KeyEvent.KEYCODE_S,
+                KeyEvent.KEYCODE_U,
+        };
+
+        // Assist.
+        if (assistPackageInfo != null) {
+            if (assistPackageInfo != null) {
+                final Icon assistIcon = Icon.createWithResource(
+                        assistPackageInfo.applicationInfo.packageName,
+                        assistPackageInfo.applicationInfo.icon);
+                CharSequence assistLabel =
+                        mContext.getString(R.string.keyboard_shortcut_group_applications_assist);
+                KeyboardShortcutInfo assistShortcutInfo = new KeyboardShortcutInfo(
+                        assistLabel,
+                        assistIcon,
+                        KeyEvent.KEYCODE_A,
+                        KeyEvent.META_META_ON);
+                shortcutMultiMappingInfos.add(
+                        new ShortcutMultiMappingInfo(
+                                assistLabel,
+                                assistIcon,
+                                Arrays.asList(new ShortcutKeyGroup(assistShortcutInfo, null))));
+            }
+        }
+
+        // Browser (Chrome as default): Meta + B
+        // Contacts: Meta + C
+        // Email (Gmail as default): Meta + E
+        // Gmail: Meta + G
+        // Calendar: Meta + K
+        // Maps: Meta + M
+        // Music: Meta + P
+        // SMS: Meta + S
+        // Calculator: Meta + U
+        for (int i = 0; i < shortcutLabels.length; i++) {
+            final Icon icon = getIconForIntentCategory(intentCategories[i], userId);
+            if (icon != null) {
+                CharSequence label =
+                        shortcutLabels[i];
+                KeyboardShortcutInfo keyboardShortcutInfo = new KeyboardShortcutInfo(
+                        label,
+                        icon,
+                        keyCodes[i],
+                        KeyEvent.META_META_ON);
+                List<ShortcutKeyGroup> shortcutKeyGroups =
+                        Arrays.asList(new ShortcutKeyGroup(keyboardShortcutInfo, null));
+                shortcutMultiMappingInfos.add(
+                        new ShortcutMultiMappingInfo(label, icon, shortcutKeyGroups));
+            }
+        }
+
+        Comparator<ShortcutMultiMappingInfo> applicationItemsComparator =
+                new Comparator<ShortcutMultiMappingInfo>() {
+                    @Override
+                    public int compare(
+                            ShortcutMultiMappingInfo ksh1, ShortcutMultiMappingInfo ksh2) {
+                        boolean ksh1ShouldBeLast = ksh1.getLabel() == null
+                                || ksh1.getLabel().toString().isEmpty();
+                        boolean ksh2ShouldBeLast = ksh2.getLabel() == null
+                                || ksh2.getLabel().toString().isEmpty();
+                        if (ksh1ShouldBeLast && ksh2ShouldBeLast) {
+                            return 0;
+                        }
+                        if (ksh1ShouldBeLast) {
+                            return 1;
+                        }
+                        if (ksh2ShouldBeLast) {
+                            return -1;
+                        }
+                        return (ksh1.getLabel().toString()).compareToIgnoreCase(
+                                ksh2.getLabel().toString());
+                    }
+                };
+        // Sorts by label, case insensitive with nulls and/or empty labels last.
+        Collections.sort(shortcutMultiMappingInfos, applicationItemsComparator);
+        return new KeyboardShortcutMultiMappingGroup(categoryTitle, shortcutMultiMappingInfos);
+    }
+
+    private Icon getIconForIntentCategory(String intentCategory, int userId) {
+        final Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(intentCategory);
+
+        final PackageInfo packageInfo = getPackageInfoForIntent(intent, userId);
+        if (packageInfo != null && packageInfo.applicationInfo.icon != 0) {
+            return Icon.createWithResource(
+                    packageInfo.applicationInfo.packageName,
+                    packageInfo.applicationInfo.icon);
+        }
+        return null;
+    }
+
+    private PackageInfo getPackageInfoForIntent(Intent intent, int userId) {
+        try {
+            ResolveInfo handler;
+            handler = mPackageManager.resolveIntent(
+                    intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), 0, userId);
+            if (handler == null || handler.activityInfo == null) {
+                return null;
+            }
+            return mPackageManager.getPackageInfo(handler.activityInfo.packageName, 0, userId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "PackageManagerService is dead", e);
+            return null;
+        }
+    }
+
+    private void showKeyboardShortcutSearchList(
+            List<List<KeyboardShortcutMultiMappingGroup>> keyboardShortcutMultiMappingGroupList) {
+        // Need to post on the main thread.
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                handleShowKeyboardShortcutSearchList(keyboardShortcutMultiMappingGroupList);
+            }
+        });
+    }
+
+    private void handleShowKeyboardShortcutSearchList(
+            List<List<KeyboardShortcutMultiMappingGroup>> keyboardShortcutMultiMappingGroupList) {
+        mQueryString = null;
+        LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
+        mKeyboardShortcutsBottomSheetDialog =
+                new BottomSheetDialog(mContext);
+        final View keyboardShortcutsView = inflater.inflate(
+                R.layout.keyboard_shortcuts_search_view, null);
+        mNoSearchResults = keyboardShortcutsView.findViewById(R.id.shortcut_search_no_result);
+        mKeyboardShortcutsBottomSheetDialog.setContentView(keyboardShortcutsView);
+        setButtonsDefaultStatus(keyboardShortcutsView);
+        populateKeyboardShortcutSearchList(
+                keyboardShortcutsView.findViewById(R.id.keyboard_shortcuts_container));
+
+        // Workaround for solve issue about dialog not full expanded when landscape.
+        FrameLayout bottomSheet = (FrameLayout)
+                mKeyboardShortcutsBottomSheetDialog.findViewById(
+                        com.google.android.material.R.id.design_bottom_sheet);
+        if (bottomSheet != null) {
+            bottomSheet.setBackgroundResource(android.R.color.transparent);
+        }
+
+        BottomSheetBehavior<FrameLayout> behavior = BottomSheetBehavior.from(bottomSheet);
+        behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
+        behavior.setSkipCollapsed(true);
+
+        mKeyboardShortcutsBottomSheetDialog.setCanceledOnTouchOutside(true);
+        Window keyboardShortcutsWindow = mKeyboardShortcutsBottomSheetDialog.getWindow();
+        keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG);
+        synchronized (sLock) {
+            // show KeyboardShortcutsBottomSheetDialog only if it has not been dismissed already
+            if (sInstance != null) {
+                mKeyboardShortcutsBottomSheetDialog.show();
+                setDialogScreenSize();
+                keyboardShortcutsView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+                    @Override
+                    public void onLayoutChange(View v, int left, int top, int right,
+                            int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
+                        setDialogScreenSize();
+                    }
+                });
+            }
+        }
+        mSearchEditText = keyboardShortcutsView.findViewById(R.id.keyboard_shortcuts_search);
+        mSearchEditText.addTextChangedListener(
+                new TextWatcher() {
+                    @Override
+                    public void afterTextChanged(Editable s) {
+                        mQueryString = s.toString();
+                        populateKeyboardShortcutSearchList(
+                                keyboardShortcutsView.findViewById(
+                                        R.id.keyboard_shortcuts_container));
+                    }
+
+                    @Override
+                    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+                        // Do nothing.
+                    }
+
+                    @Override
+                    public void onTextChanged(CharSequence s, int start, int before, int count) {
+                        // Do nothing.
+                    }
+                });
+        mEditTextCancel = keyboardShortcutsView.findViewById(R.id.keyboard_shortcuts_search_cancel);
+        mEditTextCancel.setOnClickListener(v -> mSearchEditText.setText(null));
+    }
+
+    private void populateKeyboardShortcutSearchList(LinearLayout keyboardShortcutsLayout) {
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        TextView shortcutsKeyView = (TextView) inflater.inflate(
+                R.layout.keyboard_shortcuts_key_view, keyboardShortcutsLayout, false);
+        shortcutsKeyView.measure(
+                View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+        final int shortcutKeyTextItemMinWidth = shortcutsKeyView.getMeasuredHeight();
+        // Needed to be able to scale the image items to the same height as the text items.
+        final int shortcutKeyIconItemHeightWidth = shortcutsKeyView.getMeasuredHeight()
+                - shortcutsKeyView.getPaddingTop()
+                - shortcutsKeyView.getPaddingBottom();
+        keyboardShortcutsLayout.removeAllViews();
+
+        // Search if user's input is contained in any shortcut groups.
+        if (mQueryString != null) {
+            for (int i = 0; i < mFullShortsGroup.size(); i++) {
+                mKeySearchResultMap.put(i, false);
+                for (KeyboardShortcutMultiMappingGroup group : mFullShortsGroup.get(i)) {
+                    for (ShortcutMultiMappingInfo info : group.getItems()) {
+                        String itemLabel = info.getLabel().toString();
+                        if (itemLabel.toUpperCase(Locale.getDefault()).contains(
+                                mQueryString.toUpperCase(Locale.getDefault()))) {
+                            mKeySearchResultMap.put(i, true);
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        // Set default color for the non-focus categories.
+        for (int i = 0; i < mKeySearchResultMap.size(); i++) {
+            if (mKeySearchResultMap.get(i)) {
+                mFullButtonList.get(i).setVisibility(View.VISIBLE);
+                setButtonFocusColor(i, false);
+            } else {
+                mFullButtonList.get(i).setVisibility(View.GONE);
+            }
+        }
+
+        // Move the focus to the suitable category.
+        if (mFullButtonList.get(mCurrentCategoryIndex).getVisibility() == View.GONE) {
+            for (int i = 0; i < mKeySearchResultMap.size(); i++) {
+                if (mKeySearchResultMap.get(i)) {
+                    setCurrentCategoryIndex(i);
+                    break;
+                }
+            }
+        }
+
+        // Set color for the current focus category
+        setButtonFocusColor(mCurrentCategoryIndex, true);
+
+        // Load shortcuts for current focus category.
+        List<KeyboardShortcutMultiMappingGroup> keyboardShortcutMultiMappingGroups =
+                mFullShortsGroup.get(mCurrentCategoryIndex);
+
+        int keyboardShortcutGroupsSize = keyboardShortcutMultiMappingGroups.size();
+        List<Boolean> groupSearchResult = new ArrayList<>();
+        for (int i = 0; i < keyboardShortcutGroupsSize; i++) {
+            View separator = inflater.inflate(
+                    R.layout.keyboard_shortcuts_category_short_separator,
+                    keyboardShortcutsLayout,
+                    false);
+
+            // If there are more than one category, add separators among categories.
+            if (i > 0) {
+                keyboardShortcutsLayout.addView(separator);
+            }
+
+            List<Boolean> itemSearchResult = new ArrayList<>();
+            KeyboardShortcutMultiMappingGroup categoryGroup =
+                    keyboardShortcutMultiMappingGroups.get(i);
+            TextView categoryTitle = (TextView) inflater.inflate(
+                    R.layout.keyboard_shortcuts_category_title, keyboardShortcutsLayout, false);
+            categoryTitle.setText(categoryGroup.getCategory());
+            keyboardShortcutsLayout.addView(categoryTitle);
+            LinearLayout shortcutContainer = (LinearLayout) inflater.inflate(
+                    R.layout.keyboard_shortcuts_container, keyboardShortcutsLayout, false);
+            final int itemsSize = categoryGroup.getItems().size();
+            for (int j = 0; j < itemsSize; j++) {
+                ShortcutMultiMappingInfo keyGroupInfo = categoryGroup.getItems().get(j);
+
+                if (mQueryString != null) {
+                    String shortcutLabel =
+                            keyGroupInfo.getLabel().toString().toUpperCase(Locale.getDefault());
+                    String queryString = mQueryString.toUpperCase(Locale.getDefault());
+                    if (!shortcutLabel.contains(queryString)) {
+                        itemSearchResult.add(j, false);
+                        continue;
+                    } else {
+                        itemSearchResult.add(j, true);
+                    }
+                }
+
+                View shortcutView = inflater.inflate(R.layout.keyboard_shortcut_app_item,
+                        shortcutContainer, false);
+                TextView shortcutKeyword =
+                        shortcutView.findViewById(R.id.keyboard_shortcuts_keyword);
+                shortcutKeyword.setText(keyGroupInfo.getLabel());
+
+                if (keyGroupInfo.getIcon() != null) {
+                    ImageView shortcutIcon =
+                            shortcutView.findViewById(R.id.keyboard_shortcuts_icon);
+                    shortcutIcon.setImageIcon(keyGroupInfo.getIcon());
+                    shortcutIcon.setVisibility(View.VISIBLE);
+                    RelativeLayout.LayoutParams lp =
+                            (RelativeLayout.LayoutParams) shortcutKeyword.getLayoutParams();
+                    lp.removeRule(RelativeLayout.ALIGN_PARENT_START);
+                    shortcutKeyword.setLayoutParams(lp);
+                }
+
+                ViewGroup shortcutItemsContainer =
+                        shortcutView.findViewById(R.id.keyboard_shortcuts_item_container);
+                final int keyGroupItemsSize = keyGroupInfo.getShortcutKeyGroups().size();
+                for (int p = 0; p < keyGroupItemsSize; p++) {
+                    KeyboardShortcutInfo keyboardShortcutInfo =
+                            keyGroupInfo.getShortcutKeyGroups().get(p).getKeyboardShortcutInfo();
+                    String complexCommand =
+                            keyGroupInfo.getShortcutKeyGroups().get(p).getComplexCommand();
+
+                    if (complexCommand == null) {
+                        List<StringDrawableContainer> shortcutKeys =
+                                getHumanReadableShortcutKeys(keyboardShortcutInfo);
+                        if (shortcutKeys == null) {
+                            // Ignore shortcuts we can't display keys for.
+                            Log.w(TAG, "Keyboard Shortcut contains unsupported keys, skipping.");
+                            continue;
+                        }
+                        final int shortcutKeysSize = shortcutKeys.size();
+                        for (int k = 0; k < shortcutKeysSize; k++) {
+                            StringDrawableContainer shortcutRepresentation = shortcutKeys.get(k);
+                            if (shortcutRepresentation.mDrawable != null) {
+                                ImageView shortcutKeyIconView = (ImageView) inflater.inflate(
+                                        R.layout.keyboard_shortcuts_key_new_icon_view,
+                                        shortcutItemsContainer,
+                                        false);
+                                Bitmap bitmap = Bitmap.createBitmap(shortcutKeyIconItemHeightWidth,
+                                        shortcutKeyIconItemHeightWidth, Bitmap.Config.ARGB_8888);
+                                Canvas canvas = new Canvas(bitmap);
+                                shortcutRepresentation.mDrawable.setBounds(0, 0, canvas.getWidth(),
+                                        canvas.getHeight());
+                                shortcutRepresentation.mDrawable.draw(canvas);
+                                shortcutKeyIconView.setImageBitmap(bitmap);
+                                shortcutKeyIconView.setImportantForAccessibility(
+                                        IMPORTANT_FOR_ACCESSIBILITY_YES);
+                                shortcutKeyIconView.setAccessibilityDelegate(
+                                        new ShortcutKeyAccessibilityDelegate(
+                                                shortcutRepresentation.mString));
+                                shortcutItemsContainer.addView(shortcutKeyIconView);
+                            } else if (shortcutRepresentation.mString != null) {
+                                TextView shortcutKeyTextView = (TextView) inflater.inflate(
+                                        R.layout.keyboard_shortcuts_key_new_view,
+                                        shortcutItemsContainer,
+                                        false);
+                                shortcutKeyTextView.setMinimumWidth(shortcutKeyTextItemMinWidth);
+                                shortcutKeyTextView.setText(shortcutRepresentation.mString);
+                                shortcutKeyTextView.setAccessibilityDelegate(
+                                        new ShortcutKeyAccessibilityDelegate(
+                                                shortcutRepresentation.mString));
+                                shortcutItemsContainer.addView(shortcutKeyTextView);
+                            }
+
+                            if (k < shortcutKeysSize - 1) {
+                                TextView shortcutKeyTextView = (TextView) inflater.inflate(
+                                        R.layout.keyboard_shortcuts_key_plus_view,
+                                        shortcutItemsContainer,
+                                        false);
+                                shortcutItemsContainer.addView(shortcutKeyTextView);
+                            }
+                        }
+                    } else {
+                        TextView shortcutKeyTextView = (TextView) inflater.inflate(
+                                R.layout.keyboard_shortcuts_key_new_view,
+                                shortcutItemsContainer,
+                                false);
+                        shortcutKeyTextView.setMinimumWidth(shortcutKeyTextItemMinWidth);
+                        shortcutKeyTextView.setText(complexCommand);
+                        shortcutKeyTextView.setAccessibilityDelegate(
+                                new ShortcutKeyAccessibilityDelegate(complexCommand));
+                        shortcutItemsContainer.addView(shortcutKeyTextView);
+                    }
+
+                    if (p < keyGroupItemsSize - 1) {
+                        TextView shortcutKeyTextView = (TextView) inflater.inflate(
+                                R.layout.keyboard_shortcuts_key_vertical_bar_view,
+                                shortcutItemsContainer,
+                                false);
+                        shortcutItemsContainer.addView(shortcutKeyTextView);
+                    }
+                }
+                shortcutContainer.addView(shortcutView);
+            }
+
+            if (!groupSearchResult.isEmpty() && !groupSearchResult.get(i - 1)) {
+                keyboardShortcutsLayout.removeView(separator);
+            }
+
+            if (!itemSearchResult.isEmpty() && !itemSearchResult.contains(true)) {
+                // No results, so remove the category title and separator
+                keyboardShortcutsLayout.removeView(categoryTitle);
+                keyboardShortcutsLayout.removeView(separator);
+                groupSearchResult.add(false);
+                if (i == keyboardShortcutGroupsSize - 1 && !groupSearchResult.contains(true)) {
+                    // show "No shortcut found"
+                    mNoSearchResults.setVisibility(View.VISIBLE);
+                }
+                continue;
+            }
+            groupSearchResult.add(true);
+            mNoSearchResults.setVisibility(View.GONE);
+            keyboardShortcutsLayout.addView(shortcutContainer);
+        }
+    }
+
+    private List<StringDrawableContainer> getHumanReadableShortcutKeys(KeyboardShortcutInfo info) {
+        List<StringDrawableContainer> shortcutKeys = getHumanReadableModifiers(info);
+        if (shortcutKeys == null) {
+            return null;
+        }
+        String shortcutKeyString = null;
+        Drawable shortcutKeyDrawable = null;
+        if (info.getBaseCharacter() > Character.MIN_VALUE) {
+            shortcutKeyString = String.valueOf(info.getBaseCharacter());
+        } else if (mSpecialCharacterDrawables.get(info.getKeycode()) != null) {
+            shortcutKeyDrawable = mSpecialCharacterDrawables.get(info.getKeycode());
+            shortcutKeyString = mSpecialCharacterNames.get(info.getKeycode());
+        } else if (mSpecialCharacterNames.get(info.getKeycode()) != null) {
+            shortcutKeyString = mSpecialCharacterNames.get(info.getKeycode());
+        } else {
+            // Special case for shortcuts with no base key or keycode.
+            if (info.getKeycode() == KeyEvent.KEYCODE_UNKNOWN) {
+                return shortcutKeys;
+            }
+            char displayLabel = mKeyCharacterMap.getDisplayLabel(info.getKeycode());
+            if (displayLabel != 0) {
+                shortcutKeyString = String.valueOf(displayLabel);
+            } else {
+                displayLabel = mBackupKeyCharacterMap.getDisplayLabel(info.getKeycode());
+                if (displayLabel != 0) {
+                    shortcutKeyString = String.valueOf(displayLabel);
+                } else {
+                    return null;
+                }
+            }
+        }
+
+        if (shortcutKeyString != null) {
+            shortcutKeys.add(new StringDrawableContainer(shortcutKeyString, shortcutKeyDrawable));
+        } else {
+            Log.w(TAG, "Keyboard Shortcut does not have a text representation, skipping.");
+        }
+
+        return shortcutKeys;
+    }
+
+    private List<StringDrawableContainer> getHumanReadableModifiers(KeyboardShortcutInfo info) {
+        final List<StringDrawableContainer> shortcutKeys = new ArrayList<>();
+        int modifiers = info.getModifiers();
+        if (modifiers == 0) {
+            return shortcutKeys;
+        }
+        for (int supportedModifier : mModifierList) {
+            if ((modifiers & supportedModifier) != 0) {
+                shortcutKeys.add(new StringDrawableContainer(
+                        mModifierNames.get(supportedModifier),
+                        mModifierDrawables.get(supportedModifier)));
+                modifiers &= ~supportedModifier;
+            }
+        }
+        if (modifiers != 0) {
+            // Remaining unsupported modifiers, don't show anything.
+            return null;
+        }
+        return shortcutKeys;
+    }
+
+    private final class ShortcutKeyAccessibilityDelegate extends AccessibilityDelegate {
+        private String mContentDescription;
+
+        ShortcutKeyAccessibilityDelegate(String contentDescription) {
+            mContentDescription = contentDescription;
+        }
+
+        @Override
+        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+            super.onInitializeAccessibilityNodeInfo(host, info);
+            if (mContentDescription != null) {
+                info.setContentDescription(mContentDescription.toLowerCase(Locale.getDefault()));
+            }
+        }
+    }
+
+    private static final class StringDrawableContainer {
+        @NonNull
+        public String mString;
+        @Nullable
+        public Drawable mDrawable;
+
+        StringDrawableContainer(String string, Drawable drawable) {
+            mString = string;
+            mDrawable = drawable;
+        }
+    }
+
+    private void setDialogScreenSize() {
+        Window window = mKeyboardShortcutsBottomSheetDialog.getWindow();
+        Display display = mWindowManager.getDefaultDisplay();
+        WindowManager.LayoutParams lp =
+                mKeyboardShortcutsBottomSheetDialog.getWindow().getAttributes();
+        if (mContext.getResources().getConfiguration().orientation
+                == Configuration.ORIENTATION_PORTRAIT) {
+            lp.width = (int) (display.getWidth() * 0.8);
+            lp.height = (int) (display.getHeight() * 0.7);
+        } else {
+            lp.width = (int) (display.getWidth() * 0.7);
+            lp.height = (int) (display.getHeight() * 0.8);
+        }
+        window.setGravity(Gravity.BOTTOM);
+        window.setAttributes(lp);
+    }
+
+    private void setCurrentCategoryIndex(int index) {
+        mCurrentCategoryIndex = index;
+    }
+
+    private void setButtonsDefaultStatus(View keyboardShortcutsView) {
+        mButtonSystem = keyboardShortcutsView.findViewById(R.id.shortcut_system);
+        mButtonInput = keyboardShortcutsView.findViewById(R.id.shortcut_input);
+        mButtonOpenApps = keyboardShortcutsView.findViewById(R.id.shortcut_open_apps);
+        mButtonSpecificApp = keyboardShortcutsView.findViewById(R.id.shortcut_specific_app);
+
+        mButtonSystem.setOnClickListener(v -> {
+            setCurrentCategoryIndex(SHORTCUT_SYSTEM_INDEX);
+            populateKeyboardShortcutSearchList(keyboardShortcutsView.findViewById(
+                    R.id.keyboard_shortcuts_container));
+        });
+
+        mButtonInput.setOnClickListener(v -> {
+            setCurrentCategoryIndex(SHORTCUT_INPUT_INDEX);
+            populateKeyboardShortcutSearchList(keyboardShortcutsView.findViewById(
+                    R.id.keyboard_shortcuts_container));
+        });
+
+        mButtonOpenApps.setOnClickListener(v -> {
+            setCurrentCategoryIndex(SHORTCUT_OPENAPPS_INDEX);
+            populateKeyboardShortcutSearchList(keyboardShortcutsView.findViewById(
+                    R.id.keyboard_shortcuts_container));
+        });
+
+        mButtonSpecificApp.setOnClickListener(v -> {
+            setCurrentCategoryIndex(SHORTCUT_SPECIFICAPP_INDEX);
+            populateKeyboardShortcutSearchList(keyboardShortcutsView.findViewById(
+                    R.id.keyboard_shortcuts_container));
+        });
+
+        mFullButtonList.add(mButtonSystem);
+        mFullButtonList.add(mButtonInput);
+        mFullButtonList.add(mButtonOpenApps);
+        mFullButtonList.add(mButtonSpecificApp);
+    }
+
+    private void setButtonFocusColor(int i, boolean isFocused) {
+        if (isFocused) {
+            mFullButtonList.get(i).setTextColor(getColorOfTextColorOnAccent());
+            mFullButtonList.get(i).setBackground(
+                    mContext.getDrawable(R.drawable.shortcut_button_focus_colored));
+        } else {
+            // Default color
+            mFullButtonList.get(i).setTextColor(getColorOfTextColorSecondary());
+            mFullButtonList.get(i).setBackground(
+                    mContext.getDrawable(R.drawable.shortcut_button_colored));
+        }
+    }
+
+    private int getColorOfTextColorOnAccent() {
+        return Utils.getColorAttrDefaultColor(
+                mContext, com.android.internal.R.attr.textColorOnAccent);
+    }
+
+    private int getColorOfTextColorSecondary() {
+        return Utils.getColorAttrDefaultColor(
+                mContext, com.android.internal.R.attr.textColorSecondary);
+    }
+
+    // Create the new data structure for handling the N-to-1 key mapping and other complex case.
+    private static class KeyboardShortcutMultiMappingGroup {
+        private final CharSequence mCategory;
+        private List<ShortcutMultiMappingInfo> mItems;
+
+        KeyboardShortcutMultiMappingGroup(
+                CharSequence category, List<ShortcutMultiMappingInfo> items) {
+            mCategory = category;
+            mItems = items;
+        }
+
+        void addItem(ShortcutMultiMappingInfo item) {
+            mItems.add(item);
+        }
+
+        CharSequence getCategory() {
+            return mCategory;
+        }
+
+        List<ShortcutMultiMappingInfo> getItems() {
+            return mItems;
+        }
+    }
+
+    private static class ShortcutMultiMappingInfo {
+        private final CharSequence mLabel;
+        private final Icon mIcon;
+        private List<ShortcutKeyGroup> mShortcutKeyGroups;
+
+        ShortcutMultiMappingInfo(
+                CharSequence label, Icon icon, List<ShortcutKeyGroup> shortcutKeyGroups) {
+            mLabel = label;
+            mIcon = icon;
+            mShortcutKeyGroups = shortcutKeyGroups;
+        }
+
+        ShortcutMultiMappingInfo(KeyboardShortcutInfo info) {
+            mLabel = info.getLabel();
+            mIcon = info.getIcon();
+            mShortcutKeyGroups = Arrays.asList(new ShortcutKeyGroup(info, null));
+        }
+
+        CharSequence getLabel() {
+            return mLabel;
+        }
+
+        Icon getIcon() {
+            return mIcon;
+        }
+
+        List<ShortcutKeyGroup> getShortcutKeyGroups() {
+            return mShortcutKeyGroups;
+        }
+    }
+
+    private static class ShortcutKeyGroup {
+        private final KeyboardShortcutInfo mKeyboardShortcutInfo;
+        private final String mComplexCommand;
+
+        ShortcutKeyGroup(KeyboardShortcutInfo keyboardShortcutInfo, String complexCommand) {
+            mKeyboardShortcutInfo = keyboardShortcutInfo;
+            mComplexCommand = complexCommand;
+        }
+
+        // To be compatible with the original functions, keep KeyboardShortcutInfo in here.
+        KeyboardShortcutInfo getKeyboardShortcutInfo() {
+            return mKeyboardShortcutInfo;
+        }
+
+        // In some case, the shortcut is a complex description not a N-to-1 key mapping.
+        String getComplexCommand() {
+            return mComplexCommand;
+        }
+    }
+
+    private static PackageInfo getAssistPackageInfo(
+            Context context, IPackageManager packageManager, int userId) {
+        AssistUtils assistUtils = new AssistUtils(context);
+        ComponentName assistComponent = assistUtils.getAssistComponentForUser(userId);
+        // Not all devices have an assist component.
+        PackageInfo assistPackageInfo = null;
+        if (assistComponent != null) {
+            try {
+                assistPackageInfo = packageManager.getPackageInfo(
+                        assistComponent.getPackageName(), 0, userId);
+            } catch (RemoteException e) {
+                Log.e(TAG, "PackageManagerService is dead");
+            }
+        }
+        return assistPackageInfo;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 7e6ddcf..f20f929 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -63,6 +63,7 @@
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.AssistUtils;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
@@ -80,7 +81,8 @@
 public final class KeyboardShortcuts {
     private static final String TAG = KeyboardShortcuts.class.getSimpleName();
     private static final Object sLock = new Object();
-    private static KeyboardShortcuts sInstance;
+    @VisibleForTesting static KeyboardShortcuts sInstance;
+    private WindowManager mWindowManager;
 
     private final SparseArray<String> mSpecialCharacterNames = new SparseArray<>();
     private final SparseArray<String> mModifierNames = new SparseArray<>();
@@ -94,7 +96,7 @@
     };
 
     private final Handler mHandler = new Handler(Looper.getMainLooper());
-    private final Context mContext;
+    @VisibleForTesting Context mContext;
     private final IPackageManager mPackageManager;
     private final OnClickListener mDialogCloseListener = new DialogInterface.OnClickListener() {
         public void onClick(DialogInterface dialog, int id) {
@@ -123,20 +125,26 @@
                 }
             };
 
-    private Dialog mKeyboardShortcutsDialog;
+    @VisibleForTesting Dialog mKeyboardShortcutsDialog;
     private KeyCharacterMap mKeyCharacterMap;
     private KeyCharacterMap mBackupKeyCharacterMap;
 
-    private KeyboardShortcuts(Context context) {
+    @VisibleForTesting
+    KeyboardShortcuts(Context context, WindowManager windowManager) {
         this.mContext = new ContextThemeWrapper(
                 context, android.R.style.Theme_DeviceDefault_Settings);
         this.mPackageManager = AppGlobals.getPackageManager();
+        if (windowManager != null) {
+            this.mWindowManager = windowManager;
+        } else {
+            this.mWindowManager = mContext.getSystemService(WindowManager.class);
+        }
         loadResources(context);
     }
 
     private static KeyboardShortcuts getInstance(Context context) {
         if (sInstance == null) {
-            sInstance = new KeyboardShortcuts(context);
+            sInstance = new KeyboardShortcuts(context, null);
         }
         return sInstance;
     }
@@ -371,10 +379,10 @@
         mKeyCharacterMap = mBackupKeyCharacterMap;
     }
 
-    private void showKeyboardShortcuts(int deviceId) {
+    @VisibleForTesting
+    void showKeyboardShortcuts(int deviceId) {
         retrieveKeyCharacterMap(deviceId);
-        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
-        wm.requestAppKeyboardShortcuts(new KeyboardShortcutsReceiver() {
+        mWindowManager.requestAppKeyboardShortcuts(new KeyboardShortcutsReceiver() {
             @Override
             public void onKeyboardShortcutsReceived(
                     final List<KeyboardShortcutGroup> result) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
index 8a5bece..e9fac28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
@@ -19,16 +19,38 @@
 import android.content.Context;
 import android.content.Intent;
 
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
+import com.android.systemui.shared.recents.utilities.Utilities;
+
+import javax.inject.Inject;
+
 /**
  * Receiver for the Keyboard Shortcuts Helper.
  */
 public class KeyboardShortcutsReceiver extends BroadcastReceiver {
+
+    private boolean mIsShortcutListSearchEnabled;
+
+    @Inject
+    public KeyboardShortcutsReceiver(FeatureFlags featureFlags) {
+        mIsShortcutListSearchEnabled = featureFlags.isEnabled(Flags.SHORTCUT_LIST_SEARCH_LAYOUT);
+    }
+
     @Override
     public void onReceive(Context context, Intent intent) {
-        if (Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
-            KeyboardShortcuts.show(context, -1 /* deviceId unknown */);
-        } else if (Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
-            KeyboardShortcuts.dismiss();
+        if (mIsShortcutListSearchEnabled && Utilities.isTablet(context)) {
+            if (Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
+                KeyboardShortcutListSearch.show(context, -1 /* deviceId unknown */);
+            } else if (Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
+                KeyboardShortcutListSearch.dismiss();
+            }
+        } else {
+            if (Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
+                KeyboardShortcuts.show(context, -1 /* deviceId unknown */);
+            } else if (Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
+                KeyboardShortcuts.dismiss();
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 250900e..d3927a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -185,6 +185,7 @@
     private boolean mPowerCharged;
     private boolean mBatteryOverheated;
     private boolean mEnableBatteryDefender;
+    private boolean mIncompatibleCharger;
     private int mChargingSpeed;
     private int mChargingWattage;
     private int mBatteryLevel;
@@ -903,6 +904,10 @@
             chargingId = R.string.keyguard_plugged_in_charging_limited;
             String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f);
             return mContext.getResources().getString(chargingId, percentage);
+        } else if (mPowerPluggedIn && mIncompatibleCharger) {
+            chargingId = R.string.keyguard_plugged_in_incompatible_charger;
+            String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f);
+            return mContext.getResources().getString(chargingId, percentage);
         } else if (mPowerCharged) {
             return mContext.getResources().getString(R.string.keyguard_charged);
         }
@@ -1063,6 +1068,7 @@
             mBatteryPresent = status.present;
             mBatteryOverheated = status.isOverheated();
             mEnableBatteryDefender = mBatteryOverheated && status.isPluggedIn();
+            mIncompatibleCharger = status.incompatibleCharger.orElse(false);
             try {
                 mChargingTimeRemaining = mPowerPluggedIn
                         ? mBatteryInfo.computeChargeTimeRemaining() : -1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 1966a66..6a52a33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -186,11 +186,13 @@
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.shade.ShadeExpansionChangeEvent;
 import com.android.systemui.shade.ShadeExpansionStateManager;
+import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.statusbar.AutoHideUiElement;
 import com.android.systemui.statusbar.BackDropView;
 import com.android.systemui.statusbar.CircleReveal;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.KeyboardShortcutListSearch;
 import com.android.systemui.statusbar.KeyboardShortcuts;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.LiftReveal;
@@ -299,6 +301,7 @@
     private CentralSurfacesCommandQueueCallbacks mCommandQueueCallbacks;
     private float mTransitionToFullShadeProgress = 0f;
     private NotificationListContainer mNotifListContainer;
+    private boolean mIsShortcutListSearchEnabled;
 
     private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
             new KeyguardStateController.Callback() {
@@ -833,6 +836,7 @@
         mCameraLauncherLazy = cameraLauncherLazy;
         mAlternateBouncerInteractor = alternateBouncerInteractor;
         mUserTracker = userTracker;
+        mIsShortcutListSearchEnabled = featureFlags.isEnabled(Flags.SHORTCUT_LIST_SEARCH_LAYOUT);
 
         mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
         mStartingSurfaceOptional = startingSurfaceOptional;
@@ -2546,7 +2550,11 @@
             String action = intent.getAction();
             String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
-                KeyboardShortcuts.dismiss();
+                if (mIsShortcutListSearchEnabled && Utilities.isTablet(mContext)) {
+                    KeyboardShortcutListSearch.dismiss();
+                } else {
+                    KeyboardShortcuts.dismiss();
+                }
                 mRemoteInputManager.closeRemoteInputs();
                 if (mLockscreenUserManager.isCurrentProfile(getSendingUserId())) {
                     int flags = CommandQueue.FLAG_EXCLUDE_NONE;
@@ -3893,11 +3901,19 @@
     }
 
     protected void toggleKeyboardShortcuts(int deviceId) {
-        KeyboardShortcuts.toggle(mContext, deviceId);
+        if (mIsShortcutListSearchEnabled && Utilities.isTablet(mContext)) {
+            KeyboardShortcutListSearch.toggle(mContext, deviceId);
+        } else {
+            KeyboardShortcuts.toggle(mContext, deviceId);
+        }
     }
 
     protected void dismissKeyboardShortcuts() {
-        KeyboardShortcuts.dismiss();
+        if (mIsShortcutListSearchEnabled && Utilities.isTablet(mContext)) {
+            KeyboardShortcutListSearch.dismiss();
+        } else {
+            KeyboardShortcuts.dismiss();
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
index 3f54aebf..dee4a6f 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
@@ -30,6 +30,9 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.shared.hardware.hasInputDevice
+import com.android.systemui.shared.hardware.isInternalStylusSource
+import com.android.systemui.statusbar.notification.collection.listbuilder.DEBUG
 import java.util.concurrent.CopyOnWriteArrayList
 import java.util.concurrent.Executor
 import javax.inject.Inject
@@ -59,8 +62,10 @@
         CopyOnWriteArrayList()
     // This map should only be accessed on the handler
     private val inputDeviceAddressMap: MutableMap<Int, String?> = ArrayMap()
-    // This variable should only be accessed on the handler
+
+    // These variables should only be accessed on the handler
     private var hasStarted: Boolean = false
+    private var isInUsiSession: Boolean = false
 
     /**
      * Starts listening to InputManager InputDevice events. Will also load the InputManager snapshot
@@ -70,6 +75,10 @@
         handler.post {
             if (hasStarted) return@post
             hasStarted = true
+            isInUsiSession =
+                inputManager.hasInputDevice {
+                    it.isInternalStylusSource && isBatteryStateValid(it.batteryState)
+                }
             addExistingStylusToMap()
 
             inputManager.registerInputDeviceListener(this, handler)
@@ -177,7 +186,18 @@
         handler.post {
             if (!hasStarted) return@post
 
-            if (batteryState.isPresent) {
+            if (DEBUG) {
+                Log.d(
+                    TAG,
+                    "onBatteryStateChanged for $deviceId. " +
+                        "batteryState present: ${batteryState.isPresent}, " +
+                        "capacity: ${batteryState.capacity}"
+                )
+            }
+
+            val batteryStateValid = isBatteryStateValid(batteryState)
+            trackAndLogUsiSession(deviceId, batteryStateValid)
+            if (batteryStateValid) {
                 onStylusUsed()
             }
 
@@ -221,6 +241,37 @@
         executeStylusCallbacks { cb -> cb.onStylusFirstUsed() }
     }
 
+    /**
+     * Uses the input device battery state to track whether a current USI session is active. The
+     * InputDevice battery state updates USI battery on USI stylus input, and removes the last-known
+     * USI stylus battery presence after 1 hour of not detecting input. As SysUI and StylusManager
+     * is persistently running, relies on tracking sessions via an in-memory isInUsiSession boolean.
+     */
+    private fun trackAndLogUsiSession(deviceId: Int, batteryStateValid: Boolean) {
+        // TODO(b/268618918) handle cases where an invalid battery callback from a previous stylus
+        //  is sent after the actual valid callback
+        if (batteryStateValid && !isInUsiSession) {
+            if (DEBUG) {
+                Log.d(
+                    TAG,
+                    "USI battery newly present, entering new USI session. Device ID: $deviceId"
+                )
+            }
+            isInUsiSession = true
+            uiEventLogger.log(StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_FIRST_DETECTED)
+        } else if (!batteryStateValid && isInUsiSession) {
+            if (DEBUG) {
+                Log.d(TAG, "USI battery newly absent, exiting USI session Device ID: $deviceId")
+            }
+            isInUsiSession = false
+            uiEventLogger.log(StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_REMOVED)
+        }
+    }
+
+    private fun isBatteryStateValid(batteryState: BatteryState): Boolean {
+        return batteryState.isPresent && batteryState.capacity > 0.0f
+    }
+
     private fun executeStylusCallbacks(run: (cb: StylusCallback) -> Unit) {
         stylusCallbacks.forEach(run)
     }
@@ -295,5 +346,6 @@
 
     companion object {
         private val TAG = StylusManager::class.simpleName.orEmpty()
+        private val DEBUG = false
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusUiEvent.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusUiEvent.kt
index 99da4ce..e77749b 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusUiEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusUiEvent.kt
@@ -31,7 +31,11 @@
     @UiEvent(doc = "UIEvent for Toast shown when stylus stopped charging")
     STYLUS_STOPPED_CHARGING(1303),
     @UiEvent(doc = "UIEvent for bluetooth stylus connected") BLUETOOTH_STYLUS_CONNECTED(1304),
-    @UiEvent(doc = "UIEvent for bluetooth stylus disconnected") BLUETOOTH_STYLUS_DISCONNECTED(1305);
+    @UiEvent(doc = "UIEvent for bluetooth stylus disconnected") BLUETOOTH_STYLUS_DISCONNECTED(1305),
+    @UiEvent(doc = "UIEvent for start of a USI session via battery presence")
+    USI_STYLUS_BATTERY_PRESENCE_FIRST_DETECTED(1306),
+    @UiEvent(doc = "UIEvent for end of a USI session via battery absence")
+    USI_STYLUS_BATTERY_PRESENCE_REMOVED(1307);
 
     override fun getId() = _id
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 4110b5a..841ec4b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -85,8 +85,12 @@
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.FingerprintSensorProperties;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbPort;
+import android.hardware.usb.UsbPortStatus;
 import android.net.Uri;
 import android.nfc.NfcAdapter;
+import android.os.BatteryManager;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.Handler;
@@ -117,6 +121,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor.BiometricAuthenticated;
 import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
+import com.android.settingslib.fuelgauge.BatteryStatus;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider;
@@ -238,9 +243,16 @@
     private UiEventLogger mUiEventLogger;
     @Mock
     private GlobalSettings mGlobalSettings;
-    private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig;
     @Mock
     private FingerprintInteractiveToAuthProvider mInteractiveToAuthProvider;
+    @Mock
+    private UsbPort mUsbPort;
+    @Mock
+    private UsbManager mUsbManager;
+    @Mock
+    private UsbPortStatus mUsbPortStatus;
+    @Mock
+    private Uri mURI;
 
     private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties;
     private final int mCurrentUserId = 100;
@@ -252,9 +264,6 @@
     @Captor
     private ArgumentCaptor<FaceManager.AuthenticationCallback> mAuthenticationCallbackCaptor;
 
-    @Mock
-    private Uri mURI;
-
     // Direct executor
     private final Executor mBackgroundExecutor = Runnable::run;
     private final Executor mMainExecutor = Runnable::run;
@@ -264,6 +273,7 @@
     private MockitoSession mMockitoSession;
     private StatusBarStateController.StateListener mStatusBarStateListener;
     private IBiometricEnabledOnKeyguardCallback mBiometricEnabledOnKeyguardCallback;
+    private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig;
     private final InstanceId mKeyguardInstanceId = InstanceId.fakeInstanceId(999);
 
     @Before
@@ -2373,6 +2383,55 @@
         assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
     }
 
+    @Test
+    public void testBatteryChangedIntent_refreshBatteryInfo() {
+        mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(mContext, getBatteryIntent());
+
+        BatteryStatus status = verifyRefreshBatteryInfo();
+        assertThat(status.incompatibleCharger.get()).isFalse();
+        assertThat(mKeyguardUpdateMonitor.mIncompatibleCharger).isFalse();
+    }
+
+    @Test
+    public void testUsbComplianceIntent_refreshBatteryInfo() {
+        Context contextSpy = getSpyContext();
+        when(contextSpy.registerReceiver(eq(null), any(IntentFilter.class)))
+                .thenReturn(getBatteryIntent());
+
+        mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(
+                contextSpy, new Intent(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED));
+
+        mTestableLooper.processAllMessages();
+        assertThat(mKeyguardUpdateMonitor.mIncompatibleCharger).isFalse();
+    }
+
+    @Test
+    public void testUsbComplianceIntent_refreshBatteryInfoWithIncompatibleCharger() {
+        Context contextSpy = getSpyContext();
+        setupIncompatibleCharging();
+        when(contextSpy.registerReceiver(eq(null), any(IntentFilter.class)))
+                .thenReturn(getBatteryIntent());
+
+        mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(
+                contextSpy, new Intent(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED));
+
+        mTestableLooper.processAllMessages();
+        assertThat(mKeyguardUpdateMonitor.mIncompatibleCharger).isTrue();
+    }
+
+    @Test
+    public void testBatteryChangedIntent_unplugDevice_resetIncompatibleCharger() {
+        mKeyguardUpdateMonitor.mIncompatibleCharger = true;
+        Intent batteryChangedIntent =
+                getBatteryIntent().putExtra(BatteryManager.EXTRA_PLUGGED, -1);
+
+        mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(mContext, batteryChangedIntent);
+
+        BatteryStatus status = verifyRefreshBatteryInfo();
+        assertThat(status.incompatibleCharger.get()).isFalse();
+        assertThat(mKeyguardUpdateMonitor.mIncompatibleCharger).isFalse();
+    }
+
     private void userDeviceLockDown() {
         when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
         when(mStrongAuthTracker.getStrongAuthForUser(mCurrentUserId))
@@ -2592,6 +2651,37 @@
         return intent;
     }
 
+    private BatteryStatus verifyRefreshBatteryInfo() {
+        mTestableLooper.processAllMessages();
+        ArgumentCaptor<BatteryStatus> captor = ArgumentCaptor.forClass(BatteryStatus.class);
+        verify(mTestCallback, atLeastOnce()).onRefreshBatteryInfo(captor.capture());
+        List<BatteryStatus> batteryStatusList = captor.getAllValues();
+        return batteryStatusList.get(batteryStatusList.size() - 1);
+    }
+
+    private void setupIncompatibleCharging() {
+        final List<UsbPort> usbPorts = new ArrayList<>();
+        usbPorts.add(mUsbPort);
+        when(mUsbManager.getPorts()).thenReturn(usbPorts);
+        when(mUsbPort.getStatus()).thenReturn(mUsbPortStatus);
+        when(mUsbPort.supportsComplianceWarnings()).thenReturn(true);
+        when(mUsbPortStatus.isConnected()).thenReturn(true);
+        when(mUsbPortStatus.getComplianceWarnings()).thenReturn(new int[]{1});
+    }
+
+    private Context getSpyContext() {
+        Context contextSpy = spy(mContext);
+        when(contextSpy.getSystemService(UsbManager.class)).thenReturn(mUsbManager);
+        when(contextSpy.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)))
+                .thenReturn(new Intent(Intent.ACTION_BATTERY_CHANGED));
+        return contextSpy;
+    }
+
+    private Intent getBatteryIntent() {
+        return new Intent(Intent.ACTION_BATTERY_CHANGED).putExtra(
+                BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
+    }
+
     private class TestableKeyguardUpdateMonitor extends KeyguardUpdateMonitor {
         AtomicBoolean mSimStateChanged = new AtomicBoolean(false);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
new file mode 100644
index 0000000..777dd4e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.accessibility.fontscaling
+
+import android.os.Handler
+import android.provider.Settings
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.widget.ImageView
+import android.widget.SeekBar
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
+import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.util.settings.SystemSettings
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests for [FontScalingDialog]. */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class FontScalingDialogTest : SysuiTestCase() {
+    private lateinit var fontScalingDialog: FontScalingDialog
+    private lateinit var systemSettings: SystemSettings
+    private val fontSizeValueArray: Array<String> =
+        mContext
+            .getResources()
+            .getStringArray(com.android.settingslib.R.array.entryvalues_font_size)
+
+    @Before
+    fun setUp() {
+        val mainHandler = Handler(TestableLooper.get(this).getLooper())
+        systemSettings = FakeSettings()
+        fontScalingDialog = FontScalingDialog(mContext, systemSettings as FakeSettings)
+    }
+
+    @Test
+    fun showTheDialog_seekbarIsShowingCorrectProgress() {
+        fontScalingDialog.show()
+
+        val seekBar: SeekBar = fontScalingDialog.findViewById<SeekBar>(R.id.seekbar)!!
+        val progress: Int = seekBar.getProgress()
+        val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def = */ 1.0f)
+
+        assertThat(currentScale).isEqualTo(fontSizeValueArray[progress].toFloat())
+
+        fontScalingDialog.dismiss()
+    }
+
+    @Test
+    fun progressIsZero_clickIconEnd_seekBarProgressIncreaseOne_fontSizeScaled() {
+        fontScalingDialog.show()
+
+        val iconEnd: ImageView = fontScalingDialog.findViewById(R.id.icon_end)!!
+        val seekBarWithIconButtonsView: SeekBarWithIconButtonsView =
+            fontScalingDialog.findViewById(R.id.font_scaling_slider)!!
+        val seekBar: SeekBar = fontScalingDialog.findViewById(R.id.seekbar)!!
+
+        seekBarWithIconButtonsView.setProgress(0)
+
+        iconEnd.performClick()
+
+        val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def = */ 1.0f)
+        assertThat(seekBar.getProgress()).isEqualTo(1)
+        assertThat(currentScale).isEqualTo(fontSizeValueArray[1].toFloat())
+
+        fontScalingDialog.dismiss()
+    }
+
+    @Test
+    fun progressIsMax_clickIconStart_seekBarProgressDecreaseOne_fontSizeScaled() {
+        fontScalingDialog.show()
+
+        val iconStart: ImageView = fontScalingDialog.findViewById(R.id.icon_start)!!
+        val seekBarWithIconButtonsView: SeekBarWithIconButtonsView =
+            fontScalingDialog.findViewById(R.id.font_scaling_slider)!!
+        val seekBar: SeekBar = fontScalingDialog.findViewById(R.id.seekbar)!!
+
+        seekBarWithIconButtonsView.setProgress(fontSizeValueArray.size - 1)
+
+        iconStart.performClick()
+
+        val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def = */ 1.0f)
+        assertThat(seekBar.getProgress()).isEqualTo(fontSizeValueArray.size - 2)
+        assertThat(currentScale)
+            .isEqualTo(fontSizeValueArray[fontSizeValueArray.size - 2].toFloat())
+
+        fontScalingDialog.dismiss()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/FontScalingTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/FontScalingTileTest.kt
new file mode 100644
index 0000000..57abae0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/FontScalingTileTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.qs.tiles.dialog
+
+import android.os.Handler
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.MetricsLogger
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.classifier.FalsingManagerFake
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.qs.QSTileHost
+import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.tiles.FontScalingTile
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class FontScalingTileTest : SysuiTestCase() {
+    @Mock private lateinit var qsHost: QSTileHost
+    @Mock private lateinit var metricsLogger: MetricsLogger
+    @Mock private lateinit var statusBarStateController: StatusBarStateController
+    @Mock private lateinit var activityStarter: ActivityStarter
+    @Mock private lateinit var qsLogger: QSLogger
+    @Mock private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
+
+    private lateinit var testableLooper: TestableLooper
+    private lateinit var fontScalingTile: FontScalingTile
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        testableLooper = TestableLooper.get(this)
+        `when`(qsHost.getContext()).thenReturn(mContext)
+        fontScalingTile =
+            FontScalingTile(
+                qsHost,
+                testableLooper.looper,
+                Handler(testableLooper.looper),
+                FalsingManagerFake(),
+                metricsLogger,
+                statusBarStateController,
+                activityStarter,
+                qsLogger,
+                dialogLaunchAnimator,
+                FakeSettings()
+            )
+        fontScalingTile.initialize()
+    }
+
+    @Test
+    fun isNotAvailable_whenNotSupportedDevice_returnsFalse() {
+        val isAvailable = fontScalingTile.isAvailable()
+
+        assertThat(isAvailable).isFalse()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java
new file mode 100644
index 0000000..109f185
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.systemui.SysuiTestCase;
+
+import com.google.android.material.bottomsheet.BottomSheetDialog;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyboardShortcutListSearchTest extends SysuiTestCase {
+
+    @Rule public MockitoRule mockito = MockitoJUnit.rule();
+
+    private static int DEVICE_ID = 1;
+    private KeyboardShortcutListSearch mKeyboardShortcutListSearch;
+
+    @Mock private BottomSheetDialog mBottomSheetDialog;
+    @Mock WindowManager mWindowManager;
+
+    @Before
+    public void setUp() {
+        mKeyboardShortcutListSearch = new KeyboardShortcutListSearch(mContext, mWindowManager);
+        mKeyboardShortcutListSearch.sInstance = mKeyboardShortcutListSearch;
+        mKeyboardShortcutListSearch.mKeyboardShortcutsBottomSheetDialog = mBottomSheetDialog;
+        mKeyboardShortcutListSearch.mContext = mContext;
+    }
+
+    @Test
+    public void toggle_isShowingTrue_instanceShouldBeNull() {
+        when(mBottomSheetDialog.isShowing()).thenReturn(true);
+
+        mKeyboardShortcutListSearch.toggle(mContext, DEVICE_ID);
+
+        assertThat(mKeyboardShortcutListSearch.sInstance).isNull();
+    }
+
+    @Test
+    public void toggle_isShowingFalse_showKeyboardShortcuts() {
+        when(mBottomSheetDialog.isShowing()).thenReturn(false);
+
+        mKeyboardShortcutListSearch.toggle(mContext, DEVICE_ID);
+
+        verify(mWindowManager).requestAppKeyboardShortcuts(any(), anyInt());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsReceiverTest.java
new file mode 100644
index 0000000..bea2cfb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsReceiverTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.flags.FakeFeatureFlags;
+import com.android.systemui.flags.Flags;
+import com.android.systemui.shared.recents.utilities.Utilities;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.quality.Strictness;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyboardShortcutsReceiverTest extends SysuiTestCase {
+
+    @Rule public MockitoRule mockito = MockitoJUnit.rule();
+
+    private KeyboardShortcutsReceiver mKeyboardShortcutsReceiver;
+    private Intent mIntent;
+    private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
+
+    @Mock private KeyboardShortcuts mKeyboardShortcuts;
+    @Mock private KeyboardShortcutListSearch mKeyboardShortcutListSearch;
+
+    @Before
+    public void setUp() {
+        mIntent = new Intent(Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS);
+        mKeyboardShortcuts.mContext = mContext;
+        mKeyboardShortcutListSearch.mContext = mContext;
+        KeyboardShortcuts.sInstance = mKeyboardShortcuts;
+        KeyboardShortcutListSearch.sInstance = mKeyboardShortcutListSearch;
+    }
+
+    @Test
+    public void onReceive_whenFlagOffDeviceIsTablet_showKeyboardShortcuts() {
+        MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+                .spyStatic(Utilities.class)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+        mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, false);
+        mKeyboardShortcutsReceiver = spy(new KeyboardShortcutsReceiver(mFeatureFlags));
+        when(Utilities.isTablet(mContext)).thenReturn(true);
+
+        mKeyboardShortcutsReceiver.onReceive(mContext, mIntent);
+
+        verify(mKeyboardShortcuts).showKeyboardShortcuts(anyInt());
+        verify(mKeyboardShortcutListSearch, never()).showKeyboardShortcuts(anyInt());
+        mockitoSession.finishMocking();
+    }
+
+    @Test
+    public void onReceive_whenFlagOffDeviceIsNotTablet_showKeyboardShortcuts() {
+        MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+                .spyStatic(Utilities.class)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+        mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, false);
+        mKeyboardShortcutsReceiver = spy(new KeyboardShortcutsReceiver(mFeatureFlags));
+        when(Utilities.isTablet(mContext)).thenReturn(false);
+
+        mKeyboardShortcutsReceiver.onReceive(mContext, mIntent);
+
+        verify(mKeyboardShortcuts).showKeyboardShortcuts(anyInt());
+        verify(mKeyboardShortcutListSearch, never()).showKeyboardShortcuts(anyInt());
+        mockitoSession.finishMocking();
+    }
+
+    @Test
+    public void onReceive_whenFlagOnDeviceIsTablet_showKeyboardShortcutListSearch() {
+        MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+                .spyStatic(Utilities.class)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+        mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, true);
+        mKeyboardShortcutsReceiver = spy(new KeyboardShortcutsReceiver(mFeatureFlags));
+        when(Utilities.isTablet(mContext)).thenReturn(true);
+
+        mKeyboardShortcutsReceiver.onReceive(mContext, mIntent);
+
+        verify(mKeyboardShortcuts, never()).showKeyboardShortcuts(anyInt());
+        verify(mKeyboardShortcutListSearch).showKeyboardShortcuts(anyInt());
+        mockitoSession.finishMocking();
+    }
+
+    @Test
+    public void onReceive_whenFlagOnDeviceIsNotTablet_showKeyboardShortcuts() {
+        MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+                .spyStatic(Utilities.class)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+        mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, true);
+        mKeyboardShortcutsReceiver = spy(new KeyboardShortcutsReceiver(mFeatureFlags));
+        when(Utilities.isTablet(mContext)).thenReturn(false);
+
+        mKeyboardShortcutsReceiver.onReceive(mContext, mIntent);
+
+        verify(mKeyboardShortcuts).showKeyboardShortcuts(anyInt());
+        verify(mKeyboardShortcutListSearch, never()).showKeyboardShortcuts(anyInt());
+        mockitoSession.finishMocking();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java
new file mode 100644
index 0000000..ea822aa
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Dialog;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyboardShortcutsTest extends SysuiTestCase {
+
+    @Rule public MockitoRule mockito = MockitoJUnit.rule();
+
+    private static int DEVICE_ID = 1;
+    private KeyboardShortcuts mKeyboardShortcuts;
+
+    @Mock private Dialog mDialog;
+    @Mock WindowManager mWindowManager;
+
+    @Before
+    public void setUp() {
+        mKeyboardShortcuts = new KeyboardShortcuts(mContext, mWindowManager);
+        mKeyboardShortcuts.sInstance = mKeyboardShortcuts;
+        mKeyboardShortcuts.mKeyboardShortcutsDialog = mDialog;
+        mKeyboardShortcuts.mContext = mContext;
+    }
+
+    @Test
+    public void toggle_isShowingTrue_instanceShouldBeNull() {
+        when(mDialog.isShowing()).thenReturn(true);
+
+        mKeyboardShortcuts.toggle(mContext, DEVICE_ID);
+
+        assertThat(mKeyboardShortcuts.sInstance).isNull();
+    }
+
+    @Test
+    public void toggle_isShowingFalse_showKeyboardShortcuts() {
+        when(mDialog.isShowing()).thenReturn(false);
+
+        mKeyboardShortcuts.toggle(mContext, DEVICE_ID);
+
+        verify(mWindowManager).requestAppKeyboardShortcuts(any(), anyInt());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 0605398..8b0d4ce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -327,6 +327,8 @@
         // CentralSurfacesImpl's runtime flag check fails if the flag is absent.
         // This value is unused, because test manifest is opted in.
         mFeatureFlags.set(Flags.WM_ENABLE_PREDICTIVE_BACK_SYSUI, false);
+        // Set default value to avoid IllegalStateException.
+        mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, false);
 
         IThermalService thermalService = mock(IThermalService.class);
         mPowerManager = new PowerManager(mContext, mPowerManagerService, thermalService,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
index 56203d9..6d7941f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
@@ -96,6 +96,9 @@
         whenever(stylusDevice.bluetoothAddress).thenReturn(null)
         whenever(btStylusDevice.bluetoothAddress).thenReturn(STYLUS_BT_ADDRESS)
 
+        whenever(stylusDevice.batteryState).thenReturn(batteryState)
+        whenever(batteryState.capacity).thenReturn(0.5f)
+
         whenever(inputManager.getInputDevice(OTHER_DEVICE_ID)).thenReturn(otherDevice)
         whenever(inputManager.getInputDevice(STYLUS_DEVICE_ID)).thenReturn(stylusDevice)
         whenever(inputManager.getInputDevice(BT_STYLUS_DEVICE_ID)).thenReturn(btStylusDevice)
@@ -494,6 +497,47 @@
     }
 
     @Test
+    fun onBatteryStateChanged_batteryPresent_notInUsiSession_logsSessionStart() {
+        whenever(batteryState.isPresent).thenReturn(true)
+
+        stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+
+        verify(uiEventLogger, times(1))
+            .log(StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_FIRST_DETECTED)
+    }
+
+    @Test
+    fun onBatteryStateChanged_batteryPresent_inUsiSession_doesNotLogSessionStart() {
+        whenever(batteryState.isPresent).thenReturn(true)
+        stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+        clearInvocations(uiEventLogger)
+
+        stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+
+        verify(uiEventLogger, never()).log(any())
+    }
+
+    @Test
+    fun onBatteryStateChanged_batteryAbsent_notInUsiSession_doesNotLogSessionEnd() {
+        whenever(batteryState.isPresent).thenReturn(false)
+
+        stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+
+        verify(uiEventLogger, never()).log(any())
+    }
+
+    @Test
+    fun onBatteryStateChanged_batteryAbsent_inUsiSession_logSessionEnd() {
+        whenever(batteryState.isPresent).thenReturn(true)
+        stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+        whenever(batteryState.isPresent).thenReturn(false)
+
+        stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+
+        verify(uiEventLogger, times(1)).log(StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_REMOVED)
+    }
+
+    @Test
     fun onBatteryStateChanged_batteryPresent_stylusUsed_doesNotUpdateEverUsedFlag() {
         whenever(inputManager.isStylusEverUsed(mContext)).thenReturn(true)
         whenever(batteryState.isPresent).thenReturn(true)
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 12a8230..4702734 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -396,5 +396,11 @@
     // Note: this is a base ID, multiple notifications will be posted for each
     // abusive apps, with notification ID based off this ID.
     NOTE_ABUSIVE_BG_APPS_BASE = 0xc1b2508; // 203105544
+
+    // Notify the user that dialer and sms functionality are unavailable whilst the apps are
+    // paused in the work profile.
+    // Package: android
+    NOTE_ALL_MANAGED_SUBSCRIPTIONS_AND_MANAGED_PROFILE_OFF = 1006;
+
   }
 }
diff --git a/services/api/current.txt b/services/api/current.txt
index a4deed3..5c7b947 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -85,69 +85,72 @@
     method @Nullable public String getAppComponentFactory();
     method @Nullable public String getApplicationClassName();
     method @Nullable public String getBackupAgentName();
-    method @DrawableRes public int getBannerRes();
+    method @DrawableRes public int getBannerResourceId();
     method public int getBaseRevisionCode();
     method public int getCategory();
     method @Nullable public String getClassLoaderName();
     method @Dimension(unit=android.annotation.Dimension.DP) public int getCompatibleWidthLimitDp();
-    method @XmlRes public int getDataExtractionRulesRes();
-    method @StringRes public int getDescriptionRes();
-    method @XmlRes public int getFullBackupContentRes();
+    method @XmlRes public int getDataExtractionRulesResourceId();
+    method @StringRes public int getDescriptionResourceId();
+    method @XmlRes public int getFullBackupContentResourceId();
     method public int getGwpAsanMode();
-    method @DrawableRes public int getIconRes();
-    method @StringRes public int getLabelRes();
+    method @DrawableRes public int getIconResourceId();
+    method @StringRes public int getLabelResourceId();
     method @Dimension(unit=android.annotation.Dimension.DP) public int getLargestWidthLimitDp();
     method @NonNull public java.util.List<java.lang.String> getLibraryNames();
-    method @XmlRes public int getLocaleConfigRes();
-    method @DrawableRes public int getLogoRes();
+    method @XmlRes public int getLocaleConfigResourceId();
+    method @DrawableRes public int getLogoResourceId();
     method public long getLongVersionCode();
     method public float getMaxAspectRatio();
     method public float getMinAspectRatio();
     method public int getNativeHeapZeroInitialized();
-    method @XmlRes public int getNetworkSecurityConfigRes();
+    method @XmlRes public int getNetworkSecurityConfigResourceId();
     method @Nullable public String getRequiredAccountType();
     method @Dimension(unit=android.annotation.Dimension.DP) public int getRequiresSmallestWidthDp();
     method @Nullable public String getRestrictedAccountType();
-    method @DrawableRes public int getRoundIconRes();
+    method @DrawableRes public int getRoundIconResourceId();
     method @Nullable public String getSdkLibraryName();
     method @Nullable public String getSharedUserId();
-    method @StringRes public int getSharedUserLabelRes();
+    method @StringRes public int getSharedUserLabelResourceId();
     method @NonNull public java.util.List<com.android.server.pm.pkg.AndroidPackageSplit> getSplits();
     method @Nullable public String getStaticSharedLibraryName();
     method @NonNull public java.util.UUID getStorageUuid();
     method public int getTargetSdkVersion();
-    method @StyleRes public int getThemeRes();
+    method @StyleRes public int getThemeResourceId();
     method public int getUiOptions();
     method @Nullable public String getVersionName();
     method @Nullable public String getZygotePreloadName();
+    method public boolean is32BitAbiPreferred();
     method public boolean isAllowAudioPlaybackCapture();
-    method public boolean isAllowBackup();
-    method public boolean isAllowClearUserData();
-    method public boolean isAllowClearUserDataOnFailedRestore();
     method public boolean isAllowNativeHeapPointerTagging();
-    method public boolean isAllowTaskReparenting();
     method public boolean isAnyDensity();
     method public boolean isAttributionsUserVisible();
+    method public boolean isBackupAllowed();
     method public boolean isBackupInForeground();
-    method public boolean isCantSaveState();
+    method public boolean isClearUserDataAllowed();
+    method public boolean isClearUserDataOnFailedRestoreAllowed();
+    method public boolean isCleartextTrafficAllowed();
     method public boolean isCoreApp();
     method public boolean isCrossProfile();
     method public boolean isDebuggable();
+    method public boolean isDeclaredHavingCode();
     method public boolean isDefaultToDeviceProtectedStorage();
     method public boolean isDirectBootAware();
-    method public boolean isExtractNativeLibs();
+    method public boolean isExtraLargeScreensSupported();
+    method public boolean isExtractNativeLibrariesRequested();
     method public boolean isFactoryTest();
     method public boolean isForceQueryable();
     method public boolean isFullBackupOnly();
     method public boolean isHardwareAccelerated();
-    method public boolean isHasCode();
-    method public boolean isHasFragileUserData();
     method public boolean isIsolatedSplitLoading();
-    method public boolean isKillAfterRestore();
+    method public boolean isKillAfterRestoreAllowed();
     method public boolean isLargeHeap();
+    method public boolean isLargeScreensSupported();
     method public boolean isLeavingSharedUser();
     method public boolean isMultiArch();
     method public boolean isNativeLibraryRootRequiresIsa();
+    method public boolean isNonSdkApiRequested();
+    method public boolean isNormalScreensSupported();
     method public boolean isOnBackInvokedCallbackEnabled();
     method public boolean isPersistent();
     method public boolean isProfileable();
@@ -157,17 +160,14 @@
     method public boolean isResetEnabledSettingsOnAppDataCleared();
     method public boolean isResourceOverlay();
     method public boolean isRestoreAnyVersion();
+    method public boolean isRtlSupported();
+    method public boolean isSaveStateDisallowed();
     method public boolean isSignedWithPlatformKey();
-    method public boolean isSupportsExtraLargeScreens();
-    method public boolean isSupportsLargeScreens();
-    method public boolean isSupportsNormalScreens();
-    method public boolean isSupportsRtl();
-    method public boolean isSupportsSmallScreens();
+    method public boolean isSmallScreensSupported();
+    method public boolean isTaskReparentingAllowed();
     method public boolean isTestOnly();
-    method public boolean isUse32BitAbi();
     method public boolean isUseEmbeddedDex();
-    method public boolean isUsesCleartextTraffic();
-    method public boolean isUsesNonSdkApi();
+    method public boolean isUserDataFragile();
     method public boolean isVmSafeMode();
   }
 
@@ -299,11 +299,11 @@
   public static final class ActivityInterceptorCallback.ActivityInterceptorInfo.Builder {
     ctor public ActivityInterceptorCallback.ActivityInterceptorInfo.Builder(int, int, int, int, int, @NonNull android.content.Intent, @NonNull android.content.pm.ResolveInfo, @NonNull android.content.pm.ActivityInfo);
     method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo build();
-    method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setCallingFeatureId(@NonNull String);
-    method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setCallingPackage(@NonNull String);
-    method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setCheckedOptions(@NonNull android.app.ActivityOptions);
-    method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setClearOptionsAnimationRunnable(@NonNull Runnable);
-    method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setResolvedType(@NonNull String);
+    method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setCallingFeatureId(@Nullable String);
+    method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setCallingPackage(@Nullable String);
+    method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setCheckedOptions(@Nullable android.app.ActivityOptions);
+    method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setClearOptionsAnimationRunnable(@Nullable Runnable);
+    method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setResolvedType(@Nullable String);
   }
 
   public class ActivityInterceptorCallbackRegistry {
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 2aeaa2f..13f327c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -260,6 +260,10 @@
       */
     private static final String KEY_LOW_SWAP_THRESHOLD_PERCENT = "low_swap_threshold_percent";
 
+    /** Default value for mFlagApplicationStartInfoEnabled. Defaults to false. */
+    private static final String KEY_DEFAULT_APPLICATION_START_INFO_ENABLED =
+            "enable_app_start_info";
+
     /**
      * Default value for mFlagBackgroundActivityStartsEnabled if not explicitly set in
      * Settings.Global. This allows it to be set experimentally unless it has been
@@ -550,6 +554,9 @@
     // Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
     volatile boolean mFlagActivityStartsLoggingEnabled;
 
+    // Indicates whether ApplicationStartInfo is enabled.
+    volatile boolean mFlagApplicationStartInfoEnabled;
+
     // Indicates whether the background activity starts is enabled.
     // Controlled by Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED.
     // If not set explicitly the default is controlled by DeviceConfig.
@@ -996,6 +1003,9 @@
                             case KEY_MAX_CACHED_PROCESSES:
                                 updateMaxCachedProcesses();
                                 break;
+                            case KEY_DEFAULT_APPLICATION_START_INFO_ENABLED:
+                                updateApplicationStartInfoEnabled();
+                                break;
                             case KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED:
                                 updateBackgroundActivityStarts();
                                 break;
@@ -1390,6 +1400,14 @@
                 Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED, 1) == 1;
     }
 
+    private void updateApplicationStartInfoEnabled() {
+        mFlagApplicationStartInfoEnabled =
+                DeviceConfig.getBoolean(
+                        DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                        KEY_DEFAULT_APPLICATION_START_INFO_ENABLED,
+                        /*defaultValue*/ false);
+    }
+
     private void updateBackgroundActivityStarts() {
         mFlagBackgroundActivityStartsEnabled = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -1970,6 +1988,10 @@
         pw.println(mFgToBgFgsGraceDuration);
         pw.print("  "); pw.print(KEY_FGS_START_FOREGROUND_TIMEOUT); pw.print("=");
         pw.println(mFgsStartForegroundTimeoutMs);
+        pw.print("  ");
+        pw.print(KEY_DEFAULT_APPLICATION_START_INFO_ENABLED);
+        pw.print("=");
+        pw.println(mFlagApplicationStartInfoEnabled);
         pw.print("  "); pw.print(KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED); pw.print("=");
         pw.println(mFlagBackgroundActivityStartsEnabled);
         pw.print("  "); pw.print(KEY_DEFAULT_BACKGROUND_FGS_STARTS_RESTRICTION_ENABLED);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b7985a5..669be1a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -184,6 +184,7 @@
 import android.app.AppOpsManagerInternal.CheckOpsDelegate;
 import android.app.ApplicationErrorReport;
 import android.app.ApplicationExitInfo;
+import android.app.ApplicationStartInfo;
 import android.app.ApplicationThreadConstants;
 import android.app.BackgroundStartPrivileges;
 import android.app.BroadcastOptions;
@@ -192,6 +193,7 @@
 import android.app.ForegroundServiceDelegationOptions;
 import android.app.IActivityController;
 import android.app.IActivityManager;
+import android.app.IApplicationStartInfoCompleteListener;
 import android.app.IApplicationThread;
 import android.app.IForegroundServiceObserver;
 import android.app.IInstrumentationWatcher;
@@ -9452,6 +9454,37 @@
     }
 
     @Override
+    public ParceledListSlice<ApplicationStartInfo> getHistoricalProcessStartReasons(
+            String packageName, int maxNum, int userId) {
+        if (!mConstants.mFlagApplicationStartInfoEnabled) {
+            return new ParceledListSlice<ApplicationStartInfo>(
+                new ArrayList<ApplicationStartInfo>());
+        }
+        enforceNotIsolatedCaller("getHistoricalProcessStartReasons");
+
+        final ArrayList<ApplicationStartInfo> results = new ArrayList<ApplicationStartInfo>();
+
+        return new ParceledListSlice<ApplicationStartInfo>(results);
+    }
+
+    @Override
+    public void setApplicationStartInfoCompleteListener(
+            IApplicationStartInfoCompleteListener listener, int userId) {
+        if (!mConstants.mFlagApplicationStartInfoEnabled) {
+            return;
+        }
+        enforceNotIsolatedCaller("setApplicationStartInfoCompleteListener");
+    }
+
+    @Override
+    public void removeApplicationStartInfoCompleteListener(int userId) {
+        if (!mConstants.mFlagApplicationStartInfoEnabled) {
+            return;
+        }
+        enforceNotIsolatedCaller("removeApplicationStartInfoCompleteListener");
+    }
+
+    @Override
     public ParceledListSlice<ApplicationExitInfo> getHistoricalProcessExitReasons(
             String packageName, int pid, int maxNum, int userId) {
         enforceNotIsolatedCaller("getHistoricalProcessExitReasons");
@@ -16851,13 +16884,14 @@
 
     @Override
     public boolean startProfile(@UserIdInt int userId) {
-        return mUserController.startProfile(userId);
+        return mUserController.startProfile(userId, /* evenWhenDisabled= */ false,
+                /* unlockListener= */ null);
     }
 
     @Override
     public boolean startProfileWithListener(@UserIdInt int userId,
             @Nullable IProgressListener unlockListener) {
-        return mUserController.startProfile(userId, unlockListener);
+        return mUserController.startProfile(userId, /* evenWhenDisabled= */ false, unlockListener);
     }
 
     @Override
@@ -18456,6 +18490,12 @@
             // has a SHORT_FGS.
             return mOomAdjuster.hasUidShortForegroundService(uid);
         }
+
+        @Override
+        public boolean startProfileEvenWhenDisabled(@UserIdInt int userId) {
+            return mUserController.startProfile(userId, /* evenWhenDisabled= */ true,
+                    /* unlockListener= */ null);
+        }
     }
 
     long inputDispatchingTimedOut(int pid, final boolean aboveSystem, TimeoutRecord timeoutRecord) {
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index d29c327..05cf5dbb 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -229,14 +229,19 @@
      * When defined, this receiver is considered "blocked" until at least the
      * given count of other receivers have reached a terminal state; typically
      * used for ordered broadcasts and priority traunches.
+     *
+     * @return the existing broadcast record in the queue that was replaced with a newer broadcast
+     *         sent with {@link Intent#FLAG_RECEIVER_REPLACE_PENDING} or {@code null} if there
+     *         wasn't any broadcast that was replaced.
      */
-    public void enqueueOrReplaceBroadcast(@NonNull BroadcastRecord record, int recordIndex,
-            @NonNull BroadcastConsumer replacedBroadcastConsumer, boolean wouldBeSkipped) {
+    @Nullable
+    public BroadcastRecord enqueueOrReplaceBroadcast(@NonNull BroadcastRecord record,
+            int recordIndex, boolean wouldBeSkipped) {
         if (record.isReplacePending()) {
-            final boolean didReplace = replaceBroadcast(record, recordIndex,
-                    replacedBroadcastConsumer, wouldBeSkipped);
-            if (didReplace) {
-                return;
+            final BroadcastRecord replacedBroadcastRecord = replaceBroadcast(record, recordIndex,
+                    wouldBeSkipped);
+            if (replacedBroadcastRecord != null) {
+                return replacedBroadcastRecord;
             }
         }
 
@@ -253,34 +258,37 @@
         // with implicit responsiveness expectations.
         getQueueForBroadcast(record).addLast(newBroadcastArgs);
         onBroadcastEnqueued(record, recordIndex, wouldBeSkipped);
+        return null;
     }
 
     /**
      * Searches from newest to oldest in the pending broadcast queues, and at the first matching
      * pending broadcast it finds, replaces it in-place and returns -- does not attempt to handle
      * "duplicate" broadcasts in the queue.
-     * <p>
-     * @return {@code true} if it found and replaced an existing record in the queue;
-     * {@code false} otherwise.
+     *
+     * @return the existing broadcast record in the queue that was replaced with a newer broadcast
+     *         sent with {@link Intent#FLAG_RECEIVER_REPLACE_PENDING} or {@code null} if there
+     *         wasn't any broadcast that was replaced.
      */
-    private boolean replaceBroadcast(@NonNull BroadcastRecord record, int recordIndex,
-            @NonNull BroadcastConsumer replacedBroadcastConsumer, boolean wouldBeSkipped) {
+    @Nullable
+    private BroadcastRecord replaceBroadcast(@NonNull BroadcastRecord record, int recordIndex,
+            boolean wouldBeSkipped) {
         final ArrayDeque<SomeArgs> queue = getQueueForBroadcast(record);
-        return replaceBroadcastInQueue(queue, record, recordIndex,
-                replacedBroadcastConsumer, wouldBeSkipped);
+        return replaceBroadcastInQueue(queue, record, recordIndex, wouldBeSkipped);
     }
 
     /**
      * Searches from newest to oldest, and at the first matching pending broadcast
      * it finds, replaces it in-place and returns -- does not attempt to handle
      * "duplicate" broadcasts in the queue.
-     * <p>
-     * @return {@code true} if it found and replaced an existing record in the queue;
-     * {@code false} otherwise.
+     *
+     * @return the existing broadcast record in the queue that was replaced with a newer broadcast
+     *         sent with {@link Intent#FLAG_RECEIVER_REPLACE_PENDING} or {@code null} if there
+     *         wasn't any broadcast that was replaced.
      */
-    private boolean replaceBroadcastInQueue(@NonNull ArrayDeque<SomeArgs> queue,
+    @Nullable
+    private BroadcastRecord replaceBroadcastInQueue(@NonNull ArrayDeque<SomeArgs> queue,
             @NonNull BroadcastRecord record, int recordIndex,
-            @NonNull BroadcastConsumer replacedBroadcastConsumer,
             boolean wouldBeSkipped) {
         final Iterator<SomeArgs> it = queue.descendingIterator();
         final Object receiver = record.receivers.get(recordIndex);
@@ -302,11 +310,10 @@
                 record.copyEnqueueTimeFrom(testRecord);
                 onBroadcastDequeued(testRecord, testRecordIndex, testWouldBeSkipped);
                 onBroadcastEnqueued(record, recordIndex, wouldBeSkipped);
-                replacedBroadcastConsumer.accept(testRecord, testRecordIndex);
-                return true;
+                return testRecord;
             }
         }
-        return false;
+        return null;
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index f954420..d4d6eb2 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -92,6 +92,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.BooleanSupplier;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
@@ -204,6 +205,14 @@
     @GuardedBy("mService")
     private final ArrayList<Pair<BooleanSupplier, CountDownLatch>> mWaitingFor = new ArrayList<>();
 
+    /**
+     * Container for holding the set of broadcasts that have been replaced by a newer broadcast
+     * sent with {@link Intent#FLAG_RECEIVER_REPLACE_PENDING}.
+     */
+    @GuardedBy("mService")
+    private final AtomicReference<ArraySet<BroadcastRecord>> mReplacedBroadcastsCache =
+            new AtomicReference<>();
+
     private final BroadcastConstants mConstants;
     private final BroadcastConstants mFgConstants;
     private final BroadcastConstants mBgConstants;
@@ -627,9 +636,10 @@
         r.enqueueRealTime = SystemClock.elapsedRealtime();
         r.enqueueClockTime = System.currentTimeMillis();
 
-        final ArraySet<BroadcastRecord> replacedBroadcasts = new ArraySet<>();
-        final BroadcastConsumer replacedBroadcastConsumer =
-                (record, i) -> replacedBroadcasts.add(record);
+        ArraySet<BroadcastRecord> replacedBroadcasts = mReplacedBroadcastsCache.getAndSet(null);
+        if (replacedBroadcasts == null) {
+            replacedBroadcasts = new ArraySet<>();
+        }
         boolean enqueuedBroadcast = false;
 
         for (int i = 0; i < r.receivers.size(); i++) {
@@ -653,7 +663,11 @@
                 }
             }
             enqueuedBroadcast = true;
-            queue.enqueueOrReplaceBroadcast(r, i, replacedBroadcastConsumer, wouldBeSkipped);
+            final BroadcastRecord replacedBroadcast = queue.enqueueOrReplaceBroadcast(
+                    r, i, wouldBeSkipped);
+            if (replacedBroadcast != null) {
+                replacedBroadcasts.add(replacedBroadcast);
+            }
             if (r.isDeferUntilActive() && queue.isDeferredUntilActive()) {
                 setDeliveryState(queue, null, r, i, receiver, BroadcastRecord.DELIVERY_DEFERRED,
                         "deferred at enqueue time");
@@ -664,7 +678,11 @@
 
         // Skip any broadcasts that have been replaced by newer broadcasts with
         // FLAG_RECEIVER_REPLACE_PENDING.
+        // TODO: Optimize and reuse mBroadcastConsumerSkipAndCanceled for the case of
+        // cancelling all receivers for a broadcast.
         skipAndCancelReplacedBroadcasts(replacedBroadcasts);
+        replacedBroadcasts.clear();
+        mReplacedBroadcastsCache.compareAndSet(null, replacedBroadcasts);
 
         // If nothing to dispatch, send any pending result immediately
         if (r.receivers.isEmpty() || !enqueuedBroadcast) {
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 8b34fe0..14ecf9f 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -376,7 +376,7 @@
         return DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_WINDOW_MANAGER,
                 ENABLE_DEFAULT_RESCIND_BAL_PRIVILEGES_FROM_PENDING_INTENT_SENDER,
-                true);
+                false); // assume false if the property is unknown
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index b0a14ab..652f84d 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -55,6 +55,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
@@ -1463,18 +1464,24 @@
     }
 
     /**
-     * Starts a user only if it's a profile, with a more relaxed permission requirement:
-     * {@link android.Manifest.permission#MANAGE_USERS} or
-     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
-     * To be called from ActivityManagerService.
-     * @param userId the id of the user to start.
-     * @return true if the operation was successful.
+     * Starts a {@link UserManager#isProfile() profile user}.
+     *
+     * <p>To be called from {@link com.android.server.am.ActivityManagerService}.
+     *
+     * @param userId the id of the profile user to start.
+     * @param evenWhenDisabled whether the profile should be started if it's not enabled yet
+     *        (most callers should pass {@code false}, except when starting the profile while it's
+     *        being provisioned).
+     * @param unlockListener listener to be informed when the profile has started and unlocked.
+     *
+     * @return {@code true} if the operation was successful.
+     *
+     * @throws IllegalArgumentException if the user doesn't exist or is not a profile.
      */
-    boolean startProfile(@UserIdInt int userId) {
-        return startProfile(userId, /* unlockListener= */ null);
-    }
-
-    boolean startProfile(@UserIdInt int userId, @Nullable IProgressListener unlockListener) {
+    @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+    boolean startProfile(@UserIdInt int userId, boolean evenWhenDisabled,
+            @Nullable IProgressListener unlockListener) {
         if (mInjector.checkCallingPermission(android.Manifest.permission.MANAGE_USERS)
                 == PackageManager.PERMISSION_DENIED && mInjector.checkCallingPermission(
                 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
@@ -1489,8 +1496,8 @@
             throw new IllegalArgumentException("User " + userId + " is not a profile");
         }
 
-        if (!userInfo.isEnabled()) {
-            Slogf.w(TAG, "Cannot start disabled profile #" + userId);
+        if (!userInfo.isEnabled() && !evenWhenDisabled) {
+            Slogf.w(TAG, "Cannot start disabled profile #%d", userId);
             return false;
         }
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e55bddb..e48c538 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2402,10 +2402,6 @@
             Log.w(TAG, "audioFormat to enable is not a surround format.");
             return false;
         }
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Missing WRITE_SETTINGS permission");
-        }
 
         final long token = Binder.clearCallingIdentity();
         try {
@@ -2473,11 +2469,6 @@
     /** @see AudioManager#getEncodedSurroundMode() */
     @Override
     public int getEncodedSurroundMode(int targetSdkVersion) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Missing WRITE_SETTINGS permission");
-        }
-
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mSettingsLock) {
diff --git a/services/core/java/com/android/server/display/DisplayControl.java b/services/core/java/com/android/server/display/DisplayControl.java
index f229d0f..a1081b2 100644
--- a/services/core/java/com/android/server/display/DisplayControl.java
+++ b/services/core/java/com/android/server/display/DisplayControl.java
@@ -37,6 +37,7 @@
     private static native void nativeSetHdrConversionMode(int conversionMode,
             int preferredHdrOutputType, int[] autoHdrTypes, int autoHdrTypesLength);
     private static native int[] nativeGetSupportedHdrOutputTypes();
+    private static native boolean nativeGetHdrOutputConversionSupport();
 
     /**
      * Create a display in SurfaceFlinger.
@@ -118,4 +119,11 @@
     public static @Display.HdrCapabilities.HdrType int[] getSupportedHdrOutputTypes() {
         return nativeGetSupportedHdrOutputTypes();
     }
+
+    /**
+     * @hide
+     */
+    public static boolean getHdrOutputConversionSupport() {
+        return nativeGetHdrOutputConversionSupport();
+    }
 }
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e200d12..49bf0f5 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -247,6 +247,8 @@
     // HDR conversion mode chosen by user
     @GuardedBy("mSyncRoot")
     private HdrConversionMode mHdrConversionMode = null;
+    // Actual HDR conversion mode, which takes app overrides into account.
+    private HdrConversionMode mOverrideHdrConversionMode = null;
 
     // The synchronization root for the display manager.
     // This lock guards most of the display manager's state.
@@ -2025,12 +2027,23 @@
             if (hdrConversionMode.getConversionMode() == HdrConversionMode.HDR_CONVERSION_SYSTEM) {
                 autoHdrOutputTypes = getEnabledAutoHdrTypesLocked();
             }
-            mInjector.setHdrConversionMode(hdrConversionMode.getConversionMode(),
-                    hdrConversionMode.getPreferredHdrOutputType(), autoHdrOutputTypes);
+
+            if (!mInjector.getHdrOutputConversionSupport()) {
+                return;
+            }
+            // If the HDR conversion is disabled by an app through WindowManager.LayoutParams, then
+            // set HDR conversion mode to HDR_CONVERSION_PASSTHROUGH.
+            if (mOverrideHdrConversionMode == null) {
+                mInjector.setHdrConversionMode(hdrConversionMode.getConversionMode(),
+                        hdrConversionMode.getPreferredHdrOutputType(), autoHdrOutputTypes);
+            } else {
+                mInjector.setHdrConversionMode(mOverrideHdrConversionMode.getConversionMode(),
+                        mOverrideHdrConversionMode.getPreferredHdrOutputType(), null);
+            }
         }
     }
 
-    private HdrConversionMode getHdrConversionModeInternal() {
+    private HdrConversionMode getHdrConversionModeSettingInternal() {
         synchronized (mSyncRoot) {
             if (mHdrConversionMode != null) {
                 return mHdrConversionMode;
@@ -2039,6 +2052,16 @@
         return new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_SYSTEM);
     }
 
+    private HdrConversionMode getHdrConversionModeInternal() {
+        HdrConversionMode mode;
+        synchronized (mSyncRoot) {
+            mode = mOverrideHdrConversionMode != null
+                    ? mOverrideHdrConversionMode
+                    : mHdrConversionMode;
+        }
+        return mode != null ? mode : new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_SYSTEM);
+    }
+
     private @Display.HdrCapabilities.HdrType int[] getSupportedHdrOutputTypesInternal() {
         if (mSupportedHdrOutputType == null) {
             mSupportedHdrOutputType = mInjector.getSupportedHdrOutputTypes();
@@ -2181,7 +2204,7 @@
     private void setDisplayPropertiesInternal(int displayId, boolean hasContent,
             float requestedRefreshRate, int requestedModeId, float requestedMinRefreshRate,
             float requestedMaxRefreshRate, boolean preferMinimalPostProcessing,
-            boolean inTraversal) {
+            boolean disableHdrConversion, boolean inTraversal) {
         synchronized (mSyncRoot) {
             final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
             if (display == null) {
@@ -2226,6 +2249,20 @@
             if (shouldScheduleTraversal) {
                 scheduleTraversalLocked(inTraversal);
             }
+
+            if (mHdrConversionMode == null) {
+                return;
+            }
+            if (mOverrideHdrConversionMode == null && disableHdrConversion) {
+                mOverrideHdrConversionMode =
+                            new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_PASSTHROUGH);
+                setHdrConversionModeInternal(mHdrConversionMode);
+                handleLogicalDisplayChangedLocked(display);
+            } else if (mOverrideHdrConversionMode != null && !disableHdrConversion) {
+                mOverrideHdrConversionMode = null;
+                setHdrConversionModeInternal(mHdrConversionMode);
+                handleLogicalDisplayChangedLocked(display);
+            }
         }
     }
 
@@ -2783,6 +2820,10 @@
         int[] getSupportedHdrOutputTypes() {
             return DisplayControl.getSupportedHdrOutputTypes();
         }
+
+        boolean getHdrOutputConversionSupport() {
+            return DisplayControl.getHdrOutputConversionSupport();
+        }
     }
 
     @VisibleForTesting
@@ -3757,6 +3798,16 @@
         }
 
         @Override // Binder call
+        public HdrConversionMode getHdrConversionModeSetting() {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getHdrConversionModeSettingInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
         public HdrConversionMode getHdrConversionMode() {
             final long token = Binder.clearCallingIdentity();
             try {
@@ -4030,10 +4081,10 @@
         public void setDisplayProperties(int displayId, boolean hasContent,
                 float requestedRefreshRate, int requestedMode, float requestedMinRefreshRate,
                 float requestedMaxRefreshRate, boolean requestedMinimalPostProcessing,
-                boolean inTraversal) {
+                boolean disableHdrConversion, boolean inTraversal) {
             setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate,
                     requestedMode, requestedMinRefreshRate, requestedMaxRefreshRate,
-                    requestedMinimalPostProcessing, inTraversal);
+                    requestedMinimalPostProcessing, disableHdrConversion, inTraversal);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/location/gnss/NetworkTimeHelper.java b/services/core/java/com/android/server/location/gnss/NetworkTimeHelper.java
index 3a25146..f5114b7 100644
--- a/services/core/java/com/android/server/location/gnss/NetworkTimeHelper.java
+++ b/services/core/java/com/android/server/location/gnss/NetworkTimeHelper.java
@@ -32,6 +32,14 @@
 abstract class NetworkTimeHelper {
 
     /**
+     * This compile-time value can be changed to switch between new and old ways to obtain network
+     * time for GNSS. If you have to turn this from {@code true} to {@code false} then please create
+     * a platform bug. This switch will be removed in a future release. If there are problems with
+     * the new impl we'd like to hear about them.
+     */
+    static final boolean USE_TIME_DETECTOR_IMPL = false;
+
+    /**
      * The callback interface used by {@link NetworkTimeHelper} to report the time to {@link
      * GnssLocationProvider}. The callback can happen at any time using the thread associated with
      * the looper passed to {@link #create(Context, Looper, InjectTimeCallback)}.
@@ -47,7 +55,13 @@
     static NetworkTimeHelper create(
             @NonNull Context context, @NonNull Looper looper,
             @NonNull InjectTimeCallback injectTimeCallback) {
-        return new NtpNetworkTimeHelper(context, looper, injectTimeCallback);
+        if (USE_TIME_DETECTOR_IMPL) {
+            TimeDetectorNetworkTimeHelper.Environment environment =
+                    new TimeDetectorNetworkTimeHelper.EnvironmentImpl(looper);
+            return new TimeDetectorNetworkTimeHelper(environment, injectTimeCallback);
+        } else {
+            return new NtpNetworkTimeHelper(context, looper, injectTimeCallback);
+        }
     }
 
     /**
@@ -74,7 +88,9 @@
      * Notifies that network connectivity has been established.
      *
      * <p>Called by {@link GnssLocationProvider} when the device establishes a data network
-     * connection.
+     * connection. This call should be removed eventually because it should be handled by the {@link
+     * NetworkTimeHelper} implementation itself, but has been retained for compatibility while
+     * switching implementations.
      */
     abstract void onNetworkAvailable();
 
@@ -82,4 +98,5 @@
      * Dumps internal state during bugreports useful for debugging.
      */
     abstract void dump(@NonNull PrintWriter pw);
+
 }
diff --git a/services/core/java/com/android/server/location/gnss/TimeDetectorNetworkTimeHelper.java b/services/core/java/com/android/server/location/gnss/TimeDetectorNetworkTimeHelper.java
new file mode 100644
index 0000000..15366d3
--- /dev/null
+++ b/services/core/java/com/android/server/location/gnss/TimeDetectorNetworkTimeHelper.java
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.gnss;
+
+import android.annotation.DurationMillisLong;
+import android.annotation.ElapsedRealtimeLong;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.time.UnixEpochTime;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.util.IndentingPrintWriter;
+import android.util.LocalLog;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
+import com.android.server.timedetector.NetworkTimeSuggestion;
+import com.android.server.timedetector.TimeDetectorInternal;
+import com.android.server.timezonedetector.StateChangeListener;
+
+import java.io.PrintWriter;
+import java.util.Objects;
+
+/**
+ * Handles injecting network time to GNSS by using information from the platform time detector.
+ */
+public class TimeDetectorNetworkTimeHelper extends NetworkTimeHelper {
+
+    /** Returns {@code true} if the TimeDetectorNetworkTimeHelper is being used. */
+    public static boolean isInUse() {
+        return NetworkTimeHelper.USE_TIME_DETECTOR_IMPL;
+    }
+
+    /**
+     * An interface exposed for easier testing that the surrounding class uses for interacting with
+     * platform services, handlers, etc.
+     */
+    interface Environment {
+
+        /**
+         * Returns the current elapsed realtime value. The same as calling {@link
+         * SystemClock#elapsedRealtime()} but easier to fake in tests.
+         */
+        @ElapsedRealtimeLong long elapsedRealtimeMillis();
+
+        /**
+         * Returns the latest / best network time available from the time detector service.
+         */
+        @Nullable NetworkTimeSuggestion getLatestNetworkTime();
+
+        /**
+         * Sets a listener that will receive a callback when the value returned by {@link
+         * #getLatestNetworkTime()} has changed.
+         */
+        void setNetworkTimeUpdateListener(StateChangeListener stateChangeListener);
+
+        /**
+         * Requests asynchronous execution of {@link
+         * TimeDetectorNetworkTimeHelper#queryAndInjectNetworkTime}, to execute as soon as possible.
+         * The thread used is the same as used by {@link #requestDelayedTimeQueryCallback}.
+         * Only one immediate callback can be requested at a time; requesting a new immediate
+         * callback will clear any previously requested one.
+         */
+        void requestImmediateTimeQueryCallback(TimeDetectorNetworkTimeHelper helper, String reason);
+
+        /**
+         * Requests a delayed call to
+         * {@link TimeDetectorNetworkTimeHelper#delayedQueryAndInjectNetworkTime()}.
+         * The thread used is the same as used by {@link #requestImmediateTimeQueryCallback}.
+         * Only one delayed callback can be scheduled at a time; requesting a new delayed callback
+         * will clear any previously requested one.
+         */
+        void requestDelayedTimeQueryCallback(
+                TimeDetectorNetworkTimeHelper helper, @DurationMillisLong long delayMillis);
+
+        /**
+         * Clear a delayed time query callback. This has no effect if no delayed callback is
+         * currently set.
+         */
+        void clearDelayedTimeQueryCallback();
+    }
+
+    private static final String TAG = "TDNetworkTimeHelper";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    /** The maximum age of a network time signal that will be passed to GNSS. */
+    @VisibleForTesting
+    static final int MAX_NETWORK_TIME_AGE_MILLIS = 24 * 60 * 60 * 1000;
+
+    /**
+     * The maximum time that is allowed to pass before a network time signal should be evaluated to
+     * be passed to GNSS when mOnDemandTimeInjection == false.
+     */
+    static final int NTP_REFRESH_INTERVAL_MILLIS = MAX_NETWORK_TIME_AGE_MILLIS;
+
+    private final LocalLog mDumpLog = new LocalLog(10, /*useLocalTimestamps=*/false);
+
+    /** The object the helper uses to interact with other components. */
+    @NonNull private final Environment mEnvironment;
+    @NonNull private final InjectTimeCallback mInjectTimeCallback;
+
+    /** Set to true if the GNSS engine requested on-demand NTP time injections. */
+    @GuardedBy("this")
+    private boolean mPeriodicTimeInjectionEnabled;
+
+    /**
+     * Set to true when a network time has been injected. Used to ensure that a network time is
+     * injected if this object wasn't listening when a network time signal first became available.
+     */
+    @GuardedBy("this")
+    private boolean mNetworkTimeInjected;
+
+    TimeDetectorNetworkTimeHelper(
+            @NonNull Environment environment, @NonNull InjectTimeCallback injectTimeCallback) {
+        mInjectTimeCallback = Objects.requireNonNull(injectTimeCallback);
+        mEnvironment = Objects.requireNonNull(environment);
+
+        // Start listening for new network time updates immediately.
+        mEnvironment.setNetworkTimeUpdateListener(this::onNetworkTimeAvailable);
+    }
+
+    @Override
+    synchronized void setPeriodicTimeInjectionMode(boolean periodicTimeInjectionEnabled) {
+        // Periodic time injection has a complicated history. See b/73893222. When it is true, it
+        // doesn't mean ONLY send it periodically.
+        //
+        // periodicTimeInjectionEnabled == true means the GNSS would like to be told the time
+        // periodically in addition to all the other triggers (e.g. network available).
+
+        mPeriodicTimeInjectionEnabled = periodicTimeInjectionEnabled;
+        if (!periodicTimeInjectionEnabled) {
+            // Cancel any previously scheduled periodic query.
+            removePeriodicNetworkTimeQuery();
+        }
+
+        // Inject the latest network time in all cases if it is available.
+        // Calling queryAndInjectNetworkTime() will cause a time signal to be injected if one is
+        // available AND will cause the next periodic query to be scheduled.
+        String reason = "setPeriodicTimeInjectionMode(" + periodicTimeInjectionEnabled + ")";
+        mEnvironment.requestImmediateTimeQueryCallback(this, reason);
+    }
+
+    void onNetworkTimeAvailable() {
+        // A new network time could become available at any time. Make sure it is passed to GNSS.
+        mEnvironment.requestImmediateTimeQueryCallback(this, "onNetworkTimeAvailable");
+    }
+
+    @Override
+    void onNetworkAvailable() {
+        // In the original NetworkTimeHelper implementation, onNetworkAvailable() would cause an NTP
+        // refresh to be made if it had previously been blocked by network issues. This
+        // implementation generally relies on components associated with the time detector to
+        // monitor the network and call onNetworkTimeAvailable() when a time is available. However,
+        // it also checks mNetworkTimeInjected in case this component wasn't listening for
+        // onNetworkTimeAvailable() when the last one became available.
+        synchronized (this) {
+            if (!mNetworkTimeInjected) {
+                // Guard against ordering issues: This check should ensure that if a network time
+                // became available before this class started listening then the initial network
+                // time will still be injected.
+                mEnvironment.requestImmediateTimeQueryCallback(this, "onNetworkAvailable");
+            }
+        }
+    }
+
+    @Override
+    void demandUtcTimeInjection() {
+        mEnvironment.requestImmediateTimeQueryCallback(this, "demandUtcTimeInjection");
+    }
+
+    // This method should always be invoked on the mEnvironment thread.
+    void delayedQueryAndInjectNetworkTime() {
+        queryAndInjectNetworkTime("delayedTimeQueryCallback");
+    }
+
+    // This method should always be invoked on the mEnvironment thread.
+    synchronized void queryAndInjectNetworkTime(@NonNull String reason) {
+        NetworkTimeSuggestion latestNetworkTime = mEnvironment.getLatestNetworkTime();
+
+        maybeInjectNetworkTime(latestNetworkTime, reason);
+
+        // Deschedule (if needed) any previously scheduled periodic query.
+        removePeriodicNetworkTimeQuery();
+
+        if (mPeriodicTimeInjectionEnabled) {
+            int maxDelayMillis = NTP_REFRESH_INTERVAL_MILLIS;
+            String debugMsg = "queryAndInjectNtpTime: Scheduling periodic query"
+                            + " reason=" + reason
+                            + " latestNetworkTime=" + latestNetworkTime
+                            + " maxDelayMillis=" + maxDelayMillis;
+            logToDumpLog(debugMsg);
+
+            // GNSS is expecting periodic injections, so schedule the next one.
+            mEnvironment.requestDelayedTimeQueryCallback(this, maxDelayMillis);
+        }
+    }
+
+    private long calculateTimeSignalAgeMillis(
+            @Nullable NetworkTimeSuggestion networkTimeSuggestion) {
+        if (networkTimeSuggestion == null) {
+            return Long.MAX_VALUE;
+        }
+
+        long suggestionElapsedRealtimeMillis =
+                networkTimeSuggestion.getUnixEpochTime().getElapsedRealtimeMillis();
+        long currentElapsedRealtimeMillis = mEnvironment.elapsedRealtimeMillis();
+        return currentElapsedRealtimeMillis - suggestionElapsedRealtimeMillis;
+    }
+
+    @GuardedBy("this")
+    private void maybeInjectNetworkTime(
+            @Nullable NetworkTimeSuggestion latestNetworkTime, @NonNull String reason) {
+        // Historically, time would only be injected if it was under a certain age. This has been
+        // kept in case it is assumed by GNSS implementations.
+        if (calculateTimeSignalAgeMillis(latestNetworkTime) > MAX_NETWORK_TIME_AGE_MILLIS) {
+            String debugMsg = "maybeInjectNetworkTime: Not injecting latest network time"
+                    + " latestNetworkTime=" + latestNetworkTime
+                    + " reason=" + reason;
+            logToDumpLog(debugMsg);
+            return;
+        }
+
+        UnixEpochTime unixEpochTime = latestNetworkTime.getUnixEpochTime();
+        long unixEpochTimeMillis = unixEpochTime.getUnixEpochTimeMillis();
+        long currentTimeMillis = System.currentTimeMillis();
+        String debugMsg = "maybeInjectNetworkTime: Injecting latest network time"
+                + " latestNetworkTime=" + latestNetworkTime
+                + " reason=" + reason
+                + " System time offset millis=" + (unixEpochTimeMillis - currentTimeMillis);
+        logToDumpLog(debugMsg);
+
+        long timeReferenceMillis = unixEpochTime.getElapsedRealtimeMillis();
+        int uncertaintyMillis = latestNetworkTime.getUncertaintyMillis();
+        mInjectTimeCallback.injectTime(unixEpochTimeMillis, timeReferenceMillis, uncertaintyMillis);
+        mNetworkTimeInjected = true;
+    }
+
+    @Override
+    void dump(@NonNull PrintWriter pw) {
+        pw.println("TimeDetectorNetworkTimeHelper:");
+
+        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
+        ipw.increaseIndent();
+        synchronized (this) {
+            ipw.println("mPeriodicTimeInjectionEnabled=" + mPeriodicTimeInjectionEnabled);
+        }
+
+        ipw.println("Debug log:");
+        mDumpLog.dump(ipw);
+    }
+
+    private void logToDumpLog(@NonNull String message) {
+        mDumpLog.log(message);
+        if (DEBUG) {
+            Log.d(TAG, message);
+        }
+    }
+
+    private void removePeriodicNetworkTimeQuery() {
+        // De-schedule any previously scheduled refresh. This is idempotent and has no effect if
+        // there isn't one.
+        mEnvironment.clearDelayedTimeQueryCallback();
+    }
+
+    /** The real implementation of {@link Environment} used outside of tests. */
+    static class EnvironmentImpl implements Environment {
+
+        /** Used to ensure one scheduled runnable is queued at a time. */
+        private final Object mScheduledRunnableToken = new Object();
+        /** Used to ensure one immediate runnable is queued at a time. */
+        private final Object mImmediateRunnableToken = new Object();
+        private final Handler mHandler;
+        private final TimeDetectorInternal mTimeDetectorInternal;
+
+        EnvironmentImpl(Looper looper) {
+            mHandler = new Handler(looper);
+            mTimeDetectorInternal = LocalServices.getService(TimeDetectorInternal.class);
+        }
+
+        @Override
+        public long elapsedRealtimeMillis() {
+            return SystemClock.elapsedRealtime();
+        }
+
+        @Override
+        public NetworkTimeSuggestion getLatestNetworkTime() {
+            return mTimeDetectorInternal.getLatestNetworkSuggestion();
+        }
+
+        @Override
+        public void setNetworkTimeUpdateListener(StateChangeListener stateChangeListener) {
+            mTimeDetectorInternal.addNetworkTimeUpdateListener(stateChangeListener);
+        }
+
+        @Override
+        public void requestImmediateTimeQueryCallback(TimeDetectorNetworkTimeHelper helper,
+                String reason) {
+            // Ensure only one immediate callback is scheduled at a time. There's no
+            // post(Runnable, Object), so we postDelayed() with a zero wait.
+            synchronized (this) {
+                mHandler.removeCallbacksAndMessages(mImmediateRunnableToken);
+                mHandler.postDelayed(() -> helper.queryAndInjectNetworkTime(reason),
+                        mImmediateRunnableToken, 0);
+            }
+        }
+
+        @Override
+        public void requestDelayedTimeQueryCallback(TimeDetectorNetworkTimeHelper helper,
+                long delayMillis) {
+            synchronized (this) {
+                clearDelayedTimeQueryCallback();
+                mHandler.postDelayed(helper::delayedQueryAndInjectNetworkTime,
+                        mScheduledRunnableToken, delayMillis);
+            }
+        }
+
+        @Override
+        public synchronized void clearDelayedTimeQueryCallback() {
+            mHandler.removeCallbacksAndMessages(mScheduledRunnableToken);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 25efe0c..77b9abe 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -287,19 +287,16 @@
             if (packageName == null || packageName.isEmpty()) {
                 throw new IllegalArgumentException("package name must not be empty");
             }
-
-            final UserHandle callingUser = Binder.getCallingUserHandle();
-            final long callingToken = Binder.clearCallingIdentity();
+            final ApplicationInfo ai;
+            try {
+                ai = mPackageManager.getApplicationInfo(packageName, 0);
+            } catch (NameNotFoundException e) {
+                throw new IllegalArgumentException("No package matching :" + packageName);
+            }
 
             MediaProjection projection;
+            final long callingToken = Binder.clearCallingIdentity();
             try {
-                ApplicationInfo ai;
-                try {
-                    ai = mPackageManager.getApplicationInfoAsUser(packageName, 0, callingUser);
-                } catch (NameNotFoundException e) {
-                    throw new IllegalArgumentException("No package matching :" + packageName);
-                }
-
                 projection = new MediaProjection(type, uid, packageName, ai.targetSdkVersion,
                         ai.isPrivilegedApp());
                 if (isPermanentGrant) {
diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java
index f989f6f..c3cc392 100644
--- a/services/core/java/com/android/server/pm/InstallingSession.java
+++ b/services/core/java/com/android/server/pm/InstallingSession.java
@@ -153,7 +153,7 @@
         mInstallSource = installSource;
         mVolumeUuid = sessionParams.volumeUuid;
         mPackageAbiOverride = sessionParams.abiOverride;
-        mPermissionStates = sessionParams.getFinalPermissionStates();
+        mPermissionStates = sessionParams.getPermissionStates();
         mAllowlistedRestrictedPermissions = sessionParams.whitelistedRestrictedPermissions;
         mAutoRevokePermissionsMode = sessionParams.autoRevokePermissionsMode;
         mSigningDetails = signingDetails;
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index e254300..85d2df3 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -388,7 +388,7 @@
                 if (abi32 >= 0) {
                     final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
                     if (abi64 >= 0) {
-                        if (pkg.isUse32BitAbi()) {
+                        if (pkg.is32BitAbiPreferred()) {
                             secondaryCpuAbi = primaryCpuAbi;
                             primaryCpuAbi = abi;
                         } else {
@@ -474,7 +474,8 @@
     private boolean shouldExtractLibs(AndroidPackage pkg, boolean isSystemApp,
             boolean isUpdatedSystemApp) {
         // We shouldn't extract libs if the package is a library or if extractNativeLibs=false
-        boolean extractLibs = !AndroidPackageUtils.isLibrary(pkg) && pkg.isExtractNativeLibs();
+        boolean extractLibs = !AndroidPackageUtils.isLibrary(pkg)
+                && pkg.isExtractNativeLibrariesRequested();
         // We shouldn't attempt to extract libs from system app when it was not updated.
         if (isSystemApp && !isUpdatedSystemApp) {
             extractLibs = false;
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index f708fbb..f338137 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -189,7 +189,7 @@
         }
 
         // We do not dexopt a package with no code.
-        if (!pkg.isHasCode()) {
+        if (!pkg.isDeclaredHavingCode()) {
             return false;
         }
 
@@ -287,7 +287,7 @@
         // For each code path in the package, this array contains the class loader context that
         // needs to be passed to dexopt in order to ensure correct optimizations.
         boolean[] pathsWithCode = new boolean[paths.size()];
-        pathsWithCode[0] = pkg.isHasCode();
+        pathsWithCode[0] = pkg.isDeclaredHavingCode();
         for (int i = 1; i < paths.size(); i++) {
             pathsWithCode[i] = (pkg.getSplitFlags()[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0;
         }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index ed9d370..0897289 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -804,7 +804,7 @@
                         + " PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS flag");
             }
 
-            var permissionStates = params.getFinalPermissionStates();
+            var permissionStates = params.getPermissionStates();
             if (!permissionStates.isEmpty()) {
                 if (!hasInstallGrantRuntimePermissions) {
                     for (int index = 0; index < permissionStates.size(); index++) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 3ad3af3e..3951903 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -4878,7 +4878,16 @@
 
     private static void writePermissionsLocked(@NonNull TypedXmlSerializer out,
             @NonNull SessionParams params) throws IOException {
-        params.writePermissionStateXml(out, TAG_GRANT_PERMISSION, TAG_DENY_PERMISSION, ATTR_NAME);
+        var permissionStates = params.getPermissionStates();
+        for (int index = 0; index < permissionStates.size(); index++) {
+            var permissionName = permissionStates.keyAt(index);
+            var state = permissionStates.valueAt(index);
+            String tag = state == SessionParams.PERMISSION_STATE_GRANTED ? TAG_GRANT_PERMISSION
+                    : TAG_DENY_PERMISSION;
+            out.startTag(null, tag);
+            writeStringAttribute(out, ATTR_NAME, permissionName);
+            out.endTag(null, tag);
+        }
     }
 
     private static void writeWhitelistedRestrictedPermissionsLocked(@NonNull TypedXmlSerializer out,
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 2538871..e4f3e2b 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -547,7 +547,7 @@
      */
     public static void assertCodePolicy(AndroidPackage pkg)
             throws PackageManagerException {
-        final boolean shouldHaveCode = pkg.isHasCode();
+        final boolean shouldHaveCode = pkg.isDeclaredHavingCode();
         if (shouldHaveCode && !apkHasCode(pkg.getBaseApkPath())) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     "Package " + pkg.getBaseApkPath() + " code is missing");
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 6541b40..f1998f7 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4864,7 +4864,7 @@
         pw.println();
         if (pkg != null) {
             pw.print(prefix); pw.print("  versionName="); pw.println(pkg.getVersionName());
-            pw.print(prefix); pw.print("  usesNonSdkApi="); pw.println(pkg.isUsesNonSdkApi());
+            pw.print(prefix); pw.print("  usesNonSdkApi="); pw.println(pkg.isNonSdkApiRequested());
             pw.print(prefix); pw.print("  splits="); dumpSplitNames(pw, pkg); pw.println();
             final int apkSigningVersion = pkg.getSigningDetails().getSignatureSchemeVersion();
             pw.print(prefix); pw.print("  apkSigningVersion="); pw.println(apkSigningVersion);
@@ -4897,25 +4897,25 @@
             pw.print(prefix); pw.print("  dataDir="); pw.println(dataDir.getAbsolutePath());
             pw.print(prefix); pw.print("  supportsScreens=[");
             boolean first = true;
-            if (pkg.isSupportsSmallScreens()) {
+            if (pkg.isSmallScreensSupported()) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("small");
             }
-            if (pkg.isSupportsNormalScreens()) {
+            if (pkg.isNormalScreensSupported()) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("medium");
             }
-            if (pkg.isSupportsLargeScreens()) {
+            if (pkg.isLargeScreensSupported()) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("large");
             }
-            if (pkg.isSupportsExtraLargeScreens()) {
+            if (pkg.isExtraLargeScreensSupported()) {
                 if (!first)
                     pw.print(", ");
                 first = false;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a22ea96..317c111 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1362,15 +1362,14 @@
         }
         try {
             if (enableQuietMode) {
-                ActivityManager.getService().stopUser(userId, /* force */true, null);
+                ActivityManager.getService().stopUser(userId, /* force= */ true, null);
                 LocalServices.getService(ActivityManagerInternal.class)
                         .killForegroundAppsForUser(userId);
             } else {
                 IProgressListener callback = target != null
                         ? new DisableQuietModeUserUnlockedCallback(target)
                         : null;
-                ActivityManager.getService().startUserInBackgroundWithListener(
-                        userId, callback);
+                ActivityManager.getService().startProfileWithListener(userId, callback);
             }
             logQuietModeEnabled(userId, enableQuietMode, callingPackage);
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index d8b6cd5..d88b66b 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -580,7 +580,7 @@
      */
     private ArrayMap<String, String> getPackageProfileNames(AndroidPackage pkg) {
         ArrayMap<String, String> result = new ArrayMap<>();
-        if (pkg.isHasCode()) {
+        if (pkg.isDeclaredHavingCode()) {
             result.put(pkg.getBaseApkPath(), ArtManager.getProfileName(null));
         }
 
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index a3be8d3..d108e14 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -133,7 +133,7 @@
         info.splitRevisionCodes = pkg.getSplitRevisionCodes();
         info.versionName = pkg.getVersionName();
         info.sharedUserId = pkg.getSharedUserId();
-        info.sharedUserLabel = pkg.getSharedUserLabelRes();
+        info.sharedUserLabel = pkg.getSharedUserLabelResourceId();
         info.applicationInfo = applicationInfo;
         info.installLocation = pkg.getInstallLocation();
         if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
@@ -876,27 +876,27 @@
         // @formatter:off
         int pkgWithoutStateFlags = flag(pkg.isExternalStorage(), ApplicationInfo.FLAG_EXTERNAL_STORAGE)
                 | flag(pkg.isHardwareAccelerated(), ApplicationInfo.FLAG_HARDWARE_ACCELERATED)
-                | flag(pkg.isAllowBackup(), ApplicationInfo.FLAG_ALLOW_BACKUP)
-                | flag(pkg.isKillAfterRestore(), ApplicationInfo.FLAG_KILL_AFTER_RESTORE)
+                | flag(pkg.isBackupAllowed(), ApplicationInfo.FLAG_ALLOW_BACKUP)
+                | flag(pkg.isKillAfterRestoreAllowed(), ApplicationInfo.FLAG_KILL_AFTER_RESTORE)
                 | flag(pkg.isRestoreAnyVersion(), ApplicationInfo.FLAG_RESTORE_ANY_VERSION)
                 | flag(pkg.isFullBackupOnly(), ApplicationInfo.FLAG_FULL_BACKUP_ONLY)
                 | flag(pkg.isPersistent(), ApplicationInfo.FLAG_PERSISTENT)
                 | flag(pkg.isDebuggable(), ApplicationInfo.FLAG_DEBUGGABLE)
                 | flag(pkg.isVmSafeMode(), ApplicationInfo.FLAG_VM_SAFE_MODE)
-                | flag(pkg.isHasCode(), ApplicationInfo.FLAG_HAS_CODE)
-                | flag(pkg.isAllowTaskReparenting(), ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING)
-                | flag(pkg.isAllowClearUserData(), ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)
+                | flag(pkg.isDeclaredHavingCode(), ApplicationInfo.FLAG_HAS_CODE)
+                | flag(pkg.isTaskReparentingAllowed(), ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING)
+                | flag(pkg.isClearUserDataAllowed(), ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)
                 | flag(pkg.isLargeHeap(), ApplicationInfo.FLAG_LARGE_HEAP)
-                | flag(pkg.isUsesCleartextTraffic(), ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC)
-                | flag(pkg.isSupportsRtl(), ApplicationInfo.FLAG_SUPPORTS_RTL)
+                | flag(pkg.isCleartextTrafficAllowed(), ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC)
+                | flag(pkg.isRtlSupported(), ApplicationInfo.FLAG_SUPPORTS_RTL)
                 | flag(pkg.isTestOnly(), ApplicationInfo.FLAG_TEST_ONLY)
                 | flag(pkg.isMultiArch(), ApplicationInfo.FLAG_MULTIARCH)
-                | flag(pkg.isExtractNativeLibs(), ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS)
+                | flag(pkg.isExtractNativeLibrariesRequested(), ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS)
                 | flag(pkg.isGame(), ApplicationInfo.FLAG_IS_GAME)
-                | flag(pkg.isSupportsSmallScreens(), ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS)
-                | flag(pkg.isSupportsNormalScreens(), ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS)
-                | flag(pkg.isSupportsLargeScreens(), ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS)
-                | flag(pkg.isSupportsExtraLargeScreens(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)
+                | flag(pkg.isSmallScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS)
+                | flag(pkg.isNormalScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS)
+                | flag(pkg.isLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS)
+                | flag(pkg.isExtraLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)
                 | flag(pkg.isResizeable(), ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS)
                 | flag(pkg.isAnyDensity(), ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
                 | flag(AndroidPackageUtils.isSystem(pkg), ApplicationInfo.FLAG_SYSTEM)
@@ -932,12 +932,12 @@
                 | flag(pkg.isDefaultToDeviceProtectedStorage(), ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE)
                 | flag(pkg.isDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE)
                 | flag(pkg.isPartiallyDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE)
-                | flag(pkg.isAllowClearUserDataOnFailedRestore(), ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE)
+                | flag(pkg.isClearUserDataOnFailedRestoreAllowed(), ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE)
                 | flag(pkg.isAllowAudioPlaybackCapture(), ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE)
                 | flag(pkg.isRequestLegacyExternalStorage(), ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE)
-                | flag(pkg.isUsesNonSdkApi(), ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API)
-                | flag(pkg.isHasFragileUserData(), ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA)
-                | flag(pkg.isCantSaveState(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+                | flag(pkg.isNonSdkApiRequested(), ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API)
+                | flag(pkg.isUserDataFragile(), ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA)
+                | flag(pkg.isSaveStateDisallowed(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
                 | flag(pkg.isResizeableActivityViaSdkVersion(), ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION)
                 | flag(pkg.isAllowNativeHeapPointerTagging(), ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING)
                 | flag(AndroidPackageUtils.isSystemExt(pkg), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index f3ee531..e2acc17 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -59,7 +59,7 @@
             AndroidPackage aPkg) {
         PackageImpl pkg = (PackageImpl) aPkg;
         ArrayList<String> paths = new ArrayList<>();
-        if (pkg.isHasCode()) {
+        if (pkg.isDeclaredHavingCode()) {
             paths.add(pkg.getBaseApkPath());
         }
         String[] splitCodePaths = pkg.getSplitCodePaths();
@@ -156,7 +156,7 @@
         return NativeLibraryHelper.Handle.create(
                 AndroidPackageUtils.getAllCodePaths(pkg),
                 pkg.isMultiArch(),
-                pkg.isExtractNativeLibs(),
+                pkg.isExtractNativeLibrariesRequested(),
                 pkg.isDebuggable()
         );
     }
@@ -243,7 +243,7 @@
         } else if (pkg.isSignedWithPlatformKey()) {
             isAllowedToUseHiddenApis = true;
         } else if (packageState.isSystem()) {
-            isAllowedToUseHiddenApis = pkg.isUsesNonSdkApi()
+            isAllowedToUseHiddenApis = pkg.isNonSdkApiRequested()
                     || SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(
                     pkg.getPackageName());
         } else {
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index d7c4a09..de31b46 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -793,7 +793,7 @@
                     null,
                     getBaseApkPath(),
                     getBaseRevisionCode(),
-                    isHasCode() ? ApplicationInfo.FLAG_HAS_CODE : 0,
+                    isDeclaredHavingCode() ? ApplicationInfo.FLAG_HAS_CODE : 0,
                     getClassLoaderName()
             ));
 
@@ -879,7 +879,7 @@
     }
 
     @Override
-    public int getBannerRes() {
+    public int getBannerResourceId() {
         return banner;
     }
 
@@ -934,12 +934,12 @@
     }
 
     @Override
-    public int getDataExtractionRulesRes() {
+    public int getDataExtractionRulesResourceId() {
         return dataExtractionRules;
     }
 
     @Override
-    public int getDescriptionRes() {
+    public int getDescriptionResourceId() {
         return descriptionRes;
     }
 
@@ -950,7 +950,7 @@
     }
 
     @Override
-    public int getFullBackupContentRes() {
+    public int getFullBackupContentResourceId() {
         return fullBackupContent;
     }
 
@@ -961,7 +961,7 @@
     }
 
     @Override
-    public int getIconRes() {
+    public int getIconResourceId() {
         return iconRes;
     }
 
@@ -995,7 +995,7 @@
     }
 
     @Override
-    public int getLabelRes() {
+    public int getLabelResourceId() {
         return labelRes;
     }
 
@@ -1011,12 +1011,12 @@
     }
 
     @Override
-    public int getLocaleConfigRes() {
+    public int getLocaleConfigResourceId() {
         return mLocaleConfigRes;
     }
 
     @Override
-    public int getLogoRes() {
+    public int getLogoResourceId() {
         return logo;
     }
 
@@ -1077,7 +1077,7 @@
     }
 
     @Override
-    public int getNetworkSecurityConfigRes() {
+    public int getNetworkSecurityConfigResourceId() {
         return networkSecurityConfigRes;
     }
 
@@ -1259,7 +1259,7 @@
     }
 
     @Override
-    public int getRoundIconRes() {
+    public int getRoundIconResourceId() {
         return roundIconRes;
     }
 
@@ -1287,7 +1287,7 @@
     }
 
     @Override
-    public int getSharedUserLabelRes() {
+    public int getSharedUserLabelResourceId() {
         return sharedUserLabel;
     }
 
@@ -1366,7 +1366,7 @@
     }
 
     @Override
-    public int getThemeRes() {
+    public int getThemeResourceId() {
         return theme;
     }
 
@@ -1531,17 +1531,17 @@
     }
 
     @Override
-    public boolean isAllowBackup() {
+    public boolean isBackupAllowed() {
         return getBoolean(Booleans.ALLOW_BACKUP);
     }
 
     @Override
-    public boolean isAllowClearUserData() {
+    public boolean isClearUserDataAllowed() {
         return getBoolean(Booleans.ALLOW_CLEAR_USER_DATA);
     }
 
     @Override
-    public boolean isAllowClearUserDataOnFailedRestore() {
+    public boolean isClearUserDataOnFailedRestoreAllowed() {
         return getBoolean(Booleans.ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE);
     }
 
@@ -1551,7 +1551,7 @@
     }
 
     @Override
-    public boolean isAllowTaskReparenting() {
+    public boolean isTaskReparentingAllowed() {
         return getBoolean(Booleans.ALLOW_TASK_REPARENTING);
     }
 
@@ -1574,7 +1574,7 @@
     }
 
     @Override
-    public boolean isCantSaveState() {
+    public boolean isSaveStateDisallowed() {
         return getBoolean(Booleans.CANT_SAVE_STATE);
     }
 
@@ -1609,7 +1609,7 @@
     }
 
     @Override
-    public boolean isExtractNativeLibs() {
+    public boolean isExtractNativeLibrariesRequested() {
         return getBoolean(Booleans.EXTRACT_NATIVE_LIBS);
     }
 
@@ -1629,7 +1629,7 @@
     }
 
     @Override
-    public boolean isHasCode() {
+    public boolean isDeclaredHavingCode() {
         return getBoolean(Booleans.HAS_CODE);
     }
 
@@ -1639,7 +1639,7 @@
     }
 
     @Override
-    public boolean isHasFragileUserData() {
+    public boolean isUserDataFragile() {
         return getBoolean(Booleans.HAS_FRAGILE_USER_DATA);
     }
 
@@ -1649,7 +1649,7 @@
     }
 
     @Override
-    public boolean isKillAfterRestore() {
+    public boolean isKillAfterRestoreAllowed() {
         return getBoolean(Booleans.KILL_AFTER_RESTORE);
     }
 
@@ -1746,7 +1746,7 @@
         return getBoolean(Booleans.STATIC_SHARED_LIBRARY);
     }
 
-    public boolean isSupportsExtraLargeScreens() {
+    public boolean isExtraLargeScreensSupported() {
         if (supportsExtraLargeScreens == null) {
             return targetSdkVersion >= Build.VERSION_CODES.GINGERBREAD;
         }
@@ -1754,7 +1754,7 @@
         return supportsExtraLargeScreens;
     }
 
-    public boolean isSupportsLargeScreens() {
+    public boolean isLargeScreensSupported() {
         if (supportsLargeScreens == null) {
             return targetSdkVersion >= Build.VERSION_CODES.DONUT;
         }
@@ -1762,16 +1762,16 @@
         return supportsLargeScreens;
     }
 
-    public boolean isSupportsNormalScreens() {
+    public boolean isNormalScreensSupported() {
         return supportsNormalScreens == null || supportsNormalScreens;
     }
 
     @Override
-    public boolean isSupportsRtl() {
+    public boolean isRtlSupported() {
         return getBoolean(Booleans.SUPPORTS_RTL);
     }
 
-    public boolean isSupportsSmallScreens() {
+    public boolean isSmallScreensSupported() {
         if (supportsSmallScreens == null) {
             return targetSdkVersion >= Build.VERSION_CODES.DONUT;
         }
@@ -1785,7 +1785,7 @@
     }
 
     @Override
-    public boolean isUse32BitAbi() {
+    public boolean is32BitAbiPreferred() {
         return getBoolean(Booleans.USE_32_BIT_ABI);
     }
 
@@ -1795,12 +1795,12 @@
     }
 
     @Override
-    public boolean isUsesCleartextTraffic() {
+    public boolean isCleartextTrafficAllowed() {
         return getBoolean(Booleans.USES_CLEARTEXT_TRAFFIC);
     }
 
     @Override
-    public boolean isUsesNonSdkApi() {
+    public boolean isNonSdkApiRequested() {
         return getBoolean(Booleans.USES_NON_SDK_API);
     }
 
@@ -1831,17 +1831,17 @@
     }
 
     @Override
-    public PackageImpl setAllowBackup(boolean value) {
+    public PackageImpl setBackupAllowed(boolean value) {
         return setBoolean(Booleans.ALLOW_BACKUP, value);
     }
 
     @Override
-    public PackageImpl setAllowClearUserData(boolean value) {
+    public PackageImpl setClearUserDataAllowed(boolean value) {
         return setBoolean(Booleans.ALLOW_CLEAR_USER_DATA, value);
     }
 
     @Override
-    public PackageImpl setAllowClearUserDataOnFailedRestore(boolean value) {
+    public PackageImpl setClearUserDataOnFailedRestoreAllowed(boolean value) {
         return setBoolean(Booleans.ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE, value);
     }
 
@@ -1851,7 +1851,7 @@
     }
 
     @Override
-    public PackageImpl setAllowTaskReparenting(boolean value) {
+    public PackageImpl setTaskReparentingAllowed(boolean value) {
         return setBoolean(Booleans.ALLOW_TASK_REPARENTING, value);
     }
 
@@ -1895,7 +1895,7 @@
     }
 
     @Override
-    public PackageImpl setBannerRes(int value) {
+    public PackageImpl setBannerResourceId(int value) {
         banner = value;
         return this;
     }
@@ -1912,7 +1912,7 @@
     }
 
     @Override
-    public PackageImpl setCantSaveState(boolean value) {
+    public PackageImpl setSaveStateDisallowed(boolean value) {
         return setBoolean(Booleans.CANT_SAVE_STATE, value);
     }
 
@@ -1958,7 +1958,7 @@
     }
 
     @Override
-    public PackageImpl setDataExtractionRulesRes(int value) {
+    public PackageImpl setDataExtractionRulesResourceId(int value) {
         dataExtractionRules = value;
         return this;
     }
@@ -1969,7 +1969,7 @@
     }
 
     @Override
-    public PackageImpl setDescriptionRes(int value) {
+    public PackageImpl setDescriptionResourceId(int value) {
         descriptionRes = value;
         return this;
     }
@@ -1985,7 +1985,7 @@
     }
 
     @Override
-    public PackageImpl setExtractNativeLibs(boolean value) {
+    public PackageImpl setExtractNativeLibrariesRequested(boolean value) {
         return setBoolean(Booleans.EXTRACT_NATIVE_LIBS, value);
     }
 
@@ -1995,7 +1995,7 @@
     }
 
     @Override
-    public PackageImpl setFullBackupContentRes(int value) {
+    public PackageImpl setFullBackupContentResourceId(int value) {
         fullBackupContent = value;
         return this;
     }
@@ -2017,7 +2017,7 @@
     }
 
     @Override
-    public PackageImpl setHasCode(boolean value) {
+    public PackageImpl setDeclaredHavingCode(boolean value) {
         return setBoolean(Booleans.HAS_CODE, value);
     }
 
@@ -2027,12 +2027,12 @@
     }
 
     @Override
-    public PackageImpl setHasFragileUserData(boolean value) {
+    public PackageImpl setUserDataFragile(boolean value) {
         return setBoolean(Booleans.HAS_FRAGILE_USER_DATA, value);
     }
 
     @Override
-    public PackageImpl setIconRes(int value) {
+    public PackageImpl setIconResourceId(int value) {
         iconRes = value;
         return this;
     }
@@ -2049,7 +2049,7 @@
     }
 
     @Override
-    public PackageImpl setKillAfterRestore(boolean value) {
+    public PackageImpl setKillAfterRestoreAllowed(boolean value) {
         return setBoolean(Booleans.KILL_AFTER_RESTORE, value);
     }
 
@@ -2060,7 +2060,7 @@
     }
 
     @Override
-    public PackageImpl setLabelRes(int value) {
+    public PackageImpl setLabelResourceId(int value) {
         labelRes = value;
         return this;
     }
@@ -2082,13 +2082,13 @@
     }
 
     @Override
-    public PackageImpl setLocaleConfigRes(int value) {
+    public PackageImpl setLocaleConfigResourceId(int value) {
         mLocaleConfigRes = value;
         return this;
     }
 
     @Override
-    public PackageImpl setLogoRes(int value) {
+    public PackageImpl setLogoResourceId(int value) {
         logo = value;
         return this;
     }
@@ -2154,7 +2154,7 @@
     }
 
     @Override
-    public PackageImpl setNetworkSecurityConfigRes(int value) {
+    public PackageImpl setNetworkSecurityConfigResourceId(int value) {
         networkSecurityConfigRes = value;
         return this;
     }
@@ -2318,7 +2318,7 @@
     }
 
     @Override
-    public PackageImpl setRoundIconRes(int value) {
+    public PackageImpl setRoundIconResourceId(int value) {
         roundIconRes = value;
         return this;
     }
@@ -2347,7 +2347,7 @@
     }
 
     @Override
-    public PackageImpl setSharedUserLabelRes(int value) {
+    public PackageImpl setSharedUserLabelResourceId(int value) {
         sharedUserLabel = value;
         return this;
     }
@@ -2384,7 +2384,7 @@
     }
 
     @Override
-    public PackageImpl setSupportsExtraLargeScreens(int supportsExtraLargeScreens) {
+    public PackageImpl setExtraLargeScreensSupported(int supportsExtraLargeScreens) {
         if (supportsExtraLargeScreens == 1) {
             return this;
         }
@@ -2394,7 +2394,7 @@
     }
 
     @Override
-    public PackageImpl setSupportsLargeScreens(int supportsLargeScreens) {
+    public PackageImpl setLargeScreensSupported(int supportsLargeScreens) {
         if (supportsLargeScreens == 1) {
             return this;
         }
@@ -2404,7 +2404,7 @@
     }
 
     @Override
-    public PackageImpl setSupportsNormalScreens(int supportsNormalScreens) {
+    public PackageImpl setNormalScreensSupported(int supportsNormalScreens) {
         if (supportsNormalScreens == 1) {
             return this;
         }
@@ -2414,12 +2414,12 @@
     }
 
     @Override
-    public PackageImpl setSupportsRtl(boolean value) {
+    public PackageImpl setRtlSupported(boolean value) {
         return setBoolean(Booleans.SUPPORTS_RTL, value);
     }
 
     @Override
-    public PackageImpl setSupportsSmallScreens(int supportsSmallScreens) {
+    public PackageImpl setSmallScreensSupported(int supportsSmallScreens) {
         if (supportsSmallScreens == 1) {
             return this;
         }
@@ -2452,7 +2452,7 @@
     }
 
     @Override
-    public PackageImpl setThemeRes(int value) {
+    public PackageImpl setThemeResourceId(int value) {
         theme = value;
         return this;
     }
@@ -2470,7 +2470,7 @@
     }
 
     @Override
-    public PackageImpl setUse32BitAbi(boolean value) {
+    public PackageImpl set32BitAbiPreferred(boolean value) {
         return setBoolean(Booleans.USE_32_BIT_ABI, value);
     }
 
@@ -2480,12 +2480,12 @@
     }
 
     @Override
-    public PackageImpl setUsesCleartextTraffic(boolean value) {
+    public PackageImpl setCleartextTrafficAllowed(boolean value) {
         return setBoolean(Booleans.USES_CLEARTEXT_TRAFFIC, value);
     }
 
     @Override
-    public PackageImpl setUsesNonSdkApi(boolean value) {
+    public PackageImpl setNonSdkApiRequested(boolean value) {
         return setBoolean(Booleans.USES_NON_SDK_API, value);
     }
 
diff --git a/services/core/java/com/android/server/pm/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
index ad73873..2fdda12 100644
--- a/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -116,7 +116,7 @@
      * @see R.styleable#AndroidManifestApplication_banner
      */
     @DrawableRes
-    int getBannerRes();
+    int getBannerResourceId();
 
     /**
      * @see PackageInfo#baseRevisionCode
@@ -149,21 +149,21 @@
      * @see R.styleable#AndroidManifestApplication_dataExtractionRules
      */
     @XmlRes
-    int getDataExtractionRulesRes();
+    int getDataExtractionRulesResourceId();
 
     /**
      * @see ApplicationInfo#descriptionRes
      * @see R.styleable#AndroidManifestApplication_description
      */
     @StringRes // This is actually format="reference"
-    int getDescriptionRes();
+    int getDescriptionResourceId();
 
     /**
      * @see ApplicationInfo#fullBackupContent
      * @see R.styleable#AndroidManifestApplication_fullBackupContent
      */
     @XmlRes
-    int getFullBackupContentRes();
+    int getFullBackupContentResourceId();
 
     /**
      * @see ApplicationInfo#getGwpAsanMode()
@@ -177,14 +177,14 @@
      * @see R.styleable#AndroidManifestApplication_icon
      */
     @DrawableRes
-    int getIconRes();
+    int getIconResourceId();
 
     /**
      * @see ApplicationInfo#labelRes
      * @see R.styleable#AndroidManifestApplication_label
      */
     @StringRes
-    int getLabelRes();
+    int getLabelResourceId();
 
     /**
      * @see ApplicationInfo#largestWidthLimitDp
@@ -206,7 +206,7 @@
      * @see R.styleable#AndroidManifestApplication_logo
      */
     @DrawableRes
-    int getLogoRes();
+    int getLogoResourceId();
 
     /**
      * The resource ID used to provide the application's locales configuration.
@@ -214,7 +214,7 @@
      * @see R.styleable#AndroidManifestApplication_localeConfig
      */
     @XmlRes
-    int getLocaleConfigRes();
+    int getLocaleConfigResourceId();
 
     /**
      * @see PackageInfo#getLongVersionCode()
@@ -247,7 +247,7 @@
      * @see R.styleable#AndroidManifestApplication_networkSecurityConfig
      */
     @XmlRes
-    int getNetworkSecurityConfigRes();
+    int getNetworkSecurityConfigResourceId();
 
     /**
      * @see PackageInfo#requiredAccountType
@@ -277,7 +277,7 @@
      * @see R.styleable#AndroidManifestApplication_roundIcon
      */
     @DrawableRes
-    int getRoundIconRes();
+    int getRoundIconResourceId();
 
     /**
      * @see R.styleable#AndroidManifestSdkLibrary_name
@@ -297,7 +297,7 @@
      * @see R.styleable#AndroidManifest_sharedUserLabel
      */
     @StringRes
-    int getSharedUserLabelRes();
+    int getSharedUserLabelResourceId();
 
     /**
      * @return List of all splits for a package. Note that base.apk is considered a
@@ -336,7 +336,7 @@
      * @see R.styleable#AndroidManifestApplication_theme
      */
     @StyleRes
-    int getThemeRes();
+    int getThemeResourceId();
 
     /**
      * @see ApplicationInfo#uiOptions
@@ -367,19 +367,19 @@
      * @see ApplicationInfo#FLAG_ALLOW_BACKUP
      * @see R.styleable#AndroidManifestApplication_allowBackup
      */
-    boolean isAllowBackup();
+    boolean isBackupAllowed();
 
     /**
      * @see ApplicationInfo#FLAG_ALLOW_CLEAR_USER_DATA
      * @see R.styleable#AndroidManifestApplication_allowClearUserData
      */
-    boolean isAllowClearUserData();
+    boolean isClearUserDataAllowed();
 
     /**
      * @see ApplicationInfo#PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE
      * @see R.styleable#AndroidManifestApplication_allowClearUserDataOnFailedRestore
      */
-    boolean isAllowClearUserDataOnFailedRestore();
+    boolean isClearUserDataOnFailedRestoreAllowed();
 
     /**
      * @see ApplicationInfo#PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING
@@ -391,7 +391,7 @@
      * @see ApplicationInfo#FLAG_ALLOW_TASK_REPARENTING
      * @see R.styleable#AndroidManifestApplication_allowTaskReparenting
      */
-    boolean isAllowTaskReparenting();
+    boolean isTaskReparentingAllowed();
 
     /**
      * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= {@link
@@ -424,7 +424,7 @@
      * @see ApplicationInfo#PRIVATE_FLAG_CANT_SAVE_STATE
      * @see R.styleable#AndroidManifestApplication_cantSaveState
      */
-    boolean isCantSaveState();
+    boolean isSaveStateDisallowed();
 
     /**
      * @see PackageInfo#coreApp
@@ -459,7 +459,7 @@
      * @see ApplicationInfo#FLAG_EXTRACT_NATIVE_LIBS
      * @see R.styleable#AndroidManifestApplication_extractNativeLibs
      */
-    boolean isExtractNativeLibs();
+    boolean isExtractNativeLibrariesRequested();
 
     /**
      * @see ApplicationInfo#FLAG_FACTORY_TEST
@@ -481,13 +481,13 @@
      * @see ApplicationInfo#FLAG_HAS_CODE
      * @see R.styleable#AndroidManifestApplication_hasCode
      */
-    boolean isHasCode();
+    boolean isDeclaredHavingCode();
 
     /**
      * @see ApplicationInfo#PRIVATE_FLAG_HAS_FRAGILE_USER_DATA
      * @see R.styleable#AndroidManifestApplication_hasFragileUserData
      */
-    boolean isHasFragileUserData();
+    boolean isUserDataFragile();
 
     /**
      * @see ApplicationInfo#PRIVATE_FLAG_ISOLATED_SPLIT_LOADING
@@ -499,7 +499,7 @@
      * @see ApplicationInfo#FLAG_KILL_AFTER_RESTORE
      * @see R.styleable#AndroidManifestApplication_killAfterRestore
      */
-    boolean isKillAfterRestore();
+    boolean isKillAfterRestoreAllowed();
 
     /**
      * @see ApplicationInfo#FLAG_LARGE_HEAP
@@ -596,7 +596,7 @@
      * @see R.styleable#AndroidManifestSupportsScreens_xlargeScreens
      * @see ApplicationInfo#FLAG_SUPPORTS_XLARGE_SCREENS
      */
-    boolean isSupportsExtraLargeScreens();
+    boolean isExtraLargeScreensSupported();
 
     /**
      * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= {@link
@@ -605,7 +605,7 @@
      * @see R.styleable#AndroidManifestSupportsScreens_largeScreens
      * @see ApplicationInfo#FLAG_SUPPORTS_LARGE_SCREENS
      */
-    boolean isSupportsLargeScreens();
+    boolean isLargeScreensSupported();
 
     /**
      * If omitted from manifest, returns true.
@@ -613,13 +613,13 @@
      * @see R.styleable#AndroidManifestSupportsScreens_normalScreens
      * @see ApplicationInfo#FLAG_SUPPORTS_NORMAL_SCREENS
      */
-    boolean isSupportsNormalScreens();
+    boolean isNormalScreensSupported();
 
     /**
      * @see ApplicationInfo#FLAG_SUPPORTS_RTL
      * @see R.styleable#AndroidManifestApplication_supportsRtl
      */
-    boolean isSupportsRtl();
+    boolean isRtlSupported();
 
     /**
      * If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= {@link
@@ -628,7 +628,7 @@
      * @see R.styleable#AndroidManifestSupportsScreens_smallScreens
      * @see ApplicationInfo#FLAG_SUPPORTS_SMALL_SCREENS
      */
-    boolean isSupportsSmallScreens();
+    boolean isSmallScreensSupported();
 
     /**
      * @see ApplicationInfo#FLAG_TEST_ONLY
@@ -643,13 +643,13 @@
      *
      * @see R.attr#use32bitAbi
      */
-    boolean isUse32BitAbi();
+    boolean is32BitAbiPreferred();
 
     /**
      * @see ApplicationInfo#FLAG_USES_CLEARTEXT_TRAFFIC
      * @see R.styleable#AndroidManifestApplication_usesCleartextTraffic
      */
-    boolean isUsesCleartextTraffic();
+    boolean isCleartextTrafficAllowed();
 
     /**
      * @see ApplicationInfo#PRIVATE_FLAG_USE_EMBEDDED_DEX
@@ -661,7 +661,7 @@
      * @see ApplicationInfo#PRIVATE_FLAG_USES_NON_SDK_API
      * @see R.styleable#AndroidManifestApplication_usesNonSdkApi
      */
-    boolean isUsesNonSdkApi();
+    boolean isNonSdkApiRequested();
 
     /**
      * @see ApplicationInfo#FLAG_VM_SAFE_MODE
@@ -892,7 +892,7 @@
 
     /**
      * If {@link R.styleable#AndroidManifestApplication_label} is a string literal, this is it.
-     * Otherwise, it's stored as {@link #getLabelRes()}.
+     * Otherwise, it's stored as {@link #getLabelResourceId()}.
      *
      * @see ApplicationInfo#nonLocalizedLabel
      * @see R.styleable#AndroidManifestApplication_label
diff --git a/services/core/java/com/android/server/pm/pkg/PackageState.java b/services/core/java/com/android/server/pm/pkg/PackageState.java
index 106b149..2c37876 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageState.java
@@ -160,6 +160,14 @@
     /**
      * List of shared libraries that this package declares a dependency on. This includes all
      * types of libraries, system or app provided and Java or native.
+     * <p/>
+     * This includes libraries declared in the manifest under the following tags:
+     * <ul>
+     *     <li>uses-library</li>
+     *     <li>uses-native-library</li>
+     *     <li>uses-sdk-library</li>
+     *     <li>uses-static-library</li>
+     * </ul>
      */
     @NonNull
     List<SharedLibrary> getSharedLibraryDependencies();
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
index b73ff34..ee793c8 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
@@ -114,7 +114,7 @@
                 return input.error(result);
             }
 
-            if (receiver && pkg.isCantSaveState()) {
+            if (receiver && pkg.isSaveStateDisallowed()) {
                 // A heavy-weight application can not have receivers in its main process
                 if (Objects.equals(activity.getProcessName(), packageName)) {
                     return input.error("Heavy-weight applications can not have receivers "
@@ -129,7 +129,7 @@
             activity.setTheme(sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0))
                     .setUiOptions(sa.getInt(R.styleable.AndroidManifestActivity_uiOptions, pkg.getUiOptions()));
 
-            activity.setFlags(activity.getFlags() | (flag(ActivityInfo.FLAG_ALLOW_TASK_REPARENTING, R.styleable.AndroidManifestActivity_allowTaskReparenting, pkg.isAllowTaskReparenting(), sa)
+            activity.setFlags(activity.getFlags() | (flag(ActivityInfo.FLAG_ALLOW_TASK_REPARENTING, R.styleable.AndroidManifestActivity_allowTaskReparenting, pkg.isTaskReparentingAllowed(), sa)
                                 | flag(ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE, R.styleable.AndroidManifestActivity_alwaysRetainTaskState, sa)
                                 | flag(ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH, R.styleable.AndroidManifestActivity_clearTaskOnLaunch, sa)
                                 | flag(ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS, R.styleable.AndroidManifestActivity_excludeFromRecents, sa)
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
index 4cb4dd0..37bed15 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
@@ -136,7 +136,7 @@
             sa.recycle();
         }
 
-        if (pkg.isCantSaveState()) {
+        if (pkg.isSaveStateDisallowed()) {
             // A heavy-weight application can not have providers in its main process
             if (Objects.equals(provider.getProcessName(), packageName)) {
                 return input.error("Heavy-weight applications can not have providers"
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
index a812257..c15266f 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
@@ -115,7 +115,7 @@
             sa.recycle();
         }
 
-        if (pkg.isCantSaveState()) {
+        if (pkg.isSaveStateDisallowed()) {
             // A heavy-weight application can not have services in its main process
             // We can do direct compare because we intern all strings.
             if (Objects.equals(service.getProcessName(), packageName)) {
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index bb36758..6cb6a97 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -163,19 +163,20 @@
 
     ParsingPackage setAllowAudioPlaybackCapture(boolean allowAudioPlaybackCapture);
 
-    ParsingPackage setAllowBackup(boolean allowBackup);
+    ParsingPackage setBackupAllowed(boolean allowBackup);
 
-    ParsingPackage setAllowClearUserData(boolean allowClearUserData);
+    ParsingPackage setClearUserDataAllowed(boolean allowClearUserData);
 
-    ParsingPackage setAllowClearUserDataOnFailedRestore(boolean allowClearUserDataOnFailedRestore);
+    ParsingPackage setClearUserDataOnFailedRestoreAllowed(
+            boolean allowClearUserDataOnFailedRestore);
 
-    ParsingPackage setAllowTaskReparenting(boolean allowTaskReparenting);
+    ParsingPackage setTaskReparentingAllowed(boolean allowTaskReparenting);
 
     ParsingPackage setResourceOverlay(boolean isResourceOverlay);
 
     ParsingPackage setBackupInForeground(boolean backupInForeground);
 
-    ParsingPackage setCantSaveState(boolean cantSaveState);
+    ParsingPackage setSaveStateDisallowed(boolean cantSaveState);
 
     ParsingPackage setDebuggable(boolean debuggable);
 
@@ -185,19 +186,19 @@
 
     ParsingPackage setExternalStorage(boolean externalStorage);
 
-    ParsingPackage setExtractNativeLibs(boolean extractNativeLibs);
+    ParsingPackage setExtractNativeLibrariesRequested(boolean extractNativeLibs);
 
     ParsingPackage setFullBackupOnly(boolean fullBackupOnly);
 
-    ParsingPackage setHasCode(boolean hasCode);
+    ParsingPackage setDeclaredHavingCode(boolean hasCode);
 
-    ParsingPackage setHasFragileUserData(boolean hasFragileUserData);
+    ParsingPackage setUserDataFragile(boolean hasFragileUserData);
 
     ParsingPackage setGame(boolean isGame);
 
     ParsingPackage setIsolatedSplitLoading(boolean isolatedSplitLoading);
 
-    ParsingPackage setKillAfterRestore(boolean killAfterRestore);
+    ParsingPackage setKillAfterRestoreAllowed(boolean killAfterRestore);
 
     ParsingPackage setLargeHeap(boolean largeHeap);
 
@@ -231,15 +232,15 @@
 
     ParsingPackage setStaticSharedLibrary(boolean staticSharedLibrary);
 
-    ParsingPackage setSupportsRtl(boolean supportsRtl);
+    ParsingPackage setRtlSupported(boolean supportsRtl);
 
     ParsingPackage setTestOnly(boolean testOnly);
 
     ParsingPackage setUseEmbeddedDex(boolean useEmbeddedDex);
 
-    ParsingPackage setUsesCleartextTraffic(boolean usesCleartextTraffic);
+    ParsingPackage setCleartextTrafficAllowed(boolean usesCleartextTraffic);
 
-    ParsingPackage setUsesNonSdkApi(boolean usesNonSdkApi);
+    ParsingPackage setNonSdkApiRequested(boolean usesNonSdkApi);
 
     ParsingPackage setVisibleToInstantApps(boolean visibleToInstantApps);
 
@@ -255,7 +256,7 @@
 
     ParsingPackage setBackupAgentName(String backupAgentName);
 
-    ParsingPackage setBannerRes(int banner);
+    ParsingPackage setBannerResourceId(int banner);
 
     ParsingPackage setCategory(int category);
 
@@ -265,7 +266,7 @@
 
     ParsingPackage setCompatibleWidthLimitDp(int compatibleWidthLimitDp);
 
-    ParsingPackage setDescriptionRes(int descriptionRes);
+    ParsingPackage setDescriptionResourceId(int descriptionRes);
 
     ParsingPackage setEnabled(boolean enabled);
 
@@ -281,24 +282,24 @@
 
     ParsingPackage setCrossProfile(boolean crossProfile);
 
-    ParsingPackage setFullBackupContentRes(int fullBackupContentRes);
+    ParsingPackage setFullBackupContentResourceId(int fullBackupContentRes);
 
-    ParsingPackage setDataExtractionRulesRes(int dataExtractionRulesRes);
+    ParsingPackage setDataExtractionRulesResourceId(int dataExtractionRulesRes);
 
     ParsingPackage setHasDomainUrls(boolean hasDomainUrls);
 
-    ParsingPackage setIconRes(int iconRes);
+    ParsingPackage setIconResourceId(int iconRes);
 
     ParsingPackage setInstallLocation(int installLocation);
 
     /** @see R#styleable.AndroidManifest_sharedUserMaxSdkVersion */
     ParsingPackage setLeavingSharedUser(boolean leavingSharedUser);
 
-    ParsingPackage setLabelRes(int labelRes);
+    ParsingPackage setLabelResourceId(int labelRes);
 
     ParsingPackage setLargestWidthLimitDp(int largestWidthLimitDp);
 
-    ParsingPackage setLogoRes(int logo);
+    ParsingPackage setLogoResourceId(int logo);
 
     ParsingPackage setManageSpaceActivityName(String manageSpaceActivityName);
 
@@ -308,7 +309,7 @@
 
     ParsingPackage setMaxSdkVersion(int maxSdkVersion);
 
-    ParsingPackage setNetworkSecurityConfigRes(int networkSecurityConfigRes);
+    ParsingPackage setNetworkSecurityConfigResourceId(int networkSecurityConfigRes);
 
     ParsingPackage setNonLocalizedLabel(CharSequence nonLocalizedLabel);
 
@@ -334,9 +335,9 @@
 
     ParsingPackage setRestrictedAccountType(String restrictedAccountType);
 
-    ParsingPackage setRoundIconRes(int roundIconRes);
+    ParsingPackage setRoundIconResourceId(int roundIconRes);
 
-    ParsingPackage setSharedUserLabelRes(int sharedUserLabelRes);
+    ParsingPackage setSharedUserLabelResourceId(int sharedUserLabelRes);
 
     ParsingPackage setSigningDetails(@NonNull SigningDetails signingDetails);
 
@@ -344,23 +345,23 @@
 
     ParsingPackage setStaticSharedLibraryVersion(long staticSharedLibraryVersion);
 
-    ParsingPackage setSupportsLargeScreens(int supportsLargeScreens);
+    ParsingPackage setLargeScreensSupported(int supportsLargeScreens);
 
-    ParsingPackage setSupportsNormalScreens(int supportsNormalScreens);
+    ParsingPackage setNormalScreensSupported(int supportsNormalScreens);
 
-    ParsingPackage setSupportsSmallScreens(int supportsSmallScreens);
+    ParsingPackage setSmallScreensSupported(int supportsSmallScreens);
 
-    ParsingPackage setSupportsExtraLargeScreens(int supportsExtraLargeScreens);
+    ParsingPackage setExtraLargeScreensSupported(int supportsExtraLargeScreens);
 
     ParsingPackage setTargetSandboxVersion(int targetSandboxVersion);
 
-    ParsingPackage setThemeRes(int theme);
+    ParsingPackage setThemeResourceId(int theme);
 
     ParsingPackage setRequestForegroundServiceExemption(boolean requestForegroundServiceExemption);
 
     ParsingPackage setUpgradeKeySets(@NonNull Set<String> upgradeKeySets);
 
-    ParsingPackage setUse32BitAbi(boolean use32BitAbi);
+    ParsingPackage set32BitAbiPreferred(boolean use32BitAbi);
 
     ParsingPackage setVolumeUuid(@Nullable String volumeUuid);
 
@@ -385,7 +386,7 @@
     ParsingPackage setResetEnabledSettingsOnAppDataCleared(
             boolean resetEnabledSettingsOnAppDataCleared);
 
-    ParsingPackage setLocaleConfigRes(int localeConfigRes);
+    ParsingPackage setLocaleConfigResourceId(int localeConfigRes);
 
     ParsingPackage setAllowUpdateOwnership(boolean value);
 
@@ -508,15 +509,15 @@
     @Nullable
     String getZygotePreloadName();
 
-    boolean isAllowBackup();
+    boolean isBackupAllowed();
 
-    boolean isAllowTaskReparenting();
+    boolean isTaskReparentingAllowed();
 
     boolean isAnyDensity();
 
     boolean isHardwareAccelerated();
 
-    boolean isCantSaveState();
+    boolean isSaveStateDisallowed();
 
     boolean isProfileable();
 
@@ -528,11 +529,11 @@
 
     boolean isStaticSharedLibrary();
 
-    boolean isSupportsExtraLargeScreens();
+    boolean isExtraLargeScreensSupported();
 
-    boolean isSupportsLargeScreens();
+    boolean isLargeScreensSupported();
 
-    boolean isSupportsNormalScreens();
+    boolean isNormalScreensSupported();
 
-    boolean isSupportsSmallScreens();
+    boolean isSmallScreensSupported();
 }
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index 31f291f..fda44e4 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -430,7 +430,7 @@
                 }
             }
 
-            pkg.setUse32BitAbi(lite.isUse32bitAbi());
+            pkg.set32BitAbiPreferred(lite.isUse32bitAbi());
             return input.success(pkg);
         } catch (IllegalArgumentException e) {
             return input.error(e.getCause() instanceof IOException ? INSTALL_FAILED_INVALID_APK
@@ -466,7 +466,7 @@
             }
 
             return input.success(result.getResult()
-                    .setUse32BitAbi(lite.isUse32bitAbi()));
+                    .set32BitAbiPreferred(lite.isUse32bitAbi()));
         } catch (IOException e) {
             return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                     "Failed to get path: " + apkFile, e);
@@ -957,10 +957,10 @@
         // cannot be windowed / resized. Note that an SDK version of 0 is common for
         // pre-Doughnut applications.
         if (pkg.getTargetSdkVersion() < DONUT
-                || (!pkg.isSupportsSmallScreens()
-                && !pkg.isSupportsNormalScreens()
-                && !pkg.isSupportsLargeScreens()
-                && !pkg.isSupportsExtraLargeScreens()
+                || (!pkg.isSmallScreensSupported()
+                && !pkg.isNormalScreensSupported()
+                && !pkg.isLargeScreensSupported()
+                && !pkg.isExtraLargeScreensSupported()
                 && !pkg.isResizeable()
                 && !pkg.isAnyDensity())) {
             adjustPackageToBeUnresizeableAndUnpipable(pkg);
@@ -1052,7 +1052,8 @@
         return input.success(pkg
                 .setLeavingSharedUser(leaving)
                 .setSharedUserId(str.intern())
-                .setSharedUserLabelRes(resId(R.styleable.AndroidManifest_sharedUserLabel, sa)));
+                .setSharedUserLabelResourceId(
+                        resId(R.styleable.AndroidManifest_sharedUserLabel, sa)));
     }
 
     private static ParseResult<ParsingPackage> parseKeySets(ParseInput input,
@@ -1885,7 +1886,7 @@
 
             TypedValue labelValue = sa.peekValue(R.styleable.AndroidManifestApplication_label);
             if (labelValue != null) {
-                pkg.setLabelRes(labelValue.resourceId);
+                pkg.setLabelResourceId(labelValue.resourceId);
                 if (labelValue.resourceId == 0) {
                     pkg.setNonLocalizedLabel(labelValue.coerceToString());
                 }
@@ -1906,7 +1907,7 @@
                 pkg.setManageSpaceActivityName(manageSpaceActivityName);
             }
 
-            if (pkg.isAllowBackup()) {
+            if (pkg.isBackupAllowed()) {
                 // backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
                 // and restoreAnyVersion are only relevant if backup is possible for the
                 // given application.
@@ -1924,7 +1925,7 @@
                     }
 
                     pkg.setBackupAgentName(backupAgentName)
-                            .setKillAfterRestore(bool(true,
+                            .setKillAfterRestoreAllowed(bool(true,
                                     R.styleable.AndroidManifestApplication_killAfterRestore, sa))
                             .setRestoreAnyVersion(bool(false,
                                     R.styleable.AndroidManifestApplication_restoreAnyVersion, sa))
@@ -1950,7 +1951,7 @@
                         fullBackupContent = v.data == 0 ? -1 : 0;
                     }
 
-                    pkg.setFullBackupContentRes(fullBackupContent);
+                    pkg.setFullBackupContentResourceId(fullBackupContent);
                 }
                 if (DEBUG_BACKUP) {
                     Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName);
@@ -2024,7 +2025,7 @@
             String processName = processNameResult.getResult();
             pkg.setProcessName(processName);
 
-            if (pkg.isCantSaveState()) {
+            if (pkg.isSaveStateDisallowed()) {
                 // A heavy-weight application can not be in a custom process.
                 // We can do direct compare because we intern all strings.
                 if (processName != null && !processName.equals(pkgName)) {
@@ -2224,31 +2225,31 @@
         // CHECKSTYLE:off
         pkg
                 // Default true
-                .setAllowBackup(bool(true, R.styleable.AndroidManifestApplication_allowBackup, sa))
-                .setAllowClearUserData(bool(true, R.styleable.AndroidManifestApplication_allowClearUserData, sa))
-                .setAllowClearUserDataOnFailedRestore(bool(true, R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore, sa))
+                .setBackupAllowed(bool(true, R.styleable.AndroidManifestApplication_allowBackup, sa))
+                .setClearUserDataAllowed(bool(true, R.styleable.AndroidManifestApplication_allowClearUserData, sa))
+                .setClearUserDataOnFailedRestoreAllowed(bool(true, R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore, sa))
                 .setAllowNativeHeapPointerTagging(bool(true, R.styleable.AndroidManifestApplication_allowNativeHeapPointerTagging, sa))
                 .setEnabled(bool(true, R.styleable.AndroidManifestApplication_enabled, sa))
-                .setExtractNativeLibs(bool(true, R.styleable.AndroidManifestApplication_extractNativeLibs, sa))
-                .setHasCode(bool(true, R.styleable.AndroidManifestApplication_hasCode, sa))
+                .setExtractNativeLibrariesRequested(bool(true, R.styleable.AndroidManifestApplication_extractNativeLibs, sa))
+                .setDeclaredHavingCode(bool(true, R.styleable.AndroidManifestApplication_hasCode, sa))
                 // Default false
-                .setAllowTaskReparenting(bool(false, R.styleable.AndroidManifestApplication_allowTaskReparenting, sa))
-                .setCantSaveState(bool(false, R.styleable.AndroidManifestApplication_cantSaveState, sa))
+                .setTaskReparentingAllowed(bool(false, R.styleable.AndroidManifestApplication_allowTaskReparenting, sa))
+                .setSaveStateDisallowed(bool(false, R.styleable.AndroidManifestApplication_cantSaveState, sa))
                 .setCrossProfile(bool(false, R.styleable.AndroidManifestApplication_crossProfile, sa))
                 .setDebuggable(bool(false, R.styleable.AndroidManifestApplication_debuggable, sa))
                 .setDefaultToDeviceProtectedStorage(bool(false, R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage, sa))
                 .setDirectBootAware(bool(false, R.styleable.AndroidManifestApplication_directBootAware, sa))
                 .setForceQueryable(bool(false, R.styleable.AndroidManifestApplication_forceQueryable, sa))
                 .setGame(bool(false, R.styleable.AndroidManifestApplication_isGame, sa))
-                .setHasFragileUserData(bool(false, R.styleable.AndroidManifestApplication_hasFragileUserData, sa))
+                .setUserDataFragile(bool(false, R.styleable.AndroidManifestApplication_hasFragileUserData, sa))
                 .setLargeHeap(bool(false, R.styleable.AndroidManifestApplication_largeHeap, sa))
                 .setMultiArch(bool(false, R.styleable.AndroidManifestApplication_multiArch, sa))
                 .setPreserveLegacyExternalStorage(bool(false, R.styleable.AndroidManifestApplication_preserveLegacyExternalStorage, sa))
                 .setRequiredForAllUsers(bool(false, R.styleable.AndroidManifestApplication_requiredForAllUsers, sa))
-                .setSupportsRtl(bool(false, R.styleable.AndroidManifestApplication_supportsRtl, sa))
+                .setRtlSupported(bool(false, R.styleable.AndroidManifestApplication_supportsRtl, sa))
                 .setTestOnly(bool(false, R.styleable.AndroidManifestApplication_testOnly, sa))
                 .setUseEmbeddedDex(bool(false, R.styleable.AndroidManifestApplication_useEmbeddedDex, sa))
-                .setUsesNonSdkApi(bool(false, R.styleable.AndroidManifestApplication_usesNonSdkApi, sa))
+                .setNonSdkApiRequested(bool(false, R.styleable.AndroidManifestApplication_usesNonSdkApi, sa))
                 .setVmSafeMode(bool(false, R.styleable.AndroidManifestApplication_vmSafeMode, sa))
                 .setAutoRevokePermissions(anInt(R.styleable.AndroidManifestApplication_autoRevokePermissions, sa))
                 .setAttributionsAreUserVisible(bool(false, R.styleable.AndroidManifestApplication_attributionsAreUserVisible, sa))
@@ -2260,7 +2261,7 @@
                 .setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa))
                 .setHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa))
                 .setRequestLegacyExternalStorage(bool(targetSdk < Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_requestLegacyExternalStorage, sa))
-                .setUsesCleartextTraffic(bool(targetSdk < Build.VERSION_CODES.P, R.styleable.AndroidManifestApplication_usesCleartextTraffic, sa))
+                .setCleartextTrafficAllowed(bool(targetSdk < Build.VERSION_CODES.P, R.styleable.AndroidManifestApplication_usesCleartextTraffic, sa))
                 // Ints Default 0
                 .setUiOptions(anInt(R.styleable.AndroidManifestApplication_uiOptions, sa))
                 // Ints
@@ -2269,16 +2270,16 @@
                 .setMaxAspectRatio(aFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, sa))
                 .setMinAspectRatio(aFloat(R.styleable.AndroidManifestApplication_minAspectRatio, sa))
                 // Resource ID
-                .setBannerRes(resId(R.styleable.AndroidManifestApplication_banner, sa))
-                .setDescriptionRes(resId(R.styleable.AndroidManifestApplication_description, sa))
-                .setIconRes(resId(R.styleable.AndroidManifestApplication_icon, sa))
-                .setLogoRes(resId(R.styleable.AndroidManifestApplication_logo, sa))
-                .setNetworkSecurityConfigRes(resId(R.styleable.AndroidManifestApplication_networkSecurityConfig, sa))
-                .setRoundIconRes(resId(R.styleable.AndroidManifestApplication_roundIcon, sa))
-                .setThemeRes(resId(R.styleable.AndroidManifestApplication_theme, sa))
-                .setDataExtractionRulesRes(
+                .setBannerResourceId(resId(R.styleable.AndroidManifestApplication_banner, sa))
+                .setDescriptionResourceId(resId(R.styleable.AndroidManifestApplication_description, sa))
+                .setIconResourceId(resId(R.styleable.AndroidManifestApplication_icon, sa))
+                .setLogoResourceId(resId(R.styleable.AndroidManifestApplication_logo, sa))
+                .setNetworkSecurityConfigResourceId(resId(R.styleable.AndroidManifestApplication_networkSecurityConfig, sa))
+                .setRoundIconResourceId(resId(R.styleable.AndroidManifestApplication_roundIcon, sa))
+                .setThemeResourceId(resId(R.styleable.AndroidManifestApplication_theme, sa))
+                .setDataExtractionRulesResourceId(
                         resId(R.styleable.AndroidManifestApplication_dataExtractionRules, sa))
-                .setLocaleConfigRes(resId(R.styleable.AndroidManifestApplication_localeConfig, sa))
+                .setLocaleConfigResourceId(resId(R.styleable.AndroidManifestApplication_localeConfig, sa))
                 // Strings
                 .setClassLoaderName(string(R.styleable.AndroidManifestApplication_classLoader, sa))
                 .setRequiredAccountType(string(R.styleable.AndroidManifestApplication_requiredAccountType, sa))
@@ -2883,13 +2884,13 @@
             // This is a trick to get a boolean and still able to detect
             // if a value was actually set.
             return input.success(pkg
-                    .setSupportsSmallScreens(
+                    .setSmallScreensSupported(
                             anInt(1, R.styleable.AndroidManifestSupportsScreens_smallScreens, sa))
-                    .setSupportsNormalScreens(
+                    .setNormalScreensSupported(
                             anInt(1, R.styleable.AndroidManifestSupportsScreens_normalScreens, sa))
-                    .setSupportsLargeScreens(
+                    .setLargeScreensSupported(
                             anInt(1, R.styleable.AndroidManifestSupportsScreens_largeScreens, sa))
-                    .setSupportsExtraLargeScreens(
+                    .setExtraLargeScreensSupported(
                             anInt(1, R.styleable.AndroidManifestSupportsScreens_xlargeScreens, sa))
                     .setResizeable(
                             anInt(1, R.styleable.AndroidManifestSupportsScreens_resizeable, sa))
diff --git a/services/core/java/com/android/server/power/LowPowerStandbyController.java b/services/core/java/com/android/server/power/LowPowerStandbyController.java
index 0dc5f76..f248a02 100644
--- a/services/core/java/com/android/server/power/LowPowerStandbyController.java
+++ b/services/core/java/com/android/server/power/LowPowerStandbyController.java
@@ -19,7 +19,6 @@
 import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST;
 import static android.os.PowerManager.lowPowerStandbyAllowedReasonsToString;
 
-import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AlarmManager;
@@ -692,8 +691,7 @@
         final Intent intent = new Intent(
                 PowerManager.ACTION_LOW_POWER_STANDBY_POLICY_CHANGED);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
-        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
-                Manifest.permission.MANAGE_LOW_POWER_STANDBY);
+        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
     }
 
     private void onStandbyTimeoutExpired() {
@@ -812,7 +810,7 @@
         }
     }
 
-    @NonNull
+    @Nullable
     LowPowerStandbyPolicy getPolicy() {
         synchronized (mLock) {
             if (!mSupportedConfig) {
@@ -914,20 +912,22 @@
             final int[] allowlistUids = getAllowlistUidsLocked();
             ipw.print("Allowed UIDs=");
             ipw.println(Arrays.toString(allowlistUids));
-            ipw.println();
 
             final LowPowerStandbyPolicy policy = getPolicy();
-            ipw.println("mPolicy:");
-            ipw.increaseIndent();
-            ipw.print("mIdentifier=");
-            ipw.println(policy.getIdentifier());
-            ipw.print("mExemptPackages=");
-            ipw.println(String.join(",", policy.getExemptPackages()));
-            ipw.print("mAllowedReasons=");
-            ipw.println(lowPowerStandbyAllowedReasonsToString(policy.getAllowedReasons()));
-            ipw.print("mAllowedFeatures=");
-            ipw.println(String.join(",", policy.getAllowedFeatures()));
-            ipw.decreaseIndent();
+            if (policy != null) {
+                ipw.println();
+                ipw.println("mPolicy:");
+                ipw.increaseIndent();
+                ipw.print("mIdentifier=");
+                ipw.println(policy.getIdentifier());
+                ipw.print("mExemptPackages=");
+                ipw.println(String.join(",", policy.getExemptPackages()));
+                ipw.print("mAllowedReasons=");
+                ipw.println(lowPowerStandbyAllowedReasonsToString(policy.getAllowedReasons()));
+                ipw.print("mAllowedFeatures=");
+                ipw.println(String.join(",", policy.getAllowedFeatures()));
+                ipw.decreaseIndent();
+            }
 
             ipw.println();
             ipw.println("UID allowed reasons:");
@@ -967,17 +967,19 @@
                 proto.write(LowPowerStandbyControllerDumpProto.ALLOWLIST, appId);
             }
 
-            long policyToken = proto.start(LowPowerStandbyControllerDumpProto.POLICY);
             final LowPowerStandbyPolicy policy = getPolicy();
-            proto.write(LowPowerStandbyPolicyProto.IDENTIFIER, policy.getIdentifier());
-            for (String exemptPackage : policy.getExemptPackages()) {
-                proto.write(LowPowerStandbyPolicyProto.EXEMPT_PACKAGES, exemptPackage);
+            if (policy != null) {
+                long policyToken = proto.start(LowPowerStandbyControllerDumpProto.POLICY);
+                proto.write(LowPowerStandbyPolicyProto.IDENTIFIER, policy.getIdentifier());
+                for (String exemptPackage : policy.getExemptPackages()) {
+                    proto.write(LowPowerStandbyPolicyProto.EXEMPT_PACKAGES, exemptPackage);
+                }
+                proto.write(LowPowerStandbyPolicyProto.ALLOWED_REASONS, policy.getAllowedReasons());
+                for (String feature : policy.getAllowedFeatures()) {
+                    proto.write(LowPowerStandbyPolicyProto.ALLOWED_FEATURES, feature);
+                }
+                proto.end(policyToken);
             }
-            proto.write(LowPowerStandbyPolicyProto.ALLOWED_REASONS, policy.getAllowedReasons());
-            for (String feature : policy.getAllowedFeatures()) {
-                proto.write(LowPowerStandbyPolicyProto.ALLOWED_FEATURES, feature);
-            }
-            proto.end(policyToken);
             proto.end(token);
         }
     }
@@ -1047,6 +1049,9 @@
                     "Adding to allowlist: uid=" + uid + ", allowedReason=" + allowedReason);
         }
         synchronized (mLock) {
+            if (!mSupportedConfig) {
+                return;
+            }
             if (allowedReason != 0 && !hasAllowedReasonLocked(uid, allowedReason)) {
                 addAllowedReasonLocked(uid, allowedReason);
                 if ((getPolicy().getAllowedReasons() & allowedReason) != 0) {
@@ -1062,6 +1067,9 @@
             Slog.i(TAG, "Removing from allowlist: uid=" + uid + ", allowedReason=" + allowedReason);
         }
         synchronized (mLock) {
+            if (!mSupportedConfig) {
+                return;
+            }
             if (allowedReason != 0 && hasAllowedReasonLocked(uid, allowedReason)) {
                 removeAllowedReasonLocked(uid, allowedReason);
                 if ((getPolicy().getAllowedReasons() & allowedReason) != 0) {
@@ -1077,6 +1085,9 @@
         final PackageManager packageManager = mContext.getPackageManager();
         final LowPowerStandbyPolicy policy = getPolicy();
         final List<Integer> appIds = new ArrayList<>();
+        if (policy == null) {
+            return appIds;
+        }
 
         for (String packageName : policy.getExemptPackages()) {
             try {
@@ -1100,6 +1111,9 @@
         final List<UserHandle> userHandles = userManager.getUserHandles(true);
         final ArraySet<Integer> uids = new ArraySet<>(mUidAllowedReasons.size());
         final LowPowerStandbyPolicy policy = getPolicy();
+        if (policy == null) {
+            return new int[0];
+        }
 
         final int policyAllowedReasons = policy.getAllowedReasons();
         for (int i = 0; i < mUidAllowedReasons.size(); i++) {
diff --git a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
index e148a48..4839c96 100644
--- a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
+++ b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
@@ -233,7 +233,9 @@
 
     void checkRecognitionSupport(
             Intent recognizerIntent,
+            AttributionSource attributionSource,
             IRecognitionSupportCallback callback) {
+
         if (!mConnected) {
             try {
                 callback.onError(SpeechRecognizer.ERROR_SERVER_DISCONNECTED);
@@ -243,15 +245,16 @@
             }
             return;
         }
-        run(service -> service.checkRecognitionSupport(recognizerIntent, callback));
+        run(service ->
+                service.checkRecognitionSupport(recognizerIntent, attributionSource, callback));
     }
 
-    void triggerModelDownload(Intent recognizerIntent) {
+    void triggerModelDownload(Intent recognizerIntent, AttributionSource attributionSource) {
         if (!mConnected) {
             Slog.e(TAG, "#downloadModel failed due to connection.");
             return;
         }
-        run(service -> service.triggerModelDownload(recognizerIntent));
+        run(service -> service.triggerModelDownload(recognizerIntent, attributionSource));
     }
 
     void shutdown(IBinder clientToken) {
diff --git a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
index e245c08..6aa600a 100644
--- a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
@@ -183,13 +183,17 @@
                         @Override
                         public void checkRecognitionSupport(
                                 Intent recognizerIntent,
+                                AttributionSource attributionSource,
                                 IRecognitionSupportCallback callback) {
-                            service.checkRecognitionSupport(recognizerIntent, callback);
+                            service.checkRecognitionSupport(
+                                    recognizerIntent, attributionSource, callback);
                         }
 
                         @Override
-                        public void triggerModelDownload(Intent recognizerIntent) {
-                            service.triggerModelDownload(recognizerIntent);
+                        public void triggerModelDownload(
+                                Intent recognizerIntent,
+                                AttributionSource attributionSource) {
+                            service.triggerModelDownload(recognizerIntent, attributionSource);
                         }
                     });
                 } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
index 5801920..fc960d8 100644
--- a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
+++ b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
@@ -129,4 +129,9 @@
     public void dumpDebugLog(@NonNull PrintWriter printWriter) {
         SystemClockTime.dump(printWriter);
     }
+
+    @Override
+    public void runAsync(@NonNull Runnable runnable) {
+        mHandler.post(runnable);
+    }
 }
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java b/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java
index 5df5cbc..4b65c55 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java
@@ -17,10 +17,13 @@
 package com.android.server.timedetector;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.time.TimeCapabilitiesAndConfig;
 import android.app.time.TimeConfiguration;
 import android.app.timedetector.ManualTimeSuggestion;
 
+import com.android.server.timezonedetector.StateChangeListener;
+
 /**
  * The internal (in-process) system server API for the time detector service.
  *
@@ -61,11 +64,26 @@
     /**
      * Suggests a network time to the time detector. The suggestion may not be used by the time
      * detector to set the device's time depending on device configuration and user settings, but
-     * can replace previous network suggestions received.
+     * can replace previous network suggestions received. See also
+     * {@link #addNetworkTimeUpdateListener(StateChangeListener)} and
+     * {@link #getLatestNetworkSuggestion()}.
      */
     void suggestNetworkTime(@NonNull NetworkTimeSuggestion suggestion);
 
     /**
+     * Adds a listener that will be notified when a new network time is available. See {@link
+     * #getLatestNetworkSuggestion()}.
+     */
+    void addNetworkTimeUpdateListener(
+            @NonNull StateChangeListener networkSuggestionUpdateListener);
+
+    /**
+     * Returns the latest / best network time received by the time detector.
+     */
+    @Nullable
+    NetworkTimeSuggestion getLatestNetworkSuggestion();
+
+    /**
      * Suggests a GNSS-derived time to the time detector. The suggestion may not be used by the time
      * detector to set the device's time depending on device configuration and user settings, but
      * can replace previous GNSS suggestions received.
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java
index af168f8..7e96a43 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java
@@ -24,6 +24,7 @@
 import android.os.Handler;
 
 import com.android.server.timezonedetector.CurrentUserIdentityInjector;
+import com.android.server.timezonedetector.StateChangeListener;
 
 import java.util.Objects;
 
@@ -87,6 +88,19 @@
     }
 
     @Override
+    public void addNetworkTimeUpdateListener(
+            @NonNull StateChangeListener networkTimeUpdateListener) {
+        Objects.requireNonNull(networkTimeUpdateListener);
+        mTimeDetectorStrategy.addNetworkTimeUpdateListener(networkTimeUpdateListener);
+    }
+
+    @Override
+    @NonNull
+    public NetworkTimeSuggestion getLatestNetworkSuggestion() {
+        return mTimeDetectorStrategy.getLatestNetworkSuggestion();
+    }
+
+    @Override
     public void suggestGnssTime(@NonNull GnssTimeSuggestion suggestion) {
         Objects.requireNonNull(suggestion);
 
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index a9dcff4..0da967a 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -47,6 +47,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.server.FgThread;
 import com.android.server.SystemService;
+import com.android.server.location.gnss.TimeDetectorNetworkTimeHelper;
 import com.android.server.timezonedetector.CallerIdentityInjector;
 import com.android.server.timezonedetector.CurrentUserIdentityInjector;
 
@@ -405,13 +406,19 @@
         // TODO(b/222295093): Return the latest network time from mTimeDetectorStrategy once we can
         //  be sure that all uses of NtpTrustedTime results in a suggestion being made to the time
         //  detector. mNtpTrustedTime can be removed once this happens.
-        NtpTrustedTime.TimeResult ntpResult = mNtpTrustedTime.getCachedTimeResult();
-        if (ntpResult != null) {
-            UnixEpochTime unixEpochTime = new UnixEpochTime(
-                    ntpResult.getElapsedRealtimeMillis(), ntpResult.getTimeMillis());
-            return new NetworkTimeSuggestion(unixEpochTime, ntpResult.getUncertaintyMillis());
+        if (TimeDetectorNetworkTimeHelper.isInUse()) {
+            // The new implementation.
+            return mTimeDetectorStrategy.getLatestNetworkSuggestion();
         } else {
-            return null;
+            // The old implementation.
+            NtpTrustedTime.TimeResult ntpResult = mNtpTrustedTime.getCachedTimeResult();
+            if (ntpResult != null) {
+                UnixEpochTime unixEpochTime = new UnixEpochTime(
+                        ntpResult.getElapsedRealtimeMillis(), ntpResult.getTimeMillis());
+                return new NetworkTimeSuggestion(unixEpochTime, ntpResult.getUncertaintyMillis());
+            } else {
+                return null;
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index dbd7172..11cec66 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -29,6 +29,7 @@
 
 import com.android.internal.util.Preconditions;
 import com.android.server.timezonedetector.Dumpable;
+import com.android.server.timezonedetector.StateChangeListener;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -104,11 +105,19 @@
     /**
      * Processes the suggested network time. The suggestion may not be used to set the device's time
      * depending on device configuration and user settings, but can replace previous network
-     * suggestions received.
+     * suggestions received. See also
+     * {@link #addNetworkTimeUpdateListener(StateChangeListener)} and
+     * {@link #getLatestNetworkSuggestion()}.
      */
     void suggestNetworkTime(@NonNull NetworkTimeSuggestion suggestion);
 
     /**
+     * Adds a listener that will be notified when a new network time is available. See {@link
+     * #getLatestNetworkSuggestion()}.
+     */
+    void addNetworkTimeUpdateListener(@NonNull StateChangeListener networkSuggestionUpdateListener);
+
+    /**
      * Returns the latest (accepted) network time suggestion. Returns {@code null} if there isn't
      * one.
      */
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index d679bbe..b293bac 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -36,6 +36,7 @@
 import android.app.timedetector.TelephonyTimeSuggestion;
 import android.content.Context;
 import android.os.Handler;
+import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
 
@@ -125,6 +126,9 @@
     private final ReferenceWithHistory<ExternalTimeSuggestion> mLastExternalSuggestion =
             new ReferenceWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
 
+    @GuardedBy("this")
+    private final ArraySet<StateChangeListener> mNetworkTimeUpdateListeners = new ArraySet<>();
+
     /**
      * Used by {@link TimeDetectorStrategyImpl} to interact with device configuration / settings
      * / system properties. It can be faked for testing.
@@ -180,6 +184,11 @@
          * Dumps the time debug log to the supplied {@link PrintWriter}.
          */
         void dumpDebugLog(PrintWriter printWriter);
+
+        /**
+         * Requests that the supplied runnable is invoked asynchronously.
+         */
+        void runAsync(@NonNull Runnable runnable);
     }
 
     static TimeDetectorStrategy create(
@@ -307,6 +316,7 @@
         NetworkTimeSuggestion lastNetworkSuggestion = mLastNetworkSuggestion.get();
         if (lastNetworkSuggestion == null || !lastNetworkSuggestion.equals(suggestion)) {
             mLastNetworkSuggestion.set(suggestion);
+            notifyNetworkTimeUpdateListenersAsynchronously();
         }
 
         // Now perform auto time detection. The new suggestion may be used to modify the system
@@ -315,6 +325,20 @@
         doAutoTimeDetection(reason);
     }
 
+    @GuardedBy("this")
+    private void notifyNetworkTimeUpdateListenersAsynchronously() {
+        for (StateChangeListener listener : mNetworkTimeUpdateListeners) {
+            // This is queuing asynchronous notification, so no need to surrender the "this" lock.
+            mEnvironment.runAsync(listener::onChange);
+        }
+    }
+
+    @Override
+    public synchronized void addNetworkTimeUpdateListener(
+            @NonNull StateChangeListener networkSuggestionUpdateListener) {
+        mNetworkTimeUpdateListeners.add(networkSuggestionUpdateListener);
+    }
+
     @Override
     @Nullable
     public synchronized NetworkTimeSuggestion getLatestNetworkSuggestion() {
@@ -325,6 +349,8 @@
     public synchronized void clearLatestNetworkSuggestion() {
         mLastNetworkSuggestion.set(null);
 
+        notifyNetworkTimeUpdateListenersAsynchronously();
+
         // The loss of network time may change the time signal to use to set the system clock.
         String reason = "Network time cleared";
         doAutoTimeDetection(reason);
diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index f829449..61c137e 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -1140,7 +1140,8 @@
 
 
         @Override
-        public void notifyRecordingStarted(IBinder sessionToken, String recordingId, int userId) {
+        public void notifyRecordingStarted(IBinder sessionToken, String recordingId,
+                String requestId, int userId) {
             final int callingUid = Binder.getCallingUid();
             final int callingPid = Binder.getCallingPid();
             final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
@@ -1151,7 +1152,8 @@
                     try {
                         SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
                                 resolvedUserId);
-                        getSessionLocked(sessionState).notifyRecordingStarted(recordingId);
+                        getSessionLocked(sessionState).notifyRecordingStarted(
+                                recordingId, requestId);
                     } catch (RemoteException | SessionNotFoundException e) {
                         Slogf.e(TAG, "error in notifyRecordingStarted", e);
                     }
@@ -2831,7 +2833,7 @@
         }
 
         @Override
-        public void onRequestStartRecording(Uri programUri) {
+        public void onRequestStartRecording(String requestId, Uri programUri) {
             synchronized (mLock) {
                 if (DEBUG) {
                     Slogf.d(TAG, "onRequestStartRecording: " + programUri);
@@ -2840,7 +2842,8 @@
                     return;
                 }
                 try {
-                    mSessionState.mClient.onRequestStartRecording(programUri, mSessionState.mSeq);
+                    mSessionState.mClient.onRequestStartRecording(
+                            requestId, programUri, mSessionState.mSeq);
                 } catch (RemoteException e) {
                     Slogf.e(TAG, "error in onRequestStartRecording", e);
                 }
@@ -2866,7 +2869,7 @@
 
         @Override
         public void onRequestScheduleRecording(
-                String inputId, Uri channelUri, Uri programUri, Bundle params) {
+                String requestId, String inputId, Uri channelUri, Uri programUri, Bundle params) {
             synchronized (mLock) {
                 if (DEBUG) {
                     Slogf.d(TAG, "onRequestScheduleRecording");
@@ -2876,7 +2879,7 @@
                 }
                 try {
                     mSessionState.mClient.onRequestScheduleRecording(
-                            inputId, channelUri, programUri, params, mSessionState.mSeq);
+                            requestId, inputId, channelUri, programUri, params, mSessionState.mSeq);
                 } catch (RemoteException e) {
                     Slogf.e(TAG, "error in onRequestScheduleRecording", e);
                 }
@@ -2884,8 +2887,8 @@
         }
 
         @Override
-        public void onRequestScheduleRecording2(String inputId, Uri channelUri, long start,
-                long duration, int repeat, Bundle params) {
+        public void onRequestScheduleRecording2(String inputId, String requestId, Uri channelUri,
+                long start, long duration, int repeat, Bundle params) {
             synchronized (mLock) {
                 if (DEBUG) {
                     Slogf.d(TAG, "onRequestScheduleRecording2");
@@ -2894,8 +2897,8 @@
                     return;
                 }
                 try {
-                    mSessionState.mClient.onRequestScheduleRecording2(inputId, channelUri, start,
-                            duration, repeat, params, mSessionState.mSeq);
+                    mSessionState.mClient.onRequestScheduleRecording2(requestId, inputId,
+                            channelUri, start, duration, repeat, params, mSessionState.mSeq);
                 } catch (RemoteException e) {
                     Slogf.e(TAG, "error in onRequestScheduleRecording2", e);
                 }
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 502bfd1..7a95987 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -1382,6 +1382,31 @@
     }
 
     @Override
+    public void overrideActivityTransition(IBinder token, boolean open, int enterAnim, int exitAnim,
+            int backgroundColor) {
+        final long origId = Binder.clearCallingIdentity();
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
+            if (r != null) {
+                r.overrideCustomTransition(open, enterAnim, exitAnim, backgroundColor);
+            }
+        }
+        Binder.restoreCallingIdentity(origId);
+    }
+
+    @Override
+    public void clearOverrideActivityTransition(IBinder token, boolean open) {
+        final long origId = Binder.clearCallingIdentity();
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
+            if (r != null) {
+                r.clearCustomTransition(open);
+            }
+        }
+        Binder.restoreCallingIdentity(origId);
+    }
+
+    @Override
     public void overridePendingTransition(IBinder token, String packageName,
             int enterAnim, int exitAnim, @ColorInt int backgroundColor) {
         final long origId = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
index ff1d442..d844c6f 100644
--- a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
+++ b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
@@ -266,7 +266,7 @@
              * @param resolvedType the resolved type.
              */
             @NonNull
-            public Builder setResolvedType(@NonNull String resolvedType) {
+            public Builder setResolvedType(@Nullable String resolvedType) {
                 mResolvedType = resolvedType;
                 return this;
             }
@@ -276,7 +276,7 @@
              * @param callingPackage the calling package.
              */
             @NonNull
-            public Builder setCallingPackage(@NonNull String callingPackage) {
+            public Builder setCallingPackage(@Nullable String callingPackage) {
                 mCallingPackage = callingPackage;
                 return this;
             }
@@ -286,7 +286,7 @@
              * @param callingFeatureId the calling feature id.
              */
             @NonNull
-            public Builder setCallingFeatureId(@NonNull String callingFeatureId) {
+            public Builder setCallingFeatureId(@Nullable String callingFeatureId) {
                 mCallingFeatureId = callingFeatureId;
                 return this;
             }
@@ -296,7 +296,7 @@
              * @param checkedOptions the {@link ActivityOptions}.
              */
             @NonNull
-            public Builder setCheckedOptions(@NonNull ActivityOptions checkedOptions) {
+            public Builder setCheckedOptions(@Nullable ActivityOptions checkedOptions) {
                 mCheckedOptions = checkedOptions;
                 return this;
             }
@@ -306,7 +306,7 @@
              * @param clearOptionsAnimationRunnable the calling package.
              */
             @NonNull
-            public Builder setClearOptionsAnimationRunnable(@NonNull
+            public Builder setClearOptionsAnimationRunnable(@Nullable
                     Runnable clearOptionsAnimationRunnable) {
                 mClearOptionsAnimation = clearOptionsAnimationRunnable;
                 return this;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 81ee9cd..828848b 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -945,6 +945,10 @@
     // Whether the ActivityEmbedding is enabled on the app.
     private final boolean mAppActivityEmbeddingSplitsEnabled;
 
+    // Records whether client has overridden the WindowAnimation_(Open/Close)(Enter/Exit)Animation.
+    private CustomAppTransition mCustomOpenTransition;
+    private CustomAppTransition mCustomCloseTransition;
+
     private final Runnable mPauseTimeoutRunnable = new Runnable() {
         @Override
         public void run() {
@@ -10352,6 +10356,41 @@
                 && !inPinnedWindowingMode() && !inFreeformWindowingMode();
     }
 
+    void overrideCustomTransition(boolean open, int enterAnim, int exitAnim, int backgroundColor) {
+        CustomAppTransition transition = getCustomAnimation(open);
+        if (transition == null) {
+            transition = new CustomAppTransition();
+            if (open) {
+                mCustomOpenTransition = transition;
+            } else {
+                mCustomCloseTransition = transition;
+            }
+        }
+
+        transition.mEnterAnim = enterAnim;
+        transition.mExitAnim = exitAnim;
+        transition.mBackgroundColor = backgroundColor;
+    }
+
+    void clearCustomTransition(boolean open) {
+        if (open) {
+            mCustomOpenTransition = null;
+        } else {
+            mCustomCloseTransition = null;
+        }
+    }
+
+    CustomAppTransition getCustomAnimation(boolean open) {
+        return open ? mCustomOpenTransition : mCustomCloseTransition;
+    }
+
+    // Override the WindowAnimation_(Open/Close)(Enter/Exit)Animation
+    static class CustomAppTransition {
+        int mEnterAnim;
+        int mExitAnim;
+        int mBackgroundColor;
+    }
+
     static class Builder {
         private final ActivityTaskManagerService mAtmService;
         private WindowProcessController mCallerApp;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index c37a3d7..9ca2015 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1967,7 +1967,7 @@
 
         FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED,
                 /* caller_uid */
-                mSourceRecord != null ? mSourceRecord.getUid() : -1,
+                mSourceRecord != null ? mSourceRecord.getUid() : mCallingUid,
                 /* caller_activity_class_name */
                 mSourceRecord != null ? mSourceRecord.info.name : null,
                 /* target_task_top_activity_uid */
@@ -1988,10 +1988,12 @@
                 /* action */
                 action,
                 /* version */
-                2,
+                3,
                 /* multi_window - we have our source not in the target task, but both are visible */
                 targetTask != null && mSourceRecord != null
-                        && !targetTask.equals(mSourceRecord.getTask()) && targetTask.isVisible()
+                        && !targetTask.equals(mSourceRecord.getTask()) && targetTask.isVisible(),
+                /* bal_code */
+                mBalCode
         );
 
         boolean shouldBlockActivityStart =
@@ -1999,19 +2001,20 @@
 
         if (ActivitySecurityModelFeatureFlags.shouldShowToast(mCallingUid)) {
             UiThread.getHandler().post(() -> Toast.makeText(mService.mContext,
-                    (shouldBlockActivityStart
-                            ? "Activity start blocked by "
-                            : "Activity start would be blocked by ")
-                            + ActivitySecurityModelFeatureFlags.DOC_LINK,
+                    "Activity start from " + r.launchedFromPackage
+                            + (shouldBlockActivityStart ? " " : " would be ")
+                            + "blocked by " + ActivitySecurityModelFeatureFlags.DOC_LINK,
                     Toast.LENGTH_SHORT).show());
         }
 
 
         if (shouldBlockActivityStart) {
             Slog.e(TAG, "Abort Launching r: " + r
-                    + " as source: " + mSourceRecord
-                    + "is in background. New task: " + newTask
-                    + ". Top activity: " + targetTopActivity);
+                    + " as source: "
+                    + (mSourceRecord != null ? mSourceRecord : r.launchedFromPackage)
+                    + " is in background. New task: " + newTask
+                    + ". Top activity: " + targetTopActivity
+                    + ". BAL Code: " + mBalCode);
 
             return false;
         }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 2869133..3876290 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -1667,9 +1667,11 @@
                         /* action */
                         FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__FINISH_TASK,
                         /* version */
-                        1,
+                        3,
                         /* multi_window */
-                        false
+                        false,
+                        /* bal_code */
+                        -1
                 );
             }
         }
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index b9a4ed8..f73c68a 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -142,6 +142,7 @@
 import com.android.internal.util.DumpUtils.Dump;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.internal.util.function.pooled.PooledPredicate;
+import com.android.server.wm.ActivityRecord.CustomAppTransition;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -886,9 +887,18 @@
                     a, appTransitionOldToString(transit), enter, Debug.getCallers(3));
         } else {
             int animAttr = mapOpenCloseTransitTypes(transit, enter);
-            a = animAttr == 0 ? null : (canCustomizeAppTransition
-                ? loadAnimationAttr(lp, animAttr, transit)
-                : mTransitionAnimation.loadDefaultAnimationAttr(animAttr, transit));
+            if (animAttr != 0) {
+                a = loadCustomActivityAnimation(animAttr, enter, container);
+                if (a == null) {
+                    if (canCustomizeAppTransition) {
+                        a = loadAnimationAttr(lp, animAttr, transit);
+                    } else {
+                        a = mTransitionAnimation.loadDefaultAnimationAttr(animAttr, transit);
+                    }
+                }
+            } else {
+                a = null;
+            }
 
             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                     "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b "
@@ -901,6 +911,48 @@
         return a;
     }
 
+    Animation loadCustomActivityAnimation(int animAttr, boolean enter, WindowContainer container) {
+        ActivityRecord customAnimationSource = container.asActivityRecord();
+        if (customAnimationSource == null) {
+            return null;
+        }
+
+        // Only top activity can customize activity animation.
+        // If the animation is for the one below, try to get from the above activity.
+        if (animAttr == WindowAnimation_activityOpenExitAnimation
+                || animAttr == WindowAnimation_activityCloseEnterAnimation) {
+            customAnimationSource = customAnimationSource.getTask()
+                    .getActivityAbove(customAnimationSource);
+            if (customAnimationSource == null) {
+                return null;
+            }
+        }
+        final CustomAppTransition custom;
+        switch (animAttr) {
+            case WindowAnimation_activityOpenEnterAnimation:
+            case WindowAnimation_activityOpenExitAnimation:
+                custom = customAnimationSource.getCustomAnimation(true /* open */);
+                break;
+            case WindowAnimation_activityCloseEnterAnimation:
+            case WindowAnimation_activityCloseExitAnimation:
+                custom = customAnimationSource.getCustomAnimation(false /* open */);
+                break;
+            default:
+                return null;
+        }
+        if (custom != null) {
+            final Animation a = mTransitionAnimation.loadAppTransitionAnimation(
+                    customAnimationSource.packageName, enter
+                            ? custom.mEnterAnim : custom.mExitAnim);
+            if (a != null && custom.mBackgroundColor != 0) {
+                a.setBackdropColor(custom.mBackgroundColor);
+                a.setShowBackdrop(true);
+            }
+            return a;
+        }
+        return null;
+    }
+
     int getAppRootTaskClipMode() {
         return mNextAppTransitionRequests.contains(TRANSIT_RELAUNCH)
                 || mNextAppTransitionRequests.contains(TRANSIT_KEYGUARD_GOING_AWAY)
diff --git a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
index 63dc7d2..f94fd2b 100644
--- a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
+++ b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
@@ -102,6 +102,41 @@
             boolean hasActivityInVisibleTask, boolean hasBackgroundActivityStartPrivileges,
             long lastStopAppSwitchesTime, long lastActivityLaunchTime,
             long lastActivityFinishTime) {
+        // Allow if the proc is instrumenting with background activity starts privs.
+        if (hasBackgroundActivityStartPrivileges) {
+            if (DEBUG_ACTIVITY_STARTS) {
+                Slog.d(TAG, "[Process(" + pid
+                        + ")] Activity start allowed: process instrumenting with background "
+                        + "activity starts privileges");
+            }
+            return BAL_ALLOW_BAL_PERMISSION;
+        }
+        // Allow if the flag was explicitly set.
+        if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) {
+            if (DEBUG_ACTIVITY_STARTS) {
+                Slog.d(TAG, "[Process(" + pid
+                        + ")] Activity start allowed: process allowed by token");
+            }
+            return BAL_ALLOW_BAL_PERMISSION;
+        }
+        // Allow if the caller is bound by a UID that's currently foreground.
+        if (isBoundByForegroundUid()) {
+            if (DEBUG_ACTIVITY_STARTS) {
+                Slog.d(TAG, "[Process(" + pid
+                        + ")] Activity start allowed: process bound by foreground uid");
+            }
+            return BAL_ALLOW_VISIBLE_WINDOW;
+        }
+        // Allow if the caller has an activity in any foreground task.
+        if (hasActivityInVisibleTask
+                && (appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY)) {
+            if (DEBUG_ACTIVITY_STARTS) {
+                Slog.d(TAG, "[Process(" + pid
+                        + ")] Activity start allowed: process has activity in foreground task");
+            }
+            return BAL_ALLOW_FOREGROUND;
+        }
+
         // If app switching is not allowed, we ignore all the start activity grace period
         // exception so apps cannot start itself in onPause() after pressing home button.
         if (appSwitchState == APP_SWITCH_ALLOW) {
@@ -129,40 +164,6 @@
 
             }
         }
-        // Allow if the proc is instrumenting with background activity starts privs.
-        if (hasBackgroundActivityStartPrivileges) {
-            if (DEBUG_ACTIVITY_STARTS) {
-                Slog.d(TAG, "[Process(" + pid
-                        + ")] Activity start allowed: process instrumenting with background "
-                        + "activity starts privileges");
-            }
-            return BAL_ALLOW_BAL_PERMISSION;
-        }
-        // Allow if the caller has an activity in any foreground task.
-        if (hasActivityInVisibleTask
-                && (appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY)) {
-            if (DEBUG_ACTIVITY_STARTS) {
-                Slog.d(TAG, "[Process(" + pid
-                        + ")] Activity start allowed: process has activity in foreground task");
-            }
-            return BAL_ALLOW_FOREGROUND;
-        }
-        // Allow if the caller is bound by a UID that's currently foreground.
-        if (isBoundByForegroundUid()) {
-            if (DEBUG_ACTIVITY_STARTS) {
-                Slog.d(TAG, "[Process(" + pid
-                        + ")] Activity start allowed: process bound by foreground uid");
-            }
-            return BAL_ALLOW_VISIBLE_WINDOW;
-        }
-        // Allow if the flag was explicitly set.
-        if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) {
-            if (DEBUG_ACTIVITY_STARTS) {
-                Slog.d(TAG, "[Process(" + pid
-                        + ")] Activity start allowed: process allowed by token");
-            }
-            return BAL_ALLOW_BAL_PERMISSION;
-        }
         return BAL_BLOCK;
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index fe9306b..626bac4 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1014,6 +1014,9 @@
                 mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing
                         |= w.mAttrs.preferMinimalPostProcessing;
 
+                mTmpApplySurfaceChangesTransactionState.disableHdrConversion
+                        |= !(w.mAttrs.isHdrConversionEnabled());
+
                 final int preferredModeId = getDisplayPolicy().getRefreshRatePolicy()
                         .getPreferredModeId(w);
 
@@ -4891,6 +4894,7 @@
                     mTmpApplySurfaceChangesTransactionState.preferredMinRefreshRate,
                     mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate,
                     mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
+                    mTmpApplySurfaceChangesTransactionState.disableHdrConversion,
                     true /* inTraversal, must call performTraversalInTrans... below */);
         }
         // If the display now has content, or no longer has content, update recording.
@@ -5095,6 +5099,7 @@
         public int preferredModeId;
         public float preferredMinRefreshRate;
         public float preferredMaxRefreshRate;
+        public boolean disableHdrConversion;
 
         void reset() {
             displayHasContent = false;
@@ -5105,6 +5110,7 @@
             preferredModeId = 0;
             preferredMinRefreshRate = 0;
             preferredMaxRefreshRate = 0;
+            disableHdrConversion = false;
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 294e90b..c2afeaf 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -904,37 +904,46 @@
      * starting (about to be visible) activity that is fullscreen (opaque).
      * @param starting The currently starting activity or null if there is none.
      */
-    @VisibleForTesting
-    boolean isTranslucent(ActivityRecord starting) {
+    boolean isTranslucent(@Nullable ActivityRecord starting) {
         if (!isAttached() || isForceHidden() || isForceTranslucent()) {
             return true;
         }
         final PooledPredicate p = PooledLambda.obtainPredicate(TaskFragment::isOpaqueActivity,
-                PooledLambda.__(ActivityRecord.class), starting);
+                PooledLambda.__(ActivityRecord.class), starting, false /* including*/);
         final ActivityRecord opaque = getActivity(p);
         p.recycle();
         return opaque == null;
     }
 
-    private static boolean isOpaqueActivity(ActivityRecord r, ActivityRecord starting) {
-        if (r.finishing) {
-            // We don't factor in finishing activities when determining translucency since
-            // they will be gone soon.
-            return false;
+    /**
+     * Whether the TaskFragment should be treated as translucent for the current transition.
+     * This is different from {@link #isTranslucent(ActivityRecord)} as this function also checks
+     * finishing activities when the TaskFragment itself is becoming invisible.
+     */
+    boolean isTranslucentForTransition() {
+        if (!isAttached() || isForceHidden() || isForceTranslucent()) {
+            return true;
         }
+        // Including finishing Activity if the TaskFragment is becoming invisible in the transition.
+        final boolean includingFinishing = !isVisibleRequested();
+        final PooledPredicate p = PooledLambda.obtainPredicate(TaskFragment::isOpaqueActivity,
+                PooledLambda.__(ActivityRecord.class), null /* starting */, includingFinishing);
+        final ActivityRecord opaque = getActivity(p);
+        p.recycle();
+        return opaque == null;
+    }
 
+    private static boolean isOpaqueActivity(@NonNull ActivityRecord r,
+            @Nullable ActivityRecord starting, boolean includingFinishing) {
         if (!r.visibleIgnoringKeyguard && r != starting) {
             // Also ignore invisible activities that are not the currently starting
             // activity (about to be visible).
             return false;
         }
 
-        if (r.occludesParent()) {
-            // Root task isn't translucent if it has at least one fullscreen activity
-            // that is visible.
-            return true;
-        }
-        return false;
+        // TaskFragment isn't translucent if it has at least one fullscreen activity that is
+        // visible.
+        return r.occludesParent(includingFinishing);
     }
 
     ActivityRecord getTopNonFinishingActivity() {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index d23b954..216544a 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1447,22 +1447,25 @@
 
     private static boolean isTranslucent(@NonNull WindowContainer wc) {
         final TaskFragment taskFragment = wc.asTaskFragment();
-        if (taskFragment != null) {
-            if (taskFragment.isTranslucent(null /* starting */)) {
-                return true;
-            }
-            final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
-            if (adjacentTaskFragment != null) {
-                // Treat the TaskFragment as translucent if its adjacent TF is, otherwise everything
-                // behind two adjacent TaskFragments are occluded.
-                return adjacentTaskFragment.isTranslucent(null /* starting */);
-            }
+        if (taskFragment == null) {
+            return !wc.fillsParent();
         }
-        // TODO(b/172695805): hierarchical check. This is non-trivial because for containers
-        //                    it is effected by child visibility but needs to work even
-        //                    before visibility is committed. This means refactoring some
-        //                    checks to use requested visibility.
-        return !wc.fillsParent();
+
+        // Check containers differently as they are affected by child visibility.
+
+        if (taskFragment.isTranslucentForTransition()) {
+            // TaskFragment doesn't contain occluded ActivityRecord.
+            return true;
+        }
+        final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
+        if (adjacentTaskFragment != null) {
+            // When the TaskFragment has an adjacent TaskFragment, sibling behind them should be
+            // hidden unless any of them are translucent.
+            return adjacentTaskFragment.isTranslucentForTransition();
+        } else {
+            // Non-filling without adjacent is considered as translucent.
+            return !wc.fillsParent();
+        }
     }
 
     /**
@@ -1878,6 +1881,12 @@
             out.addChange(change);
         }
 
+        TransitionInfo.AnimationOptions animOptions = null;
+        if (topApp.asActivityRecord() != null) {
+            final ActivityRecord topActivity = topApp.asActivityRecord();
+            animOptions = addCustomActivityTransition(topActivity, true/* open */, null);
+            animOptions = addCustomActivityTransition(topActivity, false/* open */, animOptions);
+        }
         final WindowManager.LayoutParams animLp =
                 getLayoutParamsForAnimationsStyle(type, sortedTargets);
         if (animLp != null && animLp.type != TYPE_APPLICATION_STARTING
@@ -1885,14 +1894,33 @@
             // Don't send animation options if no windowAnimations have been set or if the we are
             // running an app starting animation, in which case we don't want the app to be able to
             // change its animation directly.
-            TransitionInfo.AnimationOptions animOptions =
-                    TransitionInfo.AnimationOptions.makeAnimOptionsFromLayoutParameters(animLp);
+            if (animOptions != null) {
+                animOptions.addOptionsFromLayoutParameters(animLp);
+            } else {
+                animOptions = TransitionInfo.AnimationOptions
+                        .makeAnimOptionsFromLayoutParameters(animLp);
+            }
+        }
+        if (animOptions != null) {
             out.setAnimationOptions(animOptions);
         }
-
         return out;
     }
 
+    static TransitionInfo.AnimationOptions addCustomActivityTransition(ActivityRecord topActivity,
+            boolean open, TransitionInfo.AnimationOptions animOptions) {
+        final ActivityRecord.CustomAppTransition customAnim =
+                topActivity.getCustomAnimation(open);
+        if (customAnim != null) {
+            if (animOptions == null) {
+                animOptions = TransitionInfo.AnimationOptions
+                        .makeCommonAnimOptions(topActivity.packageName);
+            }
+            animOptions.addCustomActivityTransition(open, customAnim.mEnterAnim,
+                    customAnim.mExitAnim, customAnim.mBackgroundColor);
+        }
+        return animOptions;
+    }
     /**
      * Finds the top-most common ancestor of app targets.
      *
@@ -2019,7 +2047,13 @@
             final DisplayContent dc = wc.asDisplayContent();
             if (dc == null || !mChanges.get(dc).hasChanged()) continue;
             dc.sendNewConfiguration();
-            setReady(dc, true);
+            // Set to ready if no other change controls the ready state. But if there is, such as
+            // if an activity is pausing, it will call setReady(ar, false) and wait for the next
+            // resumed activity. Then do not set to ready because the transition only contains
+            // partial participants. Otherwise the transition may only handle HIDE and miss OPEN.
+            if (!mReadyTracker.mUsed) {
+                setReady(dc, true);
+            }
         }
     }
 
diff --git a/services/core/jni/com_android_server_display_DisplayControl.cpp b/services/core/jni/com_android_server_display_DisplayControl.cpp
index db7fced..77e8324 100644
--- a/services/core/jni/com_android_server_display_DisplayControl.cpp
+++ b/services/core/jni/com_android_server_display_DisplayControl.cpp
@@ -110,6 +110,15 @@
     return array;
 }
 
+static jboolean nativeGetHdrOutputConversionSupport(JNIEnv* env, jclass clazz) {
+    bool isSupported;
+    status_t err = SurfaceComposerClient::getHdrOutputConversionSupport(&isSupported);
+    if (err == OK) {
+        return isSupported;
+    }
+    return JNI_FALSE;
+}
+
 static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
     const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
     ScopedLongArrayRW values(env, env->NewLongArray(displayIds.size()));
@@ -150,6 +159,8 @@
             (void*)nativeSetHdrConversionMode },
     {"nativeGetSupportedHdrOutputTypes", "()[I",
             (void*)nativeGetSupportedHdrOutputTypes },
+     {"nativeGetHdrOutputConversionSupport", "()Z",
+            (void*) nativeGetHdrOutputConversionSupport },
         // clang-format on
 };
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index d7a2095..88b82d7 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -176,7 +176,8 @@
     private static final String ATTR_PACKAGE_POLICY_MODE = "package-policy-type";
     private static final String TAG_CREDENTIAL_MANAGER_POLICY = "credential-manager-policy";
 
-
+    // If the ActiveAdmin is a permission-based admin, then info will be null because the
+    // permission-based admin is not mapped to a device administrator component.
     DeviceAdminInfo info;
 
     static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
@@ -378,9 +379,11 @@
 
     void writeToXml(TypedXmlSerializer out)
             throws IllegalArgumentException, IllegalStateException, IOException {
-        out.startTag(null, TAG_POLICIES);
-        info.writePoliciesToXml(out);
-        out.endTag(null, TAG_POLICIES);
+        if (info != null) {
+            out.startTag(null, TAG_POLICIES);
+            info.writePoliciesToXml(out);
+            out.endTag(null, TAG_POLICIES);
+        }
         if (mPasswordPolicy.quality != PASSWORD_QUALITY_UNSPECIFIED) {
             writeAttributeValueToXml(
                     out, TAG_PASSWORD_QUALITY, mPasswordPolicy.quality);
@@ -1188,14 +1191,16 @@
         pw.print("testOnlyAdmin=");
         pw.println(testOnlyAdmin);
 
-        pw.println("policies:");
-        ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
-        if (pols != null) {
-            pw.increaseIndent();
-            for (int i = 0; i < pols.size(); i++) {
-                pw.println(pols.get(i).tag);
+        if (info != null) {
+            pw.println("policies:");
+            ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
+            if (pols != null) {
+                pw.increaseIndent();
+                for (int i = 0; i < pols.size(); i++) {
+                    pw.println(pols.get(i).tag);
+                }
+                pw.decreaseIndent();
             }
-            pw.decreaseIndent();
         }
 
         pw.print("passwordQuality=0x");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index 8e430b3..a5b9d43 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -123,6 +123,23 @@
     final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>();
     final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>();
 
+    // Some DevicePolicyManager APIs can be called by (1) a DPC or (2) an app with permissions that
+    // isn't a DPC. For the latter, the caller won't have to provide a ComponentName and won't be
+    // mapped to an ActiveAdmin. This permission-based admin should be used to persist policies
+    // set by the permission-based caller. This admin should not be added to mAdminMap or mAdminList
+    // since a lot of methods in DPMS assume the ActiveAdmins here have a valid ComponentName.
+    // Instead, use variants of DPMS active admin getters to include the permission-based admin.
+    ActiveAdmin mPermissionBasedAdmin;
+
+    // Create or get the permission-based admin. The permission-based admin will not have a
+    // DeviceAdminInfo or ComponentName.
+    ActiveAdmin createOrGetPermissionBasedAdmin() {
+        if (mPermissionBasedAdmin == null) {
+            mPermissionBasedAdmin = new ActiveAdmin(/* info= */ null, /* parent= */ false);
+        }
+        return mPermissionBasedAdmin;
+    }
+
     // TODO(b/35385311): Keep track of metadata in TrustedCertificateStore instead.
     final ArraySet<String> mAcceptedCaCertificates = new ArraySet<>();
 
@@ -256,6 +273,12 @@
                 }
             }
 
+            if (policyData.mPermissionBasedAdmin != null) {
+                out.startTag(null, "permission-based-admin");
+                policyData.mPermissionBasedAdmin.writeToXml(out);
+                out.endTag(null, "permission-based-admin");
+            }
+
             if (policyData.mPasswordOwner >= 0) {
                 out.startTag(null, "password-owner");
                 out.attributeInt(null, "value", policyData.mPasswordOwner);
@@ -457,6 +480,7 @@
             policy.mLockTaskPackages.clear();
             policy.mAdminList.clear();
             policy.mAdminMap.clear();
+            policy.mPermissionBasedAdmin = null;
             policy.mAffiliationIds.clear();
             policy.mOwnerInstalledCaCerts.clear();
             policy.mUserControlDisabledPackages = null;
@@ -484,6 +508,10 @@
                     } catch (RuntimeException e) {
                         Slogf.w(TAG, e, "Failed loading admin %s", name);
                     }
+                } else if ("permission-based-admin".equals(tag)) {
+                    ActiveAdmin ap = new ActiveAdmin(/* info= */ null, /* parent= */ false);
+                    ap.readFromXml(parser, /* overwritePolicies= */ false);
+                    policy.mPermissionBasedAdmin = ap;
                 } else if ("delegation".equals(tag)) {
                     // Parse delegation info.
                     final String delegatePackage = parser.getAttributeValue(null,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index cdcfaba..c847aa2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -21,6 +21,7 @@
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY;
 import static android.Manifest.permission.QUERY_ADMIN_POLICY;
 import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
@@ -33,10 +34,12 @@
 import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION;
 import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_APP_STANDBY;
 import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS;
+import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION;
 import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION;
 import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_AFFILIATED;
 import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED;
 import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
+import static android.app.admin.DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY;
 import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
 import static android.app.admin.DevicePolicyManager.ACTION_MANAGED_PROFILE_PROVISIONED;
@@ -44,7 +47,6 @@
 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
 import static android.app.admin.DevicePolicyManager.ACTION_SYSTEM_UPDATE_POLICY_CHANGED;
-import static android.app.admin.DevicePolicyManager.AUTO_TIMEZONE_POLICY;
 import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
 import static android.app.admin.DevicePolicyManager.DELEGATION_BLOCK_UNINSTALL;
 import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
@@ -62,6 +64,7 @@
 import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION;
 import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_APP_STANDBY;
 import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS;
+import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION;
 import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_HIBERNATION;
 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE;
 import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_IDS;
@@ -142,6 +145,9 @@
 import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_GENERIC_MESSAGE;
 import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_ORG_OWNED_MESSAGE;
 import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_TELEPHONY_PAUSED_BODY;
+import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_TELEPHONY_PAUSED_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_TELEPHONY_PAUSED_TURN_ON_BUTTON;
 import static android.app.admin.ProvisioningException.ERROR_ADMIN_PACKAGE_INSTALLATION_FAILED;
 import static android.app.admin.ProvisioningException.ERROR_PRE_CONDITION_FAILED;
 import static android.app.admin.ProvisioningException.ERROR_PROFILE_CREATION_FAILED;
@@ -149,6 +155,8 @@
 import static android.app.admin.ProvisioningException.ERROR_SETTING_PROFILE_OWNER_FAILED;
 import static android.app.admin.ProvisioningException.ERROR_SET_DEVICE_OWNER_FAILED;
 import static android.app.admin.ProvisioningException.ERROR_STARTING_PROFILE_FAILED;
+import static android.content.Intent.ACTION_MANAGED_PROFILE_AVAILABLE;
+import static android.content.Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.pm.PackageManager.GET_META_DATA;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
@@ -731,6 +739,9 @@
                 OPSTR_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION);
         APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS.put(
                 EXEMPT_FROM_HIBERNATION, OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION);
+        APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS.put(
+                EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION,
+                OPSTR_SYSTEM_EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION);
     }
 
     /**
@@ -1157,6 +1168,12 @@
             } else if (ACTION_TURN_PROFILE_ON_NOTIFICATION.equals(action)) {
                 Slogf.i(LOG_TAG, "requesting to turn on the profile: " + userHandle);
                 mUserManager.requestQuietModeEnabled(false, UserHandle.of(userHandle));
+            } else if (ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
+                notifyIfManagedSubscriptionsAreUnavailable(
+                        UserHandle.of(userHandle), /* managedProfileAvailable= */ false);
+            } else if (ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)) {
+                notifyIfManagedSubscriptionsAreUnavailable(
+                        UserHandle.of(userHandle), /* managedProfileAvailable= */ true);
             }
         }
 
@@ -2001,7 +2018,8 @@
         filter.addAction(Intent.ACTION_USER_STOPPED);
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_USER_UNLOCKED);
-        filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+        filter.addAction(ACTION_MANAGED_PROFILE_UNAVAILABLE);
+        filter.addAction(ACTION_MANAGED_PROFILE_AVAILABLE);
         filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
         mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
         filter = new IntentFilter();
@@ -4168,6 +4186,27 @@
     }
 
     /**
+     * Get the list of active admins for an affected user:
+     * <ul>
+     * <li>The active admins associated with the userHandle itself</li>
+     * <li>The parent active admins for each managed profile associated with the userHandle</li>
+     * <li>The permission based admin associated with the userHandle itself</li>
+     * </ul>
+     *
+     * @param userHandle the affected user for whom to get the active admins
+     * @return the list of active admins for the affected user
+     */
+    @GuardedBy("getLockObject()")
+    private List<ActiveAdmin> getActiveAdminsForAffectedUserInclPermissionBasedAdminLocked(
+            int userHandle) {
+        List<ActiveAdmin> list = getActiveAdminsForAffectedUserLocked(userHandle);
+        if (getUserData(userHandle).mPermissionBasedAdmin != null) {
+            list.add(getUserData(userHandle).mPermissionBasedAdmin);
+        }
+        return list;
+    }
+
+    /**
      * Returns the list of admins on the given user, as well as parent admins for each managed
      * profile associated with the given user. Optionally also include the admin of each managed
      * profile.
@@ -8472,24 +8511,39 @@
      * Disables all device cameras according to the specified admin.
      */
     @Override
-    public void setCameraDisabled(ComponentName who, boolean disabled, boolean parent) {
+    public void setCameraDisabled(ComponentName who, String callerPackageName, boolean disabled,
+            boolean parent) {
         if (!mHasFeature) {
             return;
         }
-        Objects.requireNonNull(who, "ComponentName is null");
 
-        final CallerIdentity caller = getCallerIdentity(who);
-        if (parent) {
-            Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller));
-        }
+        final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
+        final int userHandle = caller.getUserId();
         checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_CAMERA_DISABLED);
 
-        final int userHandle = caller.getUserId();
+        ActiveAdmin admin = null;
+        if (isPermissionCheckFlagEnabled()) {
+            EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+                    who,
+                    MANAGE_DEVICE_POLICY_CAMERA,
+                    callerPackageName,
+                    getProfileParentUserIfRequested(userHandle, parent));
+            admin = enforcingAdmin.getActiveAdmin();
+        } else {
+            Objects.requireNonNull(who, "ComponentName is null");
+            if (parent) {
+                Preconditions.checkCallAuthorization(
+                        isProfileOwnerOfOrganizationOwnedDevice(caller));
+            }
+            synchronized (getLockObject()) {
+                admin = getActiveAdminForCallerLocked(who,
+                        DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA, parent);
+            }
+        }
+
         synchronized (getLockObject()) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA, parent);
-            if (ap.disableCamera != disabled) {
-                ap.disableCamera = disabled;
+            if (admin.disableCamera != disabled) {
+                admin.disableCamera = disabled;
                 saveSettingsLocked(userHandle);
             }
         }
@@ -8518,14 +8572,19 @@
         if (!mHasFeature) {
             return false;
         }
-
         final CallerIdentity caller = getCallerIdentity(who);
-        Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle)
-                || isCameraServerUid(caller));
-
-        if (parent) {
+        if (isPermissionCheckFlagEnabled()) {
             Preconditions.checkCallAuthorization(
-                    isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId()));
+                    hasFullCrossUsersPermission(caller, userHandle) || isCameraServerUid(caller)
+                            || hasPermission(MANAGE_DEVICE_POLICY_CAMERA, userHandle)
+                            || hasPermission(QUERY_ADMIN_POLICY));
+        } else {
+            Preconditions.checkCallAuthorization(
+                    hasFullCrossUsersPermission(caller, userHandle) || isCameraServerUid(caller));
+            if (parent) {
+                Preconditions.checkCallAuthorization(
+                        isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId()));
+            }
         }
 
         synchronized (getLockObject()) {
@@ -8538,12 +8597,19 @@
             if (deviceOwner != null && deviceOwner.disableCamera) {
                 return true;
             }
-            final int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
+
             // Return the strictest policy across all participating admins.
-            List<ActiveAdmin> admins = getActiveAdminsForAffectedUserLocked(affectedUserId);
+            List<ActiveAdmin> admins;
+            final int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
+            if (isPermissionCheckFlagEnabled()) {
+                admins = getActiveAdminsForAffectedUserInclPermissionBasedAdminLocked(
+                        affectedUserId);
+            } else {
+                admins = getActiveAdminsForAffectedUserLocked(affectedUserId);
+            }
             // Determine whether or not the device camera is disabled for any active admins.
-            for (ActiveAdmin admin : admins) {
-                if (admin.disableCamera) {
+            for (ActiveAdmin activeAdmin : admins) {
+                if (activeAdmin.disableCamera) {
                     return true;
                 }
             }
@@ -13776,6 +13842,26 @@
         return false;
     }
 
+    @Override
+    public boolean isStatusBarDisabled(String callerPackage) {
+        final CallerIdentity caller = getCallerIdentity(callerPackage);
+        Preconditions.checkCallAuthorization(
+                isProfileOwner(caller) || isDefaultDeviceOwner(caller));
+
+        int userId = caller.getUserId();
+        synchronized (getLockObject()) {
+            Preconditions.checkCallAuthorization(isUserAffiliatedWithDeviceLocked(userId),
+                    "Admin " + callerPackage
+                            + " is neither the device owner or affiliated user's profile owner.");
+            if (isManagedProfile(userId)) {
+                throw new SecurityException("Managed profile cannot disable status bar");
+            }
+            DevicePolicyData policy = getUserData(userId);
+            return policy.mStatusBarDisabled;
+        }
+    }
+
+
     /**
      * We need to update the internal state of whether a user has completed setup or a
      * device has paired once. After that, we ignore any changes that reset the
@@ -15601,6 +15687,7 @@
             EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
                     who,
                     MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+                    caller.getPackageName(),
                     caller.getUserId());
             admin = enforcingAdmin.getActiveAdmin();
         } else {
@@ -15631,6 +15718,7 @@
             EnforcingAdmin enforcingAdmin = enforceCanQueryAndGetEnforcingAdmin(
                     who,
                     MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+                    caller.getPackageName(),
                     caller.getUserId());
             admin = enforcingAdmin.getActiveAdmin();
         } else {
@@ -18679,6 +18767,83 @@
         });
     }
 
+    private void notifyIfManagedSubscriptionsAreUnavailable(
+            UserHandle managedProfile, boolean managedProfileAvailable) {
+        if (!isManagedProfile(managedProfile.getIdentifier())) {
+            Slog.wtf(
+                    LOG_TAG,
+                    "Expected managed profile when notified of profile availability change.");
+        }
+        if (getManagedSubscriptionsPolicy().getPolicyType()
+                != ManagedSubscriptionsPolicy.TYPE_ALL_MANAGED_SUBSCRIPTIONS) {
+            // There may be a subscription in the personal profile, in which case calls and
+            // texts may still be available. No need to notify the user.
+            return;
+        }
+        if (managedProfileAvailable) {
+            // When quiet mode is switched off calls and texts then become available to the user,
+            // so no need to keep showing the notification.
+            mInjector
+                    .getNotificationManager()
+                    .cancel(SystemMessage.NOTE_ALL_MANAGED_SUBSCRIPTIONS_AND_MANAGED_PROFILE_OFF);
+            return;
+        }
+        final Intent intent = new Intent(ACTION_TURN_PROFILE_ON_NOTIFICATION);
+        intent.putExtra(Intent.EXTRA_USER_HANDLE, managedProfile.getIdentifier());
+        final PendingIntent pendingIntent =
+                mInjector.pendingIntentGetBroadcast(
+                        mContext,
+                        /* requestCode= */ 0,
+                        intent,
+                        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+        final Notification.Action turnProfileOnButton =
+                new Notification.Action.Builder(
+                        /* icon= */ null, getUnpauseWorkAppsButtonText(), pendingIntent)
+                        .build();
+
+        final Bundle extras = new Bundle();
+        extras.putString(
+                Notification.EXTRA_SUBSTITUTE_APP_NAME, getWorkProfileContentDescription());
+        final Notification notification =
+                new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
+                        .setSmallIcon(R.drawable.ic_phone_disabled)
+                        .setContentTitle(getUnpauseWorkAppsForTelephonyTitle())
+                        .setContentText(getUnpauseWorkAppsForTelephonyText())
+                        .setStyle(new Notification.BigTextStyle().bigText(
+                                getUnpauseWorkAppsForTelephonyText()))
+                        .addAction(turnProfileOnButton)
+                        .addExtras(extras)
+                        .setOngoing(false)
+                        .setShowWhen(true)
+                        .setAutoCancel(true)
+                        .build();
+
+        mInjector
+                .getNotificationManager()
+                .notifyAsUser(
+                        /* tag= */ null,
+                        SystemMessage.NOTE_ALL_MANAGED_SUBSCRIPTIONS_AND_MANAGED_PROFILE_OFF,
+                        notification,
+                        UserHandle.of(getProfileParentId(managedProfile.getIdentifier())));
+    }
+
+    private String getUnpauseWorkAppsButtonText() {
+        return getUpdatableString(
+                WORK_PROFILE_TELEPHONY_PAUSED_TURN_ON_BUTTON,
+                R.string.work_profile_telephony_paused_turn_on_button);
+    }
+
+    private String getUnpauseWorkAppsForTelephonyTitle() {
+        return getUpdatableString(
+                WORK_PROFILE_TELEPHONY_PAUSED_TITLE, R.string.work_profile_telephony_paused_title);
+    }
+
+    private String getUnpauseWorkAppsForTelephonyText() {
+        return getUpdatableString(
+                WORK_PROFILE_TELEPHONY_PAUSED_BODY,
+                R.string.work_profile_telephony_paused_text);
+    }
+
     @GuardedBy("getLockObject()")
     private void updateProfileOffDeadlineNotificationLocked(
             int profileUserId, ActiveAdmin profileOwner, int notificationState) {
@@ -19049,7 +19214,7 @@
             }
             setUserSetupComplete(userInfo.id);
 
-            startUser(userInfo.id, callerPackage);
+            startProfileForSetup(userInfo.id, callerPackage);
             maybeMigrateAccount(
                     userInfo.id, caller.getUserId(), provisioningParams.getAccountToMigrate(),
                     provisioningParams.isKeepingAccountOnMigration(), callerPackage);
@@ -19280,8 +19445,9 @@
                 mContext.getContentResolver(), USER_SETUP_COMPLETE, 1, userId);
     }
 
-    private void startUser(@UserIdInt int userId, String callerPackage)
+    private void startProfileForSetup(@UserIdInt int userId, String callerPackage)
             throws IllegalStateException {
+        Slogf.i(LOG_TAG, "Starting profile %d as requested by package %s", userId, callerPackage);
         final long startTime = SystemClock.elapsedRealtime();
         final UserUnlockedBlockingReceiver unlockedReceiver = new UserUnlockedBlockingReceiver(
                 userId);
@@ -19292,7 +19458,8 @@
                 /* broadcastPermission = */ null,
                 /* scheduler= */ null);
         try {
-            if (!mInjector.getIActivityManager().startUserInBackground(userId)) {
+            // Must call startProfileEvenWhenDisabled(), as profile is not enabled yet
+            if (!mInjector.getActivityManagerInternal().startProfileEvenWhenDisabled(userId)) {
                 throw new ServiceSpecificException(ERROR_STARTING_PROFILE_FAILED,
                         String.format("Unable to start user %d in background", userId));
             }
@@ -19305,9 +19472,6 @@
                     DevicePolicyEnums.PLATFORM_PROVISIONING_START_PROFILE_MS,
                     startTime,
                     callerPackage);
-        } catch (RemoteException e) {
-            // Shouldn't happen.
-            Slogf.wtf(LOG_TAG, "Error starting user", e);
         } finally {
             mContext.unregisterReceiver(unlockedReceiver);
         }
@@ -20404,9 +20568,9 @@
      * the associated cross-user permission if the caller's user is different to the target user.
      */
     private EnforcingAdmin enforcePermissionAndGetEnforcingAdmin(@Nullable ComponentName admin,
-            String permission, int targetUserId) {
+            String permission, String callerPackageName, int targetUserId) {
         enforcePermission(permission, targetUserId);
-        return getEnforcingAdminForCaller(admin, getCallerIdentity());
+        return getEnforcingAdminForCaller(admin, callerPackageName);
     }
 
     /**
@@ -20421,9 +20585,9 @@
      * the associated cross-user permission if the caller's user is different to the target user.
      */
     private EnforcingAdmin enforceCanQueryAndGetEnforcingAdmin(@Nullable ComponentName admin,
-            String permission, int targetUserId) {
+            String permission, String callerPackageName, int targetUserId) {
         enforceCanQuery(permission, targetUserId);
-        return getEnforcingAdminForCaller(admin, getCallerIdentity());
+        return getEnforcingAdminForCaller(admin, callerPackageName);
     }
 
     private static final HashMap<String, String> POLICY_IDENTIFIER_TO_PERMISSION = new HashMap<>();
@@ -20567,7 +20731,8 @@
     }
 
     private EnforcingAdmin getEnforcingAdminForCaller(@Nullable ComponentName who,
-            CallerIdentity caller) {
+            String callerPackageName) {
+        CallerIdentity caller = getCallerIdentity(callerPackageName);
         int userId = caller.getUserId();
         ActiveAdmin admin = null;
         synchronized (getLockObject()) {
@@ -20579,7 +20744,10 @@
         if (getActiveAdminUncheckedLocked(who, userId) != null) {
             return EnforcingAdmin.createDeviceAdminEnforcingAdmin(who, userId, admin);
         }
-        return  EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId);
+        if (admin == null) {
+            admin = getUserData(userId).createOrGetPermissionBasedAdmin();
+        }
+        return  EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId, admin);
     }
 
     private boolean isPermissionCheckFlagEnabled() {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
index 10e972d..a303fde 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
@@ -19,10 +19,10 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.admin.Authority;
-import android.app.admin.UnknownAuthority;
 import android.app.admin.DeviceAdminAuthority;
 import android.app.admin.DpcAuthority;
 import android.app.admin.RoleAuthority;
+import android.app.admin.UnknownAuthority;
 import android.content.ComponentName;
 import android.os.UserHandle;
 
@@ -71,9 +71,10 @@
     private final boolean mIsRoleAuthority;
     private final ActiveAdmin mActiveAdmin;
 
-    static EnforcingAdmin createEnforcingAdmin(@NonNull String packageName, int userId) {
+    static EnforcingAdmin createEnforcingAdmin(@NonNull String packageName, int userId,
+            ActiveAdmin admin) {
         Objects.requireNonNull(packageName);
-        return new EnforcingAdmin(packageName, userId);
+        return new EnforcingAdmin(packageName, userId, admin);
     }
 
     static EnforcingAdmin createEnterpriseEnforcingAdmin(
@@ -111,6 +112,23 @@
         return ROLE_AUTHORITY_PREFIX + roleName;
     }
 
+    static Authority getParcelableAuthority(String authority) {
+        if (authority == null || authority.isEmpty()) {
+            return UnknownAuthority.UNKNOWN_AUTHORITY;
+        }
+        if (DPC_AUTHORITY.equals(authority)) {
+            return DpcAuthority.DPC_AUTHORITY;
+        }
+        if (DEVICE_ADMIN_AUTHORITY.equals(authority)) {
+            return DeviceAdminAuthority.DEVICE_ADMIN_AUTHORITY;
+        }
+        if (authority.startsWith(ROLE_AUTHORITY_PREFIX)) {
+            String role = authority.substring(ROLE_AUTHORITY_PREFIX.length());
+            return new RoleAuthority(Set.of(role));
+        }
+        return UnknownAuthority.UNKNOWN_AUTHORITY;
+    }
+
     private EnforcingAdmin(
             String packageName, ComponentName componentName, Set<String> authorities, int userId,
             ActiveAdmin activeAdmin) {
@@ -127,7 +145,7 @@
         mActiveAdmin = activeAdmin;
     }
 
-    private EnforcingAdmin(String packageName, int userId) {
+    private EnforcingAdmin(String packageName, int userId, ActiveAdmin activeAdmin) {
         Objects.requireNonNull(packageName);
 
         // Only role authorities use this constructor.
@@ -137,7 +155,7 @@
         mComponentName = null;
         // authorities will be loaded when needed
         mAuthorities = null;
-        mActiveAdmin = null;
+        mActiveAdmin = activeAdmin;
     }
 
     private static Set<String> getRoleAuthoritiesOrDefault(String packageName, int userId) {
@@ -274,7 +292,7 @@
         int userId = parser.getAttributeInt(/* namespace= */ null, ATTR_USER_ID);
 
         if (isRoleAuthority) {
-            return new EnforcingAdmin(packageName, userId);
+            return new EnforcingAdmin(packageName, userId, null);
         } else {
             String className = parser.getAttributeValue(/* namespace= */ null, ATTR_CLASS_NAME);
             ComponentName componentName = new ComponentName(packageName, className);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 9e0da26..21c9434 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.admin.BooleanPolicyValue;
+import android.app.admin.DevicePolicyIdentifiers;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.IntegerPolicyValue;
 import android.app.admin.IntentFilterPolicyKey;
@@ -73,7 +74,7 @@
             List.of(new BooleanPolicyValue(true), new BooleanPolicyValue(false)));
 
     static PolicyDefinition<Boolean> AUTO_TIMEZONE = new PolicyDefinition<>(
-            new NoArgsPolicyKey(DevicePolicyManager.AUTO_TIMEZONE_POLICY),
+            new NoArgsPolicyKey(DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY),
             // auto timezone is disabled by default, hence enabling it is more restrictive.
             TRUE_MORE_RESTRICTIVE,
             POLICY_FLAG_GLOBAL_ONLY_POLICY,
@@ -86,7 +87,7 @@
     // when reading the policies from xml.
     static final PolicyDefinition<Integer> GENERIC_PERMISSION_GRANT =
             new PolicyDefinition<>(
-                    new PackagePermissionPolicyKey(DevicePolicyManager.PERMISSION_GRANT_POLICY),
+                    new PackagePermissionPolicyKey(DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY),
                     // TODO: is this really the best mechanism, what makes denied more
                     //  restrictive than
                     //  granted?
@@ -113,16 +114,17 @@
         }
         return GENERIC_PERMISSION_GRANT.createPolicyDefinition(
                 new PackagePermissionPolicyKey(
-                        DevicePolicyManager.PERMISSION_GRANT_POLICY,
+                        DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY,
                         packageName,
                         permissionName));
     }
 
     static PolicyDefinition<LockTaskPolicy> LOCK_TASK = new PolicyDefinition<>(
-            new NoArgsPolicyKey(DevicePolicyManager.LOCK_TASK_POLICY),
+            new NoArgsPolicyKey(DevicePolicyIdentifiers.LOCK_TASK_POLICY),
             new TopPriority<>(List.of(
                     // TODO(b/258166155): add correct device lock role name
-                    EnforcingAdmin.getRoleAuthorityOf("DeviceLock"),
+                    EnforcingAdmin.getRoleAuthorityOf(
+                            "android.app.role.SYSTEM_FINANCED_DEVICE_CONTROLLER"),
                     EnforcingAdmin.DPC_AUTHORITY)),
             POLICY_FLAG_LOCAL_ONLY_POLICY,
             (LockTaskPolicy value, Context context, Integer userId, PolicyKey policyKey) ->
@@ -131,7 +133,8 @@
 
     static PolicyDefinition<Set<String>> USER_CONTROLLED_DISABLED_PACKAGES =
             new PolicyDefinition<>(
-                    new NoArgsPolicyKey(DevicePolicyManager.USER_CONTROL_DISABLED_PACKAGES_POLICY),
+                    new NoArgsPolicyKey(
+                            DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY),
                     new StringSetUnion(),
                     (Set<String> value, Context context, Integer userId, PolicyKey policyKey) ->
                             PolicyEnforcerCallbacks.setUserControlDisabledPackages(value, userId),
@@ -143,10 +146,11 @@
     static PolicyDefinition<ComponentName> GENERIC_PERSISTENT_PREFERRED_ACTIVITY =
             new PolicyDefinition<>(
                     new IntentFilterPolicyKey(
-                            DevicePolicyManager.PERSISTENT_PREFERRED_ACTIVITY_POLICY),
+                            DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY),
             new TopPriority<>(List.of(
                     // TODO(b/258166155): add correct device lock role name
-                    EnforcingAdmin.getRoleAuthorityOf("DeviceLock"),
+                    EnforcingAdmin.getRoleAuthorityOf(
+                            "android.app.role.SYSTEM_FINANCED_DEVICE_CONTROLLER"),
                     EnforcingAdmin.DPC_AUTHORITY)),
             POLICY_FLAG_LOCAL_ONLY_POLICY,
             PolicyEnforcerCallbacks::addPersistentPreferredActivity,
@@ -163,7 +167,8 @@
         }
         return GENERIC_PERSISTENT_PREFERRED_ACTIVITY.createPolicyDefinition(
                 new IntentFilterPolicyKey(
-                        DevicePolicyManager.PERSISTENT_PREFERRED_ACTIVITY_POLICY, intentFilter));
+                        DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY,
+                        intentFilter));
     }
 
     // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
@@ -172,7 +177,7 @@
     static PolicyDefinition<Boolean> GENERIC_PACKAGE_UNINSTALL_BLOCKED =
             new PolicyDefinition<>(
                     new PackagePolicyKey(
-                            DevicePolicyManager.PACKAGE_UNINSTALL_BLOCKED_POLICY),
+                            DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY),
                     TRUE_MORE_RESTRICTIVE,
                     POLICY_FLAG_LOCAL_ONLY_POLICY,
                     PolicyEnforcerCallbacks::setUninstallBlocked,
@@ -189,7 +194,7 @@
         }
         return GENERIC_PACKAGE_UNINSTALL_BLOCKED.createPolicyDefinition(
                 new PackagePolicyKey(
-                        DevicePolicyManager.PACKAGE_UNINSTALL_BLOCKED_POLICY, packageName));
+                        DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY, packageName));
     }
 
     // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
@@ -198,7 +203,7 @@
     static PolicyDefinition<Bundle> GENERIC_APPLICATION_RESTRICTIONS =
             new PolicyDefinition<>(
                     new PackagePolicyKey(
-                            DevicePolicyManager.APPLICATION_RESTRICTIONS_POLICY),
+                            DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY),
                     // Don't need to take in a resolution mechanism since its never used, but might
                     // need some refactoring to not always assume a non-null mechanism.
                     new MostRecent<>(),
@@ -220,11 +225,11 @@
         }
         return GENERIC_APPLICATION_RESTRICTIONS.createPolicyDefinition(
                 new PackagePolicyKey(
-                        DevicePolicyManager.APPLICATION_RESTRICTIONS_POLICY, packageName));
+                        DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY, packageName));
     }
 
     static PolicyDefinition<Long> RESET_PASSWORD_TOKEN = new PolicyDefinition<>(
-            new NoArgsPolicyKey(DevicePolicyManager.RESET_PASSWORD_TOKEN_POLICY),
+            new NoArgsPolicyKey(DevicePolicyIdentifiers.RESET_PASSWORD_TOKEN_POLICY),
             // Don't need to take in a resolution mechanism since its never used, but might
             // need some refactoring to not always assume a non-null mechanism.
             new MostRecent<>(),
@@ -234,19 +239,21 @@
             new LongPolicySerializer());
 
     private static final Map<String, PolicyDefinition<?>> sPolicyDefinitions = Map.of(
-            DevicePolicyManager.AUTO_TIMEZONE_POLICY, AUTO_TIMEZONE,
-            DevicePolicyManager.PERMISSION_GRANT_POLICY, GENERIC_PERMISSION_GRANT,
-            DevicePolicyManager.LOCK_TASK_POLICY, LOCK_TASK,
-            DevicePolicyManager.USER_CONTROL_DISABLED_PACKAGES_POLICY,
+            DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY, AUTO_TIMEZONE,
+            DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY, GENERIC_PERMISSION_GRANT,
+            DevicePolicyIdentifiers.LOCK_TASK_POLICY, LOCK_TASK,
+            DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY,
             USER_CONTROLLED_DISABLED_PACKAGES,
-            DevicePolicyManager.PERSISTENT_PREFERRED_ACTIVITY_POLICY,
+            DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY,
             GENERIC_PERSISTENT_PREFERRED_ACTIVITY,
-            DevicePolicyManager.PACKAGE_UNINSTALL_BLOCKED_POLICY, GENERIC_PACKAGE_UNINSTALL_BLOCKED,
-            DevicePolicyManager.APPLICATION_RESTRICTIONS_POLICY, GENERIC_APPLICATION_RESTRICTIONS,
-            DevicePolicyManager.RESET_PASSWORD_TOKEN_POLICY, RESET_PASSWORD_TOKEN
+            DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY,
+            GENERIC_PACKAGE_UNINSTALL_BLOCKED,
+            DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY,
+            GENERIC_APPLICATION_RESTRICTIONS,
+            DevicePolicyIdentifiers.RESET_PASSWORD_TOKEN_POLICY,
+            RESET_PASSWORD_TOKEN
     );
 
-
     private final PolicyKey mPolicyKey;
     private final ResolutionMechanism<V> mResolutionMechanism;
     private final int mPolicyFlags;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/TopPriority.java b/services/devicepolicy/java/com/android/server/devicepolicy/TopPriority.java
index 839840b..825157f0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/TopPriority.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/TopPriority.java
@@ -17,8 +17,10 @@
 package com.android.server.devicepolicy;
 
 import android.annotation.NonNull;
+import android.app.admin.Authority;
 import android.app.admin.PolicyValue;
 
+import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -54,7 +56,15 @@
 
     @Override
     android.app.admin.TopPriority<V> getParcelableResolutionMechanism() {
-        return new android.app.admin.TopPriority<>(mHighestToLowestPriorityAuthorities);
+        return new android.app.admin.TopPriority<>(getParcelableAuthorities());
+    }
+
+    private List<Authority> getParcelableAuthorities() {
+        List<Authority> authorities = new ArrayList<>();
+        for (String authority : mHighestToLowestPriorityAuthorities) {
+            authorities.add(EnforcingAdmin.getParcelableAuthority(authority));
+        }
+        return authorities;
     }
 
     @Override
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b117cae..850b5b6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -2095,6 +2095,14 @@
             mSystemServiceManager.startService(DeviceStorageMonitorService.class);
             t.traceEnd();
 
+            t.traceBegin("StartTimeDetectorService");
+            try {
+                mSystemServiceManager.startService(TIME_DETECTOR_SERVICE_CLASS);
+            } catch (Throwable e) {
+                reportWtf("starting TimeDetectorService service", e);
+            }
+            t.traceEnd();
+
             t.traceBegin("StartLocationManagerService");
             mSystemServiceManager.startService(LocationManagerService.Lifecycle.class);
             t.traceEnd();
@@ -2108,14 +2116,6 @@
             }
             t.traceEnd();
 
-            t.traceBegin("StartTimeDetectorService");
-            try {
-                mSystemServiceManager.startService(TIME_DETECTOR_SERVICE_CLASS);
-            } catch (Throwable e) {
-                reportWtf("starting TimeDetectorService service", e);
-            }
-            t.traceEnd();
-
             t.traceBegin("StartTimeZoneDetectorService");
             try {
                 mSystemServiceManager.startService(TIME_ZONE_DETECTOR_SERVICE_CLASS);
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index 61f8681..ef35010 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -18,6 +18,7 @@
 
 import android.Manifest
 import android.app.ActivityManager
+import android.app.AppOpsManager
 import android.compat.annotation.ChangeId
 import android.compat.annotation.EnabledAfter
 import android.content.Context
@@ -59,10 +60,12 @@
 import com.android.server.ServiceThread
 import com.android.server.SystemConfig
 import com.android.server.permission.access.AccessCheckingService
+import com.android.server.permission.access.AppOpUri
 import com.android.server.permission.access.GetStateScope
 import com.android.server.permission.access.MutateStateScope
 import com.android.server.permission.access.PermissionUri
 import com.android.server.permission.access.UidUri
+import com.android.server.permission.access.appop.UidAppOpPolicy
 import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
 import com.android.server.permission.access.util.andInv
 import com.android.server.permission.access.util.hasAnyBit
@@ -733,18 +736,46 @@
         }
     }
 
-    private fun grantRequestedRuntimePermissions(
+    private fun setRequestedPermissionStates(
         packageState: PackageState,
         userId: Int,
-        permissionNames: IndexedList<String>
+        permissionStates: IndexedMap<String, Int>
     ) {
         service.mutateState {
-            permissionNames.forEachIndexed { _, permissionName ->
-                setRuntimePermissionGranted(
-                    packageState, userId, permissionName, isGranted = true,
-                    canManageRolePermission = false, overridePolicyFixed = false,
-                    reportError = false, "grantRequestedRuntimePermissions"
-                )
+            permissionStates.forEachIndexed { _, permissionName, permissionState ->
+                when (permissionState) {
+                    PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED,
+                    PackageInstaller.SessionParams.PERMISSION_STATE_DENIED -> {}
+                    else -> {
+                        Log.w(
+                            LOG_TAG, "setRequestedPermissionStates: Unknown permission state" +
+                            " $permissionState for permission $permissionName"
+                        )
+                        return@forEachIndexed
+                    }
+                }
+                if (permissionName !in packageState.androidPackage!!.requestedPermissions) {
+                    return@forEachIndexed
+                }
+                val permission = with(policy) { getPermissions()[permissionName] }
+                    ?: return@forEachIndexed
+                when {
+                    permission.isDevelopment || permission.isRuntime -> {
+                        if (permissionState ==
+                            PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED) {
+                            setRuntimePermissionGranted(
+                                packageState, userId, permissionName, isGranted = true,
+                                canManageRolePermission = false, overridePolicyFixed = false,
+                                reportError = false, "setRequestedPermissionStates"
+                            )
+                        }
+                    }
+                    permission.isAppOp -> setAppOpPermissionGranted(
+                        packageState, userId, permissionName,
+                        permissionState == PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED
+                    )
+                    else -> {}
+                }
             }
         }
     }
@@ -890,6 +921,18 @@
         }
     }
 
+    private fun MutateStateScope.setAppOpPermissionGranted(
+        packageState: PackageState,
+        userId: Int,
+        permissionName: String,
+        isGranted: Boolean
+    ) {
+        val appOpPolicy = service.getSchemePolicy(UidUri.SCHEME, AppOpUri.SCHEME) as UidAppOpPolicy
+        val appOpName = AppOpsManager.permissionToOp(permissionName)
+        val mode = if (isGranted) AppOpsManager.MODE_ALLOWED else AppOpsManager.MODE_ERRORED
+        with(appOpPolicy) { setAppOpMode(packageState.appId, userId, appOpName, mode) }
+    }
+
     override fun getPermissionFlags(packageName: String, permissionName: String, userId: Int): Int {
         if (!userManagerInternal.exists(userId)) {
             Log.w(LOG_TAG, "getPermissionFlags: Unknown user $userId")
@@ -1814,15 +1857,7 @@
             val packageState =
                 packageManagerInternal.getPackageStateInternal(androidPackage.packageName)!!
             // TODO: Add allowlisting
-            grantRequestedRuntimePermissions(
-                packageState,
-                userId,
-                params.permissionStates.mapNotNullIndexed { _, permissionName, permissionState ->
-                    permissionName.takeIf {
-                        permissionState == PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED
-                    }
-                }
-            )
+            setRequestedPermissionStates(packageState, userId, params.permissionStates)
         }
     }
 
diff --git a/services/robotests/src/com/android/server/location/gnss/TimeDetectorNetworkTimeHelperTest.java b/services/robotests/src/com/android/server/location/gnss/TimeDetectorNetworkTimeHelperTest.java
new file mode 100644
index 0000000..3e2e46c
--- /dev/null
+++ b/services/robotests/src/com/android/server/location/gnss/TimeDetectorNetworkTimeHelperTest.java
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.gnss;
+
+import static com.android.server.location.gnss.TimeDetectorNetworkTimeHelper.MAX_NETWORK_TIME_AGE_MILLIS;
+import static com.android.server.location.gnss.TimeDetectorNetworkTimeHelper.NTP_REFRESH_INTERVAL_MILLIS;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.app.time.UnixEpochTime;
+import android.platform.test.annotations.Presubmit;
+
+import com.android.server.location.gnss.NetworkTimeHelper.InjectTimeCallback;
+import com.android.server.location.gnss.TimeDetectorNetworkTimeHelper.Environment;
+import com.android.server.timedetector.NetworkTimeSuggestion;
+import com.android.server.timezonedetector.StateChangeListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+/**
+ * Unit tests for {@link TimeDetectorNetworkTimeHelper}.
+ */
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class TimeDetectorNetworkTimeHelperTest {
+
+    private static final NetworkTimeSuggestion ARBITRARY_NETWORK_TIME =
+            new NetworkTimeSuggestion(new UnixEpochTime(1234L, 7777L), 123);
+
+    private FakeEnvironment mFakeEnvironment;
+    @Mock private InjectTimeCallback mMockInjectTimeCallback;
+    private TimeDetectorNetworkTimeHelper mTimeDetectorNetworkTimeHelper;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mFakeEnvironment = new FakeEnvironment();
+        mTimeDetectorNetworkTimeHelper = new TimeDetectorNetworkTimeHelper(
+                mFakeEnvironment, mMockInjectTimeCallback);
+
+        // TimeDetectorNetworkTimeHelper should register for network time updates during
+        // construction.
+        mFakeEnvironment.assertHasNetworkTimeChangeListener();
+    }
+
+    @Test
+    public void setPeriodicTimeInjectionMode_true() {
+        testSetPeriodicTimeInjectionMode(true);
+    }
+
+    @Test
+    public void setPeriodicTimeInjectionMode_false() {
+        testSetPeriodicTimeInjectionMode(false);
+    }
+
+    private void testSetPeriodicTimeInjectionMode(boolean periodicTimeInjectionMode) {
+        NetworkTimeSuggestion networkTime = ARBITRARY_NETWORK_TIME;
+        int millisElapsedSinceNetworkTimeReceived = 1000;
+        mFakeEnvironment.pokeLatestNetworkTime(networkTime);
+
+        long currentElapsedRealtimeMillis =
+                networkTime.getUnixEpochTime().getElapsedRealtimeMillis()
+                        + millisElapsedSinceNetworkTimeReceived;
+        mFakeEnvironment.pokeElapsedRealtimeMillis(currentElapsedRealtimeMillis);
+
+        mTimeDetectorNetworkTimeHelper.setPeriodicTimeInjectionMode(periodicTimeInjectionMode);
+
+        // All injections are async, so we have to simulate the async work taking place.
+        mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+        mFakeEnvironment.assertHasImmediateCallback();
+        mFakeEnvironment.simulateTimeAdvancing(1);
+
+        // Any call to setPeriodicTimeInjectionMode() should result in an (async) injected time
+        verify(mMockInjectTimeCallback).injectTime(
+                networkTime.getUnixEpochTime().getUnixEpochTimeMillis(),
+                networkTime.getUnixEpochTime().getElapsedRealtimeMillis(),
+                networkTime.getUncertaintyMillis());
+
+        // Check whether the scheduled async is set up / not set up for the periodic request.
+        if (periodicTimeInjectionMode) {
+            mFakeEnvironment.assertHasScheduledAsyncCallback(
+                    mFakeEnvironment.elapsedRealtimeMillis() + NTP_REFRESH_INTERVAL_MILLIS);
+        } else {
+            mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+        }
+    }
+
+    @Test
+    public void periodicInjectionBehavior() {
+        // Set the elapsed realtime clock to an arbitrary start value.
+        mFakeEnvironment.pokeElapsedRealtimeMillis(12345L);
+
+        // Configure periodic time injections. Doing so should cause a time query, but no time is
+        // available.
+        mTimeDetectorNetworkTimeHelper.setPeriodicTimeInjectionMode(true);
+
+        // All query/injections are async, so we have to simulate the async work taking place.
+        mFakeEnvironment.assertHasImmediateCallback();
+        mFakeEnvironment.simulateTimeAdvancing(1);
+
+        // No time available, so no injection.
+        verifyNoMoreInteractions(mMockInjectTimeCallback);
+
+        // A periodic check should be scheduled.
+        mFakeEnvironment.assertHasScheduledAsyncCallback(
+                mFakeEnvironment.elapsedRealtimeMillis() + NTP_REFRESH_INTERVAL_MILLIS);
+
+        // Time passes...
+        mFakeEnvironment.simulateTimeAdvancing(NTP_REFRESH_INTERVAL_MILLIS / 2);
+
+        // A network time becomes available: This should cause the registered listener to trigger.
+        NetworkTimeSuggestion networkTime = ARBITRARY_NETWORK_TIME;
+        mFakeEnvironment.simulateLatestNetworkTimeChange(networkTime);
+
+        // All query/injections are async, so we have to simulate the async work taking place,
+        // causing a query, time injection and a re-schedule.
+        mFakeEnvironment.simulateTimeAdvancing(1);
+        verify(mMockInjectTimeCallback).injectTime(
+                networkTime.getUnixEpochTime().getUnixEpochTimeMillis(),
+                networkTime.getUnixEpochTime().getElapsedRealtimeMillis(),
+                networkTime.getUncertaintyMillis());
+
+        // A new periodic check should be scheduled.
+        mFakeEnvironment.assertHasNoImmediateCallback();
+
+        mFakeEnvironment.assertHasScheduledAsyncCallback(
+                mFakeEnvironment.elapsedRealtimeMillis() + NTP_REFRESH_INTERVAL_MILLIS);
+
+        int arbitraryIterationCount = 3;
+        for (int i = 0; i < arbitraryIterationCount; i++) {
+            // Advance by the amount needed for the scheduled work to run. That work should query
+            // and inject.
+            mFakeEnvironment.simulateTimeAdvancing(NTP_REFRESH_INTERVAL_MILLIS);
+
+            // All query/injections are async, so we have to simulate the async work taking place,
+            // causing a query, time injection and a re-schedule.
+            verify(mMockInjectTimeCallback).injectTime(
+                    networkTime.getUnixEpochTime().getUnixEpochTimeMillis(),
+                    networkTime.getUnixEpochTime().getElapsedRealtimeMillis(),
+                    networkTime.getUncertaintyMillis());
+
+            // A new periodic check should be scheduled.
+            mFakeEnvironment.assertHasScheduledAsyncCallback(
+                    mFakeEnvironment.elapsedRealtimeMillis() + NTP_REFRESH_INTERVAL_MILLIS);
+            mFakeEnvironment.assertHasNoImmediateCallback();
+        }
+    }
+
+    @Test
+    public void networkTimeAvailableBehavior() {
+        // Set the elapsed realtime clock to an arbitrary start value.
+        mFakeEnvironment.pokeElapsedRealtimeMillis(12345L);
+
+        // No periodic time injections. This call causes a time query, but no time is available yet.
+        mTimeDetectorNetworkTimeHelper.setPeriodicTimeInjectionMode(false);
+
+        // All query/injections are async, so we have to simulate the async work taking place.
+        mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+        mFakeEnvironment.assertHasImmediateCallback();
+        mFakeEnvironment.simulateTimeAdvancing(1);
+
+        // No time available, so no injection.
+        verifyNoMoreInteractions(mMockInjectTimeCallback);
+
+        // No periodic check should be scheduled.
+        mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+
+        // Time passes...
+        mFakeEnvironment.simulateTimeAdvancing(NTP_REFRESH_INTERVAL_MILLIS / 2);
+
+        // A network time becomes available: This should cause the registered listener to trigger
+        // and cause time to be injected.
+        NetworkTimeSuggestion networkTime = ARBITRARY_NETWORK_TIME;
+        mFakeEnvironment.simulateLatestNetworkTimeChange(networkTime);
+
+        // All query/injections are async, so we have to simulate the async work taking place,
+        // causing a query, time injection and a re-schedule.
+        mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+        mFakeEnvironment.assertHasImmediateCallback();
+        mFakeEnvironment.simulateTimeAdvancing(1);
+        verify(mMockInjectTimeCallback).injectTime(
+                networkTime.getUnixEpochTime().getUnixEpochTimeMillis(),
+                networkTime.getUnixEpochTime().getElapsedRealtimeMillis(),
+                networkTime.getUncertaintyMillis());
+
+        // No periodic check should be scheduled.
+        mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+        mFakeEnvironment.assertHasNoImmediateCallback();
+    }
+
+    @Test
+    public void networkConnectivityAvailableBehavior() {
+        // Set the elapsed realtime clock to an arbitrary start value.
+        mFakeEnvironment.pokeElapsedRealtimeMillis(12345L);
+
+        // No periodic time injections. This call causes a time query, but no time is available yet.
+        mTimeDetectorNetworkTimeHelper.setPeriodicTimeInjectionMode(false);
+
+        // All query/injections are async, so we have to simulate the async work taking place.
+        mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+        mFakeEnvironment.assertHasImmediateCallback();
+        mFakeEnvironment.simulateTimeAdvancing(1);
+
+        // No time available, so no injection.
+        verifyNoMoreInteractions(mMockInjectTimeCallback);
+
+        // No periodic check should be scheduled.
+        mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+
+        // Time passes...
+        mFakeEnvironment.simulateTimeAdvancing(NTP_REFRESH_INTERVAL_MILLIS / 2);
+
+        NetworkTimeSuggestion networkTime = ARBITRARY_NETWORK_TIME;
+        mFakeEnvironment.pokeLatestNetworkTime(networkTime);
+
+        // Simulate location code noticing that connectivity has changed and notifying the helper.
+        mTimeDetectorNetworkTimeHelper.onNetworkAvailable();
+
+        // All query/injections are async, so we have to simulate the async work taking place,
+        // causing a query, time injection and a re-schedule.
+        mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+        mFakeEnvironment.assertHasImmediateCallback();
+        mFakeEnvironment.simulateTimeAdvancing(1);
+        verify(mMockInjectTimeCallback).injectTime(
+                networkTime.getUnixEpochTime().getUnixEpochTimeMillis(),
+                networkTime.getUnixEpochTime().getElapsedRealtimeMillis(),
+                networkTime.getUncertaintyMillis());
+
+        // No periodic check should be scheduled.
+        mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+        mFakeEnvironment.assertHasNoImmediateCallback();
+    }
+
+    @Test
+    public void oldTimesNotInjected() {
+        NetworkTimeSuggestion networkTime = ARBITRARY_NETWORK_TIME;
+        mFakeEnvironment.pokeLatestNetworkTime(networkTime);
+
+        int millisElapsedSinceNetworkTimeReceived = MAX_NETWORK_TIME_AGE_MILLIS;
+        long currentElapsedRealtimeMillis =
+                networkTime.getUnixEpochTime().getElapsedRealtimeMillis()
+                        + millisElapsedSinceNetworkTimeReceived;
+        mFakeEnvironment.pokeElapsedRealtimeMillis(currentElapsedRealtimeMillis);
+
+        mTimeDetectorNetworkTimeHelper.setPeriodicTimeInjectionMode(true);
+
+        // All injections are async, so we have to simulate the async work taking place.
+        mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+        mFakeEnvironment.assertHasImmediateCallback();
+
+        // The age of the network time will now be MAX_NETWORK_TIME_AGE_MILLIS + 1, which is too
+        // old to inject.
+        mFakeEnvironment.simulateTimeAdvancing(1);
+
+        // Old network times should not be injected.
+        verify(mMockInjectTimeCallback, never()).injectTime(anyLong(), anyLong(), anyInt());
+
+        // Check whether the scheduled async is set up / not set up for the periodic request.
+        mFakeEnvironment.assertHasScheduledAsyncCallback(
+                mFakeEnvironment.elapsedRealtimeMillis() + NTP_REFRESH_INTERVAL_MILLIS);
+    }
+
+    /** A fake implementation of {@link Environment} for use by this test. */
+    private static class FakeEnvironment implements Environment {
+
+        private StateChangeListener mNetworkTimeUpdateListener;
+
+        private long mCurrentElapsedRealtimeMillis;
+        private NetworkTimeSuggestion mLatestNetworkTime;
+
+        private TimeDetectorNetworkTimeHelper mImmediateAsyncCallback;
+        private String mImmediateAsyncCallbackReason;
+
+        private TimeDetectorNetworkTimeHelper mScheduledAsyncCallback;
+        private long mScheduledAsyncRunnableTimeMillis;
+
+        @Override
+        public long elapsedRealtimeMillis() {
+            return mCurrentElapsedRealtimeMillis;
+        }
+
+        @Override
+        public NetworkTimeSuggestion getLatestNetworkTime() {
+            return mLatestNetworkTime;
+        }
+
+        @Override
+        public void setNetworkTimeUpdateListener(StateChangeListener stateChangeListener) {
+            mNetworkTimeUpdateListener = stateChangeListener;
+        }
+
+        @Override
+        public void requestImmediateTimeQueryCallback(TimeDetectorNetworkTimeHelper helper,
+                String reason) {
+            if (mImmediateAsyncCallback != null) {
+                fail("Only one immediate callback expected at a time, found reason: "
+                        + mImmediateAsyncCallbackReason);
+            }
+            mImmediateAsyncCallback = helper;
+            mImmediateAsyncCallbackReason = reason;
+        }
+
+        @Override
+        public void requestDelayedTimeQueryCallback(
+                TimeDetectorNetworkTimeHelper instance, long delayMillis) {
+            mScheduledAsyncCallback = instance;
+            mScheduledAsyncRunnableTimeMillis = mCurrentElapsedRealtimeMillis + delayMillis;
+        }
+
+        @Override
+        public void clearDelayedTimeQueryCallback() {
+            mScheduledAsyncCallback = null;
+            mScheduledAsyncRunnableTimeMillis = -1;
+        }
+
+        void pokeLatestNetworkTime(NetworkTimeSuggestion networkTime) {
+            mLatestNetworkTime = networkTime;
+        }
+
+        void pokeElapsedRealtimeMillis(long currentElapsedRealtimeMillis) {
+            mCurrentElapsedRealtimeMillis = currentElapsedRealtimeMillis;
+        }
+
+        void simulateLatestNetworkTimeChange(NetworkTimeSuggestion networkTime) {
+            mLatestNetworkTime = networkTime;
+            mNetworkTimeUpdateListener.onChange();
+        }
+
+        void simulateTimeAdvancing(long durationMillis) {
+            mCurrentElapsedRealtimeMillis += durationMillis;
+
+            if (mImmediateAsyncCallback != null) {
+                TimeDetectorNetworkTimeHelper helper = mImmediateAsyncCallback;
+                String reason = mImmediateAsyncCallbackReason;
+                mImmediateAsyncCallback = null;
+                mImmediateAsyncCallbackReason = null;
+                helper.queryAndInjectNetworkTime(reason);
+            }
+
+            if (mScheduledAsyncCallback != null
+                    && mCurrentElapsedRealtimeMillis >= mScheduledAsyncRunnableTimeMillis) {
+                TimeDetectorNetworkTimeHelper helper = mScheduledAsyncCallback;
+                mScheduledAsyncCallback = null;
+                mScheduledAsyncRunnableTimeMillis = -1;
+                helper.delayedQueryAndInjectNetworkTime();
+            }
+        }
+
+        void assertHasNetworkTimeChangeListener() {
+            assertNotNull(mNetworkTimeUpdateListener);
+        }
+
+        void assertHasImmediateCallback() {
+            assertNotNull(mImmediateAsyncCallback);
+        }
+
+        void assertHasNoImmediateCallback() {
+            assertNull(mImmediateAsyncCallback);
+        }
+
+        void assertHasScheduledAsyncCallback(long expectedScheduledAsyncRunnableTimeMillis) {
+            assertNotNull(mScheduledAsyncCallback);
+            assertEquals(expectedScheduledAsyncRunnableTimeMillis,
+                    mScheduledAsyncRunnableTimeMillis);
+        }
+
+        void assertHasNoScheduledAsyncCallback() {
+            assertNull(mScheduledAsyncCallback);
+        }
+    }
+}
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
index 31c49b3..9c4e6fd 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
+++ b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
@@ -33,6 +33,7 @@
         "Harrier",
     ],
     platform_apis: true,
+    certificate: "platform",
     test_suites: ["device-tests"],
     data: [
         ":AppEnumerationCrossUserPackageVisibilityTestApp",
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml b/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml
index 0395aa8..4749419 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml
+++ b/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml
@@ -25,6 +25,7 @@
 
     <!-- It's merged from Harrier library. Remove it since this test should not hold it. -->
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:node="remove" />
+    <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                      android:targetPackage="com.android.server.pm.test.appenumeration"
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
index 31fe184..4012d8e 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
+++ b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
@@ -16,6 +16,8 @@
 
 package com.android.server.pm.test.appenumeration;
 
+import static android.content.Context.MEDIA_PROJECTION_SERVICE;
+
 import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -26,7 +28,10 @@
 import android.content.IntentSender;
 import android.content.pm.IPackageManager;
 import android.content.pm.ProviderInfo;
+import android.media.projection.IMediaProjectionManager;
+import android.media.projection.MediaProjectionManager;
 import android.os.Process;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -160,6 +165,31 @@
                         null /* onFinished */, null /* handler */));
     }
 
+    @Test
+    public void mediaProjectionManager_createProjection_canSeeForceQueryable()
+            throws Exception {
+        installPackage(SHARED_USER_APK_PATH, true /* forceQueryable */);
+        final IMediaProjectionManager mediaProjectionManager =
+                IMediaProjectionManager.Stub.asInterface(
+                        ServiceManager.getService(MEDIA_PROJECTION_SERVICE));
+
+        assertThat(mediaProjectionManager.createProjection(0 /* uid */, TARGET_SHARED_USER,
+                MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */))
+                .isNotNull();
+    }
+
+    @Test
+    public void mediaProjectionManager_createProjection_cannotSeeTarget() {
+        installPackage(SHARED_USER_APK_PATH, false /* forceQueryable */);
+        final IMediaProjectionManager mediaProjectionManager =
+                IMediaProjectionManager.Stub.asInterface(
+                        ServiceManager.getService(MEDIA_PROJECTION_SERVICE));
+
+        Assert.assertThrows(IllegalArgumentException.class,
+                () -> mediaProjectionManager.createProjection(0 /* uid */, TARGET_SHARED_USER,
+                        MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */));
+    }
+
     private static void installPackage(String apkPath, boolean forceQueryable) {
         final StringBuilder cmd = new StringBuilder("pm install ");
         if (forceQueryable) {
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt
index d760dc7..811b086 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt
@@ -15,7 +15,6 @@
  */
 package com.android.server.pm
 
-import android.Manifest
 import android.content.Context
 import android.content.pm.PackageInstaller
 import android.content.pm.PackageInstaller.SessionParams
@@ -122,12 +121,10 @@
         writeRestoreAssert(sessions).single().params.run {
             assertThat(legacyGrantedRuntimePermissions).asList()
                 .containsExactly("grantPermission", "denyToGrantPermission")
-            assertThat(finalPermissionStates)
+            assertThat(permissionStates)
                 .containsExactlyEntriesIn(mapOf(
                     "grantPermission" to PERMISSION_STATE_GRANTED,
                     "denyToGrantPermission" to PERMISSION_STATE_GRANTED,
-                    // Fullscreen Intent is auto-granted if the caller has no opinion
-                    Manifest.permission.USE_FULL_SCREEN_INTENT to PERMISSION_STATE_GRANTED,
                     "denyPermission" to PERMISSION_STATE_DENIED,
                     "grantToDenyPermission" to PERMISSION_STATE_DENIED,
                 ))
@@ -282,7 +279,7 @@
         assertThat(expected.referrerUri).isEqualTo(actual.referrerUri)
         assertThat(expected.abiOverride).isEqualTo(actual.abiOverride)
         assertThat(expected.volumeUuid).isEqualTo(actual.volumeUuid)
-        assertThat(expected.finalPermissionStates).isEqualTo(actual.finalPermissionStates)
+        assertThat(expected.permissionStates).isEqualTo(actual.permissionStates)
         assertThat(expected.installerPackageName).isEqualTo(actual.installerPackageName)
         assertThat(expected.isMultiPackage).isEqualTo(actual.isMultiPackage)
         assertThat(expected.isStaged).isEqualTo(actual.isStaged)
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
index 9895e7c..c7fb32c 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
@@ -753,7 +753,7 @@
                 .setPVersionCode(pkg.getLongVersionCode())
                 .setPkgFlags(PackageInfoUtils.appInfoFlags(pkg, null))
                 .setPrivateFlags(PackageInfoUtils.appInfoPrivateFlags(pkg, null))
-                .setSharedUserId(pkg.getSharedUserLabelRes())
+                .setSharedUserId(pkg.getSharedUserLabelResourceId())
                 .build();
     }
 
@@ -763,13 +763,13 @@
         assertEquals(a.getBaseRevisionCode(), b.getBaseRevisionCode());
         assertEquals(a.isHardwareAccelerated(), b.isHardwareAccelerated());
         assertEquals(a.getLongVersionCode(), b.getLongVersionCode());
-        assertEquals(a.getSharedUserLabelRes(), b.getSharedUserLabelRes());
+        assertEquals(a.getSharedUserLabelResourceId(), b.getSharedUserLabelResourceId());
         assertEquals(a.getInstallLocation(), b.getInstallLocation());
         assertEquals(a.isCoreApp(), b.isCoreApp());
         assertEquals(a.isRequiredForAllUsers(), b.isRequiredForAllUsers());
         assertEquals(a.getCompileSdkVersion(), b.getCompileSdkVersion());
         assertEquals(a.getCompileSdkVersionCodeName(), b.getCompileSdkVersionCodeName());
-        assertEquals(a.isUse32BitAbi(), b.isUse32BitAbi());
+        assertEquals(a.is32BitAbiPreferred(), b.is32BitAbiPreferred());
         assertEquals(a.getPackageName(), b.getPackageName());
         assertArrayEquals(a.getSplitNames(), b.getSplitNames());
         assertEquals(a.getVolumeUuid(), b.getVolumeUuid());
@@ -1039,7 +1039,7 @@
 
         ((ParsedPackage) pkg.setBaseRevisionCode(100)
                 .setHardwareAccelerated(true)
-                .setSharedUserLabelRes(100)
+                .setSharedUserLabelResourceId(100)
                 .setInstallLocation(100)
                 .setRequiredForAllUsers(true)
                 .asSplit(
@@ -1048,7 +1048,7 @@
                         new int[]{100},
                         null
                 )
-                .setUse32BitAbi(true)
+                .set32BitAbiPreferred(true)
                 .setVolumeUuid("d52ef59a-7def-4541-bf21-4c28ed4b65a0")
                 .addPermission(permission)
                 .addPermissionGroup(new ParsedPermissionGroupImpl())
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 0b7020c7..6d3cdff 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -155,7 +155,7 @@
         AndroidPackage::getAppComponentFactory,
         AndroidPackage::getAutoRevokePermissions,
         AndroidPackage::getBackupAgentName,
-        AndroidPackage::getBannerRes,
+        AndroidPackage::getBannerResourceId,
         AndroidPackage::getBaseApkPath,
         AndroidPackage::getBaseRevisionCode,
         AndroidPackage::getCategory,
@@ -163,16 +163,16 @@
         AndroidPackage::getCompatibleWidthLimitDp,
         AndroidPackage::getCompileSdkVersion,
         AndroidPackage::getCompileSdkVersionCodeName,
-        AndroidPackage::getDataExtractionRulesRes,
-        AndroidPackage::getDescriptionRes,
-        AndroidPackage::getFullBackupContentRes,
+        AndroidPackage::getDataExtractionRulesResourceId,
+        AndroidPackage::getDescriptionResourceId,
+        AndroidPackage::getFullBackupContentResourceId,
         AndroidPackage::getGwpAsanMode,
-        AndroidPackage::getIconRes,
+        AndroidPackage::getIconResourceId,
         AndroidPackage::getInstallLocation,
-        AndroidPackage::getLabelRes,
+        AndroidPackage::getLabelResourceId,
         AndroidPackage::getLargestWidthLimitDp,
-        AndroidPackage::getLogoRes,
-        AndroidPackage::getLocaleConfigRes,
+        AndroidPackage::getLogoResourceId,
+        AndroidPackage::getLocaleConfigResourceId,
         AndroidPackage::getManageSpaceActivityName,
         AndroidPackage::getMaxSdkVersion,
         AndroidPackage::getMemtagMode,
@@ -180,7 +180,7 @@
         AndroidPackage::getNativeHeapZeroInitialized,
         AndroidPackage::getNativeLibraryDir,
         AndroidPackage::getNativeLibraryRootDir,
-        AndroidPackage::getNetworkSecurityConfigRes,
+        AndroidPackage::getNetworkSecurityConfigResourceId,
         AndroidPackage::getNonLocalizedLabel,
         AndroidPackage::getOverlayCategory,
         AndroidPackage::getOverlayPriority,
@@ -195,11 +195,11 @@
         AndroidPackage::getRequiresSmallestWidthDp,
         AndroidPackage::getResizeableActivity,
         AndroidPackage::getRestrictedAccountType,
-        AndroidPackage::getRoundIconRes,
+        AndroidPackage::getRoundIconResourceId,
         PackageImpl::getSecondaryCpuAbi,
         AndroidPackage::getSecondaryNativeLibraryDir,
         AndroidPackage::getSharedUserId,
-        AndroidPackage::getSharedUserLabelRes,
+        AndroidPackage::getSharedUserLabelResourceId,
         AndroidPackage::getSdkLibraryName,
         AndroidPackage::getSdkLibVersionMajor,
         AndroidPackage::getStaticSharedLibraryName,
@@ -207,21 +207,21 @@
         AndroidPackage::getTargetSandboxVersion,
         AndroidPackage::getTargetSdkVersion,
         AndroidPackage::getTaskAffinity,
-        AndroidPackage::getThemeRes,
+        AndroidPackage::getThemeResourceId,
         AndroidPackage::getUiOptions,
         AndroidPackage::getUid,
         AndroidPackage::getVersionName,
         AndroidPackage::getZygotePreloadName,
         AndroidPackage::isAllowAudioPlaybackCapture,
-        AndroidPackage::isAllowBackup,
-        AndroidPackage::isAllowClearUserData,
-        AndroidPackage::isAllowClearUserDataOnFailedRestore,
+        AndroidPackage::isBackupAllowed,
+        AndroidPackage::isClearUserDataAllowed,
+        AndroidPackage::isClearUserDataOnFailedRestoreAllowed,
         AndroidPackage::isAllowNativeHeapPointerTagging,
-        AndroidPackage::isAllowTaskReparenting,
+        AndroidPackage::isTaskReparentingAllowed,
         AndroidPackage::isAllowUpdateOwnership,
         AndroidPackage::isBackupInForeground,
         AndroidPackage::isHardwareAccelerated,
-        AndroidPackage::isCantSaveState,
+        AndroidPackage::isSaveStateDisallowed,
         AndroidPackage::isCoreApp,
         AndroidPackage::isCrossProfile,
         AndroidPackage::isDebuggable,
@@ -229,17 +229,17 @@
         AndroidPackage::isDirectBootAware,
         AndroidPackage::isEnabled,
         AndroidPackage::isExternalStorage,
-        AndroidPackage::isExtractNativeLibs,
+        AndroidPackage::isExtractNativeLibrariesRequested,
         AndroidPackage::isFactoryTest,
         AndroidPackage::isApex,
         AndroidPackage::isForceQueryable,
         AndroidPackage::isFullBackupOnly,
         AndroidPackage::isGame,
-        AndroidPackage::isHasCode,
+        AndroidPackage::isDeclaredHavingCode,
         AndroidPackage::isHasDomainUrls,
-        AndroidPackage::isHasFragileUserData,
+        AndroidPackage::isUserDataFragile,
         AndroidPackage::isIsolatedSplitLoading,
-        AndroidPackage::isKillAfterRestore,
+        AndroidPackage::isKillAfterRestoreAllowed,
         AndroidPackage::isLargeHeap,
         AndroidPackage::isMultiArch,
         AndroidPackage::isNativeLibraryRootRequiresIsa,
@@ -257,12 +257,12 @@
         AndroidPackage::isSdkLibrary,
         AndroidPackage::isStaticSharedLibrary,
         AndroidPackage::isStub,
-        AndroidPackage::isSupportsRtl,
+        AndroidPackage::isRtlSupported,
         AndroidPackage::isTestOnly,
-        AndroidPackage::isUse32BitAbi,
+        AndroidPackage::is32BitAbiPreferred,
         AndroidPackage::isUseEmbeddedDex,
-        AndroidPackage::isUsesCleartextTraffic,
-        AndroidPackage::isUsesNonSdkApi,
+        AndroidPackage::isCleartextTrafficAllowed,
+        AndroidPackage::isNonSdkApiRequested,
         AndroidPackage::isVisibleToInstantApps,
         AndroidPackage::isVmSafeMode,
         AndroidPackage::isLeavingSharedUser,
@@ -282,10 +282,10 @@
         getter(AndroidPackage::getUpgradeKeySets, setOf("testUpgradeKeySet")),
         getter(AndroidPackage::isAnyDensity, false, 0),
         getter(AndroidPackage::isResizeable, false, 0),
-        getter(AndroidPackage::isSupportsSmallScreens, false, 0),
-        getter(AndroidPackage::isSupportsNormalScreens, false, 0),
-        getter(AndroidPackage::isSupportsLargeScreens, false, 0),
-        getter(AndroidPackage::isSupportsExtraLargeScreens, false, 0),
+        getter(AndroidPackage::isSmallScreensSupported, false, 0),
+        getter(AndroidPackage::isNormalScreensSupported, false, 0),
+        getter(AndroidPackage::isLargeScreensSupported, false, 0),
+        getter(AndroidPackage::isExtraLargeScreensSupported, false, 0),
         adder(AndroidPackage::getAdoptPermissions, "test.adopt.PERMISSION"),
         adder(AndroidPackage::getOriginalPackages, "com.test.original"),
         adder(AndroidPackage::getImplicitPermissions, "test.implicit.PERMISSION"),
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
index 8a855e5..5a733c7 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
@@ -312,4 +312,4 @@
                 .that(exception)
                 .isNotNull()
     }
-}
\ No newline at end of file
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index ad224df5..68cfe45 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -223,8 +223,7 @@
 
     private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue,
             BroadcastRecord record, int recordIndex, long enqueueTime) {
-        queue.enqueueOrReplaceBroadcast(record, recordIndex,
-                null /* replacedBroadcastConsumer */, false);
+        queue.enqueueOrReplaceBroadcast(record, recordIndex, false);
         record.enqueueTime = enqueueTime;
     }
 
@@ -354,8 +353,7 @@
         final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
         final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane,
                 List.of(makeMockRegisteredReceiver()));
-        queue.enqueueOrReplaceBroadcast(airplaneRecord, 0,
-                null /* replacedBroadcastConsumer */, false);
+        queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false);
 
         queue.setProcessCached(false);
         final long notCachedRunnableAt = queue.getRunnableAt();
@@ -377,14 +375,12 @@
         // enqueue a bg-priority broadcast then a fg-priority one
         final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
         final BroadcastRecord timezoneRecord = makeBroadcastRecord(timezone);
-        queue.enqueueOrReplaceBroadcast(timezoneRecord, 0,
-                null /* replacedBroadcastConsumer */, false);
+        queue.enqueueOrReplaceBroadcast(timezoneRecord, 0, false);
 
         final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
         airplane.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane);
-        queue.enqueueOrReplaceBroadcast(airplaneRecord, 0,
-                null /* replacedBroadcastConsumer */, false);
+        queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false);
 
         // verify that:
         // (a) the queue is immediately runnable by existence of a fg-priority broadcast
@@ -415,8 +411,7 @@
         final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane, null,
                 List.of(withPriority(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 10),
                         withPriority(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 0)), true);
-        queue.enqueueOrReplaceBroadcast(airplaneRecord, 1,
-                null /* replacedBroadcastConsumer */, false);
+        queue.enqueueOrReplaceBroadcast(airplaneRecord, 1, false);
 
         assertFalse(queue.isRunnable());
         assertEquals(BroadcastProcessQueue.REASON_BLOCKED, queue.getRunnableAtReason());
@@ -439,8 +434,7 @@
         final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
         final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane,
                 List.of(makeMockRegisteredReceiver()));
-        queue.enqueueOrReplaceBroadcast(airplaneRecord, 0,
-                null /* replacedBroadcastConsumer */, false);
+        queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false);
 
         mConstants.MAX_PENDING_BROADCASTS = 128;
         queue.invalidateRunnableAt();
@@ -466,13 +460,11 @@
                 new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED),
                 List.of(makeMockRegisteredReceiver()));
 
-        queue.enqueueOrReplaceBroadcast(lazyRecord, 0,
-                null /* replacedBroadcastConsumer */, false);
+        queue.enqueueOrReplaceBroadcast(lazyRecord, 0, false);
         assertThat(queue.getRunnableAt()).isGreaterThan(lazyRecord.enqueueTime);
         assertThat(queue.getRunnableAtReason()).isNotEqualTo(testRunnableAtReason);
 
-        queue.enqueueOrReplaceBroadcast(testRecord, 0,
-                null /* replacedBroadcastConsumer */, false);
+        queue.enqueueOrReplaceBroadcast(testRecord, 0, false);
         assertThat(queue.getRunnableAt()).isAtMost(testRecord.enqueueTime);
         assertThat(queue.getRunnableAtReason()).isEqualTo(testRunnableAtReason);
     }
@@ -534,26 +526,20 @@
 
         queue.enqueueOrReplaceBroadcast(
                 makeBroadcastRecord(new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED)
-                        .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0,
-                null /* replacedBroadcastConsumer */, false);
+                        .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, false);
         queue.enqueueOrReplaceBroadcast(
-                makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0,
-                null /* replacedBroadcastConsumer */, false);
+                makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0, false);
         queue.enqueueOrReplaceBroadcast(
                 makeBroadcastRecord(new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED)
-                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0,
-                null /* replacedBroadcastConsumer */, false);
+                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, false);
         queue.enqueueOrReplaceBroadcast(
                 makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED)
-                        .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0,
-                null /* replacedBroadcastConsumer */, false);
+                        .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, false);
         queue.enqueueOrReplaceBroadcast(
-                makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0,
-                null /* replacedBroadcastConsumer */, false);
+                makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0, false);
         queue.enqueueOrReplaceBroadcast(
                 makeBroadcastRecord(new Intent(Intent.ACTION_LOCALE_CHANGED)
-                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0,
-                null /* replacedBroadcastConsumer */, false);
+                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, false);
 
         queue.makeActiveNextPending();
         assertEquals(Intent.ACTION_LOCKED_BOOT_COMPLETED, queue.getActive().intent.getAction());
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
index b9893f6..f1acf66 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
@@ -147,12 +147,12 @@
             TEST_PACKAGE_NAME,
             1L,
             rule.system().dataAppDirectory,
-            withPackage = { it.apply { isHasCode = true } })
+            withPackage = { it.apply { isDeclaredHavingCode = true } })
         rule.system().stageScanExistingPackage(
             TEST_PACKAGE_2_NAME,
             1L,
             rule.system().dataAppDirectory,
-            withPackage = { it.apply { isHasCode = true } })
+            withPackage = { it.apply { isDeclaredHavingCode = true } })
         val pm = createPackageManagerService()
         rule.system().validateFinalState()
         whenever(appHibernationManager.isHibernatingGlobally(TEST_PACKAGE_2_NAME)).thenReturn(true)
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 76dfe02..89a5b12 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -708,7 +708,8 @@
     public void testStartProfile_fullUserFails() {
         setUpUser(TEST_USER_ID1, 0);
         assertThrows(IllegalArgumentException.class,
-                () -> mUserController.startProfile(TEST_USER_ID1));
+                () -> mUserController.startProfile(TEST_USER_ID1, /* evenWhenDisabled= */ false,
+                        /* unlockListener= */ null));
 
         verifyUserNeverAssignedToDisplay();
     }
@@ -725,7 +726,8 @@
     public void testStartProfile_disabledProfileFails() {
         setUpUser(TEST_USER_ID1, UserInfo.FLAG_PROFILE | UserInfo.FLAG_DISABLED, /* preCreated= */
                 false, UserManager.USER_TYPE_PROFILE_MANAGED);
-        assertThat(mUserController.startProfile(TEST_USER_ID1)).isFalse();
+        assertThat(mUserController.startProfile(TEST_USER_ID1, /* evenWhenDisabled=*/ false,
+                /* unlockListener= */ null)).isFalse();
 
         verifyUserNeverAssignedToDisplay();
     }
@@ -906,7 +908,8 @@
 
     private void setUpAndStartProfileInBackground(int userId) throws Exception {
         setUpUser(userId, UserInfo.FLAG_PROFILE, false, UserManager.USER_TYPE_PROFILE_MANAGED);
-        assertThat(mUserController.startProfile(userId)).isTrue();
+        assertThat(mUserController.startProfile(userId, /* evenWhenDisabled=*/ false,
+                /* unlockListener= */ null)).isTrue();
 
         verify(mInjector.mLockPatternUtilsMock, times(1)).unlockUserKeyIfUnsecured(userId);
         mUserStates.put(userId, mUserController.getStartedUserState(userId));
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 1904671..a616fbc 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -183,6 +183,10 @@
         int[] getSupportedHdrOutputTypes() {
             return new int[]{};
         }
+
+        boolean getHdrOutputConversionSupport() {
+            return false;
+        }
    }
 
     private final DisplayManagerService.Injector mBasicInjector = new BasicInjector();
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
index 704b06b..87aa272 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
@@ -24,6 +24,8 @@
 import android.app.timedetector.TelephonyTimeSuggestion;
 import android.util.IndentingPrintWriter;
 
+import com.android.server.timezonedetector.StateChangeListener;
+
 /**
  * A fake implementation of {@link com.android.server.timedetector.TimeDetectorStrategy} for use
  * in tests.
@@ -31,6 +33,7 @@
 public class FakeTimeDetectorStrategy implements TimeDetectorStrategy {
     // State
     private TimeState mTimeState;
+    private NetworkTimeSuggestion mLatestNetworkTimeSuggestion;
 
     @Override
     public TimeState getTimeState() {
@@ -62,8 +65,12 @@
     }
 
     @Override
+    public void addNetworkTimeUpdateListener(StateChangeListener networkSuggestionUpdateListener) {
+    }
+
+    @Override
     public NetworkTimeSuggestion getLatestNetworkSuggestion() {
-        return null;
+        return mLatestNetworkTimeSuggestion;
     }
 
     @Override
@@ -81,4 +88,8 @@
     @Override
     public void dump(IndentingPrintWriter pw, String[] args) {
     }
+
+    void setLatestNetworkTime(NetworkTimeSuggestion networkTimeSuggestion) {
+        mLatestNetworkTimeSuggestion = networkTimeSuggestion;
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 0b339ad..5a0867f 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -54,6 +54,7 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.location.gnss.TimeDetectorNetworkTimeHelper;
 import com.android.server.timezonedetector.TestCallerIdentityInjector;
 import com.android.server.timezonedetector.TestHandler;
 
@@ -420,21 +421,35 @@
 
     @Test
     public void testGetLatestNetworkSuggestion() {
-        NtpTrustedTime.TimeResult latestNetworkTime = new NtpTrustedTime.TimeResult(
-                1234L, 54321L, 999, InetSocketAddress.createUnresolved("test.timeserver", 123));
-        when(mMockNtpTrustedTime.getCachedTimeResult())
-                .thenReturn(latestNetworkTime);
-        UnixEpochTime expectedUnixEpochTime = new UnixEpochTime(
-                latestNetworkTime.getElapsedRealtimeMillis(), latestNetworkTime.getTimeMillis());
-        NetworkTimeSuggestion expected = new NetworkTimeSuggestion(
-                expectedUnixEpochTime, latestNetworkTime.getUncertaintyMillis());
-        assertEquals(expected, mTimeDetectorService.getLatestNetworkSuggestion());
+        if (TimeDetectorNetworkTimeHelper.isInUse()) {
+            NetworkTimeSuggestion latestNetworkTime = createNetworkTimeSuggestion();
+            mFakeTimeDetectorStrategySpy.setLatestNetworkTime(latestNetworkTime);
+
+            assertEquals(latestNetworkTime, mTimeDetectorService.getLatestNetworkSuggestion());
+        } else {
+            NtpTrustedTime.TimeResult latestNetworkTime = new NtpTrustedTime.TimeResult(
+                    1234L, 54321L, 999, InetSocketAddress.createUnresolved("test.timeserver", 123));
+            when(mMockNtpTrustedTime.getCachedTimeResult())
+                    .thenReturn(latestNetworkTime);
+            UnixEpochTime expectedUnixEpochTime = new UnixEpochTime(
+                    latestNetworkTime.getElapsedRealtimeMillis(),
+                    latestNetworkTime.getTimeMillis());
+            NetworkTimeSuggestion expected = new NetworkTimeSuggestion(
+                    expectedUnixEpochTime, latestNetworkTime.getUncertaintyMillis());
+            assertEquals(expected, mTimeDetectorService.getLatestNetworkSuggestion());
+        }
     }
 
     @Test
     public void testGetLatestNetworkSuggestion_noTimeAvailable() {
-        when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null);
-        assertNull(mTimeDetectorService.getLatestNetworkSuggestion());
+        if (TimeDetectorNetworkTimeHelper.isInUse()) {
+            mFakeTimeDetectorStrategySpy.setLatestNetworkTime(null);
+
+            assertNull(mTimeDetectorService.getLatestNetworkSuggestion());
+        } else {
+            when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null);
+            assertNull(mTimeDetectorService.getLatestNetworkSuggestion());
+        }
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index 37da2a2..4df21e0 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -41,6 +41,7 @@
 import com.android.server.SystemClockTime.TimeConfidence;
 import com.android.server.timedetector.TimeDetectorStrategy.Origin;
 import com.android.server.timezonedetector.StateChangeListener;
+import com.android.server.timezonedetector.TestStateChangeListener;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -51,6 +52,8 @@
 import java.time.Instant;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 import junitparams.JUnitParamsRunner;
@@ -863,8 +866,11 @@
                 new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
                         .setOriginPriorities(ORIGIN_NETWORK)
                         .build();
-        Script script = new Script().simulateConfigurationInternalChange(configInternal)
-                .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
+        TestStateChangeListener networkTimeUpdateListener = new TestStateChangeListener();
+        Script script = new Script()
+                .simulateConfigurationInternalChange(configInternal)
+                .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
+                .addNetworkTimeUpdateListener(networkTimeUpdateListener);
 
         NetworkTimeSuggestion timeSuggestion =
                 script.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
@@ -877,6 +883,11 @@
                 .assertLatestNetworkSuggestion(timeSuggestion)
                 .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
                 .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
+
+        // Confirm the network time update listener is notified of a change.
+        networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+        script.simulateAsyncRunnableExecution();
+        networkTimeUpdateListener.assertNotificationsReceivedAndReset(1);
     }
 
     @Test
@@ -885,7 +896,10 @@
                 new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
                         .setOriginPriorities(ORIGIN_NETWORK)
                         .build();
-        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+        TestStateChangeListener networkTimeUpdateListener = new TestStateChangeListener();
+        Script script = new Script()
+                .simulateConfigurationInternalChange(configInternal)
+                .addNetworkTimeUpdateListener(networkTimeUpdateListener);
 
         NetworkTimeSuggestion timeSuggestion =
                 script.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
@@ -894,6 +908,11 @@
                 .simulateNetworkTimeSuggestion(timeSuggestion)
                 .assertLatestNetworkSuggestion(timeSuggestion)
                 .verifySystemClockWasNotSetAndResetCallTracking();
+
+        // Confirm the network time update listener is notified of a change.
+        networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+        script.simulateAsyncRunnableExecution();
+        networkTimeUpdateListener.assertNotificationsReceivedAndReset(1);
     }
 
     @Test
@@ -902,7 +921,11 @@
                 new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
                         .setOriginPriorities(ORIGIN_NETWORK, ORIGIN_EXTERNAL)
                         .build();
-        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+        TestStateChangeListener networkTimeUpdateListener = new TestStateChangeListener();
+        Script script = new Script()
+                .simulateConfigurationInternalChange(configInternal)
+                .addNetworkTimeUpdateListener(networkTimeUpdateListener);
 
         // Create two different time suggestions for the current elapsedRealtimeMillis.
         ExternalTimeSuggestion externalTimeSuggestion =
@@ -927,6 +950,11 @@
             script.simulateNetworkTimeSuggestion(networkTimeSuggestion)
                     .assertLatestNetworkSuggestion(networkTimeSuggestion)
                     .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
+
+            // Confirm the network time update listener is notified of a change.
+            networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+            script.simulateAsyncRunnableExecution();
+            networkTimeUpdateListener.assertNotificationsReceivedAndReset(1);
         }
 
         // Clear the network time. This should cause the device to change back to the external time,
@@ -937,6 +965,11 @@
             script.simulateClearLatestNetworkSuggestion()
                     .assertLatestNetworkSuggestion(null)
                     .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
+
+            // Confirm network time update listeners are asynchronously notified of a change.
+            networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+            script.simulateAsyncRunnableExecution();
+            networkTimeUpdateListener.assertNotificationsReceivedAndReset(1);
         }
     }
 
@@ -947,8 +980,11 @@
                         .setOriginPriorities(ORIGIN_NETWORK)
                         .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
                         .build();
-        Script script = new Script().simulateConfigurationInternalChange(configInternal)
-                .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
+        TestStateChangeListener networkTimeUpdateListener = new TestStateChangeListener();
+        Script script = new Script()
+                .simulateConfigurationInternalChange(configInternal)
+                .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
+                .addNetworkTimeUpdateListener(networkTimeUpdateListener);
 
         Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1);
         NetworkTimeSuggestion timeSuggestion =
@@ -957,6 +993,11 @@
                 .assertLatestNetworkSuggestion(null)
                 .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
                 .verifySystemClockWasNotSetAndResetCallTracking();
+
+        // Confirm the network time update listener is not notified of a change.
+        networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+        script.simulateAsyncRunnableExecution();
+        networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
     }
 
     @Test
@@ -966,8 +1007,10 @@
                         .setOriginPriorities(ORIGIN_NETWORK)
                         .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
                         .build();
+        TestStateChangeListener networkTimeUpdateListener = new TestStateChangeListener();
         Script script = new Script().simulateConfigurationInternalChange(configInternal)
-                .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
+                .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
+                .addNetworkTimeUpdateListener(networkTimeUpdateListener);
 
         Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1);
         NetworkTimeSuggestion timeSuggestion =
@@ -976,6 +1019,11 @@
                 .assertLatestNetworkSuggestion(timeSuggestion)
                 .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
                 .verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli());
+
+        // Confirm the network time update listener is notified of a change.
+        networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+        script.simulateAsyncRunnableExecution();
+        networkTimeUpdateListener.assertNotificationsReceivedAndReset(1);
     }
 
     @Test
@@ -985,8 +1033,10 @@
                         .setOriginPriorities(ORIGIN_NETWORK)
                         .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
                         .build();
+        TestStateChangeListener networkTimeUpdateListener = new TestStateChangeListener();
         Script script = new Script().simulateConfigurationInternalChange(configInternal)
-                .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
+                .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
+                .addNetworkTimeUpdateListener(networkTimeUpdateListener);
 
         Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1);
         NetworkTimeSuggestion timeSuggestion =
@@ -995,6 +1045,11 @@
                 .assertLatestNetworkSuggestion(null)
                 .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
                 .verifySystemClockWasNotSetAndResetCallTracking();
+
+        // Confirm the network time update listener is not notified of a change.
+        networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+        script.simulateAsyncRunnableExecution();
+        networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
     }
 
     @Test
@@ -1004,8 +1059,10 @@
                         .setOriginPriorities(ORIGIN_NETWORK)
                         .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
                         .build();
+        TestStateChangeListener networkTimeUpdateListener = new TestStateChangeListener();
         Script script = new Script().simulateConfigurationInternalChange(configInternal)
-                .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
+                .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
+                .addNetworkTimeUpdateListener(networkTimeUpdateListener);
 
         Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1);
         NetworkTimeSuggestion timeSuggestion =
@@ -1014,6 +1071,11 @@
                 .assertLatestNetworkSuggestion(timeSuggestion)
                 .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
                 .verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli());
+
+        // Confirm the network time update listener is notified of a change.
+        networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+        script.simulateAsyncRunnableExecution();
+        networkTimeUpdateListener.assertNotificationsReceivedAndReset(1);
     }
 
     @Test
@@ -1800,7 +1862,10 @@
                 new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
                         .setOriginPriorities(ORIGIN_TELEPHONY)
                         .build();
-        Script script = new Script().simulateConfigurationInternalChange(configInternal);
+        TestStateChangeListener networkTimeUpdateListener = new TestStateChangeListener();
+        Script script = new Script()
+                .simulateConfigurationInternalChange(configInternal)
+                .addNetworkTimeUpdateListener(networkTimeUpdateListener);
 
         NetworkTimeSuggestion timeSuggestion = script.generateNetworkTimeSuggestion(
                 ARBITRARY_TEST_TIME);
@@ -1809,6 +1874,11 @@
                 .assertLatestNetworkSuggestion(timeSuggestion)
                 .assertLatestNetworkSuggestion(timeSuggestion)
                 .verifySystemClockWasNotSetAndResetCallTracking();
+
+        // Confirm the network time update listener is notified of a change.
+        networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+        script.simulateAsyncRunnableExecution();
+        networkTimeUpdateListener.assertNotificationsReceivedAndReset(1);
     }
 
     @Test
@@ -1867,6 +1937,8 @@
      */
     private static class FakeEnvironment implements TimeDetectorStrategyImpl.Environment {
 
+        private final List<Runnable> mAsyncRunnables = new ArrayList<>();
+
         private ConfigurationInternal mConfigurationInternal;
         private boolean mWakeLockAcquired;
         private long mElapsedRealtimeMillis;
@@ -1951,8 +2023,20 @@
             // No-op for tests
         }
 
+        @Override
+        public void runAsync(Runnable runnable) {
+            mAsyncRunnables.add(runnable);
+        }
+
         // Methods below are for managing the fake's behavior.
 
+        void runAsyncRunnables() {
+            for (Runnable runnable : mAsyncRunnables) {
+                runnable.run();
+            }
+            mAsyncRunnables.clear();
+        }
+
         void simulateConfigurationInternalChange(ConfigurationInternal configurationInternal) {
             mConfigurationInternal = configurationInternal;
             mConfigurationInternalChangeListener.onChange();
@@ -1992,7 +2076,7 @@
             assertEquals(expectedSystemClockMillis, mSystemClockMillis);
         }
 
-        public void verifySystemClockConfidenceLatest(@TimeConfidence int expectedConfidence) {
+        void verifySystemClockConfidenceLatest(@TimeConfidence int expectedConfidence) {
             assertEquals(expectedConfidence, mSystemClockConfidence);
         }
 
@@ -2118,6 +2202,17 @@
             return this;
         }
 
+        /** Calls {@link TimeDetectorStrategy#addNetworkTimeUpdateListener(StateChangeListener)}. */
+        Script addNetworkTimeUpdateListener(StateChangeListener listener) {
+            mTimeDetectorStrategy.addNetworkTimeUpdateListener(listener);
+            return this;
+        }
+
+        Script simulateAsyncRunnableExecution() {
+            mFakeEnvironment.runAsyncRunnables();
+            return this;
+        }
+
         Script verifySystemClockWasNotSetAndResetCallTracking() {
             mFakeEnvironment.verifySystemClockNotSet();
             mFakeEnvironment.resetCallTracking();
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TestStateChangeListener.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TestStateChangeListener.java
new file mode 100644
index 0000000..9cbf0a3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TestStateChangeListener.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import static org.junit.Assert.assertEquals;
+
+public class TestStateChangeListener implements StateChangeListener {
+
+    private int mNotificationsReceived;
+
+    @Override
+    public void onChange() {
+        mNotificationsReceived++;
+    }
+
+    public void assertNotificationsReceivedAndReset(int expectedCount) {
+        assertNotificationsReceived(expectedCount);
+        resetNotificationsReceivedCount();
+    }
+
+    private void resetNotificationsReceivedCount() {
+        mNotificationsReceived = 0;
+    }
+
+    private void assertNotificationsReceived(int expectedCount) {
+        assertEquals(expectedCount, mNotificationsReceived);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index 590aba9..03d406f 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -2001,26 +2001,4 @@
         return new TelephonyTestCase(matchType, quality, expectedScore);
     }
 
-    private static class TestStateChangeListener implements StateChangeListener {
-
-        private int mNotificationsReceived;
-
-        @Override
-        public void onChange() {
-            mNotificationsReceived++;
-        }
-
-        public void assertNotificationsReceivedAndReset(int expectedCount) {
-            assertNotificationsReceived(expectedCount);
-            resetNotificationsReceivedCount();
-        }
-
-        private void resetNotificationsReceivedCount() {
-            mNotificationsReceived = 0;
-        }
-
-        private void assertNotificationsReceived(int expectedCount) {
-            assertEquals(expectedCount, mNotificationsReceived);
-        }
-    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index cdbcecc..05ee2f2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -704,15 +704,15 @@
         ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
         ArraySet<WindowContainer> participants = transition.mParticipants;
 
-        final Task newTask = createTask(mDisplayContent);
-        doReturn(false).when(newTask).isTranslucent(any());
         final Task oldTask = createTask(mDisplayContent);
-        doReturn(false).when(oldTask).isTranslucent(any());
+        final Task newTask = createTask(mDisplayContent);
 
         final ActivityRecord closing = createActivityRecord(oldTask);
         closing.setOccludesParent(true);
+        closing.visibleIgnoringKeyguard = true;
         final ActivityRecord opening = createActivityRecord(newTask);
-        opening.setOccludesParent(false);
+        opening.setOccludesParent(true);
+        opening.visibleIgnoringKeyguard = true;
         // Start states.
         changes.put(newTask, new Transition.ChangeInfo(newTask, false /* vis */, true /* exChg */));
         changes.put(oldTask, new Transition.ChangeInfo(oldTask, true /* vis */, false /* exChg */));
@@ -735,8 +735,8 @@
         assertEquals(2, info.getChanges().size());
         assertEquals(transit, info.getType());
 
-        assertTrue((info.getChanges().get(0).getFlags() & FLAG_TRANSLUCENT) == 0);
-        assertTrue((info.getChanges().get(1).getFlags() & FLAG_TRANSLUCENT) == 0);
+        assertFalse(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+        assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
     }
 
     @Test
@@ -745,15 +745,15 @@
         ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
         ArraySet<WindowContainer> participants = transition.mParticipants;
 
-        final Task newTask = createTask(mDisplayContent);
-        doReturn(true).when(newTask).isTranslucent(any());
         final Task oldTask = createTask(mDisplayContent);
-        doReturn(false).when(oldTask).isTranslucent(any());
+        final Task newTask = createTask(mDisplayContent);
 
         final ActivityRecord closing = createActivityRecord(oldTask);
         closing.setOccludesParent(true);
+        closing.visibleIgnoringKeyguard = true;
         final ActivityRecord opening = createActivityRecord(newTask);
         opening.setOccludesParent(false);
+        opening.visibleIgnoringKeyguard = true;
         // Start states.
         changes.put(newTask, new Transition.ChangeInfo(newTask, false /* vis */, true /* exChg */));
         changes.put(oldTask, new Transition.ChangeInfo(oldTask, true /* vis */, false /* exChg */));
@@ -776,8 +776,186 @@
         assertEquals(2, info.getChanges().size());
         assertEquals(transit, info.getType());
 
-        assertTrue((info.getChanges().get(0).getFlags() & FLAG_TRANSLUCENT) != 0);
-        assertTrue((info.getChanges().get(1).getFlags() & FLAG_TRANSLUCENT) == 0);
+        assertTrue(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+        assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
+    }
+
+    @Test
+    public void testOpenOpaqueTaskFragment() {
+        final Transition transition = createTestTransition(TRANSIT_OPEN);
+        ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+        ArraySet<WindowContainer> participants = transition.mParticipants;
+
+        final Task task = createTask(mDisplayContent);
+        final TaskFragment closingTaskFragment = createTaskFragmentWithActivity(task);
+        final TaskFragment openingTaskFragment = createTaskFragmentWithActivity(task);
+
+        final ActivityRecord closing = closingTaskFragment.getTopMostActivity();
+        closing.setOccludesParent(true);
+        closing.visibleIgnoringKeyguard = true;
+        final ActivityRecord opening = openingTaskFragment.getTopMostActivity();
+        opening.setOccludesParent(true);
+        opening.visibleIgnoringKeyguard = true;
+        // Start states.
+        changes.put(openingTaskFragment, new Transition.ChangeInfo(openingTaskFragment,
+                false /* vis */, true /* exChg */));
+        changes.put(closingTaskFragment, new Transition.ChangeInfo(closingTaskFragment,
+                true /* vis */, false /* exChg */));
+        changes.put(opening, new Transition.ChangeInfo(opening, false /* vis */, true /* exChg */));
+        changes.put(closing, new Transition.ChangeInfo(closing, true /* vis */, false /* exChg */));
+        fillChangeMap(changes, openingTaskFragment);
+        // End states.
+        closing.setVisibleRequested(false);
+        opening.setVisibleRequested(true);
+
+        final int transit = transition.mType;
+        int flags = 0;
+
+        // Check basic both tasks participating
+        participants.add(closingTaskFragment);
+        participants.add(openingTaskFragment);
+        ArrayList<Transition.ChangeInfo> targets =
+                Transition.calculateTargets(participants, changes);
+        TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, mMockT);
+        assertEquals(2, info.getChanges().size());
+        assertEquals(transit, info.getType());
+
+        assertFalse(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+        assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
+    }
+
+    @Test
+    public void testOpenTranslucentTaskFragment() {
+        final Transition transition = createTestTransition(TRANSIT_OPEN);
+        ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+        ArraySet<WindowContainer> participants = transition.mParticipants;
+
+        final Task task = createTask(mDisplayContent);
+        final TaskFragment closingTaskFragment = createTaskFragmentWithActivity(task);
+        final TaskFragment openingTaskFragment = createTaskFragmentWithActivity(task);
+
+        final ActivityRecord closing = closingTaskFragment.getTopMostActivity();
+        closing.setOccludesParent(true);
+        closing.visibleIgnoringKeyguard = true;
+        final ActivityRecord opening = openingTaskFragment.getTopMostActivity();
+        opening.setOccludesParent(false);
+        opening.visibleIgnoringKeyguard = true;
+        // Start states.
+        changes.put(openingTaskFragment, new Transition.ChangeInfo(openingTaskFragment,
+                false /* vis */, true /* exChg */));
+        changes.put(closingTaskFragment, new Transition.ChangeInfo(closingTaskFragment,
+                true /* vis */, false /* exChg */));
+        changes.put(opening, new Transition.ChangeInfo(opening, false /* vis */, true /* exChg */));
+        changes.put(closing, new Transition.ChangeInfo(closing, true /* vis */, false /* exChg */));
+        fillChangeMap(changes, openingTaskFragment);
+        // End states.
+        closing.setVisibleRequested(false);
+        opening.setVisibleRequested(true);
+
+        final int transit = transition.mType;
+        int flags = 0;
+
+        // Check basic both tasks participating
+        participants.add(closingTaskFragment);
+        participants.add(openingTaskFragment);
+        ArrayList<Transition.ChangeInfo> targets =
+                Transition.calculateTargets(participants, changes);
+        TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, mMockT);
+        assertEquals(2, info.getChanges().size());
+        assertEquals(transit, info.getType());
+
+        assertTrue(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+        assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
+    }
+
+    @Test
+    public void testCloseOpaqueTaskFragment_withFinishingActivity() {
+        final Transition transition = createTestTransition(TRANSIT_CLOSE);
+        ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+        ArraySet<WindowContainer> participants = transition.mParticipants;
+
+        final Task task = createTask(mDisplayContent);
+        final TaskFragment openingTaskFragment = createTaskFragmentWithActivity(task);
+        final TaskFragment closingTaskFragment = createTaskFragmentWithActivity(task);
+
+        final ActivityRecord opening = openingTaskFragment.getTopMostActivity();
+        opening.setOccludesParent(true);
+        opening.visibleIgnoringKeyguard = true;
+        final ActivityRecord closing = closingTaskFragment.getTopMostActivity();
+        closing.setOccludesParent(true);
+        closing.visibleIgnoringKeyguard = true;
+        closing.finishing = true;
+        // Start states.
+        changes.put(openingTaskFragment, new Transition.ChangeInfo(openingTaskFragment,
+                false /* vis */, true /* exChg */));
+        changes.put(closingTaskFragment, new Transition.ChangeInfo(closingTaskFragment,
+                true /* vis */, false /* exChg */));
+        changes.put(opening, new Transition.ChangeInfo(opening, false /* vis */, true /* exChg */));
+        changes.put(closing, new Transition.ChangeInfo(closing, true /* vis */, false /* exChg */));
+        fillChangeMap(changes, openingTaskFragment);
+        // End states.
+        closing.setVisibleRequested(false);
+        opening.setVisibleRequested(true);
+
+        final int transit = transition.mType;
+        int flags = 0;
+
+        // Check basic both tasks participating
+        participants.add(closingTaskFragment);
+        participants.add(openingTaskFragment);
+        ArrayList<Transition.ChangeInfo> targets =
+                Transition.calculateTargets(participants, changes);
+        TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, mMockT);
+        assertEquals(2, info.getChanges().size());
+        assertEquals(transit, info.getType());
+
+        assertFalse(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+        assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
+    }
+
+    @Test
+    public void testCloseTranslucentTaskFragment_withFinishingActivity() {
+        final Transition transition = createTestTransition(TRANSIT_CLOSE);
+        ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+        ArraySet<WindowContainer> participants = transition.mParticipants;
+
+        final Task task = createTask(mDisplayContent);
+        final TaskFragment openingTaskFragment = createTaskFragmentWithActivity(task);
+        final TaskFragment closingTaskFragment = createTaskFragmentWithActivity(task);
+
+        final ActivityRecord opening = openingTaskFragment.getTopMostActivity();
+        opening.setOccludesParent(true);
+        opening.visibleIgnoringKeyguard = true;
+        final ActivityRecord closing = closingTaskFragment.getTopMostActivity();
+        closing.setOccludesParent(false);
+        closing.visibleIgnoringKeyguard = true;
+        closing.finishing = true;
+        // Start states.
+        changes.put(openingTaskFragment, new Transition.ChangeInfo(openingTaskFragment,
+                false /* vis */, true /* exChg */));
+        changes.put(closingTaskFragment, new Transition.ChangeInfo(closingTaskFragment,
+                true /* vis */, false /* exChg */));
+        changes.put(opening, new Transition.ChangeInfo(opening, false /* vis */, true /* exChg */));
+        changes.put(closing, new Transition.ChangeInfo(closing, true /* vis */, false /* exChg */));
+        fillChangeMap(changes, openingTaskFragment);
+        // End states.
+        closing.setVisibleRequested(false);
+        opening.setVisibleRequested(true);
+
+        final int transit = transition.mType;
+        int flags = 0;
+
+        // Check basic both tasks participating
+        participants.add(closingTaskFragment);
+        participants.add(openingTaskFragment);
+        ArrayList<Transition.ChangeInfo> targets =
+                Transition.calculateTargets(participants, changes);
+        TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, mMockT);
+        assertEquals(2, info.getChanges().size());
+        assertEquals(transit, info.getType());
+
+        assertTrue(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+        assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
     }
 
     @Test
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 7404adb..d75e573 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -174,7 +174,7 @@
     /**
      * Key to the backup & restore data byte array in the Bundle that is returned by {@link
      * #getAllSimSpecificSettingsForBackup()} or to be pass in to {@link
-     * #restoreAllSimSpecificSettings()}.
+     * #restoreAllSimSpecificSettingsFromBackup(byte[])}.
      *
      * @hide
      */
@@ -4051,39 +4051,16 @@
     }
 
     /**
-     * Called to attempt to restore the backed up sim-specific configs to device for specific sim.
-     * This will try to restore the data that was stored internally when {@link
-     * #restoreAllSimSpecificSettingsFromBackup(byte[] data)} was called during setup wizard.
-     * End result is SimInfoDB is modified to match any backed up configs for the requested
-     * inserted sim.
-     *
-     * <p>
-     * The {@link Uri} {@link #SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI} is notified if any SimInfoDB
-     * entry is updated as the result of this method call.
-     *
-     * @param iccId of the sim that a restore is requested for.
-     *
-     * @hide
-     */
-    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
-    public void restoreSimSpecificSettingsForIccIdFromBackup(@NonNull String iccId) {
-        mContext.getContentResolver().call(
-                SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI,
-                RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME,
-                iccId, null);
-    }
-
-    /**
      * Called during setup wizard restore flow to attempt to restore the backed up sim-specific
-     * configs to device for all existing SIMs in SimInfoDB. Internally, it will store the backup
-     * data in an internal file. This file will persist on device for device's lifetime and will be
-     * used later on when a SIM is inserted to restore that specific SIM's settings by calling
-     * {@link #restoreSimSpecificSettingsForIccIdFromBackup(String iccId)}. End result is
-     * SimInfoDB is modified to match any backed up configs for the appropriate inserted SIMs.
+     * configs to device for all existing SIMs in the subscription database {@link SimInfo}.
+     * Internally, it will store the backup data in an internal file. This file will persist on
+     * device for device's lifetime and will be used later on when a SIM is inserted to restore that
+     * specific SIM's settings. End result is subscription database is modified to match any backed
+     * up configs for the appropriate inserted SIMs.
      *
      * <p>
-     * The {@link Uri} {@link #SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI} is notified if any SimInfoDB
-     * entry is updated as the result of this method call.
+     * The {@link Uri} {@link #SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI} is notified if any
+     * {@link SimInfo} entry is updated as the result of this method call.
      *
      * @param data with the sim specific configs to be backed up.
      *
@@ -4092,12 +4069,18 @@
     @SystemApi
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public void restoreAllSimSpecificSettingsFromBackup(@NonNull byte[] data) {
-        Bundle bundle = new Bundle();
-        bundle.putByteArray(KEY_SIM_SPECIFIC_SETTINGS_DATA, data);
-        mContext.getContentResolver().call(
-                SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI,
-                RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME,
-                null, bundle);
+        try {
+            ISub iSub = TelephonyManager.getSubscriptionService();
+            if (iSub != null) {
+                iSub.restoreAllSimSpecificSettingsFromBackup(data);
+            } else {
+                throw new IllegalStateException("subscription service unavailable.");
+            }
+        } catch (RemoteException ex) {
+            if (!isSystemProcess()) {
+                ex.rethrowAsRuntimeException();
+            }
+        }
     }
 
     /**
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 5f6218d..100799e 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -1070,6 +1070,45 @@
         return SATELLITE_REQUEST_FAILED;
     }
 
+    /**
+     * Send datagram over satellite.
+     * @param datagramType - type of datagram
+     * @param datagram - datagram to send over satellite
+     * @param executor - The executor on which the result listener will be called.
+     * @param resultListener - Listener that will be called with the result of the operation.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     */
+    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+    public void sendSatelliteDatagram(@DatagramType int datagramType,
+            @NonNull SatelliteDatagram datagram, @NonNull @CallbackExecutor Executor executor,
+            @SatelliteError @NonNull Consumer<Integer> resultListener) {
+        Objects.requireNonNull(datagram);
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(resultListener);
+
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
+                    @Override
+                    public void accept(int result) {
+                        executor.execute(() -> Binder.withCleanCallingIdentity(
+                                () -> resultListener.accept(result)));
+                    }
+                };
+                telephony.sendSatelliteDatagram(mSubId, datagramType, datagram,
+                        internalCallback);
+            } else {
+                throw new IllegalStateException("telephony service is null.");
+            }
+        } catch (RemoteException ex) {
+            loge("sendSatelliteDatagram() RemoteException:" + ex);
+            ex.rethrowFromSystemServer();
+        }
+    }
+
     private static ITelephony getITelephony() {
         ITelephony binder = ITelephony.Stub.asInterface(TelephonyFrameworkInitializer
                 .getTelephonyServiceManager()
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index defa046..af4edc4 100644
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -363,4 +363,20 @@
         */
        //TODO: Removed before U AOSP public release.
        boolean isSubscriptionManagerServiceEnabled();
+
+      /**
+       * Called during setup wizard restore flow to attempt to restore the backed up sim-specific
+       * configs to device for all existing SIMs in the subscription database
+       * {@link Telephony.SimInfo}. Internally, it will store the backup data in an internal file.
+       * This file will persist on device for device's lifetime and will be used later on when a SIM
+       * is inserted to restore that specific SIM's settings. End result is subscription database is
+       * modified to match any backed up configs for the appropriate inserted SIMs.
+       *
+       * <p>
+       * The {@link Uri} {@link #SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI} is notified if any
+       * {@link Telephony.SimInfo} entry is updated as the result of this method call.
+       *
+       * @param data with the sim specific configs to be backed up.
+       */
+       void restoreAllSimSpecificSettingsFromBackup(in byte[] data);
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 331ee6f..9090edb 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -69,6 +69,7 @@
 import android.telephony.ims.aidl.IRcsConfigCallback;
 import android.telephony.satellite.ISatelliteStateListener;
 import android.telephony.satellite.SatelliteCapabilities;
+import android.telephony.satellite.SatelliteDatagram;
 import com.android.ims.internal.IImsServiceFeatureCallback;
 import com.android.internal.telephony.CellNetworkScanResult;
 import com.android.internal.telephony.IBooleanConsumer;
@@ -2894,4 +2895,17 @@
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
                 + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
     int pollPendingSatelliteDatagrams(int subId);
+
+   /**
+    * Send datagram over satellite.
+    *
+    * @param subId - The subId of the subscription used for receiving datagrams.
+    * @param datagramType - type of datagram
+    * @param datagram - datagram to send over satellite
+    * @param callback - The callback to get the error code of the request.
+    */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+                    + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+    void sendSatelliteDatagram(int subId, int datagramType, in SatelliteDatagram datagram,
+            IIntegerConsumer callback);
 }
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
index daff76f..5d4a4ef 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
@@ -61,10 +61,11 @@
         return intent;
     }
 
-    protected Intent createBroadcastIntent(String action) {
+    protected Intent createFgBroadcastIntent(String action) {
         final Intent intent = new Intent(action);
-        intent.addFlags(
-                Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
+                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
+                | Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
         putTimeReceiverBinderExtra(intent);
         return intent;
     }
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
index bc528d4..6a53575 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
@@ -30,11 +30,11 @@
 @LargeTest
 public class BroadcastPerfTest extends BasePerfTest {
     @Test
-    public void manifestBroadcastRunning() {
+    public void manifestFgBroadcastRunning() {
         runPerfFunction(() -> {
             startTargetPackage();
 
-            final Intent intent = createBroadcastIntent(
+            final Intent intent = createFgBroadcastIntent(
                     Constants.ACTION_BROADCAST_MANIFEST_RECEIVE);
 
             final long startTime = System.nanoTime();
@@ -48,9 +48,9 @@
     }
 
     @Test
-    public void manifestBroadcastNotRunning() {
+    public void manifestFgBroadcastNotRunning() {
         runPerfFunction(() -> {
-            final Intent intent = createBroadcastIntent(
+            final Intent intent = createFgBroadcastIntent(
                     Constants.ACTION_BROADCAST_MANIFEST_RECEIVE);
 
             final long startTime = System.nanoTime();
@@ -64,11 +64,11 @@
     }
 
     @Test
-    public void registeredBroadcast() {
+    public void registeredFgBroadcast() {
         runPerfFunction(() -> {
             startTargetPackage();
 
-            final Intent intent = createBroadcastIntent(
+            final Intent intent = createFgBroadcastIntent(
                     Constants.ACTION_BROADCAST_REGISTERED_RECEIVE);
 
             final long startTime = System.nanoTime();
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
index c298189..8aa369e 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
@@ -35,6 +35,8 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.internal.R;
+
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -51,8 +53,6 @@
 public class SharedConnectivityManager {
     private static final String TAG = SharedConnectivityManager.class.getSimpleName();
     private static final boolean DEBUG = true;
-    private static final String SERVICE_PACKAGE_NAME = "sharedconnectivity_service_package";
-    private static final String SERVICE_CLASS_NAME = "sharedconnectivity_service_class";
 
     private static final class SharedConnectivityCallbackProxy extends
             ISharedConnectivityCallback.Stub {
@@ -101,7 +101,7 @@
                     Binder.restoreCallingIdentity(token);
                 }
             }
-        };
+        }
 
         @Override
         public void onTetherNetworkConnectionStatusChanged(
@@ -115,7 +115,7 @@
                     Binder.restoreCallingIdentity(token);
                 }
             }
-        };
+        }
 
         @Override
         public void onKnownNetworkConnectionStatusChanged(
@@ -129,7 +129,7 @@
                     Binder.restoreCallingIdentity(token);
                 }
             }
-        };
+        }
     }
 
     private ISharedConnectivityService mService;
@@ -137,14 +137,33 @@
             mProxyMap = new HashMap<>();
 
     /**
-     * Constructor for new instance of {@link SharedConnectivityManager}.
+     * Creates a new instance of {@link SharedConnectivityManager}.
      *
      * Automatically binds to implementation of {@link SharedConnectivityService} specified in
      * device overlay.
      *
+     * @return An instance of {@link SharedConnectivityManager} or null if the shared connectivity
+     * service is not found.
      * @hide
      */
-    public SharedConnectivityManager(@NonNull Context context) {
+    @Nullable
+    public static SharedConnectivityManager create(@NonNull Context context) {
+        Resources resources = context.getResources();
+        try {
+            String servicePackageName = resources.getString(
+                    R.string.shared_connectivity_service_package);
+            String serviceIntentAction = resources.getString(
+                    R.string.shared_connectivity_service_intent_action);
+            return new SharedConnectivityManager(context, servicePackageName, serviceIntentAction);
+        } catch (Resources.NotFoundException e) {
+            Log.e(TAG, "To support shared connectivity service on this device, the service's"
+                    + " package name and intent action string must be defined");
+        }
+        return null;
+    }
+
+    private SharedConnectivityManager(@NonNull Context context, String servicePackageName,
+            String serviceIntentAction) {
         ServiceConnection serviceConnection = new ServiceConnection() {
             @Override
             public void onServiceConnected(ComponentName name, IBinder service) {
@@ -158,7 +177,10 @@
                 mProxyMap.clear();
             }
         };
-        bind(context, serviceConnection);
+
+        context.bindService(
+                new Intent().setPackage(servicePackageName).setAction(serviceIntentAction),
+                serviceConnection, Context.BIND_AUTO_CREATE);
     }
 
     /**
@@ -169,25 +191,6 @@
         mService = (ISharedConnectivityService) service;
     }
 
-    private void bind(Context context, ServiceConnection serviceConnection) {
-        Resources resources = context.getResources();
-        int packageNameId = resources.getIdentifier(SERVICE_PACKAGE_NAME, "string",
-                context.getPackageName());
-        int classNameId = resources.getIdentifier(SERVICE_CLASS_NAME, "string",
-                context.getPackageName());
-        if (packageNameId == 0 || classNameId == 0) {
-            throw new Resources.NotFoundException("Package and class names for"
-                    + " shared connectivity service must be defined");
-        }
-
-        Intent intent = new Intent();
-        intent.setComponent(new ComponentName(resources.getString(packageNameId),
-                resources.getString(classNameId)));
-        context.bindService(
-                intent,
-                serviceConnection, Context.BIND_AUTO_CREATE);
-    }
-
     /**
      * Registers a callback for receiving updates to the list of Tether Networks and Known Networks.
      *
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
index 9aeccac..784e9c4 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
@@ -89,7 +89,7 @@
      */
     @Test
     public void testBindingToService() {
-        new SharedConnectivityManager(mContext);
+        SharedConnectivityManager.create(mContext);
         verify(mContext).bindService(any(), any(), anyInt());
     }
 
@@ -98,22 +98,22 @@
      */
     @Test
     public void testRegisterCallback() throws Exception {
-        SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+        SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
         manager.setService(null);
         assertFalse(manager.registerCallback(mExecutor, mClientCallback));
 
-        manager = new SharedConnectivityManager(mContext);
+        manager = SharedConnectivityManager.create(mContext);
         manager.setService(mService);
         assertTrue(manager.registerCallback(mExecutor, mClientCallback));
         verify(mService).registerCallback(any());
 
         // Registering the same callback twice should fail.
-        manager = new SharedConnectivityManager(mContext);
+        manager = SharedConnectivityManager.create(mContext);
         manager.setService(mService);
         manager.registerCallback(mExecutor, mClientCallback);
         assertFalse(manager.registerCallback(mExecutor, mClientCallback));
 
-        manager = new SharedConnectivityManager(mContext);
+        manager = SharedConnectivityManager.create(mContext);
         manager.setService(mService);
         doThrow(new RemoteException()).when(mService).registerCallback(any());
         assertFalse(manager.registerCallback(mExecutor, mClientCallback));
@@ -125,24 +125,24 @@
      */
     @Test
     public void testUnregisterCallback() throws Exception {
-        SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+        SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
         manager.setService(null);
         assertFalse(manager.unregisterCallback(mClientCallback));
 
-        manager = new SharedConnectivityManager(mContext);
+        manager = SharedConnectivityManager.create(mContext);
         manager.setService(mService);
         manager.registerCallback(mExecutor, mClientCallback);
         assertTrue(manager.unregisterCallback(mClientCallback));
         verify(mService).unregisterCallback(any());
 
 
-        manager = new SharedConnectivityManager(mContext);
+        manager = SharedConnectivityManager.create(mContext);
         manager.setService(mService);
         manager.registerCallback(mExecutor, mClientCallback);
         manager.unregisterCallback(mClientCallback);
         assertFalse(manager.unregisterCallback(mClientCallback));
 
-        manager = new SharedConnectivityManager(mContext);
+        manager = SharedConnectivityManager.create(mContext);
         manager.setService(mService);
         doThrow(new RemoteException()).when(mService).unregisterCallback(any());
         assertFalse(manager.unregisterCallback(mClientCallback));
@@ -156,11 +156,11 @@
     public void testConnectTetherNetwork() throws RemoteException {
         TetherNetwork network = buildTetherNetwork();
 
-        SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+        SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
         manager.setService(null);
         assertFalse(manager.connectTetherNetwork(network));
 
-        manager = new SharedConnectivityManager(mContext);
+        manager = SharedConnectivityManager.create(mContext);
         manager.setService(mService);
         manager.connectTetherNetwork(network);
         verify(mService).connectTetherNetwork(network);
@@ -175,11 +175,11 @@
      */
     @Test
     public void testDisconnectTetherNetwork() throws RemoteException {
-        SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+        SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
         manager.setService(null);
         assertFalse(manager.disconnectTetherNetwork());
 
-        manager = new SharedConnectivityManager(mContext);
+        manager = SharedConnectivityManager.create(mContext);
         manager.setService(mService);
         manager.disconnectTetherNetwork();
         verify(mService).disconnectTetherNetwork();
@@ -196,11 +196,11 @@
     public void testConnectKnownNetwork() throws RemoteException {
         KnownNetwork network = buildKnownNetwork();
 
-        SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+        SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
         manager.setService(null);
         assertFalse(manager.connectKnownNetwork(network));
 
-        manager = new SharedConnectivityManager(mContext);
+        manager = SharedConnectivityManager.create(mContext);
         manager.setService(mService);
         manager.connectKnownNetwork(network);
         verify(mService).connectKnownNetwork(network);
@@ -217,11 +217,11 @@
     public void testForgetKnownNetwork() throws RemoteException {
         KnownNetwork network = buildKnownNetwork();
 
-        SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+        SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
         manager.setService(null);
         assertFalse(manager.forgetKnownNetwork(network));
 
-        manager = new SharedConnectivityManager(mContext);
+        manager = SharedConnectivityManager.create(mContext);
         manager.setService(mService);
         manager.forgetKnownNetwork(network);
         verify(mService).forgetKnownNetwork(network);