Merge "Added network objects to ConnectionStatus classes."
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/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index 1022490..bd8d27c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -27,6 +27,7 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
+import android.app.BackgroundStartPrivileges;
 import android.app.UserSwitchObserver;
 import android.app.job.JobInfo;
 import android.app.job.JobParameters;
@@ -388,6 +389,12 @@
     private final ArrayList<ContextAssignment> mRecycledPreferredUidOnly = new ArrayList<>();
     private final ArrayList<ContextAssignment> mRecycledStoppable = new ArrayList<>();
     private final AssignmentInfo mRecycledAssignmentInfo = new AssignmentInfo();
+    private final SparseIntArray mRecycledPrivilegedState = new SparseIntArray();
+
+    private static final int PRIVILEGED_STATE_UNDEFINED = 0;
+    private static final int PRIVILEGED_STATE_NONE = 1;
+    private static final int PRIVILEGED_STATE_BAL = 2;
+    private static final int PRIVILEGED_STATE_TOP = 3;
 
     private final Pools.Pool<ContextAssignment> mContextAssignmentPool =
             new Pools.SimplePool<>(MAX_RETAINED_OBJECTS);
@@ -792,7 +799,7 @@
 
         cleanUpAfterAssignmentChangesLocked(
                 mRecycledChanged, mRecycledIdle, mRecycledPreferredUidOnly, mRecycledStoppable,
-                mRecycledAssignmentInfo);
+                mRecycledAssignmentInfo, mRecycledPrivilegedState);
 
         noteConcurrency();
     }
@@ -915,7 +922,8 @@
                 continue;
             }
 
-            final boolean hasImmediacyPrivilege = hasImmediacyPrivilegeLocked(nextPending);
+            final boolean hasImmediacyPrivilege =
+                    hasImmediacyPrivilegeLocked(nextPending, mRecycledPrivilegedState);
             if (DEBUG && isSimilarJobRunningLocked(nextPending)) {
                 Slog.w(TAG, "Already running similar job to: " + nextPending);
             }
@@ -1183,7 +1191,8 @@
             final ArraySet<ContextAssignment> idle,
             final List<ContextAssignment> preferredUidOnly,
             final List<ContextAssignment> stoppable,
-            final AssignmentInfo assignmentInfo) {
+            final AssignmentInfo assignmentInfo,
+            final SparseIntArray privilegedState) {
         for (int s = stoppable.size() - 1; s >= 0; --s) {
             final ContextAssignment assignment = stoppable.get(s);
             assignment.clear();
@@ -1205,20 +1214,58 @@
         stoppable.clear();
         preferredUidOnly.clear();
         assignmentInfo.clear();
+        privilegedState.clear();
         mWorkCountTracker.resetStagingCount();
         mActivePkgStats.forEach(mPackageStatsStagingCountClearer);
     }
 
     @VisibleForTesting
     @GuardedBy("mLock")
-    boolean hasImmediacyPrivilegeLocked(@NonNull JobStatus job) {
+    boolean hasImmediacyPrivilegeLocked(@NonNull JobStatus job,
+            @NonNull SparseIntArray cachedPrivilegedState) {
+        if (!job.shouldTreatAsExpeditedJob() && !job.shouldTreatAsUserInitiatedJob()) {
+            return false;
+        }
         // EJs & user-initiated jobs for the TOP app should run immediately.
         // However, even for user-initiated jobs, if the app has not recently been in TOP or BAL
         // state, we don't give the immediacy privilege so that we can try and maintain
         // reasonably concurrency behavior.
-        return job.lastEvaluatedBias == JobInfo.BIAS_TOP_APP
-                // TODO(): include BAL state for user-initiated jobs
-                && (job.shouldTreatAsExpeditedJob() || job.shouldTreatAsUserInitiatedJob());
+        if (job.lastEvaluatedBias == JobInfo.BIAS_TOP_APP) {
+            return true;
+        }
+        final int uid = job.getSourceUid();
+        final int privilegedState = cachedPrivilegedState.get(uid, PRIVILEGED_STATE_UNDEFINED);
+        switch (privilegedState) {
+            case PRIVILEGED_STATE_TOP:
+                return true;
+            case PRIVILEGED_STATE_BAL:
+                return job.shouldTreatAsUserInitiatedJob();
+            case PRIVILEGED_STATE_NONE:
+                return false;
+            case PRIVILEGED_STATE_UNDEFINED:
+            default:
+                final ActivityManagerInternal activityManagerInternal =
+                        LocalServices.getService(ActivityManagerInternal.class);
+                final int procState = activityManagerInternal.getUidProcessState(uid);
+                if (procState == ActivityManager.PROCESS_STATE_TOP) {
+                    cachedPrivilegedState.put(uid, PRIVILEGED_STATE_TOP);
+                    return true;
+                }
+                if (job.shouldTreatAsExpeditedJob()) {
+                    // EJs only get the TOP privilege.
+                    return false;
+                }
+
+                final BackgroundStartPrivileges bsp =
+                        activityManagerInternal.getBackgroundStartPrivileges(uid);
+                final boolean balAllowed = bsp.allowsBackgroundActivityStarts();
+                if (DEBUG) {
+                    Slog.d(TAG, "Job " + job.toShortString() + " bal state: " + bsp);
+                }
+                cachedPrivilegedState.put(uid,
+                        balAllowed ? PRIVILEGED_STATE_BAL : PRIVILEGED_STATE_NONE);
+                return balAllowed;
+        }
     }
 
     @GuardedBy("mLock")
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 419111a..22fea7f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -31,6 +31,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
+import android.app.BackgroundStartPrivileges;
 import android.app.IUidObserver;
 import android.app.compat.CompatChanges;
 import android.app.job.IJobScheduler;
@@ -3841,6 +3842,25 @@
                         return callingResult;
                     }
                 }
+
+                final int uid = sourceUid != -1 ? sourceUid : callingUid;
+                final int procState = mActivityManagerInternal.getUidProcessState(uid);
+                if (DEBUG) {
+                    Slog.d(TAG, "Uid " + uid + " proc state="
+                            + ActivityManager.procStateToString(procState));
+                }
+                if (procState != ActivityManager.PROCESS_STATE_TOP) {
+                    final BackgroundStartPrivileges bsp =
+                            mActivityManagerInternal.getBackgroundStartPrivileges(uid);
+                    if (DEBUG) {
+                        Slog.d(TAG, "Uid " + uid + ": " + bsp);
+                    }
+                    if (!bsp.allowsBackgroundActivityStarts()) {
+                        Slog.e(TAG,
+                                "Uid " + uid + " not in a state to schedule user-initiated jobs");
+                        return JobScheduler.RESULT_FAILURE;
+                    }
+                }
             }
             if (jobWorkItem != null) {
                 jobWorkItem.enforceValidity(rejectNegativeNetworkEstimates);
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 1a8166b..7ed066e 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
@@ -7750,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);
@@ -7757,6 +7782,7 @@
     method public int addOverrideApn(@NonNull android.content.ComponentName, @NonNull android.telephony.data.ApnSetting);
     method public void addPersistentPreferredActivity(@NonNull android.content.ComponentName, android.content.IntentFilter, @NonNull android.content.ComponentName);
     method public void addUserRestriction(@NonNull android.content.ComponentName, String);
+    method public void addUserRestrictionGlobally(@NonNull String);
     method public boolean bindDeviceAdminServiceAsUser(@NonNull android.content.ComponentName, android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull android.os.UserHandle);
     method public boolean canAdminGrantSensorsPermissions();
     method public boolean canUsbDataSignalingBeDisabled();
@@ -7859,6 +7885,7 @@
     method @Nullable public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(@Nullable android.content.ComponentName, @NonNull android.content.ComponentName);
     method @NonNull public java.util.List<java.lang.String> getUserControlDisabledPackages(@NonNull android.content.ComponentName);
     method @NonNull public android.os.Bundle getUserRestrictions(@NonNull android.content.ComponentName);
+    method @NonNull public android.os.Bundle getUserRestrictionsGlobally();
     method @Nullable public String getWifiMacAddress(@NonNull android.content.ComponentName);
     method @Nullable public android.app.admin.WifiSsidPolicy getWifiSsidPolicy();
     method public boolean grantKeyPairToApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String);
@@ -7901,6 +7928,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();
@@ -7935,7 +7963,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);
@@ -8141,6 +8169,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
@@ -8302,6 +8331,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
@@ -8314,6 +8345,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";
@@ -14903,6 +14935,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();
@@ -14918,6 +14951,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();
@@ -14929,6 +14963,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);
@@ -15464,6 +15499,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();
@@ -27363,6 +27418,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();
@@ -27651,8 +27707,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);
@@ -27687,8 +27748,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();
@@ -27729,7 +27792,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);
@@ -27783,8 +27847,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);
@@ -33394,6 +33460,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
@@ -41386,9 +41453,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";
   }
@@ -53721,12 +53790,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);
@@ -53737,6 +53808,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/system-current.txt b/core/api/system-current.txt
index 2d7be50..ba9663f 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";
@@ -1205,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;
   }
@@ -1290,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";
@@ -1393,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();
@@ -1521,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;
@@ -1541,10 +1554,18 @@
   }
 
   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;
   }
 
+  public final class UserRestrictionPolicyKey extends android.app.admin.PolicyKey {
+    method public int describeContents();
+    method @NonNull public String getRestriction();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.UserRestrictionPolicyKey> CREATOR;
+  }
+
 }
 
 package android.app.ambientcontext {
@@ -2262,7 +2283,6 @@
     method public void notifyEvent(@NonNull android.app.search.Query, @NonNull android.app.search.SearchTargetEvent);
     method @Nullable public void query(@NonNull android.app.search.Query, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.app.search.SearchTarget>>);
     method public void registerEmptyQueryResultUpdateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.app.search.SearchSession.Callback);
-    method public void requestEmptyQueryResultUpdate();
     method public void unregisterEmptyQueryResultUpdateCallback(@NonNull android.app.search.SearchSession.Callback);
   }
 
@@ -10651,7 +10671,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";
@@ -12675,7 +12694,6 @@
     method @MainThread public abstract void onDestroy(@NonNull android.app.search.SearchSessionId);
     method @MainThread public abstract void onNotifyEvent(@NonNull android.app.search.SearchSessionId, @NonNull android.app.search.Query, @NonNull android.app.search.SearchTargetEvent);
     method @MainThread public abstract void onQuery(@NonNull android.app.search.SearchSessionId, @NonNull android.app.search.Query, @NonNull java.util.function.Consumer<java.util.List<android.app.search.SearchTarget>>);
-    method @MainThread public void onRequestEmptyQueryResultUpdate(@NonNull android.app.search.SearchSessionId);
     method public void onSearchSessionCreated(@NonNull android.app.search.SearchContext, @NonNull android.app.search.SearchSessionId);
     method @MainThread public void onStartUpdateEmptyQueryResult();
     method @MainThread public void onStopUpdateEmptyQueryResult();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index f310d8d..bb3ea7b 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);
@@ -1479,10 +1497,13 @@
     method @RequiresPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT) public void removeKeyboardLayoutForInputDevice(@NonNull android.hardware.input.InputDeviceIdentifier, @NonNull String);
     method public void removeUniqueIdAssociation(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT) public void setCurrentKeyboardLayoutForInputDevice(@NonNull android.hardware.input.InputDeviceIdentifier, @NonNull String);
-    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setMaximumObscuringOpacityForTouch(@FloatRange(from=0, to=1) float);
     field public static final long BLOCK_UNTRUSTED_TOUCHES = 158002302L; // 0x96aec7eL
   }
 
+  public class InputSettings {
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void setMaximumObscuringOpacityForTouch(@NonNull android.content.Context, @FloatRange(from=0, to=1) float);
+  }
+
 }
 
 package android.hardware.lights {
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/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 0fa1a37..aa9212f 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -464,6 +464,11 @@
     public abstract boolean isActivityStartsLoggingEnabled();
     /** Returns true if the background activity starts is enabled. */
     public abstract boolean isBackgroundActivityStartsEnabled();
+    /**
+     * Returns The current {@link BackgroundStartPrivileges} of the UID.
+     */
+    @NonNull
+    public abstract BackgroundStartPrivileges getBackgroundStartPrivileges(int uid);
     public abstract void reportCurKeyguardUsageEvent(boolean keyguardShowing);
 
     /** @see com.android.server.am.ActivityManagerService#monitor */
@@ -963,4 +968,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/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 a2c4820..29d80f8 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -95,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,
@@ -487,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
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..4016e32 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}
      */
@@ -11300,6 +11269,13 @@
      * See the constants in {@link android.os.UserManager} for the list of restrictions that can
      * be enforced device-wide.
      *
+     * <p>For callers targeting Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or
+     * above, calling this API will result in applying the restriction locally on the calling user,
+     * or locally on the parent profile if called from the
+     * {@link DevicePolicyManager} instance obtained from
+     * {@link #getParentProfileInstance(ComponentName)}. To set a restriction globally, call
+     * {@link #addUserRestrictionGlobally} instead.
+     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param key   The key of the restriction.
      * @throws SecurityException if {@code admin} is not a device or profile owner.
@@ -11308,7 +11284,38 @@
             @UserManager.UserRestrictionKey String key) {
         if (mService != null) {
             try {
-                mService.setUserRestriction(admin, key, true, mParentInstance);
+                mService.setUserRestriction(
+                        admin, mContext.getPackageName(), key, true, mParentInstance);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Called by a profile or device owner to set a user restriction specified by the provided
+     * {@code key} globally on all users. To clear the restriction use
+     * {@link #clearUserRestriction}.
+     *
+     * <p>For a given user, a restriction will be set if it was applied globally or locally by any
+     * admin.
+     *
+     * <p> The calling device admin must be a profile or device owner; if it is not, a security
+     * exception will be thrown.
+     *
+     * <p> See the constants in {@link android.os.UserManager} for the list of restrictions that can
+     * be enforced device-wide.
+     *
+     * @param key The key of the restriction.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
+     * @throws IllegalStateException if caller is not targeting Android
+     * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or above.
+     */
+    public void addUserRestrictionGlobally(@NonNull @UserManager.UserRestrictionKey String key) {
+        throwIfParentInstance("addUserRestrictionGlobally");
+        if (mService != null) {
+            try {
+                mService.setUserRestrictionGlobally(mContext.getPackageName(), key);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -11327,6 +11334,10 @@
      * <p>
      * See the constants in {@link android.os.UserManager} for the list of restrictions.
      *
+     * <p>For callers targeting Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or
+     * above, calling this API will result in clearing any local and global restriction with the
+     * specified key that was previously set by the caller.
+     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param key   The key of the restriction.
      * @throws SecurityException if {@code admin} is not a device or profile owner.
@@ -11335,7 +11346,8 @@
             @UserManager.UserRestrictionKey String key) {
         if (mService != null) {
             try {
-                mService.setUserRestriction(admin, key, false, mParentInstance);
+                mService.setUserRestriction(
+                        admin, mContext.getPackageName(), key, false, mParentInstance);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -11355,6 +11367,18 @@
      * {@link #getParentProfileInstance(ComponentName)}, for retrieving device-wide restrictions
      * it previously set with {@link #addUserRestriction(ComponentName, String)}.
      *
+     * <p>For callers targeting Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or
+     * above, this API will return the local restrictions set on the calling user, or on the parent
+     * profile if called from the {@link DevicePolicyManager} instance obtained from
+     * {@link #getParentProfileInstance(ComponentName)}. To get global restrictions set by admin,
+     * call {@link #getUserRestrictionsGlobally()} instead.
+     *
+     * <p>Note that this is different that the returned restrictions for callers targeting pre
+     * Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, were this API returns
+     * all local/global restrictions set by the admin on the calling user using
+     * {@link #addUserRestriction(ComponentName, String)} or the parent user if called on the
+     * {@link DevicePolicyManager} instance it obtained from {@link #getParentProfileInstance}.
+     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return a {@link Bundle} whose keys are the user restrictions, and the values a
      * {@code boolean} indicating whether the restriction is set.
@@ -11364,7 +11388,33 @@
         Bundle ret = null;
         if (mService != null) {
             try {
-                ret = mService.getUserRestrictions(admin, mParentInstance);
+                ret = mService.getUserRestrictions(
+                        admin, mContext.getPackageName(), mParentInstance);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return ret == null ? new Bundle() : ret;
+    }
+
+    /**
+     * Called by a profile or device owner to get global user restrictions set with
+     * {@link #addUserRestrictionGlobally(String)}.
+     * <p>
+     * To get all the user restrictions currently set for a certain user, use
+     * {@link UserManager#getUserRestrictions()}.
+     * @return a {@link Bundle} whose keys are the user restrictions, and the values a
+     * {@code boolean} indicating whether the restriction is set.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
+     * @throws IllegalStateException if caller is not targeting Android
+     * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or above.
+     */
+    public @NonNull Bundle getUserRestrictionsGlobally() {
+        throwIfParentInstance("createAdminSupportIntent");
+        Bundle ret = null;
+        if (mService != null) {
+            try {
+                ret = mService.getUserRestrictionsGlobally(mContext.getPackageName());
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -12586,6 +12636,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..5b9e948 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);
@@ -247,8 +247,11 @@
     void setRestrictionsProvider(in ComponentName who, in ComponentName provider);
     ComponentName getRestrictionsProvider(int userHandle);
 
-    void setUserRestriction(in ComponentName who, in String key, boolean enable, boolean parent);
-    Bundle getUserRestrictions(in ComponentName who, boolean parent);
+    void setUserRestriction(in ComponentName who, in String callerPackage, in String key, boolean enable, boolean parent);
+    void setUserRestrictionGlobally(in String callerPackage, in String key);
+    Bundle getUserRestrictions(in ComponentName who, in String callerPackage, boolean parent);
+    Bundle getUserRestrictionsGlobally(in String callerPackage);
+
     void addCrossProfileIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
     void clearCrossProfileIntentFilters(in ComponentName admin);
 
@@ -379,6 +382,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..a49152d 100644
--- a/core/java/android/app/admin/IntentFilterPolicyKey.java
+++ b/core/java/android/app/admin/IntentFilterPolicyKey.java
@@ -18,6 +18,7 @@
 
 import static android.app.admin.PolicyUpdatesReceiver.EXTRA_INTENT_FILTER;
 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;
@@ -100,7 +101,7 @@
      */
     @Override
     public void writeToBundle(Bundle bundle) {
-        super.writeToBundle(bundle);
+        bundle.putString(EXTRA_POLICY_KEY, getIdentifier());
         Bundle extraPolicyParams = new Bundle();
         extraPolicyParams.putParcelable(EXTRA_INTENT_FILTER, mFilter);
         bundle.putBundle(EXTRA_POLICY_BUNDLE_KEY, extraPolicyParams);
@@ -117,7 +118,7 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(getIdentifier(), mFilter);
+        return Objects.hash(getIdentifier());
     }
 
     @Override
@@ -133,7 +134,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/NoArgsPolicyKey.java b/core/java/android/app/admin/NoArgsPolicyKey.java
index 57b67d5..2c9d2be 100644
--- a/core/java/android/app/admin/NoArgsPolicyKey.java
+++ b/core/java/android/app/admin/NoArgsPolicyKey.java
@@ -16,8 +16,11 @@
 
 package android.app.admin;
 
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_KEY;
+
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -41,6 +44,14 @@
         this(source.readString());
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public void writeToBundle(Bundle bundle) {
+        bundle.putString(EXTRA_POLICY_KEY, getIdentifier());
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/core/java/android/app/admin/PackagePermissionPolicyKey.java b/core/java/android/app/admin/PackagePermissionPolicyKey.java
index 4aa2e38..90ca052 100644
--- a/core/java/android/app/admin/PackagePermissionPolicyKey.java
+++ b/core/java/android/app/admin/PackagePermissionPolicyKey.java
@@ -19,6 +19,7 @@
 import static android.app.admin.PolicyUpdatesReceiver.EXTRA_PACKAGE_NAME;
 import static android.app.admin.PolicyUpdatesReceiver.EXTRA_PERMISSION_NAME;
 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;
@@ -119,7 +120,7 @@
      */
     @Override
     public void writeToBundle(Bundle bundle) {
-        super.writeToBundle(bundle);
+        bundle.putString(EXTRA_POLICY_KEY, getIdentifier());
         Bundle extraPolicyParams = new Bundle();
         extraPolicyParams.putString(EXTRA_PACKAGE_NAME, mPackageName);
         extraPolicyParams.putString(EXTRA_PERMISSION_NAME, mPermissionName);
diff --git a/core/java/android/app/admin/PackagePolicyKey.java b/core/java/android/app/admin/PackagePolicyKey.java
index 3469970..08b6110 100644
--- a/core/java/android/app/admin/PackagePolicyKey.java
+++ b/core/java/android/app/admin/PackagePolicyKey.java
@@ -18,6 +18,7 @@
 
 import static android.app.admin.PolicyUpdatesReceiver.EXTRA_PACKAGE_NAME;
 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;
@@ -101,7 +102,7 @@
      */
     @Override
     public void writeToBundle(Bundle bundle) {
-        super.writeToBundle(bundle);
+        bundle.putString(EXTRA_POLICY_KEY, getIdentifier());
         Bundle extraPolicyParams = new Bundle();
         extraPolicyParams.putString(EXTRA_PACKAGE_NAME, mPackageName);
         bundle.putBundle(EXTRA_POLICY_BUNDLE_KEY, extraPolicyParams);
diff --git a/core/java/android/app/admin/PolicyKey.java b/core/java/android/app/admin/PolicyKey.java
index a35f634..3544c19 100644
--- a/core/java/android/app/admin/PolicyKey.java
+++ b/core/java/android/app/admin/PolicyKey.java
@@ -16,8 +16,6 @@
 
 package android.app.admin;
 
-import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_KEY;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
@@ -39,8 +37,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 {
@@ -104,9 +101,7 @@
     /**
      * @hide
      */
-    public void writeToBundle(Bundle bundle) {
-        bundle.putString(EXTRA_POLICY_KEY, mIdentifier);
-    }
+    public abstract void writeToBundle(Bundle bundle);
 
     @Override
     public boolean equals(@Nullable Object o) {
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/app/admin/UserRestrictionPolicyKey.java b/core/java/android/app/admin/UserRestrictionPolicyKey.java
new file mode 100644
index 0000000..92014763
--- /dev/null
+++ b/core/java/android/app/admin/UserRestrictionPolicyKey.java
@@ -0,0 +1,97 @@
+/*
+ * 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_POLICY_KEY;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+
+import java.util.Objects;
+
+/**
+ * Class used to identify a policy that relates to a certain user restriction
+ * (See {@link DevicePolicyManager#addUserRestriction} and
+ * {@link DevicePolicyManager#addUserRestrictionGlobally}).
+ *
+ * @hide
+ */
+@SystemApi
+public final class UserRestrictionPolicyKey extends PolicyKey {
+
+    private final String mRestriction;
+
+    /**
+     * @hide
+     */
+    public UserRestrictionPolicyKey(@NonNull String identifier, @NonNull String restriction) {
+        super(identifier);
+        mRestriction = Objects.requireNonNull(restriction);
+    }
+
+    private UserRestrictionPolicyKey(Parcel source) {
+        this(source.readString(), source.readString());
+    }
+
+    /**
+     * Returns the user restriction associated with this policy.
+     */
+    @NonNull
+    public String getRestriction() {
+        return mRestriction;
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void writeToBundle(Bundle bundle) {
+        bundle.putString(EXTRA_POLICY_KEY, getIdentifier());
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(getIdentifier());
+        dest.writeString(mRestriction);
+    }
+
+    @NonNull
+    public static final Creator<UserRestrictionPolicyKey> CREATOR =
+            new Creator<UserRestrictionPolicyKey>() {
+                @Override
+                public UserRestrictionPolicyKey createFromParcel(Parcel source) {
+                    return new UserRestrictionPolicyKey(source);
+                }
+
+                @Override
+                public UserRestrictionPolicyKey[] newArray(int size) {
+                    return new UserRestrictionPolicyKey[size];
+                }
+            };
+
+    @Override
+    public String toString() {
+        return "UserRestrictionPolicyKey " + getIdentifier();
+    }
+}
diff --git a/core/java/android/app/search/ISearchUiManager.aidl b/core/java/android/app/search/ISearchUiManager.aidl
index fefbd5a..4cf0b81 100644
--- a/core/java/android/app/search/ISearchUiManager.aidl
+++ b/core/java/android/app/search/ISearchUiManager.aidl
@@ -38,8 +38,6 @@
 
     void registerEmptyQueryResultUpdateCallback(in SearchSessionId sessionId, in ISearchCallback callback);
 
-    void requestEmptyQueryResultUpdate(in SearchSessionId sessionId);
-
     void unregisterEmptyQueryResultUpdateCallback(in SearchSessionId sessionId, in ISearchCallback callback);
 
     void destroySearchSession(in SearchSessionId sessionId);
diff --git a/core/java/android/app/search/SearchSession.java b/core/java/android/app/search/SearchSession.java
index 9e0a1d0..0dbd81e 100644
--- a/core/java/android/app/search/SearchSession.java
+++ b/core/java/android/app/search/SearchSession.java
@@ -225,32 +225,6 @@
     }
 
     /**
-     * Requests the search ui service to dispatch a new set of search targets to the pre-registered
-     * callback for zero state. Zero state means when user entered search ui but not issued any
-     * query yet. This method can be used for client to sync up with server data if they think data
-     * might be out of sync, for example, after restart.
-     * Pre-register a callback with
-     * {@link SearchSession#registerEmptyQueryResultUpdateCallback(Executor, Callback)}
-     * is required before calling this method. Otherwise this is no-op.
-     *
-     * @see {@link SearchSession#registerEmptyQueryResultUpdateCallback(Executor, Callback)}
-     * @see {@link SearchSession.Callback#onTargetsAvailable(List)}.
-     */
-    public void requestEmptyQueryResultUpdate() {
-        if (mIsClosed.get()) {
-            throw new IllegalStateException("This client has already been destroyed.");
-        }
-
-        try {
-            mInterface.requestEmptyQueryResultUpdate(mSessionId);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to request empty query result update", e);
-            e.rethrowAsRuntimeException();
-        }
-    }
-
-
-    /**
      * Destroys the client and unregisters the callback. Any method on this class after this call
      * will throw {@link IllegalStateException}.
      *
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/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index 709fa60..41c406d 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -614,8 +614,15 @@
             boolean status = true;
             synchronized (mInterfaceLock) {
                 try {
-                    mSessionProcessor.onCaptureSessionStart(mRequestProcessor);
-                    mInitialized = true;
+                    if (mSessionProcessor != null) {
+                        mSessionProcessor.onCaptureSessionStart(mRequestProcessor);
+                        mInitialized = true;
+                    } else {
+                        Log.v(TAG, "Failed to start capture session, session released before " +
+                                "extension start!");
+                        status = false;
+                        mCaptureSession.close();
+                    }
                 } catch (RemoteException e) {
                     Log.e(TAG, "Failed to start capture session,"
                             + " extension service does not respond!");
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 7164dc3..067d0c5 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -541,7 +541,8 @@
             EVENT_FLAG_DISPLAY_ADDED,
             EVENT_FLAG_DISPLAY_CHANGED,
             EVENT_FLAG_DISPLAY_REMOVED,
-            EVENT_FLAG_DISPLAY_BRIGHTNESS
+            EVENT_FLAG_DISPLAY_BRIGHTNESS,
+            EVENT_FLAG_HDR_SDR_RATIO_CHANGED
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EventsMask {}
@@ -584,6 +585,19 @@
      */
     public static final long EVENT_FLAG_DISPLAY_BRIGHTNESS = 1L << 3;
 
+    /**
+     * Event flag to register for a display's hdr/sdr ratio changes. This notification is sent
+     * through the {@link DisplayListener#onDisplayChanged} callback method. New hdr/sdr
+     * values can be retrieved via {@link Display#getHdrSdrRatio()}.
+     *
+     * Requires that {@link Display#isHdrSdrRatioAvailable()} is true.
+     *
+     * @see #registerDisplayListener(DisplayListener, Handler, long)
+     *
+     * @hide
+     */
+    public static final long EVENT_FLAG_HDR_SDR_RATIO_CHANGED = 1L << 4;
+
     /** @hide */
     public DisplayManager(Context context) {
         mContext = context;
@@ -1429,6 +1443,7 @@
      * hdrConversionMode.conversionMode is not {@link HdrConversionMode#HDR_CONVERSION_FORCE}.
      *
      * @see #getHdrConversionMode
+     * @see #getHdrConversionModeSetting
      * @see #getSupportedHdrOutputTypes
      * @hide
      */
@@ -1440,9 +1455,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 +1472,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..f419ae4 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -38,6 +38,7 @@
 import android.media.projection.IMediaProjection;
 import android.media.projection.MediaProjection;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
@@ -56,11 +57,12 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * Manager communication with the display manager service on behalf of
@@ -82,11 +84,12 @@
     // orientation change before the display info cache has actually been invalidated.
     private static final boolean USE_CACHE = false;
 
-    @IntDef(prefix = {"SWITCHING_TYPE_"}, value = {
+    @IntDef(prefix = {"EVENT_DISPLAY_"}, flag = true, value = {
             EVENT_DISPLAY_ADDED,
             EVENT_DISPLAY_CHANGED,
             EVENT_DISPLAY_REMOVED,
-            EVENT_DISPLAY_BRIGHTNESS_CHANGED
+            EVENT_DISPLAY_BRIGHTNESS_CHANGED,
+            EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface DisplayEvent {}
@@ -95,6 +98,7 @@
     public static final int EVENT_DISPLAY_CHANGED = 2;
     public static final int EVENT_DISPLAY_REMOVED = 3;
     public static final int EVENT_DISPLAY_BRIGHTNESS_CHANGED = 4;
+    public static final int EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED = 5;
 
     @UnsupportedAppUsage
     private static DisplayManagerGlobal sInstance;
@@ -109,7 +113,8 @@
 
     private DisplayManagerCallback mCallback;
     private @EventsMask long mRegisteredEventsMask = 0;
-    private final ArrayList<DisplayListenerDelegate> mDisplayListeners = new ArrayList<>();
+    private final CopyOnWriteArrayList<DisplayListenerDelegate> mDisplayListeners =
+            new CopyOnWriteArrayList<>();
 
     private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<>();
     private final ColorSpace mWideColorSpace;
@@ -315,6 +320,19 @@
      */
     public void registerDisplayListener(@NonNull DisplayListener listener,
             @Nullable Handler handler, @EventsMask long eventsMask) {
+        Looper looper = getLooperForHandler(handler);
+        Handler springBoard = new Handler(looper);
+        registerDisplayListener(listener, new HandlerExecutor(springBoard), eventsMask);
+    }
+
+    /**
+     * Register a listener for display-related changes.
+     *
+     * @param listener The listener that will be called when display changes occur.
+     * @param executor Executor for the thread that will be receiving the callbacks. Cannot be null.
+     */
+    public void registerDisplayListener(@NonNull DisplayListener listener,
+            @NonNull Executor executor, @EventsMask long eventsMask) {
         if (listener == null) {
             throw new IllegalArgumentException("listener must not be null");
         }
@@ -326,8 +344,7 @@
         synchronized (mLock) {
             int index = findDisplayListenerLocked(listener);
             if (index < 0) {
-                Looper looper = getLooperForHandler(handler);
-                mDisplayListeners.add(new DisplayListenerDelegate(listener, looper, eventsMask));
+                mDisplayListeners.add(new DisplayListenerDelegate(listener, executor, eventsMask));
                 registerCallbackIfNeededLocked();
             } else {
                 mDisplayListeners.get(index).setEventsMask(eventsMask);
@@ -408,6 +425,7 @@
     }
 
     private void handleDisplayEvent(int displayId, @DisplayEvent int event) {
+        final DisplayInfo info;
         synchronized (mLock) {
             if (USE_CACHE) {
                 mDisplayInfoCache.remove(displayId);
@@ -417,11 +435,7 @@
                 }
             }
 
-            final int numListeners = mDisplayListeners.size();
-            DisplayInfo info = getDisplayInfo(displayId);
-            for (int i = 0; i < numListeners; i++) {
-                mDisplayListeners.get(i).sendDisplayEvent(displayId, event, info);
-            }
+            info = getDisplayInfoLocked(displayId);
             if (event == EVENT_DISPLAY_CHANGED && mDispatchNativeCallbacks) {
                 // Choreographer only supports a single display, so only dispatch refresh rate
                 // changes for the default display.
@@ -438,6 +452,11 @@
                 }
             }
         }
+        // Accepting an Executor means the listener may be synchronously invoked, so we must
+        // not be holding mLock when we do so
+        for (DisplayListenerDelegate listener : mDisplayListeners) {
+            listener.sendDisplayEvent(displayId, event, info);
+        }
     }
 
     public void startWifiDisplayScan() {
@@ -990,6 +1009,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() {
@@ -1075,34 +1107,42 @@
         }
     }
 
-    private static final class DisplayListenerDelegate extends Handler {
+    private static final class DisplayListenerDelegate {
         public final DisplayListener mListener;
         public volatile long mEventsMask;
 
         private final DisplayInfo mDisplayInfo = new DisplayInfo();
+        private final Executor mExecutor;
+        private AtomicLong mGenerationId = new AtomicLong(1);
 
-        DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper,
+        DisplayListenerDelegate(DisplayListener listener, @NonNull Executor executor,
                 @EventsMask long eventsMask) {
-            super(looper, null, true /*async*/);
+            mExecutor = executor;
             mListener = listener;
             mEventsMask = eventsMask;
         }
 
         public void sendDisplayEvent(int displayId, @DisplayEvent int event, DisplayInfo info) {
-            Message msg = obtainMessage(event, displayId, 0, info);
-            sendMessage(msg);
+            long generationId = mGenerationId.get();
+            Message msg = Message.obtain(null, event, displayId, 0, info);
+            mExecutor.execute(() -> {
+                // If the generation id's don't match we were canceled but still need to recycle()
+                if (generationId == mGenerationId.get()) {
+                    handleMessage(msg);
+                }
+                msg.recycle();
+            });
         }
 
         public void clearEvents() {
-            removeCallbacksAndMessages(null);
+            mGenerationId.incrementAndGet();
         }
 
         public void setEventsMask(@EventsMask long newEventsMask) {
             mEventsMask = newEventsMask;
         }
 
-        @Override
-        public void handleMessage(Message msg) {
+        private void handleMessage(Message msg) {
             if (DEBUG) {
                 Trace.beginSection(
                         "DisplayListenerDelegate(" + eventToString(msg.what)
@@ -1134,6 +1174,11 @@
                         mListener.onDisplayRemoved(msg.arg1);
                     }
                     break;
+                case EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED:
+                    if ((mEventsMask & DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED) != 0) {
+                        mListener.onDisplayChanged(msg.arg1);
+                    }
+                    break;
             }
             if (DEBUG) {
                 Trace.endSection();
@@ -1255,6 +1300,8 @@
                 return "REMOVED";
             case EVENT_DISPLAY_BRIGHTNESS_CHANGED:
                 return "BRIGHTNESS_CHANGED";
+            case EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED:
+                return "HDR_SDR_RATIO_CHANGED";
         }
         return "UNKNOWN";
     }
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/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 657541c..2ea9ea0 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -51,11 +51,9 @@
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.os.SystemClock;
-import android.os.UserHandle;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.os.VibratorManager;
-import android.provider.Settings;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.Display;
@@ -215,30 +213,6 @@
             "android.hardware.input.metadata.KEYBOARD_LAYOUTS";
 
     /**
-     * Pointer Speed: The minimum (slowest) pointer speed (-7).
-     * @hide
-     */
-    public static final int MIN_POINTER_SPEED = -7;
-
-    /**
-     * Pointer Speed: The maximum (fastest) pointer speed (7).
-     * @hide
-     */
-    public static final int MAX_POINTER_SPEED = 7;
-
-    /**
-     * Pointer Speed: The default pointer speed (0).
-     * @hide
-     */
-    public static final int DEFAULT_POINTER_SPEED = 0;
-
-    /**
-     * The maximum allowed obscuring opacity by UID to propagate touches (0 <= x <= 1).
-     * @hide
-     */
-    public static final float DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH = .8f;
-
-    /**
      * Prevent touches from being consumed by apps if these touches passed through a non-trusted
      * window from a different UID and are considered unsafe.
      *
@@ -1135,58 +1109,18 @@
     }
 
     /**
-     * Gets the mouse pointer speed.
-     * <p>
-     * Only returns the permanent mouse pointer speed.  Ignores any temporary pointer
-     * speed set by {@link #tryPointerSpeed}.
-     * </p>
-     *
-     * @param context The application context.
-     * @return The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
-     * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
-     *
-     * @hide
-     */
-    public int getPointerSpeed(Context context) {
-        return Settings.System.getInt(context.getContentResolver(),
-                Settings.System.POINTER_SPEED, DEFAULT_POINTER_SPEED);
-    }
-
-    /**
-     * Sets the mouse pointer speed.
-     * <p>
-     * Requires {@link android.Manifest.permission#WRITE_SETTINGS}.
-     * </p>
-     *
-     * @param context The application context.
-     * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
-     * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
-     *
-     * @hide
-     */
-    @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
-    public void setPointerSpeed(Context context, int speed) {
-        if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) {
-            throw new IllegalArgumentException("speed out of range");
-        }
-
-        Settings.System.putInt(context.getContentResolver(),
-                Settings.System.POINTER_SPEED, speed);
-    }
-
-    /**
      * Changes the mouse pointer speed temporarily, but does not save the setting.
      * <p>
      * Requires {@link android.Manifest.permission#SET_POINTER_SPEED}.
      * </p>
      *
-     * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
-     * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+     * @param speed The pointer speed as a value between {@link InputSettings#MIN_POINTER_SPEED} and
+     * {@link InputSettings#MAX_POINTER_SPEED}, or the default value {@link InputSettings#DEFAULT_POINTER_SPEED}.
      *
      * @hide
      */
     public void tryPointerSpeed(int speed) {
-        if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) {
+        if (speed < InputSettings.MIN_POINTER_SPEED || speed > InputSettings.MAX_POINTER_SPEED) {
             throw new IllegalArgumentException("speed out of range");
         }
 
@@ -1211,44 +1145,8 @@
      */
     @FloatRange(from = 0, to = 1)
     public float getMaximumObscuringOpacityForTouch() {
-        return Settings.Global.getFloat(getContext().getContentResolver(),
-                Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH,
-                DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH);
-    }
-
-    /**
-     * Sets the maximum allowed obscuring opacity by UID to propagate touches.
-     *
-     * <p>For certain window types (eg. SAWs), the decision of honoring {@link LayoutParams
-     * #FLAG_NOT_TOUCHABLE} or not depends on the combined obscuring opacity of the windows
-     * above the touch-consuming window.
-     *
-     * <p>For a certain UID:
-     * <ul>
-     *     <li>If it's the same as the UID of the touch-consuming window, allow it to propagate
-     *     the touch.
-     *     <li>Otherwise take all its windows of eligible window types above the touch-consuming
-     *     window, compute their combined obscuring opacity considering that {@code
-     *     opacity(A, B) = 1 - (1 - opacity(A))*(1 - opacity(B))}. If the computed value is
-     *     lesser than or equal to this setting and there are no other windows preventing the
-     *     touch, allow the UID to propagate the touch.
-     * </ul>
-     *
-     * <p>This value should be between 0 (inclusive) and 1 (inclusive).
-     *
-     * @see #getMaximumObscuringOpacityForTouch()
-     *
-     * @hide
-     */
-    @TestApi
-    @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
-    public void setMaximumObscuringOpacityForTouch(@FloatRange(from = 0, to = 1) float opacity) {
-        if (opacity < 0 || opacity > 1) {
-            throw new IllegalArgumentException(
-                    "Maximum obscuring opacity for touch should be >= 0 and <= 1");
-        }
-        Settings.Global.putFloat(getContext().getContentResolver(),
-                Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH, opacity);
+        Context context = ActivityThread.currentApplication();
+        return InputSettings.getMaximumObscuringOpacityForTouch(context);
     }
 
     /**
@@ -2145,26 +2043,6 @@
     }
 
     /**
-     * Whether stylus has ever been used on device (false by default).
-     * @hide
-     */
-    public boolean isStylusEverUsed(@NonNull Context context) {
-        return Settings.Global.getInt(context.getContentResolver(),
-                        Settings.Global.STYLUS_EVER_USED, 0) == 1;
-    }
-
-    /**
-     * Set whether stylus has ever been used on device.
-     * Should only ever be set to true once after stylus first usage.
-     * @hide
-     */
-    @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
-    public void setStylusEverUsed(@NonNull Context context, boolean stylusEverUsed) {
-        Settings.Global.putInt(context.getContentResolver(),
-                Settings.Global.STYLUS_EVER_USED, stylusEverUsed ? 1 : 0);
-    }
-
-    /**
      * Whether there is a gesture-compatible touchpad connected to the device.
      * @hide
      */
@@ -2174,200 +2052,6 @@
     }
 
     /**
-     * Gets the touchpad pointer speed.
-     *
-     * The returned value only applies to gesture-compatible touchpads.
-     *
-     * @param context The application context.
-     * @return The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
-     * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
-     *
-     * @hide
-     */
-    public int getTouchpadPointerSpeed(@NonNull Context context) {
-        return Settings.System.getIntForUser(context.getContentResolver(),
-                Settings.System.TOUCHPAD_POINTER_SPEED, DEFAULT_POINTER_SPEED,
-                UserHandle.USER_CURRENT);
-    }
-
-    /**
-     * Sets the touchpad pointer speed, and saves it in the settings.
-     *
-     * The new speed will only apply to gesture-compatible touchpads.
-     *
-     * @param context The application context.
-     * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
-     * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
-     *
-     * @hide
-     */
-    @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
-    public void setTouchpadPointerSpeed(@NonNull Context context, int speed) {
-        if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) {
-            throw new IllegalArgumentException("speed out of range");
-        }
-
-        Settings.System.putIntForUser(context.getContentResolver(),
-                Settings.System.TOUCHPAD_POINTER_SPEED, speed, UserHandle.USER_CURRENT);
-    }
-
-    /**
-     * Returns true if the touchpad should use pointer acceleration.
-     *
-     * The returned value only applies to gesture-compatible touchpads.
-     *
-     * @param context The application context.
-     * @return Whether the touchpad should use pointer acceleration.
-     *
-     * @hide
-     */
-    public boolean useTouchpadPointerAcceleration(@NonNull Context context) {
-        // TODO: obtain the actual behavior from the settings
-        return true;
-    }
-
-    /**
-     * Sets the pointer acceleration behavior for the touchpad.
-     *
-     * The new behavior is only applied to gesture-compatible touchpads.
-     *
-     * @param context The application context.
-     * @param enabled Will enable pointer acceleration if true, disable it if false
-     *
-     * @hide
-     */
-    public void setTouchpadPointerAcceleration(@NonNull Context context, boolean enabled) {
-        // TODO: set the right setting
-    }
-
-    /**
-     * Returns true if moving two fingers upwards on the touchpad should
-     * scroll down, which is known as natural scrolling.
-     *
-     * The returned value only applies to gesture-compatible touchpads.
-     *
-     * @param context The application context.
-     * @return Whether the touchpad should use natural scrolling.
-     *
-     * @hide
-     */
-    public boolean useTouchpadNaturalScrolling(@NonNull Context context) {
-        return Settings.System.getIntForUser(context.getContentResolver(),
-                Settings.System.TOUCHPAD_NATURAL_SCROLLING, 0, UserHandle.USER_CURRENT) == 1;
-    }
-
-    /**
-     * Sets the natural scroll behavior for the touchpad.
-     *
-     * If natural scrolling is enabled, moving two fingers upwards on the
-     * touchpad will scroll down.
-     *
-     * @param context The application context.
-     * @param enabled Will enable natural scroll if true, disable it if false
-     *
-     * @hide
-     */
-    @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
-    public void setTouchpadNaturalScrolling(@NonNull Context context, boolean enabled) {
-        Settings.System.putIntForUser(context.getContentResolver(),
-                Settings.System.TOUCHPAD_NATURAL_SCROLLING, enabled ? 1 : 0,
-                UserHandle.USER_CURRENT);
-    }
-
-    /**
-     * Returns true if the touchpad should use tap to click.
-     *
-     * The returned value only applies to gesture-compatible touchpads.
-     *
-     * @param context The application context.
-     * @return Whether the touchpad should use tap to click.
-     *
-     * @hide
-     */
-    public boolean useTouchpadTapToClick(@NonNull Context context) {
-        return Settings.System.getIntForUser(context.getContentResolver(),
-                Settings.System.TOUCHPAD_TAP_TO_CLICK, 0, UserHandle.USER_CURRENT) == 1;
-    }
-
-    /**
-     * Sets the tap to click behavior for the touchpad.
-     *
-     * The new behavior is only applied to gesture-compatible touchpads.
-     *
-     * @param context The application context.
-     * @param enabled Will enable tap to click if true, disable it if false
-     *
-     * @hide
-     */
-    @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
-    public void setTouchpadTapToClick(@NonNull Context context, boolean enabled) {
-        Settings.System.putIntForUser(context.getContentResolver(),
-                Settings.System.TOUCHPAD_TAP_TO_CLICK, enabled ? 1 : 0,
-                UserHandle.USER_CURRENT);
-    }
-
-    /**
-     * Returns true if the touchpad should use tap dragging.
-     *
-     * The returned value only applies to gesture-compatible touchpads.
-     *
-     * @param context The application context.
-     * @return Whether the touchpad should use tap dragging.
-     *
-     * @hide
-     */
-    public boolean useTouchpadTapDragging(@NonNull Context context) {
-        // TODO: obtain the actual behavior from the settings
-        return true;
-    }
-
-    /**
-     * Sets the tap dragging behavior for the touchpad.
-     *
-     * The new behavior is only applied to gesture-compatible touchpads.
-     *
-     * @param context The application context.
-     * @param enabled Will enable tap dragging if true, disable it if false
-     *
-     * @hide
-     */
-    public void setTouchpadTapDragging(@NonNull Context context, boolean enabled) {
-        // TODO: set the right setting
-    }
-
-    /**
-     * Returns true if the touchpad should use the right click zone.
-     *
-     * The returned value only applies to gesture-compatible touchpads.
-     *
-     * @param context The application context.
-     * @return Whether the touchpad should use the right click zone.
-     *
-     * @hide
-     */
-    public boolean useTouchpadRightClickZone(@NonNull Context context) {
-        return Settings.System.getIntForUser(context.getContentResolver(),
-                Settings.System.TOUCHPAD_RIGHT_CLICK_ZONE, 0, UserHandle.USER_CURRENT) == 1;
-    }
-
-    /**
-     * Sets the right click zone behavior for the touchpad.
-     *
-     * The new behavior is only applied to gesture-compatible touchpads.
-     *
-     * @param context The application context.
-     * @param enabled Will enable the right click zone if true, disable it if false
-     *
-     * @hide
-     */
-    @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
-    public void setTouchpadRightClickZone(@NonNull Context context, boolean enabled) {
-        Settings.System.putIntForUser(context.getContentResolver(),
-                Settings.System.TOUCHPAD_RIGHT_CLICK_ZONE, enabled ? 1 : 0,
-                UserHandle.USER_CURRENT);
-    }
-
-    /**
      * Registers a Keyboard backlight change listener to be notified about {@link
      * KeyboardBacklightState} changes for connected keyboard devices.
      *
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
new file mode 100644
index 0000000..cdf9ea5
--- /dev/null
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.input;
+
+import android.Manifest;
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+import android.annotation.TestApi;
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+/**
+ * InputSettings encapsulates reading and writing settings related to input
+ *
+ * @hide
+ */
+@TestApi
+public class InputSettings {
+    /**
+     * Pointer Speed: The minimum (slowest) pointer speed (-7).
+     * @hide
+     */
+    public static final int MIN_POINTER_SPEED = -7;
+
+    /**
+     * Pointer Speed: The maximum (fastest) pointer speed (7).
+     * @hide
+     */
+    public static final int MAX_POINTER_SPEED = 7;
+
+    /**
+     * Pointer Speed: The default pointer speed (0).
+     * @hide
+     */
+    public static final int DEFAULT_POINTER_SPEED = 0;
+
+    /**
+     * The maximum allowed obscuring opacity by UID to propagate touches (0 <= x <= 1).
+     * @hide
+     */
+    public static final float DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH = .8f;
+
+
+    private InputSettings() {
+    }
+
+    /**
+     * Gets the mouse pointer speed.
+     * <p>
+     * Only returns the permanent mouse pointer speed.  Ignores any temporary pointer
+     * speed set by {@link InputManager#tryPointerSpeed}.
+     * </p>
+     *
+     * @param context The application context.
+     * @return The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
+     * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+     *
+     * @hide
+     */
+    @SuppressLint("NonUserGetterCalled")
+    public static int getPointerSpeed(Context context) {
+        return Settings.System.getInt(context.getContentResolver(),
+                Settings.System.POINTER_SPEED, DEFAULT_POINTER_SPEED);
+    }
+
+    /**
+     * Sets the mouse pointer speed.
+     * <p>
+     * Requires {@link android.Manifest.permission#WRITE_SETTINGS}.
+     * </p>
+     *
+     * @param context The application context.
+     * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
+     * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+    public static void setPointerSpeed(Context context, int speed) {
+        if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) {
+            throw new IllegalArgumentException("speed out of range");
+        }
+
+        Settings.System.putInt(context.getContentResolver(),
+                Settings.System.POINTER_SPEED, speed);
+    }
+
+    /**
+     * Returns the maximum allowed obscuring opacity per UID to propagate touches.
+     *
+     * <p>For certain window types (e.g. {@link LayoutParams#TYPE_APPLICATION_OVERLAY}),
+     * the decision of honoring {@link LayoutParams#FLAG_NOT_TOUCHABLE} or not depends on
+     * the combined obscuring opacity of the windows above the touch-consuming window, per
+     * UID. Check documentation of {@link LayoutParams#FLAG_NOT_TOUCHABLE} for more details.
+     *
+     * <p>The value returned is between 0 (inclusive) and 1 (inclusive).
+     *
+     * @see LayoutParams#FLAG_NOT_TOUCHABLE
+     *
+     * @hide
+     */
+    @FloatRange(from = 0, to = 1)
+    public static float getMaximumObscuringOpacityForTouch(Context context) {
+        return Settings.Global.getFloat(context.getContentResolver(),
+                Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH,
+                DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH);
+    }
+
+    /**
+     * Sets the maximum allowed obscuring opacity by UID to propagate touches.
+     *
+     * <p>For certain window types (e.g. SAWs), the decision of honoring {@link LayoutParams
+     * #FLAG_NOT_TOUCHABLE} or not depends on the combined obscuring opacity of the windows
+     * above the touch-consuming window.
+     *
+     * <p>For a certain UID:
+     * <ul>
+     *     <li>If it's the same as the UID of the touch-consuming window, allow it to propagate
+     *     the touch.
+     *     <li>Otherwise take all its windows of eligible window types above the touch-consuming
+     *     window, compute their combined obscuring opacity considering that {@code
+     *     opacity(A, B) = 1 - (1 - opacity(A))*(1 - opacity(B))}. If the computed value is
+     *     less than or equal to this setting and there are no other windows preventing the
+     *     touch, allow the UID to propagate the touch.
+     * </ul>
+     *
+     * <p>This value should be between 0 (inclusive) and 1 (inclusive).
+     *
+     * @see #getMaximumObscuringOpacityForTouch(Context)
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+    public static void setMaximumObscuringOpacityForTouch(
+            @NonNull Context context,
+            @FloatRange(from = 0, to = 1) float opacity) {
+        if (opacity < 0 || opacity > 1) {
+            throw new IllegalArgumentException(
+                    "Maximum obscuring opacity for touch should be >= 0 and <= 1");
+        }
+        Settings.Global.putFloat(context.getContentResolver(),
+                Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH, opacity);
+    }
+
+    /**
+     * Whether stylus has ever been used on device (false by default).
+     * @hide
+     */
+    public static boolean isStylusEverUsed(@NonNull Context context) {
+        return Settings.Global.getInt(context.getContentResolver(),
+                        Settings.Global.STYLUS_EVER_USED, 0) == 1;
+    }
+
+    /**
+     * Set whether stylus has ever been used on device.
+     * Should only ever be set to true once after stylus first usage.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+    public static void setStylusEverUsed(@NonNull Context context, boolean stylusEverUsed) {
+        Settings.Global.putInt(context.getContentResolver(),
+                Settings.Global.STYLUS_EVER_USED, stylusEverUsed ? 1 : 0);
+    }
+
+
+    /**
+     * Gets the touchpad pointer speed.
+     *
+     * The returned value only applies to gesture-compatible touchpads.
+     *
+     * @param context The application context.
+     * @return The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
+     * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+     *
+     * @hide
+     */
+    public static int getTouchpadPointerSpeed(@NonNull Context context) {
+        return Settings.System.getIntForUser(context.getContentResolver(),
+                Settings.System.TOUCHPAD_POINTER_SPEED, DEFAULT_POINTER_SPEED,
+                UserHandle.USER_CURRENT);
+    }
+
+    /**
+     * Sets the touchpad pointer speed, and saves it in the settings.
+     *
+     * The new speed will only apply to gesture-compatible touchpads.
+     *
+     * @param context The application context.
+     * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
+     * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+    public static void setTouchpadPointerSpeed(@NonNull Context context, int speed) {
+        if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) {
+            throw new IllegalArgumentException("speed out of range");
+        }
+
+        Settings.System.putIntForUser(context.getContentResolver(),
+                Settings.System.TOUCHPAD_POINTER_SPEED, speed, UserHandle.USER_CURRENT);
+    }
+
+    /**
+     * Returns true if moving two fingers upwards on the touchpad should
+     * scroll down, which is known as natural scrolling.
+     *
+     * The returned value only applies to gesture-compatible touchpads.
+     *
+     * @param context The application context.
+     * @return Whether the touchpad should use natural scrolling.
+     *
+     * @hide
+     */
+    public static boolean useTouchpadNaturalScrolling(@NonNull Context context) {
+        return Settings.System.getIntForUser(context.getContentResolver(),
+                Settings.System.TOUCHPAD_NATURAL_SCROLLING, 0, UserHandle.USER_CURRENT) == 1;
+    }
+
+    /**
+     * Sets the natural scroll behavior for the touchpad.
+     *
+     * If natural scrolling is enabled, moving two fingers upwards on the
+     * touchpad will scroll down.
+     *
+     * @param context The application context.
+     * @param enabled Will enable natural scroll if true, disable it if false
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+    public static void setTouchpadNaturalScrolling(@NonNull Context context, boolean enabled) {
+        Settings.System.putIntForUser(context.getContentResolver(),
+                Settings.System.TOUCHPAD_NATURAL_SCROLLING, enabled ? 1 : 0,
+                UserHandle.USER_CURRENT);
+    }
+
+    /**
+     * Returns true if the touchpad should use tap to click.
+     *
+     * The returned value only applies to gesture-compatible touchpads.
+     *
+     * @param context The application context.
+     * @return Whether the touchpad should use tap to click.
+     *
+     * @hide
+     */
+    public static boolean useTouchpadTapToClick(@NonNull Context context) {
+        return Settings.System.getIntForUser(context.getContentResolver(),
+                Settings.System.TOUCHPAD_TAP_TO_CLICK, 0, UserHandle.USER_CURRENT) == 1;
+    }
+
+    /**
+     * Sets the tap to click behavior for the touchpad.
+     *
+     * The new behavior is only applied to gesture-compatible touchpads.
+     *
+     * @param context The application context.
+     * @param enabled Will enable tap to click if true, disable it if false
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+    public static void setTouchpadTapToClick(@NonNull Context context, boolean enabled) {
+        Settings.System.putIntForUser(context.getContentResolver(),
+                Settings.System.TOUCHPAD_TAP_TO_CLICK, enabled ? 1 : 0,
+                UserHandle.USER_CURRENT);
+    }
+
+    /**
+     * Returns true if the touchpad should use the right click zone.
+     *
+     * The returned value only applies to gesture-compatible touchpads.
+     *
+     * @param context The application context.
+     * @return Whether the touchpad should use the right click zone.
+     *
+     * @hide
+     */
+    public static boolean useTouchpadRightClickZone(@NonNull Context context) {
+        return Settings.System.getIntForUser(context.getContentResolver(),
+                Settings.System.TOUCHPAD_RIGHT_CLICK_ZONE, 0, UserHandle.USER_CURRENT) == 1;
+    }
+
+    /**
+     * Sets the right click zone behavior for the touchpad.
+     *
+     * The new behavior is only applied to gesture-compatible touchpads.
+     *
+     * @param context The application context.
+     * @param enabled Will enable the right click zone if true, disable it if false
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+    public static void setTouchpadRightClickZone(@NonNull Context context, boolean enabled) {
+        Settings.System.putIntForUser(context.getContentResolver(),
+                Settings.System.TOUCHPAD_RIGHT_CLICK_ZONE, enabled ? 1 : 0,
+                UserHandle.USER_CURRENT);
+    }
+}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 13d54ef..03c32d70 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";
@@ -2984,6 +2982,12 @@
     /**
      * Signals that wake-on-lan/wake-on-wlan is allowed in Low Power Standby.
      *
+     * <p>If Low Power Standby is enabled ({@link #isLowPowerStandbyEnabled()}),
+     * wake-on-lan/wake-on-wlan may not be available while in standby.
+     * Use {@link #isAllowedInLowPowerStandby(String)} to determine whether the device allows this
+     * feature to be used during Low Power Standby with the currently active Low Power Standby
+     * policy.
+     *
      * @see #isAllowedInLowPowerStandby(String)
      */
     public static final String LOW_POWER_STANDBY_FEATURE_WAKE_ON_LAN =
diff --git a/core/java/android/service/search/ISearchUiService.aidl b/core/java/android/service/search/ISearchUiService.aidl
index bc6d421..f59347f 100644
--- a/core/java/android/service/search/ISearchUiService.aidl
+++ b/core/java/android/service/search/ISearchUiService.aidl
@@ -39,8 +39,6 @@
 
     void onRegisterEmptyQueryResultUpdateCallback (in SearchSessionId sessionId, in ISearchCallback callback);
 
-    void onRequestEmptyQueryResultUpdate(in SearchSessionId sessionId);
-
     void onUnregisterEmptyQueryResultUpdateCallback(in SearchSessionId sessionId, in ISearchCallback callback);
 
     void onDestroy(in SearchSessionId sessionId);
diff --git a/core/java/android/service/search/SearchUiService.java b/core/java/android/service/search/SearchUiService.java
index 55a96fa..8d05b80 100644
--- a/core/java/android/service/search/SearchUiService.java
+++ b/core/java/android/service/search/SearchUiService.java
@@ -112,12 +112,6 @@
         }
 
         @Override
-        public void onRequestEmptyQueryResultUpdate(SearchSessionId sessionId) {
-            mHandler.sendMessage(obtainMessage(SearchUiService::doRequestEmptyQueryResultUpdate,
-                    SearchUiService.this, sessionId));
-        }
-
-        @Override
         public void onUnregisterEmptyQueryResultUpdateCallback(SearchSessionId sessionId,
                 ISearchCallback callback) {
             mHandler.sendMessage(
@@ -220,24 +214,6 @@
     @MainThread
     public void onStartUpdateEmptyQueryResult() {}
 
-    private void doRequestEmptyQueryResultUpdate(@NonNull SearchSessionId sessionId) {
-        // Just an optimization, if there are no callbacks, then don't bother notifying the service
-        final ArrayList<CallbackWrapper> callbacks = mSessionEmptyQueryResultCallbacks.get(
-                sessionId);
-        if (callbacks != null && !callbacks.isEmpty()) {
-            onRequestEmptyQueryResultUpdate(sessionId);
-        }
-    }
-
-    /**
-     * Called by a client to request empty query search target result for zero state. This method
-     * is only called if there are one or more empty query result update callbacks registered.
-     *
-     * @see #updateEmptyQueryResult(SearchSessionId, List)
-     */
-    @MainThread
-    public void onRequestEmptyQueryResultUpdate(@NonNull SearchSessionId sessionId) {}
-
     private void doUnregisterEmptyQueryResultUpdateCallback(@NonNull SearchSessionId sessionId,
             @NonNull ISearchCallback callback) {
         final ArrayList<CallbackWrapper> callbacks = mSessionEmptyQueryResultCallbacks.get(
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/Choreographer.java b/core/java/android/view/Choreographer.java
index d0acedb..4a83bbe 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -1173,7 +1173,8 @@
          *
          * @param data The payload which includes frame information. Divide nanosecond values by
          *             {@code 1000000} to convert it to the {@link SystemClock#uptimeMillis()}
-         *             time base.
+         *             time base. {@code data} is not valid outside of {@code onVsync} and should
+         *             not be accessed outside the callback.
          * @see FrameCallback#doFrame
          **/
         void onVsync(@NonNull FrameData data);
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 6b1499f..1563fc0 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -56,6 +56,8 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * Provides information about the size and density of a logical display.
@@ -111,6 +113,8 @@
     private int mCachedAppWidthCompat;
     private int mCachedAppHeightCompat;
 
+    private ArrayList<HdrSdrRatioListenerWrapper> mHdrSdrRatioListeners = new ArrayList<>();
+
     /**
      * The default Display id, which is the id of the primary display assuming there is one.
      */
@@ -1292,6 +1296,102 @@
     }
 
     /**
+     * @return Whether the display supports reporting an hdr/sdr ratio. If this is false,
+     *         {@link #getHdrSdrRatio()} will always be 1.0f
+     * @hide
+     * TODO: make public
+     */
+    public boolean isHdrSdrRatioAvailable() {
+        synchronized (mLock) {
+            updateDisplayInfoLocked();
+            return !Float.isNaN(mDisplayInfo.hdrSdrRatio);
+        }
+    }
+
+    /**
+     * @return The current hdr/sdr ratio expressed as the ratio of targetHdrPeakBrightnessInNits /
+     *         targetSdrWhitePointInNits. If {@link #isHdrSdrRatioAvailable()} is false, this
+     *         always returns 1.0f.
+     *
+     * @hide
+     * TODO: make public
+     */
+    public float getHdrSdrRatio() {
+        synchronized (mLock) {
+            updateDisplayInfoLocked();
+            return Float.isNaN(mDisplayInfo.hdrSdrRatio)
+                    ? 1.0f : mDisplayInfo.hdrSdrRatio;
+        }
+    }
+
+    private int findHdrSdrRatioListenerLocked(Consumer<Display> listener) {
+        for (int i = 0; i < mHdrSdrRatioListeners.size(); i++) {
+            final HdrSdrRatioListenerWrapper wrapper = mHdrSdrRatioListeners.get(i);
+            if (wrapper.mListener == listener) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Registers a listener that will be invoked whenever the display's hdr/sdr ratio has changed.
+     * After receiving the callback on the specified Executor, call {@link #getHdrSdrRatio()} to
+     * get the updated value.
+     * If {@link #isHdrSdrRatioAvailable()} is false, then an IllegalStateException will be thrown
+     *
+     * @see #unregisterHdrSdrRatioChangedListener(Consumer)
+     * @param executor The executor to invoke the listener on
+     * @param listener The listener to invoke when the HDR/SDR ratio changes
+     * @throws IllegalStateException if {@link #isHdrSdrRatioAvailable()} is false
+     * @hide
+     * TODO: Make public
+     */
+    public void registerHdrSdrRatioChangedListener(@NonNull Executor executor,
+            @NonNull Consumer<Display> listener) {
+        if (!isHdrSdrRatioAvailable()) {
+            throw new IllegalStateException("HDR/SDR ratio changed not available");
+        }
+        HdrSdrRatioListenerWrapper toRegister = null;
+        synchronized (mLock) {
+            if (findHdrSdrRatioListenerLocked(listener) == -1) {
+                toRegister = new HdrSdrRatioListenerWrapper(listener);
+                mHdrSdrRatioListeners.add(toRegister);
+            } // else already listening, don't do anything
+        }
+        if (toRegister != null) {
+            // Although we only care about the HDR/SDR ratio changing, that can also come in the
+            // form of the larger DISPLAY_CHANGED event
+            mGlobal.registerDisplayListener(toRegister, executor,
+                    DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED
+                            | DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+        }
+
+    }
+
+    /**
+     * @param listener  The previously
+     *                  {@link #registerHdrSdrRatioChangedListener(Executor, Consumer) registered}
+     *                  hdr/sdr ratio listener to remove.
+     *
+     * @see #registerHdrSdrRatioChangedListener(Executor, Consumer)
+     * @hide
+     * TODO: Make public
+     */
+    public void unregisterHdrSdrRatioChangedListener(Consumer<Display> listener) {
+        HdrSdrRatioListenerWrapper toRemove = null;
+        synchronized (mLock) {
+            int index = findHdrSdrRatioListenerLocked(listener);
+            if (index != -1) {
+                toRemove = mHdrSdrRatioListeners.remove(index);
+            }
+        }
+        if (toRemove != null) {
+            mGlobal.unregisterDisplayListener(toRemove);
+        }
+    }
+
+    /**
      * Sets the default {@link Display.Mode} to use for the display.  The display mode includes
      * preference for resolution and refresh rate.
      * If the mode specified is not supported by the display, then no mode change occurs.
@@ -2528,4 +2628,33 @@
             }
         }
     }
+
+    private class HdrSdrRatioListenerWrapper implements DisplayManager.DisplayListener {
+        Consumer<Display> mListener;
+        float mLastReportedRatio = 1.f;
+
+        private HdrSdrRatioListenerWrapper(Consumer<Display> listener) {
+            mListener = listener;
+        }
+
+        @Override
+        public void onDisplayAdded(int displayId) {
+            // don't care
+        }
+
+        @Override
+        public void onDisplayRemoved(int displayId) {
+            // don't care
+        }
+
+        @Override
+        public void onDisplayChanged(int displayId) {
+            if (displayId == getDisplayId()) {
+                float newRatio = getHdrSdrRatio();
+                if (newRatio != mLastReportedRatio) {
+                    mListener.accept(Display.this);
+                }
+            }
+        }
+    }
 }
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 3a02c48..0368918 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -39,6 +39,8 @@
 import android.util.DisplayMetrics;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.display.BrightnessSynchronizer;
+
 import java.util.Arrays;
 import java.util.Objects;
 
@@ -340,6 +342,13 @@
     @Nullable
     public SurfaceControl.RefreshRateRange layoutLimitedRefreshRate;
 
+    /**
+     * The current hdr/sdr ratio for the display. If the display doesn't support hdr/sdr ratio
+     * queries then this is NaN
+     */
+    public float hdrSdrRatio = Float.NaN;
+
+
     public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
         @Override
         public DisplayInfo createFromParcel(Parcel source) {
@@ -415,7 +424,8 @@
                 && Objects.equals(roundedCorners, other.roundedCorners)
                 && installOrientation == other.installOrientation
                 && Objects.equals(displayShape, other.displayShape)
-                && Objects.equals(layoutLimitedRefreshRate, other.layoutLimitedRefreshRate);
+                && Objects.equals(layoutLimitedRefreshRate, other.layoutLimitedRefreshRate)
+                && BrightnessSynchronizer.floatEquals(hdrSdrRatio, other.hdrSdrRatio);
     }
 
     @Override
@@ -471,6 +481,7 @@
         installOrientation = other.installOrientation;
         displayShape = other.displayShape;
         layoutLimitedRefreshRate = other.layoutLimitedRefreshRate;
+        hdrSdrRatio = other.hdrSdrRatio;
     }
 
     public void readFromParcel(Parcel source) {
@@ -532,6 +543,7 @@
         installOrientation = source.readInt();
         displayShape = source.readTypedObject(DisplayShape.CREATOR);
         layoutLimitedRefreshRate = source.readTypedObject(SurfaceControl.RefreshRateRange.CREATOR);
+        hdrSdrRatio = source.readFloat();
     }
 
     @Override
@@ -591,6 +603,7 @@
         dest.writeInt(installOrientation);
         dest.writeTypedObject(displayShape, flags);
         dest.writeTypedObject(layoutLimitedRefreshRate, flags);
+        dest.writeFloat(hdrSdrRatio);
     }
 
     @Override
@@ -852,6 +865,12 @@
         sb.append(Surface.rotationToString(installOrientation));
         sb.append(", layoutLimitedRefreshRate ");
         sb.append(layoutLimitedRefreshRate);
+        sb.append(", hdrSdrRatio ");
+        if (Float.isNaN(hdrSdrRatio)) {
+            sb.append("not_available");
+        } else {
+            sb.append(hdrSdrRatio);
+        }
         sb.append("}");
         return sb.toString();
     }
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/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 159775c..d1c4201 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -169,7 +169,7 @@
     private static final boolean DEBUG_UNDO = false;
 
     // TODO(nona): Make this configurable.
-    private static final boolean FLAG_USE_NEW_CONTEXT_MENU = true;
+    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;
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.bp b/core/jni/Android.bp
index b4599c8..fc26766 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -334,8 +334,6 @@
                 "libtimeinstate",
                 "server_configurable_flags",
                 "libimage_io",
-                "libjpegdecoder",
-                "libjpegencoder",
                 "libjpegrecoverymap",
             ],
             export_shared_lib_headers: [
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/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 688fec6..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 -->
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/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 111cfd8..f11836e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -650,7 +650,6 @@
         }
 
         mPipUiEventLoggerLogger.setTaskInfo(mTaskInfo);
-        mPipUiEventLoggerLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER);
 
         // If the displayId of the task is different than what PipBoundsHandler has, then update
         // it. This is possible if we entered PiP on an external display.
@@ -659,6 +658,17 @@
             mOnDisplayIdChangeCallback.accept(info.displayId);
         }
 
+        // UiEvent logging.
+        final PipUiEventLogger.PipUiEventEnum uiEventEnum;
+        if (isLaunchIntoPipTask()) {
+            uiEventEnum = PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER_CONTENT_PIP;
+        } else if (mPipTransitionState.getInSwipePipToHomeTransition()) {
+            uiEventEnum = PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_AUTO_ENTER;
+        } else {
+            uiEventEnum = PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER;
+        }
+        mPipUiEventLoggerLogger.log(uiEventEnum);
+
         if (mPipTransitionState.getInSwipePipToHomeTransition()) {
             if (!mWaitForFixedRotation) {
                 onEndOfSwipePipToHomeTransition();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
index 513ebba..3e5a19b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
@@ -78,6 +78,12 @@
         @UiEvent(doc = "Activity enters picture-in-picture mode")
         PICTURE_IN_PICTURE_ENTER(603),
 
+        @UiEvent(doc = "Activity enters picture-in-picture mode with auto-enter-pip API")
+        PICTURE_IN_PICTURE_AUTO_ENTER(1313),
+
+        @UiEvent(doc = "Activity enters picture-in-picture mode from content-pip API")
+        PICTURE_IN_PICTURE_ENTER_CONTENT_PIP(1314),
+
         @UiEvent(doc = "Expands from picture-in-picture to fullscreen")
         PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN(604),
 
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/Android.bp b/libs/hwui/Android.bp
index 9e3f115..03d89cc 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -396,8 +396,6 @@
         "libharfbuzz_ng",
         "libimage_io",
         "libjpeg",
-        "libjpegdecoder",
-        "libjpegencoder",
         "libjpegrecoverymap",
         "liblog",
         "libminikin",
diff --git a/libs/hwui/hwui/ImageDecoder.cpp b/libs/hwui/hwui/ImageDecoder.cpp
index 6d7c727..8266beb 100644
--- a/libs/hwui/hwui/ImageDecoder.cpp
+++ b/libs/hwui/hwui/ImageDecoder.cpp
@@ -17,13 +17,25 @@
 #include "ImageDecoder.h"
 
 #include <Gainmap.h>
+#include <SkAlphaType.h>
 #include <SkAndroidCodec.h>
 #include <SkBitmap.h>
 #include <SkBlendMode.h>
 #include <SkCanvas.h>
+#include <SkCodec.h>
+#include <SkCodecAnimation.h>
+#include <SkColorSpace.h>
+#include <SkColorType.h>
 #include <SkEncodedOrigin.h>
+#include <SkImageInfo.h>
 #include <SkGainmapInfo.h>
+#include <SkMatrix.h>
 #include <SkPaint.h>
+#include <SkPngChunkReader.h>
+#include <SkRect.h>
+#include <SkRefCnt.h>
+#include <SkSamplingOptions.h>
+#include <SkSize.h>
 #include <SkStream.h>
 #include <hwui/Bitmap.h>
 #include <log/log.h>
@@ -506,6 +518,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 +543,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/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp
index add62b1..fda7080 100644
--- a/libs/hwui/jni/ImageDecoder.cpp
+++ b/libs/hwui/jni/ImageDecoder.cpp
@@ -18,11 +18,16 @@
 
 #include <FrontBufferedStream.h>
 #include <HardwareBitmapUploader.h>
+#include <SkAlphaType.h>
 #include <SkAndroidCodec.h>
 #include <SkBitmap.h>
+#include <SkCodec.h>
+#include <SkCodecAnimation.h>
 #include <SkColorSpace.h>
+#include <SkColorType.h>
 #include <SkImageInfo.h>
 #include <SkRect.h>
+#include <SkSize.h>
 #include <SkStream.h>
 #include <SkString.h>
 #include <androidfw/Asset.h>
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/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/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp
index cd6ed23..e18b4a9 100644
--- a/native/graphics/jni/imagedecoder.cpp
+++ b/native/graphics/jni/imagedecoder.cpp
@@ -25,10 +25,14 @@
 #include <hwui/ImageDecoder.h>
 #include <log/log.h>
 #include <SkAndroidCodec.h>
+#include <SkAlphaType.h>
 #include <SkCodec.h>
+#include <SkCodecAnimation.h>
 #include <SkColorSpace.h>
+#include <SkColorType.h>
 #include <SkImageInfo.h>
 #include <SkRect.h>
+#include <SkRefCnt.h>
 #include <SkSize.h>
 #include <SkStream.h>
 #include <utils/Color.h>
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/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/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/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/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/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/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/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/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 c45af6d..754433b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2304,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>
@@ -3021,4 +3029,22 @@
     [CHAR LIMIT=32]
     -->
     <string name="lock_screen_settings">Lock screen settings</string>
+
+    <!-- Content description for Wi-Fi not available icon on dream [CHAR LIMIT=NONE]-->
+    <string name="wifi_unavailable_dream_overlay_content_description">Wi-Fi not available</string>
+
+    <!-- Content description for camera blocked icon on dream [CHAR LIMIT=NONE] -->
+    <string name="camera_blocked_dream_overlay_content_description">Camera blocked</string>
+
+    <!-- Content description for camera and microphone blocked icon on dream [CHAR LIMIT=NONE] -->
+    <string name="camera_and_microphone_blocked_dream_overlay_content_description">Camera and microphone blocked</string>
+
+    <!-- Content description for camera and microphone disabled icon on dream [CHAR LIMIT=NONE] -->
+    <string name="microphone_blocked_dream_overlay_content_description">Microphone blocked</string>
+
+    <!-- Content description for priority mode icon on dream [CHAR LIMIT=NONE] -->
+    <string name="priority_mode_dream_overlay_content_description">Priority mode on</string>
+
+    <!-- Content description for when assistant attention is active [CHAR LIMIT=NONE] -->
+    <string name="assistant_attention_content_description">Assistant attention on</string>
 </resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
index 54ae84f9..ead1a10 100644
--- a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
@@ -303,9 +303,18 @@
         pw.println("   requestActiveUnlockOnWakeup=$requestActiveUnlockOnWakeup")
         pw.println("   requestActiveUnlockOnUnlockIntent=$requestActiveUnlockOnUnlockIntent")
         pw.println("   requestActiveUnlockOnBioFail=$requestActiveUnlockOnBioFail")
-        pw.println("   requestActiveUnlockOnUnlockIntentWhenBiometricEnrolled=${
-            onUnlockIntentWhenBiometricEnrolled.map { BiometricType.values()[it] }
-        }")
+
+        val onUnlockIntentWhenBiometricEnrolledString =
+            onUnlockIntentWhenBiometricEnrolled.map {
+                for (biometricType in BiometricType.values()) {
+                    if (biometricType.intValue == it) {
+                        return@map biometricType.name
+                    }
+                }
+                return@map "UNKNOWN"
+            }
+        pw.println("   requestActiveUnlockOnUnlockIntentWhenBiometricEnrolled=" +
+                "$onUnlockIntentWhenBiometricEnrolledString")
         pw.println("   requestActiveUnlockOnFaceError=$faceErrorsToTriggerBiometricFailOn")
         pw.println("   requestActiveUnlockOnFaceAcquireInfo=" +
                 "$faceAcquireInfoToTriggerBiometricFailOn")
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/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 27641fe..a14aa52 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -269,6 +269,8 @@
      */
     private void addOverlayWindowLocked(WindowManager.LayoutParams layoutParams) {
         mWindow = new PhoneWindow(mContext);
+        // Default to SystemUI name for TalkBack.
+        mWindow.setTitle("");
         mWindow.setAttributes(layoutParams);
         mWindow.setWindowManager(null, layoutParams.token, "DreamOverlay", true);
 
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
index 2221a04..74a49a8 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
@@ -259,7 +259,8 @@
                         mConnectivityManager.getActiveNetwork());
         final boolean available = capabilities != null
                 && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
-        showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, !available);
+        showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, !available,
+                R.string.wifi_unavailable_dream_overlay_content_description);
     }
 
     private void updateAlarmStatusIcon() {
@@ -274,7 +275,8 @@
 
     private void updateAssistantAttentionIcon() {
         showIcon(DreamOverlayStatusBarView.STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE,
-                mDreamOverlayStateController.hasAssistantAttention());
+                mDreamOverlayStateController.hasAssistantAttention(),
+                R.string.assistant_attention_content_description);
     }
 
     private void updateVisibility() {
@@ -304,13 +306,16 @@
         @DreamOverlayStatusBarView.StatusIconType int iconType = Resources.ID_NULL;
         showIcon(
                 DreamOverlayStatusBarView.STATUS_ICON_CAMERA_DISABLED,
-                !micBlocked && cameraBlocked);
+                !micBlocked && cameraBlocked,
+                R.string.camera_blocked_dream_overlay_content_description);
         showIcon(
                 DreamOverlayStatusBarView.STATUS_ICON_MIC_DISABLED,
-                micBlocked && !cameraBlocked);
+                micBlocked && !cameraBlocked,
+                R.string.microphone_blocked_dream_overlay_content_description);
         showIcon(
                 DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED,
-                micBlocked && cameraBlocked);
+                micBlocked && cameraBlocked,
+                R.string.camera_and_microphone_blocked_dream_overlay_content_description);
     }
 
     private String buildNotificationsContentDescription(int notificationCount) {
@@ -323,11 +328,13 @@
     private void updatePriorityModeStatusIcon() {
         showIcon(
                 DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON,
-                mZenModeController.getZen() != Settings.Global.ZEN_MODE_OFF);
+                mZenModeController.getZen() != Settings.Global.ZEN_MODE_OFF,
+                R.string.priority_mode_dream_overlay_content_description);
     }
 
-    private void showIcon(@DreamOverlayStatusBarView.StatusIconType int iconType, boolean show) {
-        showIcon(iconType, show, null);
+    private void showIcon(@DreamOverlayStatusBarView.StatusIconType int iconType, boolean show,
+            int contentDescriptionResId) {
+        showIcon(iconType, show, mResources.getString(contentDescriptionResId));
     }
 
     private void showIcon(
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index b75b6d8..85e050c 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -566,6 +566,12 @@
     val CONTROLS_MANAGEMENT_NEW_FLOWS =
         releasedFlag(2002, "controls_management_new_flows", teamfood = true)
 
+    // Enables removing app from Home control panel as a part of a new flow
+    // TODO(b/269132640): Tracking Bug
+    @JvmField
+    val APP_PANELS_REMOVE_APPS_ALLOWED =
+        unreleasedFlag(2003, "app_panels_remove_apps_allowed", teamfood = false)
+
     // 2100 - Falsing Manager
     @JvmField val FALSING_FOR_LONG_TAPS = releasedFlag(2100, "falsing_for_long_taps")
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
index 5a9f775..c9f645d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
@@ -18,6 +18,7 @@
 package com.android.systemui.keyguard.data.quickaffordance
 
 import android.app.StatusBarManager
+import android.app.admin.DevicePolicyManager
 import android.content.Context
 import android.content.pm.PackageManager
 import com.android.systemui.R
@@ -27,10 +28,14 @@
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.settings.UserTracker
 import dagger.Lazy
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.withContext
 
 @SysUISingleton
 class CameraQuickAffordanceConfig
@@ -39,6 +44,9 @@
     @Application private val context: Context,
     private val packageManager: PackageManager,
     private val cameraGestureHelper: Lazy<CameraGestureHelper>,
+    private val userTracker: UserTracker,
+    private val devicePolicyManager: DevicePolicyManager,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
 ) : KeyguardQuickAffordanceConfig {
 
     override val key: String
@@ -79,7 +87,12 @@
         return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
     }
 
-    private fun isLaunchable(): Boolean {
-        return packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)
+    private suspend fun isLaunchable(): Boolean {
+        return packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY) &&
+            withContext(backgroundDispatcher) {
+                !devicePolicyManager.getCameraDisabled(null, userTracker.userId) &&
+                    devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId) and
+                        DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA == 0
+            }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt
index d9ec3b1..6f821a2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt
@@ -18,6 +18,7 @@
 package com.android.systemui.keyguard.data.quickaffordance
 
 import android.app.StatusBarManager
+import android.app.admin.DevicePolicyManager
 import android.content.Context
 import android.content.Intent
 import com.android.systemui.ActivityIntentHelper
@@ -29,10 +30,13 @@
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.settings.UserTracker
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.withContext
 
 @SysUISingleton
 class VideoCameraQuickAffordanceConfig
@@ -42,6 +46,8 @@
     private val cameraIntents: CameraIntentsWrapper,
     private val activityIntentHelper: ActivityIntentHelper,
     private val userTracker: UserTracker,
+    private val devicePolicyManager: DevicePolicyManager,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
 ) : KeyguardQuickAffordanceConfig {
 
     private val intent: Intent by lazy {
@@ -63,8 +69,8 @@
         get() = R.drawable.ic_videocam
 
     override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState>
-        get() =
-            flowOf(
+        get() = flow {
+            emit(
                 if (isLaunchable()) {
                     KeyguardQuickAffordanceConfig.LockScreenState.Visible(
                         icon =
@@ -77,6 +83,7 @@
                     KeyguardQuickAffordanceConfig.LockScreenState.Hidden
                 }
             )
+        }
 
     override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState {
         return if (isLaunchable()) {
@@ -95,11 +102,14 @@
         )
     }
 
-    private fun isLaunchable(): Boolean {
+    private suspend fun isLaunchable(): Boolean {
         return activityIntentHelper.getTargetActivityInfo(
             intent,
             userTracker.userId,
             true,
-        ) != null
+        ) != null &&
+            withContext(backgroundDispatcher) {
+                !devicePolicyManager.getCameraDisabled(null, userTracker.userId)
+            }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
index b72923a..68d2c5c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
@@ -164,13 +164,13 @@
                 mediaCarouselScrollHandler.scrollToStart()
             }
         }
-    private var currentlyExpanded = true
+
+    @VisibleForTesting
+    var currentlyExpanded = true
         set(value) {
             if (field != value) {
                 field = value
-                for (player in MediaPlayerData.players()) {
-                    player.setListening(field)
-                }
+                updateSeekbarListening(mediaCarouselScrollHandler.visibleToUser)
             }
         }
 
@@ -259,6 +259,7 @@
                 executor,
                 this::onSwipeToDismiss,
                 this::updatePageIndicatorLocation,
+                this::updateSeekbarListening,
                 this::closeGuts,
                 falsingCollector,
                 falsingManager,
@@ -590,6 +591,17 @@
                     ?: mediaCarouselScrollHandler.scrollToPlayer(destIndex = mediaIndex)
             }
         }
+        // Check postcondition: mediaContent should have the same number of children as there
+        // are
+        // elements in mediaPlayers.
+        if (MediaPlayerData.players().size != mediaContent.childCount) {
+            Log.e(
+                TAG,
+                "Size of players list and number of views in carousel are out of sync. " +
+                    "Players size is ${MediaPlayerData.players().size}. " +
+                    "View count is ${mediaContent.childCount}."
+            )
+        }
     }
 
     // Returns true if new player is added
@@ -618,7 +630,9 @@
                     )
                 newPlayer.mediaViewHolder?.player?.setLayoutParams(lp)
                 newPlayer.bindPlayer(data, key)
-                newPlayer.setListening(currentlyExpanded)
+                newPlayer.setListening(
+                    mediaCarouselScrollHandler.visibleToUser && currentlyExpanded
+                )
                 MediaPlayerData.addMediaPlayer(
                     key,
                     data,
@@ -665,17 +679,6 @@
             updatePageIndicator()
             mediaCarouselScrollHandler.onPlayersChanged()
             mediaFrame.requiresRemeasuring = true
-            // Check postcondition: mediaContent should have the same number of children as there
-            // are
-            // elements in mediaPlayers.
-            if (MediaPlayerData.players().size != mediaContent.childCount) {
-                Log.e(
-                    TAG,
-                    "Size of players list and number of views in carousel are out of sync. " +
-                        "Players size is ${MediaPlayerData.players().size}. " +
-                        "View count is ${mediaContent.childCount}."
-                )
-            }
             return existingPlayer == null
         }
 
@@ -914,6 +917,13 @@
                 .toFloat()
     }
 
+    /** Update listening to seekbar. */
+    private fun updateSeekbarListening(visibleToUser: Boolean) {
+        for (player in MediaPlayerData.players()) {
+            player.setListening(visibleToUser && currentlyExpanded)
+        }
+    }
+
     /** Update the dimension of this carousel. */
     private fun updateCarouselDimensions() {
         var width = 0
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
index 36b2eda..1ace316 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
@@ -57,6 +57,7 @@
     private val mainExecutor: DelayableExecutor,
     val dismissCallback: () -> Unit,
     private var translationChangedListener: () -> Unit,
+    private var seekBarUpdateListener: (visibleToUser: Boolean) -> Unit,
     private val closeGuts: (immediate: Boolean) -> Unit,
     private val falsingCollector: FalsingCollector,
     private val falsingManager: FalsingManager,
@@ -177,6 +178,12 @@
 
     /** Whether the media card is visible to user if any */
     var visibleToUser: Boolean = false
+        set(value) {
+            if (field != value) {
+                field = value
+                seekBarUpdateListener.invoke(field)
+            }
+        }
 
     /** Whether the quick setting is expanded or not */
     var qsExpanded: Boolean = false
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index 6076e58..288266a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -347,6 +347,11 @@
         mSeekBarViewModel.setListening(listening);
     }
 
+    @VisibleForTesting
+    public boolean getListening() {
+        return mSeekBarViewModel.getListening();
+    }
+
     /** Sets whether the user is touching the seek bar to change the track position. */
     private void setIsScrubbing(boolean isScrubbing) {
         if (mMediaData == null || mMediaData.getSemanticActions() == null) {
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/screenshot/ScreenshotEvent.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
index 7a62bae..fc94aed 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
@@ -93,7 +93,13 @@
     @UiEvent(doc = "User has discarded the result of a long screenshot")
     SCREENSHOT_LONG_SCREENSHOT_EXIT(911),
     @UiEvent(doc = "A screenshot has been taken and saved to work profile")
-    SCREENSHOT_SAVED_TO_WORK_PROFILE(1240);
+    SCREENSHOT_SAVED_TO_WORK_PROFILE(1240),
+    @UiEvent(doc = "Notes application triggered the screenshot for notes")
+    SCREENSHOT_FOR_NOTE_TRIGGERED(1308),
+    @UiEvent(doc = "User accepted the screenshot to be sent to the notes app")
+    SCREENSHOT_FOR_NOTE_ACCEPTED(1309),
+    @UiEvent(doc = "User cancelled the screenshot for notes app flow")
+    SCREENSHOT_FOR_NOTE_CANCELLED(1310);
 
     private final int mId;
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
index f8d86a0..3133924 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
@@ -17,15 +17,21 @@
 package com.android.systemui.screenshot;
 
 import static com.android.systemui.screenshot.AppClipsTrampolineActivity.ACTION_FINISH_FROM_TRAMPOLINE;
+import static com.android.systemui.screenshot.AppClipsTrampolineActivity.EXTRA_CALLING_PACKAGE_NAME;
 import static com.android.systemui.screenshot.AppClipsTrampolineActivity.EXTRA_RESULT_RECEIVER;
 import static com.android.systemui.screenshot.AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI;
 import static com.android.systemui.screenshot.AppClipsTrampolineActivity.PERMISSION_SELF;
+import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_ACCEPTED;
+import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_CANCELLED;
 
 import android.app.Activity;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
@@ -33,15 +39,20 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.ResultReceiver;
+import android.util.Log;
 import android.view.View;
 import android.widget.Button;
 import android.widget.ImageView;
 
 import androidx.activity.ComponentActivity;
+import androidx.annotation.Nullable;
 import androidx.lifecycle.ViewModelProvider;
 
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.UiEventLogger.UiEventEnum;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
+import com.android.systemui.settings.UserTracker;
 
 import javax.inject.Inject;
 
@@ -64,9 +75,15 @@
  *
  * TODO(b/267309532): Polish UI and animations.
  */
-public final class AppClipsActivity extends ComponentActivity {
+public class AppClipsActivity extends ComponentActivity {
+
+    private static final String TAG = AppClipsActivity.class.getSimpleName();
+    private static final ApplicationInfoFlags APPLICATION_INFO_FLAGS = ApplicationInfoFlags.of(0);
 
     private final AppClipsViewModel.Factory mViewModelFactory;
+    private final PackageManager mPackageManager;
+    private final UserTracker mUserTracker;
+    private final UiEventLogger mUiEventLogger;
     private final BroadcastReceiver mBroadcastReceiver;
     private final IntentFilter mIntentFilter;
 
@@ -80,10 +97,17 @@
     private AppClipsViewModel mViewModel;
 
     private ResultReceiver mResultReceiver;
+    @Nullable
+    private String mCallingPackageName;
+    private int mCallingPackageUid;
 
     @Inject
-    public AppClipsActivity(AppClipsViewModel.Factory viewModelFactory) {
+    public AppClipsActivity(AppClipsViewModel.Factory viewModelFactory,
+            PackageManager packageManager, UserTracker userTracker, UiEventLogger uiEventLogger) {
         mViewModelFactory = viewModelFactory;
+        mPackageManager = packageManager;
+        mUserTracker = userTracker;
+        mUiEventLogger = uiEventLogger;
 
         mBroadcastReceiver = new BroadcastReceiver() {
             @Override
@@ -113,6 +137,7 @@
                 RECEIVER_NOT_EXPORTED);
 
         Intent intent = getIntent();
+        setUpUiLogging(intent);
         mResultReceiver = intent.getParcelableExtra(EXTRA_RESULT_RECEIVER, ResultReceiver.class);
         if (mResultReceiver == null) {
             setErrorThenFinish(Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED);
@@ -169,6 +194,17 @@
         }
     }
 
+    private void setUpUiLogging(Intent intent) {
+        mCallingPackageName = intent.getStringExtra(EXTRA_CALLING_PACKAGE_NAME);
+        mCallingPackageUid = 0;
+        try {
+            mCallingPackageUid = mPackageManager.getApplicationInfoAsUser(mCallingPackageName,
+                    APPLICATION_INFO_FLAGS, mUserTracker.getUserId()).uid;
+        } catch (NameNotFoundException e) {
+            Log.d(TAG, "Couldn't find notes app UID " + e);
+        }
+    }
+
     private void setScreenshot(Bitmap screenshot) {
         // Set background, status and navigation bar colors as the activity is no longer
         // translucent.
@@ -228,6 +264,7 @@
         data.putParcelable(EXTRA_SCREENSHOT_URI, uri);
         try {
             mResultReceiver.send(Activity.RESULT_OK, data);
+            logUiEvent(SCREENSHOT_FOR_NOTE_ACCEPTED);
         } catch (Exception e) {
             // Do nothing.
         }
@@ -251,6 +288,9 @@
         data.putInt(Intent.EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE, errorCode);
         try {
             mResultReceiver.send(RESULT_OK, data);
+            if (errorCode == Intent.CAPTURE_CONTENT_FOR_NOTE_USER_CANCELED) {
+                logUiEvent(SCREENSHOT_FOR_NOTE_CANCELLED);
+            }
         } catch (Exception e) {
             // Do nothing.
         }
@@ -259,6 +299,10 @@
         mResultReceiver = null;
     }
 
+    private void logUiEvent(UiEventEnum uiEvent) {
+        mUiEventLogger.log(uiEvent, mCallingPackageUid, mCallingPackageName);
+    }
+
     private void updateImageDimensions() {
         Drawable drawable = mPreview.getDrawable();
         if (drawable == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java
index 4759cc6..1946b8e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java
@@ -24,26 +24,33 @@
 import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
 
 import static com.android.systemui.flags.Flags.SCREENSHOT_APP_CLIPS;
+import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_TRIGGERED;
 
 import android.app.Activity;
 import android.app.admin.DevicePolicyManager;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Parcel;
 import android.os.ResultReceiver;
+import android.util.Log;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.notetask.NoteTaskController;
+import com.android.systemui.settings.UserTracker;
 import com.android.wm.shell.bubbles.Bubbles;
 
 import java.util.Optional;
@@ -70,15 +77,23 @@
 public class AppClipsTrampolineActivity extends Activity {
 
     private static final String TAG = AppClipsTrampolineActivity.class.getSimpleName();
-    public static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
+    static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
+    @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
     public static final String EXTRA_SCREENSHOT_URI = TAG + "SCREENSHOT_URI";
-    public static final String ACTION_FINISH_FROM_TRAMPOLINE = TAG + "FINISH_FROM_TRAMPOLINE";
-    static final String EXTRA_RESULT_RECEIVER = TAG + "RESULT_RECEIVER";
+    static final String ACTION_FINISH_FROM_TRAMPOLINE = TAG + "FINISH_FROM_TRAMPOLINE";
+    @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+    public static final String EXTRA_RESULT_RECEIVER = TAG + "RESULT_RECEIVER";
+    @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+    public static final String EXTRA_CALLING_PACKAGE_NAME = TAG + "CALLING_PACKAGE_NAME";
+    private static final ApplicationInfoFlags APPLICATION_INFO_FLAGS = ApplicationInfoFlags.of(0);
 
     private final DevicePolicyManager mDevicePolicyManager;
     private final FeatureFlags mFeatureFlags;
     private final Optional<Bubbles> mOptionalBubbles;
     private final NoteTaskController mNoteTaskController;
+    private final PackageManager mPackageManager;
+    private final UserTracker mUserTracker;
+    private final UiEventLogger mUiEventLogger;
     private final ResultReceiver mResultReceiver;
 
     private Intent mKillAppClipsBroadcastIntent;
@@ -86,11 +101,15 @@
     @Inject
     public AppClipsTrampolineActivity(DevicePolicyManager devicePolicyManager, FeatureFlags flags,
             Optional<Bubbles> optionalBubbles, NoteTaskController noteTaskController,
+            PackageManager packageManager, UserTracker userTracker, UiEventLogger uiEventLogger,
             @Main Handler mainHandler) {
         mDevicePolicyManager = devicePolicyManager;
         mFeatureFlags = flags;
         mOptionalBubbles = optionalBubbles;
         mNoteTaskController = noteTaskController;
+        mPackageManager = packageManager;
+        mUserTracker = userTracker;
+        mUiEventLogger = uiEventLogger;
 
         mResultReceiver = createResultReceiver(mainHandler);
     }
@@ -138,8 +157,12 @@
             return;
         }
 
-        Intent intent = new Intent().setComponent(componentName).addFlags(
-                Intent.FLAG_ACTIVITY_NEW_TASK).putExtra(EXTRA_RESULT_RECEIVER, mResultReceiver);
+        String callingPackageName = getCallingPackage();
+        Intent intent = new Intent().setComponent(componentName)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                .putExtra(EXTRA_RESULT_RECEIVER, mResultReceiver)
+                .putExtra(EXTRA_CALLING_PACKAGE_NAME, callingPackageName);
+
         try {
             // Start the App Clips activity.
             startActivity(intent);
@@ -150,6 +173,9 @@
                     new Intent(ACTION_FINISH_FROM_TRAMPOLINE)
                             .setComponent(componentName)
                             .setPackage(componentName.getPackageName());
+
+            // Log successful triggering of screenshot for notes.
+            logScreenshotTriggeredUiEvent(callingPackageName);
         } catch (ActivityNotFoundException e) {
             setErrorResultAndFinish(CAPTURE_CONTENT_FOR_NOTE_FAILED);
         }
@@ -170,6 +196,18 @@
         finish();
     }
 
+    private void logScreenshotTriggeredUiEvent(@Nullable String callingPackageName) {
+        int callingPackageUid = 0;
+        try {
+            callingPackageUid = mPackageManager.getApplicationInfoAsUser(callingPackageName,
+                    APPLICATION_INFO_FLAGS, mUserTracker.getUserId()).uid;
+        } catch (NameNotFoundException e) {
+            Log.d(TAG, "Couldn't find notes app UID " + e);
+        }
+
+        mUiEventLogger.log(SCREENSHOT_FOR_NOTE_TRIGGERED, callingPackageUid, callingPackageName);
+    }
+
     private class AppClipsResultReceiver extends ResultReceiver {
 
         AppClipsResultReceiver(Handler handler) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java
index 5a7b5f9..b2910fd 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java
@@ -18,6 +18,8 @@
 
 import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED;
 
+import static androidx.annotation.VisibleForTesting.PACKAGE_PRIVATE;
+
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.graphics.HardwareRenderer;
@@ -29,6 +31,7 @@
 import android.os.Process;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
 import androidx.lifecycle.ViewModel;
@@ -49,7 +52,8 @@
 import javax.inject.Inject;
 
 /** A {@link ViewModel} to help with the App Clips screenshot flow. */
-final class AppClipsViewModel extends ViewModel {
+@VisibleForTesting(otherwise = PACKAGE_PRIVATE)
+public final class AppClipsViewModel extends ViewModel {
 
     private final AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
     private final ImageExporter mImageExporter;
@@ -76,7 +80,8 @@
     }
 
     /** Grabs a screenshot and updates the {@link Bitmap} set in screenshot {@link LiveData}. */
-    void performScreenshot() {
+    @VisibleForTesting(otherwise = PACKAGE_PRIVATE)
+    public void performScreenshot() {
         mBgExecutor.execute(() -> {
             Bitmap screenshot = mAppClipsCrossProcessHelper.takeScreenshot();
             mMainExecutor.execute(() -> {
@@ -90,12 +95,14 @@
     }
 
     /** Returns a {@link LiveData} that holds the captured screenshot. */
-    LiveData<Bitmap> getScreenshot() {
+    @VisibleForTesting(otherwise = PACKAGE_PRIVATE)
+    public LiveData<Bitmap> getScreenshot() {
         return mScreenshotLiveData;
     }
 
     /** Returns a {@link LiveData} that holds the {@link Uri} where screenshot is saved. */
-    LiveData<Uri> getResultLiveData() {
+    @VisibleForTesting(otherwise = PACKAGE_PRIVATE)
+    public LiveData<Uri> getResultLiveData() {
         return mResultLiveData;
     }
 
@@ -103,7 +110,8 @@
      * Returns a {@link LiveData} that holds the error codes for
      * {@link Intent#EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE}.
      */
-    LiveData<Integer> getErrorLiveData() {
+    @VisibleForTesting(otherwise = PACKAGE_PRIVATE)
+    public LiveData<Integer> getErrorLiveData() {
         return mErrorLiveData;
     }
 
@@ -111,7 +119,8 @@
      * Saves the provided {@link Drawable} to storage then informs the result {@link Uri} to
      * {@link LiveData}.
      */
-    void saveScreenshotThenFinish(Drawable screenshotDrawable, Rect bounds) {
+    @VisibleForTesting(otherwise = PACKAGE_PRIVATE)
+    public void saveScreenshotThenFinish(Drawable screenshotDrawable, Rect bounds) {
         mBgExecutor.execute(() -> {
             // Render the screenshot bitmap in background.
             Bitmap screenshotBitmap = renderBitmap(screenshotDrawable, bounds);
@@ -151,7 +160,8 @@
     }
 
     /** Helper factory to help with injecting {@link AppClipsViewModel}. */
-    static final class Factory implements ViewModelProvider.Factory {
+    @VisibleForTesting(otherwise = PACKAGE_PRIVATE)
+    public static final class Factory implements ViewModelProvider.Factory {
 
         private final AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
         private final ImageExporter mImageExporter;
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/pipeline/mobile/data/model/SubscriptionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
index 2f34516..16c4027 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.pipeline.mobile.data.model
 
+import android.os.ParcelUuid
+
 /**
  * SystemUI representation of [SubscriptionInfo]. Currently we only use two fields on the
  * subscriptions themselves: subscriptionId and isOpportunistic. Any new fields that we need can be
@@ -29,4 +31,7 @@
      * filtering in certain cases. See [MobileIconsInteractor] for the filtering logic
      */
     val isOpportunistic: Boolean = false,
+
+    /** Subscriptions in the same group may be filtered or treated as a single subscription */
+    val groupUuid: ParcelUuid? = null,
 )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index c9049d8..e77266f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -376,6 +376,7 @@
         SubscriptionModel(
             subscriptionId = subscriptionId,
             isOpportunistic = isOpportunistic,
+            groupUuid = groupUuid,
         )
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index 72d5113..5a2e11e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -150,6 +150,12 @@
 
                 val info1 = unfilteredSubs[0]
                 val info2 = unfilteredSubs[1]
+
+                // Filtering only applies to subscriptions in the same group
+                if (info1.groupUuid == null || info1.groupUuid != info2.groupUuid) {
+                    return@combine unfilteredSubs
+                }
+
                 // If both subscriptions are primary, show both
                 if (!info1.isOpportunistic && !info2.isOpportunistic) {
                     return@combine unfilteredSubs
@@ -186,7 +192,7 @@
      * validated bit from the old active network (A) while data is changing to the new one (B).
      *
      * This condition only applies if
-     * 1. A and B are in the same subscription group (e.c. for CBRS data switching) and
+     * 1. A and B are in the same subscription group (e.g. for CBRS data switching) and
      * 2. A was validated before the switch
      *
      * The goal of this is to minimize the flickering in the UI of the cellular indicator
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
index 3f54aebf..c0cbd62 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
@@ -21,6 +21,7 @@
 import android.content.Context
 import android.hardware.BatteryState
 import android.hardware.input.InputManager
+import android.hardware.input.InputSettings
 import android.os.Handler
 import android.util.ArrayMap
 import android.util.Log
@@ -30,6 +31,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 +63,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 +76,10 @@
         handler.post {
             if (hasStarted) return@post
             hasStarted = true
+            isInUsiSession =
+                inputManager.hasInputDevice {
+                    it.isInternalStylusSource && isBatteryStateValid(it.batteryState)
+                }
             addExistingStylusToMap()
 
             inputManager.registerInputDeviceListener(this, handler)
@@ -177,7 +187,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()
             }
 
@@ -215,12 +236,43 @@
      */
     private fun onStylusUsed() {
         if (!featureFlags.isEnabled(Flags.TRACK_STYLUS_EVER_USED)) return
-        if (inputManager.isStylusEverUsed(context)) return
+        if (InputSettings.isStylusEverUsed(context)) return
 
-        inputManager.setStylusEverUsed(context, true)
+        InputSettings.setStylusEverUsed(context, true)
         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 +347,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/src/com/android/systemui/util/condition/ConditionalCoreStartable.java b/packages/SystemUI/src/com/android/systemui/util/condition/ConditionalCoreStartable.java
index b41bca0..8d32a48 100644
--- a/packages/SystemUI/src/com/android/systemui/util/condition/ConditionalCoreStartable.java
+++ b/packages/SystemUI/src/com/android/systemui/util/condition/ConditionalCoreStartable.java
@@ -43,11 +43,6 @@
 
     @Override
     public final void start() {
-        if (mConditionSet == null || mConditionSet.isEmpty()) {
-            onStart();
-            return;
-        }
-
         mStartToken = mMonitor.addSubscription(
                 new Monitor.Subscription.Builder(allConditionsMet -> {
                     if (allConditionsMet) {
@@ -63,11 +58,6 @@
 
     @Override
     public final void onBootCompleted() {
-        if (mConditionSet == null || mConditionSet.isEmpty()) {
-            bootCompleted();
-            return;
-        }
-
         mBootCompletedToken = mMonitor.addSubscription(
                 new Monitor.Subscription.Builder(allConditionsMet -> {
                     if (allConditionsMet) {
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index ed2772a..2ef3511 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -165,6 +165,12 @@
             android:exported="false"
             android:permission="com.android.systemui.permission.SELF"
             android:excludeFromRecents="true" />
+
+        <activity
+            android:name="com.android.systemui.screenshot.appclips.AppClipsActivityTest$AppClipsActivityTestable"
+            android:exported="false"
+            android:permission="com.android.systemui.permission.SELF"
+            android:excludeFromRecents="true" />
     </application>
 
     <instrumentation android:name="android.testing.TestableInstrumentation"
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
index e8d50ca..badeb27 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
@@ -24,13 +24,19 @@
 import android.os.PowerManager
 import android.os.PowerManager.WAKE_REASON_BIOMETRIC
 import android.os.UserHandle
-import android.provider.Settings
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_WAKE
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.FakeSettings
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
 import org.junit.Before
@@ -41,20 +47,11 @@
 import org.mockito.Mockito.`when`
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
+import java.io.PrintWriter
 
 @SmallTest
 class ActiveUnlockConfigTest : SysuiTestCase() {
-    private val fakeWakeUri = Uri.Builder().appendPath("wake").build()
-    private val fakeUnlockIntentUri = Uri.Builder().appendPath("unlock-intent").build()
-    private val fakeBioFailUri = Uri.Builder().appendPath("bio-fail").build()
-    private val fakeFaceErrorsUri = Uri.Builder().appendPath("face-errors").build()
-    private val fakeFaceAcquiredUri = Uri.Builder().appendPath("face-acquired").build()
-    private val fakeUnlockIntentBioEnroll = Uri.Builder().appendPath("unlock-intent-bio").build()
-    private val fakeWakeupsConsideredUnlockIntents =
-        Uri.Builder().appendPath("wakeups-considered-unlock-intent").build()
-
-    @Mock
-    private lateinit var secureSettings: SecureSettings
+    private lateinit var secureSettings: FakeSettings
     @Mock
     private lateinit var contentResolver: ContentResolver
     @Mock
@@ -63,33 +60,20 @@
     private lateinit var dumpManager: DumpManager
     @Mock
     private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+    @Mock private lateinit var mockPrintWriter: PrintWriter
 
     @Captor
     private lateinit var settingsObserverCaptor: ArgumentCaptor<ContentObserver>
 
     private lateinit var activeUnlockConfig: ActiveUnlockConfig
+    private var currentUser: Int = 0
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
-        `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_WAKE))
-                .thenReturn(fakeWakeUri)
-        `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT))
-                .thenReturn(fakeUnlockIntentUri)
-        `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL))
-                .thenReturn(fakeBioFailUri)
-        `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS))
-                .thenReturn(fakeFaceErrorsUri)
-        `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO))
-                .thenReturn(fakeFaceAcquiredUri)
-        `when`(secureSettings.getUriFor(
-                Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED))
-                .thenReturn(fakeUnlockIntentBioEnroll)
-        `when`(secureSettings.getUriFor(
-            Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS))
-            .thenReturn(fakeWakeupsConsideredUnlockIntents)
-
+        currentUser = KeyguardUpdateMonitor.getCurrentUser()
+        secureSettings = FakeSettings()
         activeUnlockConfig = ActiveUnlockConfig(
                 handler,
                 secureSettings,
@@ -105,8 +89,6 @@
 
     @Test
     fun onWakeupSettingChanged() {
-        verifyRegisterSettingObserver()
-
         // GIVEN no active unlock settings enabled
         assertFalse(
                 activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
@@ -114,9 +96,8 @@
         )
 
         // WHEN unlock on wake is allowed
-        `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_WAKE,
-                0, 0)).thenReturn(1)
-        updateSetting(fakeWakeUri)
+        secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_WAKE, 1, currentUser)
+        updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_WAKE))
 
         // THEN active unlock triggers allowed on: wake, unlock-intent, and biometric failure
         assertTrue(
@@ -135,8 +116,6 @@
 
     @Test
     fun onUnlockIntentSettingChanged() {
-        verifyRegisterSettingObserver()
-
         // GIVEN no active unlock settings enabled
         assertFalse(
                 activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
@@ -144,9 +123,8 @@
         )
 
         // WHEN unlock on biometric failed is allowed
-        `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT,
-                0, 0)).thenReturn(1)
-        updateSetting(fakeUnlockIntentUri)
+        secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_UNLOCK_INTENT, 1, currentUser)
+        updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT))
 
         // THEN active unlock triggers allowed on: biometric failure ONLY
         assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
@@ -159,21 +137,19 @@
 
     @Test
     fun onBioFailSettingChanged() {
-        verifyRegisterSettingObserver()
-
         // GIVEN no active unlock settings enabled and triggering unlock intent on biometric
         // enrollment setting is disabled (empty string is disabled, null would use the default)
-        `when`(secureSettings.getStringForUser(
-                Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
-                0)).thenReturn("")
-        updateSetting(fakeUnlockIntentBioEnroll)
+        secureSettings.putStringForUser(
+                ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED, "", currentUser)
+        updateSetting(secureSettings.getUriFor(
+            ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
+        ))
         assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
                 ActiveUnlockConfig.ActiveUnlockRequestOrigin.BIOMETRIC_FAIL))
 
         // WHEN unlock on biometric failed is allowed
-        `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
-                0, 0)).thenReturn(1)
-        updateSetting(fakeBioFailUri)
+        secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, 1, currentUser)
+        updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL))
 
         // THEN active unlock triggers allowed on: biometric failure ONLY
         assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
@@ -186,17 +162,14 @@
 
     @Test
     fun faceErrorSettingsChanged() {
-        verifyRegisterSettingObserver()
-
         // GIVEN unlock on biometric fail
-        `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
-                0, 0)).thenReturn(1)
-        updateSetting(fakeBioFailUri)
+        secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, 1, currentUser)
+        updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL))
 
         // WHEN face error timeout (3), allow trigger active unlock
-        `when`(secureSettings.getStringForUser(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS,
-                0)).thenReturn("3")
-        updateSetting(fakeFaceAcquiredUri)
+        secureSettings.putStringForUser(
+            ACTIVE_UNLOCK_ON_FACE_ERRORS, "3", currentUser)
+        updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ERRORS))
 
         // THEN active unlock triggers allowed on error TIMEOUT
         assertTrue(activeUnlockConfig.shouldRequestActiveUnlockOnFaceError(
@@ -208,19 +181,17 @@
 
     @Test
     fun faceAcquiredSettingsChanged() {
-        verifyRegisterSettingObserver()
-
         // GIVEN unlock on biometric fail
-        `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
-                0, 0)).thenReturn(1)
-        updateSetting(fakeBioFailUri)
+        secureSettings.putStringForUser(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, "1", currentUser)
+        updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL))
 
         // WHEN face acquiredMsg DARK_GLASSESand MOUTH_COVERING are allowed to trigger
-        `when`(secureSettings.getStringForUser(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO,
-                0)).thenReturn(
+        secureSettings.putStringForUser(
+            ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO,
                 "${BiometricFaceConstants.FACE_ACQUIRED_MOUTH_COVERING_DETECTED}" +
-                        "|${BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED}")
-        updateSetting(fakeFaceAcquiredUri)
+                        "|${BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED}",
+            currentUser)
+        updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO))
 
         // THEN active unlock triggers allowed on acquired messages DARK_GLASSES & MOUTH_COVERING
         assertTrue(activeUnlockConfig.shouldRequestActiveUnlockOnFaceAcquireInfo(
@@ -236,23 +207,23 @@
 
     @Test
     fun triggerOnUnlockIntentWhenBiometricEnrolledNone() {
-        verifyRegisterSettingObserver()
-
         // GIVEN unlock on biometric fail
-        `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
-                0, 0)).thenReturn(1)
-        updateSetting(fakeBioFailUri)
+        secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, 1, currentUser)
+        updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL))
 
         // GIVEN fingerprint and face are NOT enrolled
         activeUnlockConfig.keyguardUpdateMonitor = keyguardUpdateMonitor
-        `when`(keyguardUpdateMonitor.isFaceEnrolled()).thenReturn(false)
+        `when`(keyguardUpdateMonitor.isFaceEnrolled).thenReturn(false)
         `when`(keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0)).thenReturn(false)
 
         // WHEN unlock intent is allowed when NO biometrics are enrolled (0)
-        `when`(secureSettings.getStringForUser(
-                Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
-                0)).thenReturn("${ActiveUnlockConfig.BiometricType.NONE.intValue}")
-        updateSetting(fakeUnlockIntentBioEnroll)
+
+        secureSettings.putStringForUser(
+            ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
+            "${ActiveUnlockConfig.BiometricType.NONE.intValue}", currentUser)
+        updateSetting(secureSettings.getUriFor(
+            ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
+        ))
 
         // THEN active unlock triggers allowed on unlock intent
         assertTrue(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
@@ -261,12 +232,9 @@
 
     @Test
     fun triggerOnUnlockIntentWhenBiometricEnrolledFingerprintOrFaceOnly() {
-        verifyRegisterSettingObserver()
-
         // GIVEN unlock on biometric fail
-        `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
-                0, 0)).thenReturn(1)
-        updateSetting(fakeBioFailUri)
+        secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, 1, currentUser)
+        updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL))
 
         // GIVEN fingerprint and face are both enrolled
         activeUnlockConfig.keyguardUpdateMonitor = keyguardUpdateMonitor
@@ -275,12 +243,14 @@
 
         // WHEN unlock intent is allowed when ONLY fingerprint is enrolled or NO biometircs
         // are enrolled
-        `when`(secureSettings.getStringForUser(
-                Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
-                0)).thenReturn(
+        secureSettings.putStringForUser(
+                ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
                 "${ActiveUnlockConfig.BiometricType.ANY_FACE.intValue}" +
-                        "|${ActiveUnlockConfig.BiometricType.ANY_FINGERPRINT.intValue}")
-        updateSetting(fakeUnlockIntentBioEnroll)
+                        "|${ActiveUnlockConfig.BiometricType.ANY_FINGERPRINT.intValue}",
+            currentUser)
+        updateSetting(secureSettings.getUriFor(
+            ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
+        ))
 
         // THEN active unlock triggers NOT allowed on unlock intent
         assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
@@ -305,13 +275,12 @@
 
     @Test
     fun isWakeupConsideredUnlockIntent_singleValue() {
-        verifyRegisterSettingObserver()
-
         // GIVEN lift is considered an unlock intent
-        `when`(secureSettings.getStringForUser(
-            Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS,
-            0)).thenReturn(PowerManager.WAKE_REASON_LIFT.toString())
-        updateSetting(fakeWakeupsConsideredUnlockIntents)
+        secureSettings.putIntForUser(
+            ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS,
+            PowerManager.WAKE_REASON_LIFT,
+            currentUser)
+        updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS))
 
         // THEN only WAKE_REASON_LIFT is considered an unlock intent
         for (wakeReason in 0..WAKE_REASON_BIOMETRIC) {
@@ -325,17 +294,15 @@
 
     @Test
     fun isWakeupConsideredUnlockIntent_multiValue() {
-        verifyRegisterSettingObserver()
-
         // GIVEN lift and tap are considered an unlock intent
-        `when`(secureSettings.getStringForUser(
-            Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS,
-            0)).thenReturn(
+        secureSettings.putStringForUser(
+            ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS,
             PowerManager.WAKE_REASON_LIFT.toString() +
                     "|" +
-                    PowerManager.WAKE_REASON_TAP.toString()
+                    PowerManager.WAKE_REASON_TAP.toString(),
+            currentUser
         )
-        updateSetting(fakeWakeupsConsideredUnlockIntents)
+        updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS))
 
         // THEN WAKE_REASON_LIFT and WAKE_REASON TAP are considered an unlock intent
         for (wakeReason in 0..WAKE_REASON_BIOMETRIC) {
@@ -354,13 +321,10 @@
 
     @Test
     fun isWakeupConsideredUnlockIntent_emptyValues() {
-        verifyRegisterSettingObserver()
-
         // GIVEN lift and tap are considered an unlock intent
-        `when`(secureSettings.getStringForUser(
-            Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS,
-            0)).thenReturn(" ")
-        updateSetting(fakeWakeupsConsideredUnlockIntents)
+        secureSettings.putStringForUser(ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS, " ",
+            currentUser)
+        updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS))
 
         // THEN no wake up gestures are considered an unlock intent
         for (wakeReason in 0..WAKE_REASON_BIOMETRIC) {
@@ -373,7 +337,23 @@
             PowerManager.WAKE_REASON_UNFOLD_DEVICE))
     }
 
+    @Test
+    fun dump_onUnlockIntentWhenBiometricEnrolled_invalidNum_noArrayOutOfBoundsException() {
+        // GIVEN an invalid input (-1)
+        secureSettings.putStringForUser(ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
+            "-1", currentUser)
+
+        // WHEN the setting updates
+        updateSetting(secureSettings.getUriFor(
+            ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
+        ))
+
+        // THEN no exception thrown
+        activeUnlockConfig.dump(mockPrintWriter, emptyArray())
+    }
+
     private fun updateSetting(uri: Uri) {
+        verifyRegisterSettingObserver()
         settingsObserverCaptor.value.onChange(
                 false,
                 listOf(uri),
@@ -383,13 +363,17 @@
     }
 
     private fun verifyRegisterSettingObserver() {
-        verifyRegisterSettingObserver(fakeWakeUri)
-        verifyRegisterSettingObserver(fakeUnlockIntentUri)
-        verifyRegisterSettingObserver(fakeBioFailUri)
-        verifyRegisterSettingObserver(fakeFaceErrorsUri)
-        verifyRegisterSettingObserver(fakeFaceAcquiredUri)
-        verifyRegisterSettingObserver(fakeUnlockIntentBioEnroll)
-        verifyRegisterSettingObserver(fakeWakeupsConsideredUnlockIntents)
+        verifyRegisterSettingObserver(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_WAKE))
+        verifyRegisterSettingObserver(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT))
+        verifyRegisterSettingObserver(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL))
+        verifyRegisterSettingObserver(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ERRORS))
+        verifyRegisterSettingObserver(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO))
+        verifyRegisterSettingObserver(secureSettings.getUriFor(
+            ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
+        ))
+        verifyRegisterSettingObserver(secureSettings.getUriFor(
+            ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS
+        ))
     }
 
     private fun verifyRegisterSettingObserver(uri: Uri) {
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/dreams/complication/ComplicationTypesUpdaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java
index b9db9c4..b3329eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java
@@ -32,6 +32,7 @@
 
 import com.android.settingslib.dream.DreamBackend;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.condition.SelfExecutingMonitor;
 import com.android.systemui.dreams.DreamOverlayStateController;
 import com.android.systemui.shared.condition.Monitor;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -67,7 +68,6 @@
 
     private ComplicationTypesUpdater mController;
 
-    @Mock
     private Monitor mMonitor;
 
     @Before
@@ -75,6 +75,7 @@
         MockitoAnnotations.initMocks(this);
         when(mDreamBackend.getEnabledComplications()).thenReturn(new HashSet<>());
 
+        mMonitor = SelfExecutingMonitor.createInstance();
         mController = new ComplicationTypesUpdater(mDreamBackend, mExecutor,
                 mSecureSettings, mDreamOverlayStateController, mMonitor);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
index 52aaea1..f6662d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
@@ -29,6 +29,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.condition.SelfExecutingMonitor;
 import com.android.systemui.dreams.DreamOverlayStateController;
 import com.android.systemui.shared.condition.Monitor;
 
@@ -70,13 +71,13 @@
     @Mock
     private ComplicationLayoutParams mLayoutParams;
 
-    @Mock
     private Monitor mMonitor;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
         when(mDreamClockTimeViewHolderProvider.get()).thenReturn(mDreamClockTimeViewHolder);
+        mMonitor = SelfExecutingMonitor.createInstance();
     }
 
     /**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
index 8534d4f..3312c43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
@@ -38,6 +38,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.view.LaunchableImageView;
+import com.android.systemui.condition.SelfExecutingMonitor;
 import com.android.systemui.controls.ControlsServiceInfo;
 import com.android.systemui.controls.controller.ControlsController;
 import com.android.systemui.controls.controller.StructureInfo;
@@ -102,7 +103,6 @@
     @Captor
     private ArgumentCaptor<DreamOverlayStateController.Callback> mStateCallbackCaptor;
 
-    @Mock
     private Monitor mMonitor;
 
     @Before
@@ -116,6 +116,8 @@
                 Optional.of(mControlsListingController));
         when(mControlsComponent.getVisibility()).thenReturn(AVAILABLE);
         when(mView.findViewById(R.id.home_controls_chip)).thenReturn(mHomeControlsView);
+
+        mMonitor = SelfExecutingMonitor.createInstance();
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java
index 77ca958..ef62abf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java
@@ -30,6 +30,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.condition.SelfExecutingMonitor;
 import com.android.systemui.dreams.DreamOverlayStateController;
 import com.android.systemui.dreams.smartspace.DreamSmartspaceController;
 import com.android.systemui.plugins.BcSmartspaceDataPlugin;
@@ -64,7 +65,6 @@
     @Mock
     private View mBcSmartspaceView;
 
-    @Mock
     private Monitor mMonitor;
 
     private final Set<Condition> mPreconditions = new HashSet<>();
@@ -72,6 +72,7 @@
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
+        mMonitor = SelfExecutingMonitor.createInstance();
     }
 
     /**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
index db18ba6..5bb8367 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
@@ -18,15 +18,19 @@
 package com.android.systemui.keyguard.data.quickaffordance
 
 import android.app.StatusBarManager
+import android.app.admin.DevicePolicyManager
 import android.content.Context
 import android.content.pm.PackageManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.camera.CameraGestureHelper
+import com.android.systemui.settings.UserTracker
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runTest
 import org.junit.Assert.assertEquals
 import org.junit.Before
@@ -44,21 +48,28 @@
     @Mock private lateinit var cameraGestureHelper: CameraGestureHelper
     @Mock private lateinit var context: Context
     @Mock private lateinit var packageManager: PackageManager
+    @Mock private lateinit var userTracker: UserTracker
+    @Mock private lateinit var devicePolicyManager: DevicePolicyManager
 
     private lateinit var underTest: CameraQuickAffordanceConfig
+    private lateinit var testScope: TestScope
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-        setLaunchable(true)
+        setLaunchable()
 
+        val testDispatcher = StandardTestDispatcher()
+        testScope = TestScope(testDispatcher)
         underTest =
             CameraQuickAffordanceConfig(
                 context,
                 packageManager,
-            ) {
-                cameraGestureHelper
-            }
+                { cameraGestureHelper },
+                userTracker,
+                devicePolicyManager,
+                testDispatcher,
+            )
     }
 
     @Test
@@ -73,23 +84,57 @@
     }
 
     @Test
-    fun `getPickerScreenState - default when launchable`() = runTest {
-        setLaunchable(true)
+    fun `getPickerScreenState - default when launchable`() =
+        testScope.runTest {
+            setLaunchable(true)
 
-        Truth.assertThat(underTest.getPickerScreenState())
-            .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java)
-    }
+            Truth.assertThat(underTest.getPickerScreenState())
+                .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java)
+        }
 
     @Test
-    fun `getPickerScreenState - unavailable when not launchable`() = runTest {
-        setLaunchable(false)
+    fun `getPickerScreenState - unavailable when camera app not installed`() =
+        testScope.runTest {
+            setLaunchable(isCameraAppInstalled = false)
 
-        Truth.assertThat(underTest.getPickerScreenState())
-            .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
-    }
+            Truth.assertThat(underTest.getPickerScreenState())
+                .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
+        }
 
-    private fun setLaunchable(isLaunchable: Boolean) {
+    @Test
+    fun `getPickerScreenState - unavailable when camera disabled by admin`() =
+        testScope.runTest {
+            setLaunchable(isCameraDisabledByDeviceAdmin = true)
+
+            Truth.assertThat(underTest.getPickerScreenState())
+                .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
+        }
+
+    @Test
+    fun `getPickerScreenState - unavailable when secure camera disabled by admin`() =
+        testScope.runTest {
+            setLaunchable(isSecureCameraDisabledByDeviceAdmin = true)
+
+            Truth.assertThat(underTest.getPickerScreenState())
+                .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
+        }
+
+    private fun setLaunchable(
+        isCameraAppInstalled: Boolean = true,
+        isCameraDisabledByDeviceAdmin: Boolean = false,
+        isSecureCameraDisabledByDeviceAdmin: Boolean = false,
+    ) {
         whenever(packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY))
-            .thenReturn(isLaunchable)
+            .thenReturn(isCameraAppInstalled)
+        whenever(devicePolicyManager.getCameraDisabled(null, userTracker.userId))
+            .thenReturn(isCameraDisabledByDeviceAdmin)
+        whenever(devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId))
+            .thenReturn(
+                if (isSecureCameraDisabledByDeviceAdmin) {
+                    DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA
+                } else {
+                    0
+                }
+            )
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt
index 5bd86bd..f1b9c5f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt
@@ -17,6 +17,7 @@
 
 package com.android.systemui.keyguard.data.quickaffordance
 
+import android.app.admin.DevicePolicyManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.ActivityIntentHelper
@@ -24,11 +25,14 @@
 import com.android.systemui.camera.CameraIntentsWrapper
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.settings.UserTracker
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
@@ -44,59 +48,94 @@
 class VideoCameraQuickAffordanceConfigTest : SysuiTestCase() {
 
     @Mock private lateinit var activityIntentHelper: ActivityIntentHelper
+    @Mock private lateinit var devicePolicyManager: DevicePolicyManager
 
     private lateinit var underTest: VideoCameraQuickAffordanceConfig
+    private lateinit var userTracker: UserTracker
+    private lateinit var testScope: TestScope
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
+        val testDispatcher = StandardTestDispatcher()
+        testScope = TestScope(testDispatcher)
+        userTracker = FakeUserTracker()
         underTest =
             VideoCameraQuickAffordanceConfig(
                 context = context,
                 cameraIntents = CameraIntentsWrapper(context),
                 activityIntentHelper = activityIntentHelper,
-                userTracker = FakeUserTracker(),
+                userTracker = userTracker,
+                devicePolicyManager = devicePolicyManager,
+                backgroundDispatcher = testDispatcher,
             )
     }
 
     @Test
-    fun `lockScreenState - visible when launchable`() = runTest {
-        setLaunchable(true)
+    fun `lockScreenState - visible when launchable`() =
+        testScope.runTest {
+            setLaunchable()
 
-        val lockScreenState = collectLastValue(underTest.lockScreenState)
+            val lockScreenState = collectLastValue(underTest.lockScreenState)
 
-        assertThat(lockScreenState())
-            .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Visible::class.java)
-    }
+            assertThat(lockScreenState())
+                .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Visible::class.java)
+        }
 
     @Test
-    fun `lockScreenState - hidden when not launchable`() = runTest {
-        setLaunchable(false)
+    fun `lockScreenState - hidden when app not installed on device`() =
+        testScope.runTest {
+            setLaunchable(isVideoCameraAppInstalled = false)
 
-        val lockScreenState = collectLastValue(underTest.lockScreenState)
+            val lockScreenState = collectLastValue(underTest.lockScreenState)
 
-        assertThat(lockScreenState())
-            .isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
-    }
+            assertThat(lockScreenState())
+                .isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
+        }
 
     @Test
-    fun `getPickerScreenState - default when launchable`() = runTest {
-        setLaunchable(true)
+    fun `lockScreenState - hidden when camera disabled by admin`() =
+        testScope.runTest {
+            setLaunchable(isCameraDisabledByAdmin = true)
 
-        assertThat(underTest.getPickerScreenState())
-            .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java)
-    }
+            val lockScreenState = collectLastValue(underTest.lockScreenState)
+
+            assertThat(lockScreenState())
+                .isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
+        }
 
     @Test
-    fun `getPickerScreenState - unavailable when not launchable`() = runTest {
-        setLaunchable(false)
+    fun `getPickerScreenState - default when launchable`() =
+        testScope.runTest {
+            setLaunchable()
 
-        assertThat(underTest.getPickerScreenState())
-            .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
-    }
+            assertThat(underTest.getPickerScreenState())
+                .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java)
+        }
 
-    private fun setLaunchable(isLaunchable: Boolean) {
+    @Test
+    fun `getPickerScreenState - unavailable when app not installed on device`() =
+        testScope.runTest {
+            setLaunchable(isVideoCameraAppInstalled = false)
+
+            assertThat(underTest.getPickerScreenState())
+                .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
+        }
+
+    @Test
+    fun `getPickerScreenState - unavailable when camera disabled by admin`() =
+        testScope.runTest {
+            setLaunchable(isCameraDisabledByAdmin = true)
+
+            assertThat(underTest.getPickerScreenState())
+                .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
+        }
+
+    private fun setLaunchable(
+        isVideoCameraAppInstalled: Boolean = true,
+        isCameraDisabledByAdmin: Boolean = false,
+    ) {
         whenever(
                 activityIntentHelper.getTargetActivityInfo(
                     any(),
@@ -105,11 +144,13 @@
                 )
             )
             .thenReturn(
-                if (isLaunchable) {
+                if (isVideoCameraAppInstalled) {
                     mock()
                 } else {
                     null
                 }
             )
+        whenever(devicePolicyManager.getCameraDisabled(null, userTracker.userId))
+            .thenReturn(isCameraDisabledByAdmin)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
index 997198e..a72634b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
@@ -61,7 +61,6 @@
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
-import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
@@ -69,6 +68,8 @@
 import org.mockito.Mock
 import org.mockito.Mockito.floatThat
 import org.mockito.Mockito.mock
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
@@ -107,7 +108,6 @@
     @Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
     @Captor
     lateinit var configListener: ArgumentCaptor<ConfigurationController.ConfigurationListener>
-    @Captor lateinit var newConfig: ArgumentCaptor<Configuration>
     @Captor lateinit var visualStabilityCallback: ArgumentCaptor<OnReorderingAllowedListener>
     @Captor lateinit var keyguardCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback>
 
@@ -150,7 +150,6 @@
         MediaPlayerData.clear()
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testPlayerOrdering() {
         // Test values: key, data, last active time
@@ -327,7 +326,6 @@
         }
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testOrderWithSmartspace_prioritized() {
         testPlayerOrdering()
@@ -335,7 +333,7 @@
         // If smartspace is prioritized
         MediaPlayerData.addMediaRecommendation(
             SMARTSPACE_KEY,
-            EMPTY_SMARTSPACE_MEDIA_DATA,
+            EMPTY_SMARTSPACE_MEDIA_DATA.copy(isActive = true),
             panel,
             true,
             clock
@@ -345,7 +343,6 @@
         assertTrue(MediaPlayerData.playerKeys().elementAt(2).isSsMediaRec)
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testOrderWithSmartspace_prioritized_updatingVisibleMediaPlayers() {
         testPlayerOrdering()
@@ -362,7 +359,6 @@
         assertTrue(MediaPlayerData.visiblePlayerKeys().elementAt(2).isSsMediaRec)
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testOrderWithSmartspace_notPrioritized() {
         testPlayerOrdering()
@@ -370,7 +366,7 @@
         // If smartspace is not prioritized
         MediaPlayerData.addMediaRecommendation(
             SMARTSPACE_KEY,
-            EMPTY_SMARTSPACE_MEDIA_DATA,
+            EMPTY_SMARTSPACE_MEDIA_DATA.copy(isActive = true),
             panel,
             false,
             clock
@@ -381,7 +377,6 @@
         assertTrue(MediaPlayerData.playerKeys().elementAt(idx).isSsMediaRec)
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testPlayingExistingMediaPlayerFromCarousel_visibleMediaPlayersNotUpdated() {
         testPlayerOrdering()
@@ -419,7 +414,6 @@
         )
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testSwipeDismiss_logged() {
         mediaCarouselController.mediaCarouselScrollHandler.dismissCallback.invoke()
@@ -427,7 +421,6 @@
         verify(logger).logSwipeDismiss()
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testSettingsButton_logged() {
         mediaCarouselController.settingsButton.callOnClick()
@@ -435,18 +428,16 @@
         verify(logger).logCarouselSettings()
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testLocationChangeQs_logged() {
         mediaCarouselController.onDesiredLocationChanged(
-            MediaHierarchyManager.LOCATION_QS,
+            LOCATION_QS,
             mediaHostState,
             animate = false
         )
-        verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_QS)
+        verify(logger).logCarouselPosition(LOCATION_QS)
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testLocationChangeQqs_logged() {
         mediaCarouselController.onDesiredLocationChanged(
@@ -457,7 +448,6 @@
         verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_QQS)
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testLocationChangeLockscreen_logged() {
         mediaCarouselController.onDesiredLocationChanged(
@@ -468,7 +458,6 @@
         verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_LOCKSCREEN)
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testLocationChangeDream_logged() {
         mediaCarouselController.onDesiredLocationChanged(
@@ -479,7 +468,6 @@
         verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_DREAM_OVERLAY)
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testRecommendationRemoved_logged() {
         val packageName = "smartspace package"
@@ -493,7 +481,6 @@
         verify(logger).logRecommendationRemoved(eq(packageName), eq(instanceId!!))
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testMediaLoaded_ScrollToActivePlayer() {
         listener.value.onMediaDataLoaded(
@@ -551,7 +538,6 @@
         )
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testMediaLoadedFromRecommendationCard_ScrollToActivePlayer() {
         listener.value.onSmartspaceMediaDataLoaded(
@@ -595,7 +581,6 @@
         assertEquals(playerIndex, 0)
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testRecommendationRemovedWhileNotVisible_updateHostVisibility() {
         var result = false
@@ -607,7 +592,6 @@
         assertEquals(true, result)
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testRecommendationRemovedWhileVisible_thenReorders_updateHostVisibility() {
         var result = false
@@ -621,7 +605,6 @@
         assertEquals(true, result)
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testGetCurrentVisibleMediaContentIntent() {
         val clickIntent1 = mock(PendingIntent::class.java)
@@ -668,7 +651,6 @@
         assertEquals(mediaCarouselController.getCurrentVisibleMediaContentIntent(), clickIntent2)
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testSetCurrentState_UpdatePageIndicatorAlphaWhenSquish() {
         val delta = 0.0001F
@@ -690,7 +672,6 @@
         verify(pageIndicator).alpha = floatThat { abs(it - 1.0F) < delta }
     }
 
-    @Ignore("b/253229241")
     @Test
     fun testOnConfigChanged_playersAreAddedBack() {
         listener.value.onMediaDataLoaded(
@@ -716,7 +697,7 @@
 
         val playersSize = MediaPlayerData.players().size
 
-        configListener.value.onConfigChanged(capture(newConfig))
+        configListener.value.onConfigChanged(Configuration())
 
         assertEquals(playersSize, MediaPlayerData.players().size)
         assertEquals(
@@ -796,4 +777,59 @@
 
             job.cancel()
         }
+
+    @Test
+    fun testInvisibleToUserAndExpanded_playersNotListening() {
+        // Add players to carousel.
+        testPlayerOrdering()
+
+        // Make the carousel visible to user in expanded layout.
+        mediaCarouselController.currentlyExpanded = true
+        mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = true
+
+        // panel is the player for each MediaPlayerData.
+        // Verify that seekbar listening attribute in media control panel is set to true.
+        verify(panel, times(MediaPlayerData.players().size)).listening = true
+
+        // Make the carousel invisible to user.
+        mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = false
+
+        // panel is the player for each MediaPlayerData.
+        // Verify that seekbar listening attribute in media control panel is set to false.
+        verify(panel, times(MediaPlayerData.players().size)).listening = false
+    }
+
+    @Test
+    fun testVisibleToUserAndExpanded_playersListening() {
+        // Add players to carousel.
+        testPlayerOrdering()
+
+        // Make the carousel visible to user in expanded layout.
+        mediaCarouselController.currentlyExpanded = true
+        mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = true
+
+        // panel is the player for each MediaPlayerData.
+        // Verify that seekbar listening attribute in media control panel is set to true.
+        verify(panel, times(MediaPlayerData.players().size)).listening = true
+    }
+
+    @Test
+    fun testUMOCollapsed_playersNotListening() {
+        // Add players to carousel.
+        testPlayerOrdering()
+
+        // Make the carousel in collapsed layout.
+        mediaCarouselController.currentlyExpanded = false
+
+        // panel is the player for each MediaPlayerData.
+        // Verify that seekbar listening attribute in media control panel is set to false.
+        verify(panel, times(MediaPlayerData.players().size)).listening = false
+
+        // Make the carousel visible to user.
+        reset(panel)
+        mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = true
+
+        // Verify that seekbar listening attribute in media control panel is set to false.
+        verify(panel, times(MediaPlayerData.players().size)).listening = false
+    }
 }
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/screenshot/appclips/AppClipsActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
new file mode 100644
index 0000000..d828e51
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
@@ -0,0 +1,232 @@
+/*
+ * 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.screenshot.appclips;
+
+import static android.app.Activity.RESULT_OK;
+
+import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_ACCEPTED;
+import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_CANCELLED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.ResultReceiver;
+import android.testing.AndroidTestingRunner;
+import android.widget.ImageView;
+
+import androidx.lifecycle.MutableLiveData;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.intercepting.SingleActivityFactory;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.screenshot.AppClipsActivity;
+import com.android.systemui.screenshot.AppClipsTrampolineActivity;
+import com.android.systemui.screenshot.AppClipsViewModel;
+import com.android.systemui.settings.UserTracker;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.BiConsumer;
+
+
+@RunWith(AndroidTestingRunner.class)
+public final class AppClipsActivityTest extends SysuiTestCase {
+
+    private static final int TEST_UID = 42;
+    private static final int TEST_USER_ID = 43;
+    private static final Bitmap TEST_BITMAP = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
+    private static final String TEST_URI_STRING = "www.test-uri.com";
+    private static final Uri TEST_URI = Uri.parse(TEST_URI_STRING);
+    private static final BiConsumer<Integer, Bundle> FAKE_CONSUMER = (unUsed1, unUsed2) -> {};
+    private static final String TEST_CALLING_PACKAGE = "test-calling-package";
+
+    @Mock
+    private AppClipsViewModel.Factory mViewModelFactory;
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private UserTracker mUserTracker;
+    @Mock
+    private UiEventLogger mUiEventLogger;
+    @Mock
+    private AppClipsViewModel mViewModel;
+
+    private MutableLiveData<Bitmap> mScreenshotLiveData;
+    private MutableLiveData<Uri> mResultLiveData;
+    private AppClipsActivity mActivity;
+
+    // Using the deprecated ActivityTestRule and SingleActivityFactory to help with injecting mocks.
+    private final SingleActivityFactory<AppClipsActivityTestable> mFactory =
+            new SingleActivityFactory<>(AppClipsActivityTestable.class) {
+                @Override
+                protected AppClipsActivityTestable create(Intent unUsed) {
+                    return new AppClipsActivityTestable(mViewModelFactory, mPackageManager,
+                            mUserTracker, mUiEventLogger);
+                }
+            };
+
+    @Rule
+    public final ActivityTestRule<AppClipsActivityTestable> mActivityRule =
+            new ActivityTestRule<>(mFactory, false, false);
+
+    @Before
+    public void setUp() throws PackageManager.NameNotFoundException {
+        MockitoAnnotations.initMocks(this);
+
+        mScreenshotLiveData = new MutableLiveData<>();
+        mResultLiveData = new MutableLiveData<>();
+        MutableLiveData<Integer> errorLiveData = new MutableLiveData<>();
+
+        when(mViewModelFactory.create(any(Class.class))).thenReturn(mViewModel);
+        when(mViewModel.getScreenshot()).thenReturn(mScreenshotLiveData);
+        when(mViewModel.getResultLiveData()).thenReturn(mResultLiveData);
+        when(mViewModel.getErrorLiveData()).thenReturn(errorLiveData);
+        when(mUserTracker.getUserId()).thenReturn(TEST_USER_ID);
+
+        ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.uid = TEST_UID;
+        when(mPackageManager.getApplicationInfoAsUser(eq(TEST_CALLING_PACKAGE),
+                any(ApplicationInfoFlags.class), eq(TEST_USER_ID))).thenReturn(applicationInfo);
+
+        doAnswer(invocation -> {
+            runOnMainThread(() -> mScreenshotLiveData.setValue(TEST_BITMAP));
+            return null;
+        }).when(mViewModel).performScreenshot();
+        doAnswer(invocation -> {
+            runOnMainThread(() -> mResultLiveData.setValue(TEST_URI));
+            return null;
+        }).when(mViewModel).saveScreenshotThenFinish(any(Drawable.class), any(Rect.class));
+    }
+
+    @After
+    public void tearDown() {
+        mActivityRule.finishActivity();
+    }
+
+    @Test
+    public void appClipsLaunched_screenshotDisplayed() {
+        launchActivity();
+
+        assertThat(((ImageView) mActivity.findViewById(R.id.preview)).getDrawable()).isNotNull();
+    }
+
+    @Test
+    public void screenshotDisplayed_userConsented_screenshotExportedSuccessfully() {
+        ResultReceiver resultReceiver = createResultReceiver((resultCode, data) -> {
+            assertThat(resultCode).isEqualTo(RESULT_OK);
+            assertThat(
+                    data.getParcelable(AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI, Uri.class))
+                    .isEqualTo(TEST_URI);
+            assertThat(data.getInt(Intent.EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE))
+                    .isEqualTo(Intent.CAPTURE_CONTENT_FOR_NOTE_SUCCESS);
+        });
+
+        launchActivity(resultReceiver);
+        runOnMainThread(() -> mActivity.findViewById(R.id.save).performClick());
+        waitForIdleSync();
+
+        assertThat(mActivity.isFinishing()).isTrue();
+        verify(mUiEventLogger).log(SCREENSHOT_FOR_NOTE_ACCEPTED, TEST_UID, TEST_CALLING_PACKAGE);
+    }
+
+    @Test
+    public void screenshotDisplayed_userDeclined() {
+        ResultReceiver resultReceiver = createResultReceiver((resultCode, data) -> {
+            assertThat(resultCode).isEqualTo(RESULT_OK);
+            assertThat(data.getInt(Intent.EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE))
+                    .isEqualTo(Intent.CAPTURE_CONTENT_FOR_NOTE_USER_CANCELED);
+            assertThat(data.keySet().contains(AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI))
+                    .isFalse();
+        });
+
+        launchActivity(resultReceiver);
+        runOnMainThread(() -> mActivity.findViewById(R.id.cancel).performClick());
+        waitForIdleSync();
+
+        assertThat(mActivity.isFinishing()).isTrue();
+        verify(mUiEventLogger).log(SCREENSHOT_FOR_NOTE_CANCELLED, TEST_UID, TEST_CALLING_PACKAGE);
+    }
+
+    private void launchActivity() {
+        launchActivity(createResultReceiver(FAKE_CONSUMER));
+    }
+
+    private void launchActivity(ResultReceiver resultReceiver) {
+        Intent intent = new Intent()
+                .putExtra(AppClipsTrampolineActivity.EXTRA_RESULT_RECEIVER, resultReceiver)
+                .putExtra(AppClipsTrampolineActivity.EXTRA_CALLING_PACKAGE_NAME,
+                        TEST_CALLING_PACKAGE);
+
+        mActivity = mActivityRule.launchActivity(intent);
+        waitForIdleSync();
+    }
+
+    private ResultReceiver createResultReceiver(
+            BiConsumer<Integer, Bundle> resultReceiverConsumer) {
+        ResultReceiver testReceiver = new ResultReceiver(mContext.getMainThreadHandler()) {
+            @Override
+            protected void onReceiveResult(int resultCode, Bundle resultData) {
+                resultReceiverConsumer.accept(resultCode, resultData);
+            }
+        };
+
+        Parcel parcel = Parcel.obtain();
+        testReceiver.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        testReceiver  = ResultReceiver.CREATOR.createFromParcel(parcel);
+        parcel.recycle();
+        return testReceiver;
+    }
+
+    private void runOnMainThread(Runnable runnable) {
+        mContext.getMainExecutor().execute(runnable);
+    }
+
+    public static class AppClipsActivityTestable extends AppClipsActivity {
+
+        public AppClipsActivityTestable(AppClipsViewModel.Factory viewModelFactory,
+                PackageManager packageManager,
+                UserTracker userTracker,
+                UiEventLogger uiEventLogger) {
+            super(viewModelFactory, packageManager, userTracker, uiEventLogger);
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java
index 6e8f5fe..ab321f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java
@@ -76,7 +76,7 @@
     }
 
     @Test
-    public void bubblesPresent_screenshotFailed_ShouldReturnNull() throws RemoteException {
+    public void bubblesPresent_screenshotFailed_shouldReturnNull() throws RemoteException {
         when(mBubblesOptional.isEmpty()).thenReturn(false);
         when(mBubblesOptional.get()).thenReturn(mBubbles);
         when(mBubbles.getScreenshotExcludingBubble(DEFAULT_DISPLAY)).thenReturn(mScreenshotSync);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
index 295d127..e40c49b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
@@ -25,23 +25,25 @@
 import static android.content.Intent.EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE;
 
 import static com.android.systemui.flags.Flags.SCREENSHOT_APP_CLIPS;
-import static com.android.systemui.screenshot.AppClipsTrampolineActivity.ACTION_FINISH_FROM_TRAMPOLINE;
 import static com.android.systemui.screenshot.AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI;
-import static com.android.systemui.screenshot.AppClipsTrampolineActivity.PERMISSION_SELF;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.Activity;
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
 import android.os.Bundle;
@@ -51,12 +53,15 @@
 import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.intercepting.SingleActivityFactory;
 
+import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.notetask.NoteTaskController;
 import com.android.systemui.screenshot.AppClipsTrampolineActivity;
+import com.android.systemui.screenshot.ScreenshotEvent;
+import com.android.systemui.settings.UserTracker;
 import com.android.wm.shell.bubbles.Bubbles;
 
 import org.junit.After;
@@ -74,7 +79,9 @@
 
     private static final String TEST_URI_STRING = "www.test-uri.com";
     private static final Uri TEST_URI = Uri.parse(TEST_URI_STRING);
-    private static final int TIME_OUT = 5000;
+    private static final int TEST_UID = 42;
+    private static final int TEST_USER_ID = 43;
+    private static final String TEST_CALLING_PACKAGE = "test-calling-package";
 
     @Mock
     private DevicePolicyManager mDevicePolicyManager;
@@ -86,6 +93,12 @@
     private Bubbles mBubbles;
     @Mock
     private NoteTaskController mNoteTaskController;
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private UserTracker mUserTracker;
+    @Mock
+    private UiEventLogger mUiEventLogger;
     @Main
     private Handler mMainHandler;
 
@@ -96,7 +109,8 @@
                 @Override
                 protected AppClipsTrampolineActivityTestable create(Intent unUsed) {
                     return new AppClipsTrampolineActivityTestable(mDevicePolicyManager,
-                            mFeatureFlags, mOptionalBubbles, mNoteTaskController, mMainHandler);
+                            mFeatureFlags, mOptionalBubbles, mNoteTaskController, mPackageManager,
+                            mUserTracker, mUiEventLogger, mMainHandler);
                 }
             };
 
@@ -104,41 +118,36 @@
     public final ActivityTestRule<AppClipsTrampolineActivityTestable> mActivityRule =
             new ActivityTestRule<>(mFactory, false, false);
 
-    private Context mContext;
     private Intent mActivityIntent;
     private ComponentName mExpectedComponentName;
-    private Intent mKillAppClipsActivityBroadcast;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mContext = getContext();
         mMainHandler = mContext.getMainThreadHandler();
 
         mActivityIntent = new Intent(mContext, AppClipsTrampolineActivityTestable.class);
         mExpectedComponentName = ComponentName.unflattenFromString(
                 mContext.getString(
                         R.string.config_screenshotAppClipsActivityComponent));
-        mKillAppClipsActivityBroadcast = new Intent(ACTION_FINISH_FROM_TRAMPOLINE)
-                .setComponent(mExpectedComponentName)
-                .setPackage(mExpectedComponentName.getPackageName());
     }
 
     @After
     public void tearDown() {
-        mContext.sendBroadcast(mKillAppClipsActivityBroadcast, PERMISSION_SELF);
         mActivityRule.finishActivity();
     }
 
     @Test
-    public void configComponentName_shouldResolve() {
+    public void appClipsActivityConfig_shouldBeConfigured() {
         // Verify component name is setup - has package and class name.
         assertThat(mExpectedComponentName).isNotNull();
         assertThat(mExpectedComponentName.getPackageName()).isNotEmpty();
         assertThat(mExpectedComponentName.getClassName()).isNotEmpty();
+    }
 
-        // Verify an intent when launched with above component resolves to the same component to
-        // confirm that component from above is available in framework.
+    @Test
+    public void configComponentName_shouldResolve() {
+        // Verify an intent when launched with configured component resolves to activity.
         Intent appClipsActivityIntent = new Intent();
         appClipsActivityIntent.setComponent(mExpectedComponentName);
         ResolveInfo resolveInfo = getContext().getPackageManager().resolveActivity(
@@ -205,7 +214,8 @@
     }
 
     @Test
-    public void startAppClipsActivity_userCanceled_shouldReturnUserCanceled() {
+    public void startAppClipsActivity_userCanceled_shouldReturnUserCanceled()
+            throws NameNotFoundException {
         mockToSatisfyAllPrerequisites();
 
         AppClipsTrampolineActivityTestable activity = mActivityRule.launchActivity(mActivityIntent);
@@ -224,7 +234,8 @@
     }
 
     @Test
-    public void startAppClipsActivity_shouldReturnSuccess() {
+    public void startAppClipsActivity_shouldReturnSuccess()
+            throws NameNotFoundException {
         mockToSatisfyAllPrerequisites();
 
         AppClipsTrampolineActivityTestable activity = mActivityRule.launchActivity(mActivityIntent);
@@ -243,12 +254,31 @@
         assertThat(actualResult.getResultData().getData()).isEqualTo(TEST_URI);
     }
 
-    private void mockToSatisfyAllPrerequisites() {
+    @Test
+    public void startAppClipsActivity_shouldLogUiEvent()
+            throws NameNotFoundException {
+        mockToSatisfyAllPrerequisites();
+
+        mActivityRule.launchActivity(mActivityIntent);
+        waitForIdleSync();
+
+        verify(mUiEventLogger).log(ScreenshotEvent.SCREENSHOT_FOR_NOTE_TRIGGERED, TEST_UID,
+                TEST_CALLING_PACKAGE);
+    }
+
+    private void mockToSatisfyAllPrerequisites() throws NameNotFoundException {
         when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(true);
         when(mOptionalBubbles.isEmpty()).thenReturn(false);
         when(mOptionalBubbles.get()).thenReturn(mBubbles);
         when(mBubbles.isAppBubbleTaskId(anyInt())).thenReturn(true);
         when(mDevicePolicyManager.getScreenCaptureDisabled(eq(null))).thenReturn(false);
+        when(mUserTracker.getUserId()).thenReturn(TEST_USER_ID);
+
+        ApplicationInfo testApplicationInfo = new ApplicationInfo();
+        testApplicationInfo.uid = TEST_UID;
+        when(mPackageManager.getApplicationInfoAsUser(eq(TEST_CALLING_PACKAGE),
+                any(ApplicationInfoFlags.class),
+                eq(TEST_USER_ID))).thenReturn(testApplicationInfo);
     }
 
     public static final class AppClipsTrampolineActivityTestable extends
@@ -258,8 +288,22 @@
                 FeatureFlags flags,
                 Optional<Bubbles> optionalBubbles,
                 NoteTaskController noteTaskController,
+                PackageManager packageManager,
+                UserTracker userTracker,
+                UiEventLogger uiEventLogger,
                 @Main Handler mainHandler) {
-            super(devicePolicyManager, flags, optionalBubbles, noteTaskController, mainHandler);
+            super(devicePolicyManager, flags, optionalBubbles, noteTaskController, packageManager,
+                    userTracker, uiEventLogger, mainHandler);
+        }
+
+        @Override
+        public String getCallingPackage() {
+            return TEST_CALLING_PACKAGE;
+        }
+
+        @Override
+        public void startActivity(Intent unUsed) {
+            // Ignore this intent to avoid App Clips screenshot editing activity from starting.
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
index 9eccbb6..aa1636d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
@@ -249,6 +249,21 @@
     }
 
     @Test
+    public void addCallback_preCondition_noConditions_reportAllConditionsMet() {
+        final Monitor
+                monitor = new Monitor(mExecutor, new HashSet<>(Arrays.asList(mCondition1)));
+        final Monitor.Callback callback = mock(
+                Monitor.Callback.class);
+
+        monitor.addSubscription(new Monitor.Subscription.Builder(callback).build());
+        mExecutor.runAllReady();
+        verify(callback, never()).onConditionsChanged(true);
+        mCondition1.fakeUpdateCondition(true);
+        mExecutor.runAllReady();
+        verify(callback).onConditionsChanged(true);
+    }
+
+    @Test
     public void removeCallback_noFailureOnDoubleRemove() {
         final Condition condition = mock(
                 Condition.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 673e559..3853b99 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -896,21 +896,31 @@
 
         // Subscription 1
         private const val SUB_1_ID = 1
+        private val GROUP_1 = ParcelUuid(UUID.randomUUID())
         private val SUB_1 =
             mock<SubscriptionInfo>().also {
                 whenever(it.subscriptionId).thenReturn(SUB_1_ID)
-                whenever(it.groupUuid).thenReturn(ParcelUuid(UUID.randomUUID()))
+                whenever(it.groupUuid).thenReturn(GROUP_1)
             }
-        private val MODEL_1 = SubscriptionModel(subscriptionId = SUB_1_ID)
+        private val MODEL_1 =
+            SubscriptionModel(
+                subscriptionId = SUB_1_ID,
+                groupUuid = GROUP_1,
+            )
 
         // Subscription 2
         private const val SUB_2_ID = 2
+        private val GROUP_2 = ParcelUuid(UUID.randomUUID())
         private val SUB_2 =
             mock<SubscriptionInfo>().also {
                 whenever(it.subscriptionId).thenReturn(SUB_2_ID)
-                whenever(it.groupUuid).thenReturn(ParcelUuid(UUID.randomUUID()))
+                whenever(it.groupUuid).thenReturn(GROUP_2)
             }
-        private val MODEL_2 = SubscriptionModel(subscriptionId = SUB_2_ID)
+        private val MODEL_2 =
+            SubscriptionModel(
+                subscriptionId = SUB_2_ID,
+                groupUuid = GROUP_2,
+            )
 
         // Subs 3 and 4 are considered to be in the same group ------------------------------------
         private val GROUP_ID_3_4 = ParcelUuid(UUID.randomUUID())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index f8a9783..bbca001 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
 
+import android.os.ParcelUuid
 import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
 import androidx.test.filters.SmallTest
 import com.android.settingslib.mobile.MobileMappings
@@ -34,6 +35,7 @@
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
+import java.util.UUID
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
@@ -104,6 +106,21 @@
             job.cancel()
         }
 
+    // Based on the logic from the old pipeline, we'll never filter subs when there are more than 2
+    @Test
+    fun filteredSubscriptions_moreThanTwo_doesNotFilter() =
+        testScope.runTest {
+            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP, SUB_4_OPP))
+            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_4_ID)
+
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(listOf(SUB_1, SUB_3_OPP, SUB_4_OPP))
+
+            job.cancel()
+        }
+
     @Test
     fun filteredSubscriptions_nonOpportunistic_updatesWithMultipleSubs() =
         testScope.runTest {
@@ -118,10 +135,50 @@
         }
 
     @Test
-    fun filteredSubscriptions_bothOpportunistic_configFalse_showsActive_3() =
+    fun filteredSubscriptions_opportunistic_differentGroups_doesNotFilter() =
         testScope.runTest {
             connectionsRepository.setSubscriptions(listOf(SUB_3_OPP, SUB_4_OPP))
             connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
+
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(listOf(SUB_3_OPP, SUB_4_OPP))
+
+            job.cancel()
+        }
+
+    @Test
+    fun filteredSubscriptions_opportunistic_nonGrouped_doesNotFilter() =
+        testScope.runTest {
+            val (sub1, sub2) =
+                createSubscriptionPair(
+                    subscriptionIds = Pair(SUB_1_ID, SUB_2_ID),
+                    opportunistic = Pair(true, true),
+                    grouped = false,
+                )
+            connectionsRepository.setSubscriptions(listOf(sub1, sub2))
+            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_1_ID)
+
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(listOf(sub1, sub2))
+
+            job.cancel()
+        }
+
+    @Test
+    fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_3() =
+        testScope.runTest {
+            val (sub3, sub4) =
+                createSubscriptionPair(
+                    subscriptionIds = Pair(SUB_3_ID, SUB_4_ID),
+                    opportunistic = Pair(true, true),
+                    grouped = true,
+                )
+            connectionsRepository.setSubscriptions(listOf(sub3, sub4))
+            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
             whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
                 .thenReturn(false)
 
@@ -129,15 +186,21 @@
             val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
 
             // Filtered subscriptions should show the active one when the config is false
-            assertThat(latest).isEqualTo(listOf(SUB_3_OPP))
+            assertThat(latest).isEqualTo(listOf(sub3))
 
             job.cancel()
         }
 
     @Test
-    fun filteredSubscriptions_bothOpportunistic_configFalse_showsActive_4() =
+    fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_4() =
         testScope.runTest {
-            connectionsRepository.setSubscriptions(listOf(SUB_3_OPP, SUB_4_OPP))
+            val (sub3, sub4) =
+                createSubscriptionPair(
+                    subscriptionIds = Pair(SUB_3_ID, SUB_4_ID),
+                    opportunistic = Pair(true, true),
+                    grouped = true,
+                )
+            connectionsRepository.setSubscriptions(listOf(sub3, sub4))
             connectionsRepository.setActiveMobileDataSubscriptionId(SUB_4_ID)
             whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
                 .thenReturn(false)
@@ -146,15 +209,21 @@
             val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
 
             // Filtered subscriptions should show the active one when the config is false
-            assertThat(latest).isEqualTo(listOf(SUB_4_OPP))
+            assertThat(latest).isEqualTo(listOf(sub4))
 
             job.cancel()
         }
 
     @Test
-    fun filteredSubscriptions_oneOpportunistic_configTrue_showsPrimary_active_1() =
+    fun filteredSubscriptions_oneOpportunistic_grouped_configTrue_showsPrimary_active_1() =
         testScope.runTest {
-            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP))
+            val (sub1, sub3) =
+                createSubscriptionPair(
+                    subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
+                    opportunistic = Pair(false, true),
+                    grouped = true,
+                )
+            connectionsRepository.setSubscriptions(listOf(sub1, sub3))
             connectionsRepository.setActiveMobileDataSubscriptionId(SUB_1_ID)
             whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
                 .thenReturn(true)
@@ -164,15 +233,21 @@
 
             // Filtered subscriptions should show the primary (non-opportunistic) if the config is
             // true
-            assertThat(latest).isEqualTo(listOf(SUB_1))
+            assertThat(latest).isEqualTo(listOf(sub1))
 
             job.cancel()
         }
 
     @Test
-    fun filteredSubscriptions_oneOpportunistic_configTrue_showsPrimary_nonActive_1() =
+    fun filteredSubscriptions_oneOpportunistic_grouped_configTrue_showsPrimary_nonActive_1() =
         testScope.runTest {
-            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP))
+            val (sub1, sub3) =
+                createSubscriptionPair(
+                    subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
+                    opportunistic = Pair(false, true),
+                    grouped = true,
+                )
+            connectionsRepository.setSubscriptions(listOf(sub1, sub3))
             connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
             whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
                 .thenReturn(true)
@@ -182,7 +257,7 @@
 
             // Filtered subscriptions should show the primary (non-opportunistic) if the config is
             // true
-            assertThat(latest).isEqualTo(listOf(SUB_1))
+            assertThat(latest).isEqualTo(listOf(sub1))
 
             job.cancel()
         }
@@ -642,6 +717,33 @@
             job.cancel()
         }
 
+    /**
+     * Convenience method for creating a pair of subscriptions to test the filteredSubscriptions
+     * flow.
+     */
+    private fun createSubscriptionPair(
+        subscriptionIds: Pair<Int, Int>,
+        opportunistic: Pair<Boolean, Boolean> = Pair(false, false),
+        grouped: Boolean = false,
+    ): Pair<SubscriptionModel, SubscriptionModel> {
+        val groupUuid = if (grouped) ParcelUuid(UUID.randomUUID()) else null
+        val sub1 =
+            SubscriptionModel(
+                subscriptionId = subscriptionIds.first,
+                isOpportunistic = opportunistic.first,
+                groupUuid = groupUuid,
+            )
+
+        val sub2 =
+            SubscriptionModel(
+                subscriptionId = subscriptionIds.second,
+                isOpportunistic = opportunistic.second,
+                groupUuid = groupUuid,
+            )
+
+        return Pair(sub1, sub2)
+    }
+
     companion object {
         private val tableLogBuffer =
             TableLogBuffer(8, "MobileIconsInteractorTest", FakeSystemClock())
@@ -655,11 +757,21 @@
         private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID, tableLogBuffer)
 
         private const val SUB_3_ID = 3
-        private val SUB_3_OPP = SubscriptionModel(subscriptionId = SUB_3_ID, isOpportunistic = true)
+        private val SUB_3_OPP =
+            SubscriptionModel(
+                subscriptionId = SUB_3_ID,
+                isOpportunistic = true,
+                groupUuid = ParcelUuid(UUID.randomUUID()),
+            )
         private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID, tableLogBuffer)
 
         private const val SUB_4_ID = 4
-        private val SUB_4_OPP = SubscriptionModel(subscriptionId = SUB_4_ID, isOpportunistic = true)
+        private val SUB_4_OPP =
+            SubscriptionModel(
+                subscriptionId = SUB_4_ID,
+                isOpportunistic = true,
+                groupUuid = ParcelUuid(UUID.randomUUID()),
+            )
         private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID, tableLogBuffer)
     }
 }
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..48a2e09 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
@@ -19,10 +19,16 @@
 import android.bluetooth.BluetoothDevice
 import android.hardware.BatteryState
 import android.hardware.input.InputManager
+import android.hardware.input.InputSettings
 import android.os.Handler
 import android.testing.AndroidTestingRunner
 import android.view.InputDevice
 import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.ExtendedMockito.never
+import com.android.dx.mockito.inline.extended.ExtendedMockito.times
+import com.android.dx.mockito.inline.extended.ExtendedMockito.verify
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.flags.FeatureFlags
@@ -30,18 +36,17 @@
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.whenever
 import java.util.concurrent.Executor
+import org.junit.After
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
 import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.inOrder
-import org.mockito.Mockito.never
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
 import org.mockito.Mockito.verifyZeroInteractions
 import org.mockito.MockitoAnnotations
+import org.mockito.quality.Strictness
 
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
@@ -67,11 +72,17 @@
 
     @Mock lateinit var otherStylusBatteryCallback: StylusManager.StylusBatteryCallback
 
+    private lateinit var mockitoSession: StaticMockitoSession
     private lateinit var stylusManager: StylusManager
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
+        mockitoSession =
+            mockitoSession()
+                .mockStatic(InputSettings::class.java)
+                .strictness(Strictness.LENIENT)
+                .startMocking()
 
         whenever(handler.post(any())).thenAnswer {
             (it.arguments[0] as Runnable).run()
@@ -96,23 +107,32 @@
         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)
         whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(STYLUS_DEVICE_ID))
-        whenever(inputManager.isStylusEverUsed(mContext)).thenReturn(false)
 
         whenever(bluetoothAdapter.getRemoteDevice(STYLUS_BT_ADDRESS)).thenReturn(bluetoothDevice)
         whenever(bluetoothDevice.address).thenReturn(STYLUS_BT_ADDRESS)
 
         whenever(featureFlags.isEnabled(Flags.TRACK_STYLUS_EVER_USED)).thenReturn(true)
 
+        whenever(InputSettings.isStylusEverUsed(mContext)).thenReturn(false)
+
         stylusManager.startListener()
         stylusManager.registerCallback(stylusCallback)
         stylusManager.registerBatteryCallback(stylusBatteryCallback)
         clearInvocations(inputManager)
     }
 
+    @After
+    fun tearDown() {
+        mockitoSession.finishMocking()
+    }
+
     @Test
     fun startListener_hasNotStarted_registersInputDeviceListener() {
         stylusManager =
@@ -206,8 +226,7 @@
     @Test
     fun onInputDeviceAdded_btStylus_firstUsed_setsFlag() {
         stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
-
-        verify(inputManager, times(1)).setStylusEverUsed(mContext, true)
+        verify({ InputSettings.setStylusEverUsed(mContext, true) }, times(1))
     }
 
     @Test
@@ -481,7 +500,7 @@
 
         stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
 
-        verify(inputManager).setStylusEverUsed(mContext, true)
+        verify({ InputSettings.setStylusEverUsed(mContext, true) }, times(1))
     }
 
     @Test
@@ -494,13 +513,55 @@
     }
 
     @Test
-    fun onBatteryStateChanged_batteryPresent_stylusUsed_doesNotUpdateEverUsedFlag() {
-        whenever(inputManager.isStylusEverUsed(mContext)).thenReturn(true)
+    fun onBatteryStateChanged_batteryPresent_notInUsiSession_logsSessionStart() {
         whenever(batteryState.isPresent).thenReturn(true)
 
         stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
 
-        verify(inputManager, never()).setStylusEverUsed(mContext, true)
+        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(InputSettings.isStylusEverUsed(mContext)).thenReturn(true)
+
+        whenever(batteryState.isPresent).thenReturn(true)
+
+        stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+
+        verify({ InputSettings.setStylusEverUsed(mContext, true) }, never())
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java
index 5ef62c1..b367a60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java
@@ -60,6 +60,11 @@
             mCallback = callback;
         }
 
+        public FakeConditionalCoreStartable(Monitor monitor, Callback callback) {
+            super(monitor);
+            mCallback = callback;
+        }
+
         @Override
         protected void onStart() {
             mCallback.onStart();
@@ -122,6 +127,31 @@
         verify(mMonitor).removeSubscription(mSubscriptionToken);
     }
 
+    @Test
+    public void testOnStartCallbackWithNoConditions() {
+        final CoreStartable coreStartable =
+                new FakeConditionalCoreStartable(mMonitor,
+                        mCallback);
+
+        when(mMonitor.addSubscription(any())).thenReturn(mSubscriptionToken);
+        coreStartable.start();
+
+        final ArgumentCaptor<Monitor.Subscription> subscriptionCaptor = ArgumentCaptor.forClass(
+                Monitor.Subscription.class);
+        verify(mMonitor).addSubscription(subscriptionCaptor.capture());
+
+        final Monitor.Subscription subscription = subscriptionCaptor.getValue();
+
+        assertThat(subscription.getConditions()).isEmpty();
+
+        verify(mCallback, never()).onStart();
+
+        subscription.getCallback().onConditionsChanged(true);
+
+        verify(mCallback).onStart();
+        verify(mMonitor).removeSubscription(mSubscriptionToken);
+    }
+
 
     /**
      * Verifies that {@link ConditionalCoreStartable#bootCompleted()} ()} is predicated on
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/condition/SelfExecutingMonitor.java b/packages/SystemUI/tests/utils/src/com/android/systemui/condition/SelfExecutingMonitor.java
new file mode 100644
index 0000000..7ee05d0
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/condition/SelfExecutingMonitor.java
@@ -0,0 +1,62 @@
+/*
+ * 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.condition;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.shared.condition.Monitor;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+/**
+ * {@link SelfExecutingMonitor} creates a monitor that independently executes its logic through
+ * a {@link FakeExecutor}, which is ran at when a subscription is added and removed.
+ */
+public class SelfExecutingMonitor extends Monitor {
+    private final FakeExecutor mExecutor;
+
+    /**
+     * Default constructor that allows specifying the FakeExecutor to use.
+     */
+    public SelfExecutingMonitor(FakeExecutor executor) {
+        super(executor);
+        mExecutor = executor;
+    }
+
+    @Override
+    public Subscription.Token addSubscription(@NonNull Subscription subscription) {
+        final Subscription.Token result = super.addSubscription(subscription);
+        mExecutor.runAllReady();
+        return result;
+    }
+
+    @Override
+    public void removeSubscription(@NonNull Subscription.Token token) {
+        super.removeSubscription(token);
+        mExecutor.runNextReady();
+    }
+
+    /**
+     * Creates a {@link SelfExecutingMonitor} with a self-managed {@link FakeExecutor}. Use only
+     * for cases where condition state only will be set at when a subscription is added.
+     */
+    public static SelfExecutingMonitor createInstance() {
+        final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
+        final FakeExecutor mExecutor = new FakeExecutor(mFakeSystemClock);
+        return new SelfExecutingMonitor(mExecutor);
+    }
+}
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/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ec69306..4d5baaf 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -487,6 +487,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.BiFunction;
+import java.util.function.Consumer;
 import java.util.function.Supplier;
 
 public class ActivityManagerService extends IActivityManager.Stub
@@ -6452,6 +6453,44 @@
         return entry == null ? null : entry.second;
     }
 
+    private static class GetBackgroundStartPrivilegesFunctor implements Consumer<ProcessRecord> {
+        private BackgroundStartPrivileges mBackgroundStartPrivileges =
+                BackgroundStartPrivileges.NONE;
+        private int mUid;
+
+        void prepare(int uid) {
+            mUid = uid;
+            mBackgroundStartPrivileges = BackgroundStartPrivileges.NONE;
+        }
+
+        @NonNull
+        BackgroundStartPrivileges getResult() {
+            return mBackgroundStartPrivileges;
+        }
+
+        public void accept(ProcessRecord pr) {
+            if (pr.uid == mUid) {
+                mBackgroundStartPrivileges =
+                        mBackgroundStartPrivileges.merge(pr.getBackgroundStartPrivileges());
+            }
+        }
+    }
+
+    private final GetBackgroundStartPrivilegesFunctor mGetBackgroundStartPrivilegesFunctor =
+            new GetBackgroundStartPrivilegesFunctor();
+
+    /**
+     * Returns the current complete {@link BackgroundStartPrivileges} of the UID.
+     */
+    @NonNull
+    private BackgroundStartPrivileges getBackgroundStartPrivileges(int uid) {
+        synchronized (mProcLock) {
+            mGetBackgroundStartPrivilegesFunctor.prepare(uid);
+            mProcessList.forEachLruProcessesLOSP(false, mGetBackgroundStartPrivilegesFunctor);
+            return mGetBackgroundStartPrivilegesFunctor.getResult();
+        }
+    }
+
     /**
      * @return allowlist tag for a uid from mPendingTempAllowlist, null if not currently on
      * the allowlist
@@ -16884,13 +16923,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
@@ -17850,6 +17890,11 @@
             return mConstants.mFlagBackgroundActivityStartsEnabled;
         }
 
+        @Override
+        public BackgroundStartPrivileges getBackgroundStartPrivileges(int uid) {
+            return ActivityManagerService.this.getBackgroundStartPrivileges(uid);
+        }
+
         public void reportCurKeyguardUsageEvent(boolean keyguardShowing) {
             ActivityManagerService.this.reportGlobalUsageEvent(keyguardShowing
                     ? UsageEvents.Event.KEYGUARD_SHOWN
@@ -18489,6 +18534,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/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index a707202..fa3f684 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -20,6 +20,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityManagerService.MY_PID;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ApplicationExitInfo;
@@ -341,6 +342,24 @@
     private boolean mInFullBackup;
 
     /**
+     * A set of tokens that currently contribute to this process being temporarily allowed
+     * to start certain components (eg. activities or foreground services) even if it's not
+     * in the foreground.
+     */
+    @GuardedBy("mBackgroundStartPrivileges")
+    private final ArrayMap<Binder, BackgroundStartPrivileges> mBackgroundStartPrivileges =
+            new ArrayMap<>();
+
+    /**
+     * The merged BackgroundStartPrivileges based on what's in {@link #mBackgroundStartPrivileges}.
+     * This is lazily generated using {@link #getBackgroundStartPrivileges()}.
+     */
+    @Nullable
+    @GuardedBy("mBackgroundStartPrivileges")
+    private BackgroundStartPrivileges mBackgroundStartPrivilegesMerged =
+            BackgroundStartPrivileges.NONE;
+
+    /**
      * Controller for driving the process state on the window manager side.
      */
     private final WindowProcessController mWindowProcessController;
@@ -1325,11 +1344,50 @@
         Objects.requireNonNull(entity);
         mWindowProcessController.addOrUpdateBackgroundStartPrivileges(entity,
                 backgroundStartPrivileges);
+        setBackgroundStartPrivileges(entity, backgroundStartPrivileges);
     }
 
     void removeBackgroundStartPrivileges(Binder entity) {
         Objects.requireNonNull(entity);
         mWindowProcessController.removeBackgroundStartPrivileges(entity);
+        setBackgroundStartPrivileges(entity, null);
+    }
+
+    @NonNull
+    BackgroundStartPrivileges getBackgroundStartPrivileges() {
+        synchronized (mBackgroundStartPrivileges) {
+            if (mBackgroundStartPrivilegesMerged == null) {
+                // Lazily generate the merged version when it's actually needed.
+                mBackgroundStartPrivilegesMerged = BackgroundStartPrivileges.NONE;
+                for (int i = mBackgroundStartPrivileges.size() - 1; i >= 0; --i) {
+                    mBackgroundStartPrivilegesMerged =
+                            mBackgroundStartPrivilegesMerged.merge(
+                                    mBackgroundStartPrivileges.valueAt(i));
+                }
+            }
+            return mBackgroundStartPrivilegesMerged;
+        }
+    }
+
+    private void setBackgroundStartPrivileges(@NonNull Binder entity,
+            @Nullable BackgroundStartPrivileges backgroundStartPrivileges) {
+        synchronized (mBackgroundStartPrivileges) {
+            final boolean changed;
+            if (backgroundStartPrivileges == null) {
+                changed = mBackgroundStartPrivileges.remove(entity) != null;
+            } else {
+                final BackgroundStartPrivileges oldBsp =
+                        mBackgroundStartPrivileges.put(entity, backgroundStartPrivileges);
+                // BackgroundStartPrivileges tries to reuse the same object and avoid creating
+                // additional objects. For now, we just compare the reference to see if something
+                // has changed.
+                // TODO: actually compare the individual values to see if there's a change
+                changed = backgroundStartPrivileges != oldBsp;
+            }
+            if (changed) {
+                mBackgroundStartPrivilegesMerged = null;
+            }
+        }
     }
 
     @Override
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/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index c0c286b..3c9af13 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -450,7 +450,7 @@
     // so -2 is used instead
     private static final float INVALID_BRIGHTNESS_IN_CONFIG = -2f;
 
-    private static final float NITS_INVALID = -1;
+    static final float NITS_INVALID = -1;
 
     // Length of the ambient light horizon used to calculate the long term estimate of ambient
     // light.
@@ -840,7 +840,7 @@
     /**
      * Calculates the nits value for the specified backlight value if a mapping exists.
      *
-     * @return The mapped nits or 0 if no mapping exits.
+     * @return The mapped nits or {@link #NITS_INVALID} if no mapping exits.
      */
     public float getNitsFromBacklight(float backlight) {
         if (mBacklightToNitsSpline == null) {
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index b7b7031..213ee64 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -226,6 +226,16 @@
     public static final int DIFF_COLOR_MODE = 1 << 2;
 
     /**
+     * Diff result: The hdr/sdr ratio differs
+     */
+    public static final int DIFF_HDR_SDR_RATIO = 1 << 3;
+
+    /**
+     * Diff result: Catch-all for "everything changed"
+     */
+    public static final int DIFF_EVERYTHING = 0XFFFFFFFF;
+
+    /**
      * Gets the name of the display device, which may be derived from EDID or
      * other sources. The name may be localized and displayed to the user.
      */
@@ -414,6 +424,9 @@
     public float brightnessMaximum;
     public float brightnessDefault;
 
+    // NaN means unsupported
+    public float hdrSdrRatio = Float.NaN;
+
     /**
      * Install orientation of display panel relative to its natural orientation.
      */
@@ -449,6 +462,9 @@
         if (colorMode != other.colorMode) {
             diff |= DIFF_COLOR_MODE;
         }
+        if (!BrightnessSynchronizer.floatEquals(hdrSdrRatio, other.hdrSdrRatio)) {
+            diff |= DIFF_HDR_SDR_RATIO;
+        }
         if (!Objects.equals(name, other.name)
                 || !Objects.equals(uniqueId, other.uniqueId)
                 || width != other.width
@@ -527,6 +543,7 @@
         brightnessMinimum = other.brightnessMinimum;
         brightnessMaximum = other.brightnessMaximum;
         brightnessDefault = other.brightnessDefault;
+        hdrSdrRatio = other.hdrSdrRatio;
         roundedCorners = other.roundedCorners;
         installOrientation = other.installOrientation;
         displayShape = other.displayShape;
@@ -575,6 +592,7 @@
         sb.append(", brightnessMinimum ").append(brightnessMinimum);
         sb.append(", brightnessMaximum ").append(brightnessMaximum);
         sb.append(", brightnessDefault ").append(brightnessDefault);
+        sb.append(", hdrSdrRatio ").append(hdrSdrRatio);
         if (roundedCorners != null) {
             sb.append(", roundedCorners ").append(roundedCorners);
         }
diff --git a/services/core/java/com/android/server/display/DisplayDeviceRepository.java b/services/core/java/com/android/server/display/DisplayDeviceRepository.java
index 33a63a9..ea52a3d 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceRepository.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceRepository.java
@@ -42,7 +42,6 @@
     private static final Boolean DEBUG = false;
 
     public static final int DISPLAY_DEVICE_EVENT_ADDED = 1;
-    public static final int DISPLAY_DEVICE_EVENT_CHANGED = 2;
     public static final int DISPLAY_DEVICE_EVENT_REMOVED = 3;
 
     /**
@@ -83,15 +82,15 @@
             Trace.beginAsyncSection(tag, 0);
         }
         switch (event) {
-            case DISPLAY_DEVICE_EVENT_ADDED:
+            case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED:
                 handleDisplayDeviceAdded(device);
                 break;
 
-            case DISPLAY_DEVICE_EVENT_CHANGED:
+            case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED:
                 handleDisplayDeviceChanged(device);
                 break;
 
-            case DISPLAY_DEVICE_EVENT_REMOVED:
+            case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED:
                 handleDisplayDeviceRemoved(device);
                 break;
         }
@@ -174,7 +173,7 @@
             if (diff == DisplayDeviceInfo.DIFF_STATE) {
                 Slog.i(TAG, "Display device changed state: \"" + info.name
                         + "\", " + Display.stateToString(info.state));
-            } else if (diff != 0) {
+            } else if (diff != DisplayDeviceInfo.DIFF_HDR_SDR_RATIO) {
                 Slog.i(TAG, "Display device changed: " + info);
             }
 
@@ -188,7 +187,7 @@
             device.mDebugLastLoggedDeviceInfo = info;
 
             device.applyPendingDisplayDeviceInfoChangesLocked();
-            sendEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
+            sendChangedEventLocked(device, diff);
             if (DEBUG) {
                 Trace.traceEnd(Trace.TRACE_TAG_POWER);
             }
@@ -216,12 +215,22 @@
         }
     }
 
+    @GuardedBy("mSyncRoot")
+    private void sendChangedEventLocked(DisplayDevice device, int diff) {
+        final int size = mListeners.size();
+        for (int i = 0; i < size; i++) {
+            mListeners.get(i).onDisplayDeviceChangedLocked(device, diff);
+        }
+    }
+
     /**
      * Listens to {@link DisplayDevice} events from {@link DisplayDeviceRepository}.
      */
     public interface Listener {
         void onDisplayDeviceEventLocked(DisplayDevice device, int event);
 
+        void onDisplayDeviceChangedLocked(DisplayDevice device, int diff);
+
         // TODO: multi-display - Try to remove the need for requestTraversal...it feels like
         // a shoe-horned method for a shoe-horned feature.
         void onTraversalRequested();
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e200d12..9f1007d 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.
@@ -1745,6 +1747,10 @@
         mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATIONS);
     }
 
+    private void handleLogicalDisplayHdrSdrRatioChangedLocked(@NonNull LogicalDisplay display) {
+        sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED);
+    }
+
     private void notifyDefaultDisplayDeviceUpdated(LogicalDisplay display) {
         mDisplayModeDirector.defaultDisplayDeviceUpdated(display.getPrimaryDisplayDeviceLocked()
                 .mDisplayDeviceConfig);
@@ -2025,12 +2031,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 +2056,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 +2208,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 +2253,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 +2824,10 @@
         int[] getSupportedHdrOutputTypes() {
             return DisplayControl.getSupportedHdrOutputTypes();
         }
+
+        boolean getHdrOutputConversionSupport() {
+            return DisplayControl.getHdrOutputConversionSupport();
+        }
     }
 
     @VisibleForTesting
@@ -2983,6 +3028,10 @@
                 case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION:
                     handleLogicalDisplayDeviceStateTransitionLocked(display);
                     break;
+
+                case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED:
+                    handleLogicalDisplayHdrSdrRatioChangedLocked(display);
+                    break;
             }
         }
 
@@ -3052,6 +3101,8 @@
                     return (mask & DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS) != 0;
                 case DisplayManagerGlobal.EVENT_DISPLAY_REMOVED:
                     return (mask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0;
+                case DisplayManagerGlobal.EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED:
+                    return (mask & DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED) != 0;
                 default:
                     // This should never happen.
                     Slog.e(TAG, "Unknown display event " + event);
@@ -3757,6 +3808,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 +4091,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/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index be5980b..8f52c97 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -204,6 +204,7 @@
         // This is only set in the runnable returned from requestDisplayStateLocked.
         private float mBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
         private float mSdrBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+        private float mCurrentHdrSdrRatio = Float.NaN;
         private int mDefaultModeId = INVALID_MODE_ID;
         private int mSystemPreferredModeId = INVALID_MODE_ID;
         private int mDefaultModeGroup;
@@ -729,6 +730,7 @@
                 mInfo.brightnessMinimum = PowerManager.BRIGHTNESS_MIN;
                 mInfo.brightnessMaximum = PowerManager.BRIGHTNESS_MAX;
                 mInfo.brightnessDefault = getDisplayDeviceConfig().getBrightnessDefault();
+                mInfo.hdrSdrRatio = mCurrentHdrSdrRatio;
             }
             return mInfo;
         }
@@ -840,12 +842,10 @@
 
                     private void setCommittedState(int state) {
                         // After the display state is set, let's update the committed state.
-                        getHandler().post(() -> {
-                            synchronized (getSyncRoot()) {
-                                mCommittedState = state;
-                                updateDeviceInfoLocked();
-                            }
-                        });
+                        synchronized (getSyncRoot()) {
+                            mCommittedState = state;
+                            updateDeviceInfoLocked();
+                        }
                     }
 
                     private void setDisplayBrightness(float brightnessState,
@@ -881,6 +881,9 @@
                                     "SdrScreenBrightness",
                                     BrightnessSynchronizer.brightnessFloatToInt(
                                             sdrBrightnessState));
+
+                            handleHdrSdrNitsChanged(nits, sdrNits);
+
                         } finally {
                             Trace.traceEnd(Trace.TRACE_TAG_POWER);
                         }
@@ -897,6 +900,23 @@
                     private float backlightToNits(float backlight) {
                         return getDisplayDeviceConfig().getNitsFromBacklight(backlight);
                     }
+
+                    void handleHdrSdrNitsChanged(float displayNits, float sdrNits) {
+                        final float newHdrSdrRatio;
+                        if (displayNits != DisplayDeviceConfig.NITS_INVALID
+                                && sdrNits != DisplayDeviceConfig.NITS_INVALID) {
+                            newHdrSdrRatio = displayNits / sdrNits;
+                        } else {
+                            newHdrSdrRatio = Float.NaN;
+                        }
+                        if (!BrightnessSynchronizer.floatEquals(
+                                mCurrentHdrSdrRatio, newHdrSdrRatio)) {
+                            synchronized (getSyncRoot()) {
+                                mCurrentHdrSdrRatio = newHdrSdrRatio;
+                                updateDeviceInfoLocked();
+                            }
+                        }
+                    }
                 };
             }
             return null;
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 667c8c8..2104ee3 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -454,6 +454,7 @@
             mBaseDisplayInfo.brightnessMinimum = deviceInfo.brightnessMinimum;
             mBaseDisplayInfo.brightnessMaximum = deviceInfo.brightnessMaximum;
             mBaseDisplayInfo.brightnessDefault = deviceInfo.brightnessDefault;
+            mBaseDisplayInfo.hdrSdrRatio = deviceInfo.hdrSdrRatio;
             mBaseDisplayInfo.roundedCorners = deviceInfo.roundedCorners;
             mBaseDisplayInfo.installOrientation = deviceInfo.installOrientation;
             mBaseDisplayInfo.displayShape = deviceInfo.displayShape;
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index b48ba65..80e76b6 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -71,6 +71,7 @@
     public static final int LOGICAL_DISPLAY_EVENT_SWAPPED = 4;
     public static final int LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED = 5;
     public static final int LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION = 6;
+    public static final int LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED = 7;
 
     public static final int DISPLAY_GROUP_EVENT_ADDED = 1;
     public static final int DISPLAY_GROUP_EVENT_CHANGED = 2;
@@ -226,14 +227,6 @@
                 handleDisplayDeviceAddedLocked(device);
                 break;
 
-            case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_CHANGED:
-                if (DEBUG) {
-                    Slog.d(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked());
-                }
-                finishStateTransitionLocked(false /*force*/);
-                updateLogicalDisplaysLocked();
-                break;
-
             case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_REMOVED:
                 if (DEBUG) {
                     Slog.d(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked());
@@ -245,6 +238,15 @@
     }
 
     @Override
+    public void onDisplayDeviceChangedLocked(DisplayDevice device, int diff) {
+        if (DEBUG) {
+            Slog.d(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked());
+        }
+        finishStateTransitionLocked(false /*force*/);
+        updateLogicalDisplaysLocked(diff);
+    }
+
+    @Override
     public void onTraversalRequested() {
         mListener.onTraversalRequested();
     }
@@ -655,13 +657,20 @@
         }
     }
 
+    private void updateLogicalDisplaysLocked() {
+        updateLogicalDisplaysLocked(DisplayDeviceInfo.DIFF_EVERYTHING);
+    }
+
     /**
      * Updates the rest of the display system once all the changes are applied for display
      * devices and logical displays. The includes releasing invalid/empty LogicalDisplays,
      * creating/adjusting/removing DisplayGroups, and notifying the rest of the system of the
      * relevant changes.
+     *
+     * @param diff The DisplayDeviceInfo.DIFF_* of what actually changed to enable finer-grained
+     *             display update listeners
      */
-    private void updateLogicalDisplaysLocked() {
+    private void updateLogicalDisplaysLocked(int diff) {
         // Go through all the displays and figure out if they need to be updated.
         // Loops in reverse so that displays can be removed during the loop without affecting the
         // rest of the loop.
@@ -715,7 +724,13 @@
             } else if (!mTempDisplayInfo.equals(newDisplayInfo)) {
                 // FLAG_OWN_DISPLAY_GROUP could have changed, recalculate just in case
                 assignDisplayGroupLocked(display);
-                mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED);
+                // If only the hdr/sdr ratio changed, then send just the event for that case
+                if ((diff == DisplayDeviceInfo.DIFF_HDR_SDR_RATIO)) {
+                    mLogicalDisplaysToUpdate.put(displayId,
+                            LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED);
+                } else {
+                    mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED);
+                }
 
             // The display is involved in a display layout transition
             } else if (updateState == UPDATE_STATE_TRANSITION) {
@@ -774,6 +789,7 @@
         sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED);
         sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_SWAPPED);
         sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_ADDED);
+        sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED);
         sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_CHANGED);
         sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_REMOVED);
 
@@ -1125,6 +1141,8 @@
                 return "swapped";
             case LOGICAL_DISPLAY_EVENT_REMOVED:
                 return "removed";
+            case LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED:
+                return "hdr_sdr_ratio_changed";
         }
         return null;
     }
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 172aa20..b2b22a0 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -50,6 +50,7 @@
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
 import android.hardware.input.InputSensorInfo;
+import android.hardware.input.InputSettings;
 import android.hardware.input.KeyboardLayout;
 import android.hardware.input.TouchCalibration;
 import android.hardware.lights.Light;
@@ -1309,7 +1310,7 @@
             throw new SecurityException("Requires SET_POINTER_SPEED permission");
         }
 
-        if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
+        if (speed < InputSettings.MIN_POINTER_SPEED || speed > InputSettings.MAX_POINTER_SPEED) {
             throw new IllegalArgumentException("speed out of range");
         }
 
@@ -1317,8 +1318,8 @@
     }
 
     private void setPointerSpeedUnchecked(int speed) {
-        speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
-                InputManager.MAX_POINTER_SPEED);
+        speed = Math.min(Math.max(speed, InputSettings.MIN_POINTER_SPEED),
+                InputSettings.MAX_POINTER_SPEED);
         mNative.setPointerSpeed(speed);
     }
 
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index a113d01..5b21669 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -21,7 +21,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.database.ContentObserver;
-import android.hardware.input.InputManager;
+import android.hardware.input.InputSettings;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.UserHandle;
@@ -32,7 +32,6 @@
 import android.view.ViewConfiguration;
 
 import java.util.Map;
-import java.util.Objects;
 import java.util.function.Consumer;
 
 /** Observes settings changes and propagates them to the native side. */
@@ -111,9 +110,9 @@
 
     private int getPointerSpeedValue(String settingName) {
         int speed = Settings.System.getIntForUser(mContext.getContentResolver(),
-                settingName, InputManager.DEFAULT_POINTER_SPEED, UserHandle.USER_CURRENT);
-        return Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
-                InputManager.MAX_POINTER_SPEED);
+                settingName, InputSettings.DEFAULT_POINTER_SPEED, UserHandle.USER_CURRENT);
+        return Math.min(Math.max(speed, InputSettings.MIN_POINTER_SPEED),
+                InputSettings.MAX_POINTER_SPEED);
     }
 
     private void updateMousePointerSpeed() {
@@ -170,8 +169,7 @@
     }
 
     private void updateMaximumObscuringOpacityForTouch() {
-        InputManager im = Objects.requireNonNull(mContext.getSystemService(InputManager.class));
-        final float opacity = im.getMaximumObscuringOpacityForTouch();
+        final float opacity = InputSettings.getMaximumObscuringOpacityForTouch(mContext);
         if (opacity < 0 || opacity > 1) {
             Log.e(TAG, "Invalid maximum obscuring opacity " + opacity
                     + ", it should be >= 0 and <= 1, rejecting update.");
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/DefaultCrossProfileIntentFiltersUtils.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
index 3799193..84ea077 100644
--- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
+++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
@@ -320,12 +320,26 @@
                 MOBILE_NETWORK_SETTINGS);
     }
 
+    /** Call intent with tel scheme */
+    private static final DefaultCrossProfileIntentFilter CALL =
+            new DefaultCrossProfileIntentFilter.Builder(
+                    DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
+                    SKIP_CURRENT_PROFILE,
+                    /* letsPersonalDataIntoProfile= */ false)
+                    .addAction(Intent.ACTION_CALL)
+                    .addCategory(Intent.CATEGORY_DEFAULT)
+                    .addDataScheme("tel")
+                    .build();
+
     /**
      * Returns default telephony related intent filters for managed profile.
      */
     public static List<DefaultCrossProfileIntentFilter> getDefaultManagedProfileTelephonyFilters() {
         return Arrays.asList(
                 DIAL_DATA,
+                DIAL_MIME,
+                DIAL_RAW,
+                CALL,
                 SMS_MMS);
     }
 
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/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7f1679a..449801d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3501,8 +3501,8 @@
     }
 
     @Override
-    public void onKeyguardOccludedChangedLw(boolean occluded) {
-        if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
+    public void onKeyguardOccludedChangedLw(boolean occluded, boolean waitAppTransition) {
+        if (mKeyguardDelegate != null && waitAppTransition) {
             mPendingKeyguardOccluded = occluded;
             mKeyguardOccludedChanged = true;
         } else {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index ca5fa5f..3c4dbf2 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -164,9 +164,10 @@
 
     /**
      * Called when the Keyguard occluded state changed.
+     *
      * @param occluded Whether Keyguard is currently occluded or not.
      */
-    void onKeyguardOccludedChangedLw(boolean occluded);
+    void onKeyguardOccludedChangedLw(boolean occluded, boolean waitAppTransition);
 
     /**
      * @param notify {@code true} if the status change should be immediately notified via
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/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
index 5fd70a8..fc659c5 100644
--- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
@@ -104,10 +104,10 @@
     }
 
     /**
-     * Returns {@code true} if location time zone detection should run all the time on supported
-     * devices, even when the user has not enabled it explicitly in settings. Enabled for internal
-     * testing only. See {@link #isGeoDetectionExecutionEnabled()} and {@link #getDetectionMode()}
-     * for details.
+     * Returns {@code true} if location time zone detection should run when auto time zone detection
+     * is enabled on supported devices, even when the user has not enabled the algorithm explicitly
+     * in settings. Enabled for internal testing only. See {@link #isGeoDetectionExecutionEnabled()}
+     * and {@link #getDetectionMode()} for details.
      */
     boolean getGeoDetectionRunInBackgroundEnabledSetting() {
         return mGeoDetectionRunInBackgroundEnabled;
@@ -219,6 +219,7 @@
     private boolean getGeoDetectionRunInBackgroundEnabledBehavior() {
         return isGeoDetectionSupported()
                 && getLocationEnabledSetting()
+                && getAutoDetectionEnabledSetting()
                 && getGeoDetectionRunInBackgroundEnabledSetting();
     }
 
@@ -433,9 +434,9 @@
         }
 
         /**
-         * Sets whether location time zone detection should run all the time on supported devices,
-         * even when the user has not enabled it explicitly in settings. Enabled for internal
-         * testing only.
+         * Sets whether location time zone detection should run when auto time zone detection is
+         * enabled on supported devices, even when the user has not enabled the algorithm explicitly
+         * in settings. Enabled for internal testing only.
          */
         public Builder setGeoDetectionRunInBackgroundEnabled(boolean enabled) {
             mGeoDetectionRunInBackgroundEnabled = enabled;
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/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index e9badef..32b3ccf 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -401,8 +401,10 @@
             return;
         }
 
-        mWindowManager.mPolicy.onKeyguardOccludedChangedLw(isDisplayOccluded(DEFAULT_DISPLAY));
-        if (isKeyguardLocked(displayId)) {
+        final boolean waitAppTransition = isKeyguardLocked(displayId);
+        mWindowManager.mPolicy.onKeyguardOccludedChangedLw(isDisplayOccluded(DEFAULT_DISPLAY),
+                waitAppTransition);
+        if (waitAppTransition) {
             mService.deferWindowLayout();
             try {
                 mRootWindowContainer.getDefaultDisplay()
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 43dbcc8..216544a 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1881,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
@@ -1888,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.
      *
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a63f9a3..ae7dc1e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -193,6 +193,7 @@
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.input.InputManager;
+import android.hardware.input.InputSettings;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -744,7 +745,7 @@
     private final DisplayHashController mDisplayHashController;
 
     volatile float mMaximumObscuringOpacityForTouch =
-            InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH;
+            InputSettings.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH;
 
     @VisibleForTesting
     final WindowContextListenerController mWindowContextListenerController =
@@ -886,11 +887,11 @@
             ContentResolver resolver = mContext.getContentResolver();
             mMaximumObscuringOpacityForTouch = Settings.Global.getFloat(resolver,
                     Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH,
-                    InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH);
+                    InputSettings.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH);
             if (mMaximumObscuringOpacityForTouch < 0.0f
                     || mMaximumObscuringOpacityForTouch > 1.0f) {
                 mMaximumObscuringOpacityForTouch =
-                        InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH;
+                        InputSettings.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH;
             }
         }
 
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/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index 8f16737..5013fb0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -33,6 +33,7 @@
 import android.app.admin.PolicyUpdatesReceiver;
 import android.app.admin.PolicyValue;
 import android.app.admin.TargetUser;
+import android.app.admin.UserRestrictionPolicyKey;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -614,6 +615,47 @@
         }
     }
 
+    /**
+     * Returns all user restriction policies set by the given admin.
+     *
+     * <p>Pass in {@link UserHandle#USER_ALL} for {@code userId} to get global restrictions set by
+     * the admin
+     */
+    @NonNull
+    Set<UserRestrictionPolicyKey> getUserRestrictionPolicyKeysForAdmin(
+            @NonNull EnforcingAdmin admin,
+            int userId) {
+        Objects.requireNonNull(admin);
+        synchronized (mLock) {
+            if (userId == UserHandle.USER_ALL) {
+                return getUserRestrictionPolicyKeysForAdminLocked(mGlobalPolicies, admin);
+            }
+            if (!mLocalPolicies.contains(userId)) {
+                return Set.of();
+            }
+            return getUserRestrictionPolicyKeysForAdminLocked(mLocalPolicies.get(userId), admin);
+        }
+    }
+
+    private Set<UserRestrictionPolicyKey> getUserRestrictionPolicyKeysForAdminLocked(
+            Map<PolicyKey, PolicyState<?>> policies,
+            EnforcingAdmin admin) {
+        Set<UserRestrictionPolicyKey> keys = new HashSet<>();
+        for (PolicyKey key : policies.keySet()) {
+            if (!policies.get(key).getPolicyDefinition().isUserRestrictionPolicy()) {
+                continue;
+            }
+            // User restriction policies are always boolean
+            PolicyValue<Boolean> value = (PolicyValue<Boolean>) policies.get(key)
+                    .getPoliciesSetByAdmins().get(admin);
+            if (value == null || !value.getValue()) {
+                continue;
+            }
+            keys.add((UserRestrictionPolicyKey) key);
+        }
+        return keys;
+    }
+
     private <V> boolean hasLocalPolicyLocked(PolicyDefinition<V> policyDefinition, int userId) {
         if (policyDefinition.isGlobalOnlyPolicy()) {
             return false;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index cdcfaba..61ee0e7 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;
@@ -256,6 +264,7 @@
 import android.app.admin.SystemUpdateInfo;
 import android.app.admin.SystemUpdatePolicy;
 import android.app.admin.UnsafeStateException;
+import android.app.admin.UserRestrictionPolicyKey;
 import android.app.admin.WifiSsidPolicy;
 import android.app.backup.IBackupManager;
 import android.app.compat.CompatChanges;
@@ -731,6 +740,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 +1169,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);
             }
         }
 
@@ -1334,7 +1352,7 @@
             if (shouldMigrateToDevicePolicyEngine()) {
                 migratePoliciesToDevicePolicyEngine();
             }
-            if (isDevicePolicyEngineFlagEnabled()) {
+            if (isDevicePolicyEngineEnabled()) {
                 mDevicePolicyEngine.handlePackageChanged(packageName, userHandle);
             }
             // Persist updates if the removed package was an admin or delegate.
@@ -2001,7 +2019,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();
@@ -2026,7 +2045,7 @@
         mUserManagerInternal.addUserLifecycleListener(new UserLifecycleListener());
 
         mDeviceManagementResourcesProvider.load();
-        if (isDevicePolicyEngineFlagEnabled()) {
+        if (isDevicePolicyEngineEnabled()) {
             mDevicePolicyEngine.load();
         }
 
@@ -2488,8 +2507,7 @@
                 if (profileOwner == null || !mUserManager.isManagedProfile(userId)) {
                     continue;
                 }
-                maybeSetDefaultRestrictionsForAdminLocked(userId, profileOwner,
-                        UserRestrictionsUtils.getDefaultEnabledForManagedProfiles());
+                maybeSetDefaultRestrictionsForAdminLocked(userId, profileOwner);
                 ensureUnknownSourcesRestrictionForProfileOwnerLocked(
                         userId, profileOwner, false /* newOwner */);
             }
@@ -2504,9 +2522,20 @@
             ActiveAdmin profileOwner, boolean newOwner) {
         if (newOwner || mInjector.settingsSecureGetIntForUser(
                 Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId) != 0) {
-            profileOwner.ensureUserRestrictions().putBoolean(
-                    UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
-            saveUserRestrictionsLocked(userId);
+            if (isDevicePolicyEngineEnabled()) {
+                mDevicePolicyEngine.setLocalPolicy(
+                        PolicyDefinition.getPolicyDefinitionForUserRestriction(
+                                UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES),
+                        EnforcingAdmin.createEnterpriseEnforcingAdmin(
+                                profileOwner.info.getComponent(),
+                                profileOwner.getUserHandle().getIdentifier()),
+                        new BooleanPolicyValue(true),
+                        userId);
+            } else {
+                profileOwner.ensureUserRestrictions().putBoolean(
+                        UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
+                saveUserRestrictionsLocked(userId);
+            }
             mInjector.settingsSecurePutIntForUser(
                     Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId);
         }
@@ -2515,11 +2544,28 @@
     /**
      * Apply default restrictions that haven't been applied to a given admin yet.
      */
-    private void maybeSetDefaultRestrictionsForAdminLocked(
-            int userId, ActiveAdmin admin, Set<String> defaultRestrictions) {
+    private void maybeSetDefaultRestrictionsForAdminLocked(int userId, ActiveAdmin admin) {
+        Set<String> defaultRestrictions =
+                UserRestrictionsUtils.getDefaultEnabledForManagedProfiles();
         if (defaultRestrictions.equals(admin.defaultEnabledRestrictionsAlreadySet)) {
             return; // The same set of default restrictions has been already applied.
         }
+        if (isDevicePolicyEngineEnabled()) {
+            for (String restriction : defaultRestrictions) {
+                mDevicePolicyEngine.setLocalPolicy(
+                        PolicyDefinition.getPolicyDefinitionForUserRestriction(restriction),
+                        EnforcingAdmin.createEnterpriseEnforcingAdmin(
+                                admin.info.getComponent(),
+                                admin.getUserHandle().getIdentifier()),
+                        new BooleanPolicyValue(true),
+                        userId);
+            }
+            admin.defaultEnabledRestrictionsAlreadySet.addAll(defaultRestrictions);
+            Slogf.i(LOG_TAG, "Enabled the following restrictions by default: " +
+                    defaultRestrictions);
+            return;
+        }
+
         Slogf.i(LOG_TAG, "New user restrictions need to be set by default for user " + userId);
 
         if (VERBOSE_LOG) {
@@ -3370,7 +3416,7 @@
         updateNetworkPreferenceForUser(userId, preferentialNetworkServiceConfigs);
 
         startOwnerService(userId, "start-user");
-        if (isDevicePolicyEngineFlagEnabled()) {
+        if (isDevicePolicyEngineEnabled()) {
             mDevicePolicyEngine.handleStartUser(userId);
         }
     }
@@ -3395,7 +3441,7 @@
 
     void handleUnlockUser(int userId) {
         startOwnerService(userId, "unlock-user");
-        if (isDevicePolicyEngineFlagEnabled()) {
+        if (isDevicePolicyEngineEnabled()) {
             mDevicePolicyEngine.handleUnlockUser(userId);
         }
     }
@@ -3407,7 +3453,7 @@
     void handleStopUser(int userId) {
         updateNetworkPreferenceForUser(userId, List.of(PreferentialNetworkServiceConfig.DEFAULT));
         mDeviceAdminServiceController.stopServicesForUser(userId, /* actionForLog= */ "stop-user");
-        if (isDevicePolicyEngineFlagEnabled()) {
+        if (isDevicePolicyEngineEnabled()) {
             mDevicePolicyEngine.handleStopUser(userId);
         }
     }
@@ -4168,6 +4214,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 +8539,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 +8600,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 +8625,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;
                 }
             }
@@ -9292,8 +9386,7 @@
 
             mInjector.binderWithCleanCallingIdentity(() -> {
                 if (mUserManager.isManagedProfile(userHandle)) {
-                    maybeSetDefaultRestrictionsForAdminLocked(userHandle, admin,
-                            UserRestrictionsUtils.getDefaultEnabledForManagedProfiles());
+                    maybeSetDefaultRestrictionsForAdminLocked(userHandle, admin);
                     ensureUnknownSourcesRestrictionForProfileOwnerLocked(userHandle, admin,
                             true /* newOwner */);
                 }
@@ -11437,7 +11530,7 @@
 
         final int userId = user.id;
 
-        if (isDevicePolicyEngineFlagEnabled()) {
+        if (isDevicePolicyEngineEnabled()) {
             mDevicePolicyEngine.handleUserCreated(user);
         }
 
@@ -12008,7 +12101,8 @@
     }
 
     @Override
-    public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner,
+    public void setUserRestriction(
+            ComponentName who, String callerPackage, String key, boolean enabledFromThisOwner,
             boolean parent) {
         Objects.requireNonNull(who, "ComponentName is null");
 
@@ -12017,18 +12111,13 @@
         if (!UserRestrictionsUtils.isValidRestriction(key)) {
             return;
         }
-
         if (parent) {
             Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller));
         } else {
             Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
         }
-
         int userId = caller.getUserId();
         synchronized (getLockObject()) {
-            final ActiveAdmin activeAdmin = getParentOfAdminIfRequired(
-                    getProfileOwnerOrDeviceOwnerLocked(userId), parent);
-
             if (isDefaultDeviceOwner(caller)) {
                 if (!UserRestrictionsUtils.canDeviceOwnerChange(key)) {
                     throw new SecurityException("Device owner cannot set user restriction " + key);
@@ -12046,27 +12135,119 @@
                 boolean profileOwnerCanChangeOnItself = !parent
                         && UserRestrictionsUtils.canProfileOwnerChange(
                                 key, userId == getMainUserId());
-                boolean orgOwnedProfileOwnerCanChangesGlobally = parent
+                boolean orgOwnedProfileOwnerCanChangeGlobally = parent
                         && isProfileOwnerOfOrganizationOwnedDevice(caller)
                         && UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange(
                         key);
 
-                if (!profileOwnerCanChangeOnItself && !orgOwnedProfileOwnerCanChangesGlobally) {
+                if (!profileOwnerCanChangeOnItself && !orgOwnedProfileOwnerCanChangeGlobally) {
                     throw new SecurityException("Profile owner cannot set user restriction " + key);
                 }
             }
-            checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_USER_RESTRICTION);
-
-            // Save the restriction to ActiveAdmin.
-            final Bundle restrictions = activeAdmin.ensureUserRestrictions();
-            if (enabledFromThisOwner) {
-                restrictions.putBoolean(key, true);
-            } else {
-                restrictions.remove(key);
-            }
-            saveUserRestrictionsLocked(userId);
         }
-        final int eventId = enabledFromThisOwner
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_USER_RESTRICTION);
+
+        if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+            EnforcingAdmin admin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
+                    who, caller.getUserId());
+            PolicyDefinition<Boolean> policyDefinition =
+                    PolicyDefinition.getPolicyDefinitionForUserRestriction(key);
+            if (enabledFromThisOwner) {
+                mDevicePolicyEngine.setLocalPolicy(
+                        policyDefinition,
+                        admin,
+                        new BooleanPolicyValue(true),
+                        parent ? getProfileParentId(userId) : userId);
+            } else {
+                // Remove any local and global policy that was set by the admin
+                if (!policyDefinition.isLocalOnlyPolicy()) {
+                    mDevicePolicyEngine.removeGlobalPolicy(
+                            policyDefinition,
+                            admin);
+                }
+                if (!policyDefinition.isGlobalOnlyPolicy()) {
+                    mDevicePolicyEngine.removeLocalPolicy(
+                            policyDefinition,
+                            admin,
+                            userId);
+
+                    int parentUserId = getProfileParentId(userId);
+                    if (parentUserId != userId) {
+                        mDevicePolicyEngine.removeLocalPolicy(
+                                policyDefinition,
+                                admin,
+                                parentUserId);
+                    }
+                }
+            }
+        } else {
+            synchronized (getLockObject()) {
+                final ActiveAdmin activeAdmin = getParentOfAdminIfRequired(
+                        getProfileOwnerOrDeviceOwnerLocked(userId), parent);
+                // Save the restriction to ActiveAdmin.
+                final Bundle restrictions = activeAdmin.ensureUserRestrictions();
+                if (enabledFromThisOwner) {
+                    restrictions.putBoolean(key, true);
+                } else {
+                    restrictions.remove(key);
+                }
+                saveUserRestrictionsLocked(userId);
+            }
+        }
+        logUserRestrictionCall(key, enabledFromThisOwner, parent, caller);
+    }
+
+    @Override
+    public void setUserRestrictionGlobally(String callerPackage, String key) {
+        final CallerIdentity caller = getCallerIdentity(callerPackage);
+        // TODO: Replace with new permission checks, for now copying this over from
+        //  setUserRestriction
+        if (!UserRestrictionsUtils.isValidRestriction(key)) {
+            return;
+        }
+        Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
+
+        int userHandle = caller.getUserId();
+        if (isDefaultDeviceOwner(caller)) {
+            if (!UserRestrictionsUtils.canDeviceOwnerChange(key)) {
+                throw new SecurityException("Device owner cannot set user restriction " + key);
+            }
+        } else if (isFinancedDeviceOwner(caller)) {
+            if (!UserRestrictionsUtils.canFinancedDeviceOwnerChange(key)) {
+                throw new SecurityException("Cannot set user restriction " + key
+                        + " when managing a financed device");
+            }
+        } else {
+            boolean profileOwnerCanChangeOnItself =
+                    UserRestrictionsUtils.canProfileOwnerChange(key, userHandle == getMainUserId());
+            boolean orgOwnedProfileOwnerCanChangeGlobally =
+                    isProfileOwnerOfOrganizationOwnedDevice(caller)
+                    && UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange(
+                    key);
+
+            if (!profileOwnerCanChangeOnItself && !orgOwnedProfileOwnerCanChangeGlobally) {
+                throw new SecurityException("Profile owner cannot set user restriction " + key);
+            }
+        }
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_USER_RESTRICTION);
+
+        if (!useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+            throw new IllegalStateException("One or more admins are not targeting Android 14.");
+        }
+        EnforcingAdmin admin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
+                caller.getPackageName(), caller.getUserId());
+
+        mDevicePolicyEngine.setGlobalPolicy(
+                PolicyDefinition.getPolicyDefinitionForUserRestriction(key),
+                admin,
+                new BooleanPolicyValue(true));
+
+        logUserRestrictionCall(key, /* enabled= */ true, /* parent= */ false, caller);
+    }
+
+    private void logUserRestrictionCall(
+            String key, boolean enabled, boolean parent, CallerIdentity caller) {
+        final int eventId = enabled
                 ? DevicePolicyEnums.ADD_USER_RESTRICTION
                 : DevicePolicyEnums.REMOVE_USER_RESTRICTION;
         DevicePolicyEventLogger
@@ -12075,14 +12256,18 @@
                 .setStrings(key, parent ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT)
                 .write();
         if (SecurityLog.isLoggingEnabled()) {
-            final int eventTag = enabledFromThisOwner
+            final int eventTag = enabled
                     ? SecurityLog.TAG_USER_RESTRICTION_ADDED
                     : SecurityLog.TAG_USER_RESTRICTION_REMOVED;
-            SecurityLog.writeEvent(eventTag, who.getPackageName(), userId, key);
+            SecurityLog.writeEvent(eventTag, caller.getPackageName(), caller.getUserId(), key);
         }
     }
 
     private void saveUserRestrictionsLocked(int userId) {
+        if (isDevicePolicyEngineEnabled()) {
+            // User restrictions are handled in the policy engine
+            return;
+        }
         saveSettingsLocked(userId);
         pushUserRestrictions(userId);
         sendChangedNotification(userId);
@@ -12144,7 +12329,7 @@
     }
 
     @Override
-    public Bundle getUserRestrictions(ComponentName who, boolean parent) {
+    public Bundle getUserRestrictions(ComponentName who, String callerPackage, boolean parent) {
         if (!mHasFeature) {
             return null;
         }
@@ -12156,14 +12341,59 @@
                 || isProfileOwner(caller)
                 || (parent && isProfileOwnerOfOrganizationOwnedDevice(caller)));
 
-        synchronized (getLockObject()) {
-            final ActiveAdmin activeAdmin = getParentOfAdminIfRequired(
-                    getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()), parent);
-            return activeAdmin.userRestrictions;
+        if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+            return getUserRestrictionsFromPolicyEngine(
+                    EnforcingAdmin.createEnterpriseEnforcingAdmin(who, caller.getUserId()),
+                    parent ? getProfileParentId(caller.getUserId()) : caller.getUserId());
+        } else {
+            synchronized (getLockObject()) {
+                final ActiveAdmin activeAdmin = getParentOfAdminIfRequired(
+                        getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()), parent);
+                return activeAdmin.userRestrictions;
+            }
         }
     }
 
     @Override
+    public Bundle getUserRestrictionsGlobally(String callerPackage) {
+        if (!mHasFeature) {
+            return null;
+        }
+        final CallerIdentity caller = getCallerIdentity(callerPackage);
+        if (!useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+            throw new IllegalStateException("One or more admins are not targeting Android 14.");
+        }
+        // TODO: Replace with new permission checks, for now copying this over from
+        //  setUserRestriction
+        Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
+                || isFinancedDeviceOwner(caller)
+                || isProfileOwner(caller));
+
+        return getUserRestrictionsFromPolicyEngine(
+                EnforcingAdmin.createEnterpriseEnforcingAdmin(
+                        caller.getPackageName(), caller.getUserId()),
+                UserHandle.USER_ALL);
+    }
+
+    /**
+     * Returns user restrictions set by the given admin for the provided {@code userId}.
+     *
+     * <p>Pass in {@link UserHandle#USER_ALL} for {@code userId} to get global restrictions set by
+     * the admin
+     */
+    private Bundle getUserRestrictionsFromPolicyEngine(EnforcingAdmin admin, int userId) {
+        Set<UserRestrictionPolicyKey> restrictionKeys =
+                mDevicePolicyEngine.getUserRestrictionPolicyKeysForAdmin(
+                        admin,
+                        userId);
+        Bundle restrictions = new Bundle();
+        for (UserRestrictionPolicyKey key : restrictionKeys) {
+            restrictions.putBoolean(key.getRestriction(), true);
+        }
+        return restrictions;
+    }
+
+    @Override
     public boolean setApplicationHidden(ComponentName who, String callerPackage, String packageName,
             boolean hidden, boolean parent) {
         final CallerIdentity caller = getCallerIdentity(who, callerPackage);
@@ -13573,7 +13803,8 @@
                             + " should be used instead.");
                 } else {
                     try {
-                        setUserRestriction(who, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
+                        setUserRestriction(who, who.getPackageName(),
+                                UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
                                 (Integer.parseInt(value) == 0) ? true : false, /* parent */ false);
                         DevicePolicyEventLogger
                                 .createEvent(DevicePolicyEnums.SET_SECURE_SETTING)
@@ -13630,7 +13861,8 @@
         checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_MASTER_VOLUME_MUTED);
 
         synchronized (getLockObject()) {
-            setUserRestriction(who, UserManager.DISALLOW_UNMUTE_DEVICE, on, /* parent */ false);
+            setUserRestriction(who, who.getPackageName(), UserManager.DISALLOW_UNMUTE_DEVICE, on,
+                    /* parent */ false);
             DevicePolicyEventLogger
                     .createEvent(DevicePolicyEnums.SET_MASTER_VOLUME_MUTED)
                     .setAdmin(who)
@@ -13776,6 +14008,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 +15853,7 @@
             EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
                     who,
                     MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+                    caller.getPackageName(),
                     caller.getUserId());
             admin = enforcingAdmin.getActiveAdmin();
         } else {
@@ -15631,6 +15884,7 @@
             EnforcingAdmin enforcingAdmin = enforceCanQueryAndGetEnforcingAdmin(
                     who,
                     MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+                    caller.getPackageName(),
                     caller.getUserId());
             admin = enforcingAdmin.getActiveAdmin();
         } else {
@@ -18220,6 +18474,15 @@
                 }
             });
         }
+        String[] appOpExemptions = new String[exemptions.length];
+        for (int i = 0; i < exemptions.length; i++) {
+            appOpExemptions[i] = APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS.get(exemptions[i]);
+        }
+        DevicePolicyEventLogger
+            .createEvent(DevicePolicyEnums.SET_APPLICATION_EXEMPTIONS)
+            .setAdmin(caller.getPackageName())
+            .setStrings(packageName, appOpExemptions)
+            .write();
     }
 
     @Override
@@ -18679,6 +18942,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 +19389,7 @@
             }
             setUserSetupComplete(userInfo.id);
 
-            startUser(userInfo.id, callerPackage);
+            startProfileForSetup(userInfo.id, callerPackage);
             maybeMigrateAccount(
                     userInfo.id, caller.getUserId(), provisioningParams.getAccountToMigrate(),
                     provisioningParams.isKeepingAccountOnMigration(), callerPackage);
@@ -19280,8 +19620,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 +19633,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 +19647,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 +20743,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 +20760,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 +20906,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 +20919,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() {
@@ -21126,10 +21469,14 @@
             }
             return true;
         } else {
-            return isDevicePolicyEngineFlagEnabled() && !hasDPCsNotSupportingCoexistence();
+            return isDevicePolicyEngineEnabled();
         }
     }
 
+    private boolean isDevicePolicyEngineEnabled() {
+        return isDevicePolicyEngineFlagEnabled() && !hasDPCsNotSupportingCoexistence();
+    }
+
     private boolean isDevicePolicyEngineFlagEnabled() {
         return DeviceConfig.getBoolean(
                 NAMESPACE_DEVICE_POLICY_MANAGER,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
index 10e972d..7ed148b 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(
@@ -92,6 +93,15 @@
                 activeAdmin);
     }
 
+
+    static EnforcingAdmin createEnterpriseEnforcingAdmin(
+            @NonNull String packageName, int userId) {
+        Objects.requireNonNull(packageName);
+        return new EnforcingAdmin(
+                packageName, /* componentName= */ null, Set.of(DPC_AUTHORITY), userId,
+                /* activeAdmin= */ null);
+    }
+
     static EnforcingAdmin createDeviceAdminEnforcingAdmin(ComponentName componentName, int userId) {
         Objects.requireNonNull(componentName);
         return new EnforcingAdmin(
@@ -111,11 +121,27 @@
         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) {
+            String packageName, @Nullable ComponentName componentName, Set<String> authorities,
+            int userId, @Nullable ActiveAdmin activeAdmin) {
         Objects.requireNonNull(packageName);
-        Objects.requireNonNull(componentName);
         Objects.requireNonNull(authorities);
 
         // Role authorities should not be using this constructor
@@ -127,7 +153,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 +163,7 @@
         mComponentName = null;
         // authorities will be loaded when needed
         mAuthorities = null;
-        mActiveAdmin = null;
+        mActiveAdmin = activeAdmin;
     }
 
     private static Set<String> getRoleAuthoritiesOrDefault(String packageName, int userId) {
@@ -244,10 +270,12 @@
     @Override
     public int hashCode() {
         if (mIsRoleAuthority) {
-            // TODO(b/256854977): should we add UserId?
-            return Objects.hash(mPackageName);
+            return Objects.hash(mPackageName, mUserId);
         } else {
-            return Objects.hash(mComponentName, getAuthorities());
+            return Objects.hash(
+                    mComponentName == null ? mPackageName : mComponentName,
+                    mUserId,
+                    getAuthorities());
         }
     }
 
@@ -256,8 +284,10 @@
         serializer.attributeBoolean(/* namespace= */ null, ATTR_IS_ROLE, mIsRoleAuthority);
         serializer.attributeInt(/* namespace= */ null, ATTR_USER_ID, mUserId);
         if (!mIsRoleAuthority) {
-            serializer.attribute(
-                    /* namespace= */ null, ATTR_CLASS_NAME, mComponentName.getClassName());
+            if (mComponentName != null) {
+                serializer.attribute(
+                        /* namespace= */ null, ATTR_CLASS_NAME, mComponentName.getClassName());
+            }
             // Role authorities get recomputed on load so no need to save them.
             serializer.attribute(
                     /* namespace= */ null,
@@ -274,10 +304,11 @@
         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);
+            ComponentName componentName = className == null
+                    ? null :  new ComponentName(packageName, className);
             Set<String> authorities = Set.of(authoritiesStr.split(ATTR_AUTHORITIES_SEPARATOR));
             return new EnforcingAdmin(packageName, componentName, authorities, userId, null);
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 9e0da26..a08c2054 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;
@@ -28,10 +29,12 @@
 import android.app.admin.PackagePolicyKey;
 import android.app.admin.PolicyKey;
 import android.app.admin.PolicyValue;
+import android.app.admin.UserRestrictionPolicyKey;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.IntentFilter;
 import android.os.Bundle;
+import android.os.UserManager;
 
 import com.android.internal.util.function.QuadFunction;
 import com.android.modules.utils.TypedXmlPullParser;
@@ -40,6 +43,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -66,6 +70,11 @@
     // global policy please add support.
     private static final int POLICY_FLAG_NON_COEXISTABLE_POLICY = 1 << 3;
 
+    // Add this flag to any policy that is a user restriction, the reason for this is that there
+    // are some special APIs to handle user restriction policies and this is the way we can identify
+    // them.
+    private static final int POLICY_FLAG_USER_RESTRICTION_POLICY = 1 << 4;
+
     private static final MostRestrictive<Boolean> FALSE_MORE_RESTRICTIVE = new MostRestrictive<>(
             List.of(new BooleanPolicyValue(false), new BooleanPolicyValue(true)));
 
@@ -73,7 +82,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 +95,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 +122,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 +141,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 +154,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 +175,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 +185,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 +202,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 +211,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 +233,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<>(),
@@ -233,19 +246,124 @@
             (Long value, Context context, Integer userId, PolicyKey policyKey) -> true,
             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,
-            USER_CONTROLLED_DISABLED_PACKAGES,
-            DevicePolicyManager.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
-    );
+    private static final Map<String, PolicyDefinition<?>> POLICY_DEFINITIONS = new HashMap<>();
+    private static Map<String, Integer> USER_RESTRICTION_FLAGS = new HashMap<>();
 
+    static {
+        POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY, AUTO_TIMEZONE);
+        POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY,
+                GENERIC_PERMISSION_GRANT);
+        POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.LOCK_TASK_POLICY, LOCK_TASK);
+        POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY,
+                USER_CONTROLLED_DISABLED_PACKAGES);
+        POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY,
+                GENERIC_PERSISTENT_PREFERRED_ACTIVITY);
+        POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY,
+                GENERIC_PACKAGE_UNINSTALL_BLOCKED);
+        POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY,
+                GENERIC_APPLICATION_RESTRICTIONS);
+        POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.RESET_PASSWORD_TOKEN_POLICY,
+                RESET_PASSWORD_TOKEN);
+
+        // User Restriction Policies
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MODIFY_ACCOUNTS, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_WIFI, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(
+                UserManager.DISALLOW_CHANGE_WIFI_STATE, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+        USER_RESTRICTION_FLAGS.put(
+                UserManager.DISALLOW_WIFI_TETHERING, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_GRANT_ADMIN, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(
+                UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+        USER_RESTRICTION_FLAGS.put(
+                UserManager.DISALLOW_WIFI_DIRECT, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+        USER_RESTRICTION_FLAGS.put(
+                UserManager.DISALLOW_ADD_WIFI_CONFIG, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_LOCALE, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_INSTALL_APPS, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNINSTALL_APPS, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SHARE_LOCATION, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(
+                UserManager.DISALLOW_AIRPLANE_MODE, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_BRIGHTNESS, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_AMBIENT_DISPLAY, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY,
+                POLICY_FLAG_GLOBAL_ONLY_POLICY);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_BLUETOOTH, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BLUETOOTH, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BLUETOOTH_SHARING, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(
+                UserManager.DISALLOW_USB_FILE_TRANSFER, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_CREDENTIALS, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_REMOVE_USER, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_DEBUGGING_FEATURES, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_VPN, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_LOCATION, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_DATE_TIME, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(
+                UserManager.DISALLOW_CONFIG_TETHERING, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(
+                UserManager.DISALLOW_NETWORK_RESET, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_FACTORY_RESET, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_USER, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_MANAGED_PROFILE, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_CLONE_PROFILE, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.ENSURE_VERIFY_APPS, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_APPS_CONTROL, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNMUTE_MICROPHONE, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADJUST_VOLUME, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_OUTGOING_CALLS, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SMS, /* flags= */ 0);
+        // TODO: check if its global only
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_FUN, /* flags= */ 0);
+        // TODO: check if its global only
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CREATE_WINDOWS, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE, /* flags= */ 0);
+        // TODO: check if its global only
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_OUTGOING_BEAM, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_WALLPAPER, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SET_WALLPAPER, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SAFE_BOOT, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_RECORD_AUDIO, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_RUN_IN_BACKGROUND, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CAMERA, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNMUTE_DEVICE, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_DATA_ROAMING, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SET_USER_ICON, /* flags= */ 0);
+            // TODO: double check flags
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_OEM_UNLOCK, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNIFIED_PASSWORD, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_AUTOFILL, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONTENT_CAPTURE, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONTENT_SUGGESTIONS, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(
+                UserManager.DISALLOW_USER_SWITCH, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_PRINTING, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(
+                UserManager.DISALLOW_CONFIG_PRIVATE_DNS, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MICROPHONE_TOGGLE, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CAMERA_TOGGLE, /* flags= */ 0);
+        // TODO: check if its global only
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BIOMETRIC, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_DEFAULT_APPS, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(
+                UserManager.DISALLOW_CELLULAR_2G, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+        USER_RESTRICTION_FLAGS.put(
+                UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+
+        for (String key : USER_RESTRICTION_FLAGS.keySet()) {
+            createAndAddUserRestrictionPolicyDefinition(key, USER_RESTRICTION_FLAGS.get(key));
+        }
+    }
 
     private final PolicyKey mPolicyKey;
     private final ResolutionMechanism<V> mResolutionMechanism;
@@ -260,6 +378,17 @@
                 mPolicyEnforcerCallback, mPolicySerializer);
     }
 
+    static PolicyDefinition<Boolean> getPolicyDefinitionForUserRestriction(
+            @UserManager.UserRestrictionKey String restriction) {
+        String key = DevicePolicyIdentifiers.getIdentifierForUserRestriction(restriction);
+
+        if (!POLICY_DEFINITIONS.containsKey(key)) {
+            throw new IllegalArgumentException("Unsupported user restriction " + restriction);
+        }
+        // All user restrictions are of type boolean
+        return (PolicyDefinition<Boolean>) POLICY_DEFINITIONS.get(key);
+    }
+
     @NonNull
     PolicyKey getPolicyKey() {
         return mPolicyKey;
@@ -298,6 +427,10 @@
         return (mPolicyFlags & POLICY_FLAG_NON_COEXISTABLE_POLICY) != 0;
     }
 
+    boolean isUserRestrictionPolicy() {
+        return (mPolicyFlags & POLICY_FLAG_USER_RESTRICTION_POLICY) != 0;
+    }
+
     @Nullable
     PolicyValue<V> resolvePolicy(LinkedHashMap<EnforcingAdmin, PolicyValue<V>> adminsPolicy) {
         return mResolutionMechanism.resolve(adminsPolicy);
@@ -307,6 +440,21 @@
         return mPolicyEnforcerCallback.apply(value, context, userId, mPolicyKey);
     }
 
+    private static void createAndAddUserRestrictionPolicyDefinition(
+            String restriction, int flags) {
+        String identifier = DevicePolicyIdentifiers.getIdentifierForUserRestriction(restriction);
+        UserRestrictionPolicyKey key = new UserRestrictionPolicyKey(identifier, restriction);
+        flags |= POLICY_FLAG_USER_RESTRICTION_POLICY;
+        PolicyDefinition<Boolean> definition = new PolicyDefinition<>(
+                key,
+                TRUE_MORE_RESTRICTIVE,
+                flags,
+                PolicyEnforcerCallbacks::setUserRestriction,
+                new BooleanPolicySerializer());
+        POLICY_DEFINITIONS.put(key.getIdentifier(), definition);
+    }
+
+
     /**
      * Callers must ensure that {@code policyType} have implemented an appropriate
      * {@link Object#equals} implementation.
@@ -353,7 +501,7 @@
         // TODO: can we avoid casting?
         PolicyKey policyKey = readPolicyKeyFromXml(parser);
         PolicyDefinition<V> genericPolicyDefinition =
-                (PolicyDefinition<V>) sPolicyDefinitions.get(policyKey.getIdentifier());
+                (PolicyDefinition<V>) POLICY_DEFINITIONS.get(policyKey.getIdentifier());
         return genericPolicyDefinition.createPolicyDefinition(policyKey);
     }
 
@@ -362,7 +510,7 @@
         // TODO: can we avoid casting?
         PolicyKey policyKey = PolicyKey.readGenericPolicyKeyFromXml(parser);
         PolicyDefinition<PolicyValue<V>> genericPolicyDefinition =
-                (PolicyDefinition<PolicyValue<V>>) sPolicyDefinitions.get(
+                (PolicyDefinition<PolicyValue<V>>) POLICY_DEFINITIONS.get(
                         policyKey.getIdentifier());
         return genericPolicyDefinition.mPolicyKey.readFromXml(parser);
     }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index 4ae7ca6..daa8a26 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -25,6 +25,7 @@
 import android.app.admin.PackagePermissionPolicyKey;
 import android.app.admin.PackagePolicyKey;
 import android.app.admin.PolicyKey;
+import android.app.admin.UserRestrictionPolicyKey;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.IntentFilter;
@@ -40,6 +41,7 @@
 import android.util.Slog;
 
 import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
 import com.android.server.utils.Slogf;
 
 import java.util.Collections;
@@ -202,4 +204,22 @@
             return true;
         }));
     }
+
+    static boolean setUserRestriction(
+            @Nullable Boolean enabled, @NonNull Context context, int userId,
+            @NonNull PolicyKey policyKey) {
+        return Boolean.TRUE.equals(Binder.withCleanCallingIdentity(() -> {
+            if (!(policyKey instanceof UserRestrictionPolicyKey)) {
+                throw new IllegalArgumentException("policyKey is not of type "
+                        + "UserRestrictionPolicyKey");
+            }
+            UserRestrictionPolicyKey parsedKey =
+                    (UserRestrictionPolicyKey) policyKey;
+            // TODO: call into new UserManager API when merged
+            UserManagerInternal userManager = LocalServices.getService(UserManagerInternal.class);
+//            userManager.setUserRestriction(
+//                    userId, parsedKey.getRestriction(), enabled != null && enabled);
+            return true;
+        }));
+    }
 }
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/searchui/java/com/android/server/searchui/SearchUiManagerService.java b/services/searchui/java/com/android/server/searchui/SearchUiManagerService.java
index 29ad537..c259701 100644
--- a/services/searchui/java/com/android/server/searchui/SearchUiManagerService.java
+++ b/services/searchui/java/com/android/server/searchui/SearchUiManagerService.java
@@ -140,12 +140,6 @@
         }
 
         @Override
-        public void requestEmptyQueryResultUpdate(@NonNull SearchSessionId sessionId) {
-            runForUserLocked("requestEmptyQueryResultUpdate", sessionId,
-                    (service) -> service.requestEmptyQueryResultUpdateLocked(sessionId));
-        }
-
-        @Override
         public void destroySearchSession(@NonNull SearchSessionId sessionId) {
             runForUserLocked("destroySearchSession", sessionId,
                     (service) -> service.onDestroyLocked(sessionId));
diff --git a/services/searchui/java/com/android/server/searchui/SearchUiPerUserService.java b/services/searchui/java/com/android/server/searchui/SearchUiPerUserService.java
index 0d70fff..dc150cf 100644
--- a/services/searchui/java/com/android/server/searchui/SearchUiPerUserService.java
+++ b/services/searchui/java/com/android/server/searchui/SearchUiPerUserService.java
@@ -181,16 +181,6 @@
     }
 
     /**
-     * Requests a new set of search targets for empty query result used for zero state.
-     */
-    @GuardedBy("mLock")
-    public void requestEmptyQueryResultUpdateLocked(@NonNull SearchSessionId sessionId) {
-        final SearchSessionInfo sessionInfo = mSessionInfos.get(sessionId);
-        if (sessionInfo == null) return;
-        resolveService(sessionId, s->s.onRequestEmptyQueryResultUpdate(sessionId));
-    }
-
-    /**
      * Notifies the service of the end of an existing search session.
      */
     @GuardedBy("mLock")
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/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 4524759..95a5884 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -69,6 +69,8 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.LinkedList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 
 @SmallTest
@@ -692,7 +694,10 @@
 
         // Verify that committed triggered a new change event and is set correctly.
         verify(mSurfaceControlProxy, never()).setDisplayPowerMode(display.token, Display.STATE_OFF);
-        assertThat(mListener.changedDisplays.size()).isEqualTo(1);
+        // We expect at least 1 update for the state change, but
+        // could get a second update for the initial brightness change if a nits mapping
+        // is available
+        assertThat(mListener.changedDisplays.size()).isAnyOf(1, 2);
         assertThat(displayDevice.getDisplayDeviceInfoLocked().state).isEqualTo(Display.STATE_OFF);
         assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState).isEqualTo(
                 Display.STATE_OFF);
@@ -964,6 +969,43 @@
                 .isTrue();
     }
 
+    @Test
+    public void testHdrSdrRatio_notifiesOnChange() throws Exception {
+        FakeDisplay display = new FakeDisplay(PORT_A);
+        setUpDisplay(display);
+        updateAvailableDisplays();
+        mAdapter.registerLocked();
+        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+        assertThat(mListener.addedDisplays.size()).isEqualTo(1);
+        DisplayDevice displayDevice = mListener.addedDisplays.get(0);
+
+        // Turn on / initialize
+        Runnable changeStateRunnable = displayDevice.requestDisplayStateLocked(Display.STATE_ON, 0,
+                0);
+        changeStateRunnable.run();
+        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+        mListener.changedDisplays.clear();
+
+        assertEquals(1.0f, displayDevice.getDisplayDeviceInfoLocked().hdrSdrRatio, 0.001f);
+
+        // HDR time!
+        Runnable goHdrRunnable = displayDevice.requestDisplayStateLocked(Display.STATE_ON, 1f,
+                0);
+        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+        // Display state didn't change, no listeners should have happened
+        assertThat(mListener.changedDisplays.size()).isEqualTo(0);
+
+        // Execute hdr change.
+        goHdrRunnable.run();
+        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+        // Display state didn't change, expect to only get the HDR/SDR ratio change notification
+        assertThat(mListener.changedDisplays.size()).isEqualTo(1);
+
+        final float expectedRatio = DISPLAY_RANGE_NITS[1] / DISPLAY_RANGE_NITS[0];
+        assertEquals(expectedRatio, displayDevice.getDisplayDeviceInfoLocked().hdrSdrRatio,
+                0.001f);
+    }
+
     private void assertDisplayDpi(DisplayDeviceInfo info, int expectedPort,
                                   float expectedXdpi,
                                   float expectedYDpi,
@@ -1107,15 +1149,9 @@
 
     private static void waitForHandlerToComplete(Handler handler, long waitTimeMs)
             throws InterruptedException {
-        final Object lock = new Object();
-        synchronized (lock) {
-            handler.post(() -> {
-                synchronized (lock) {
-                    lock.notify();
-                }
-            });
-            lock.wait(waitTimeMs);
-        }
+        final CountDownLatch fence = new CountDownLatch(1);
+        handler.post(fence::countDown);
+        assertTrue(fence.await(waitTimeMs, TimeUnit.MILLISECONDS));
     }
 
     private class HotplugTransmitter {
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
index 3750aa0..2fbbf0d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
@@ -49,6 +49,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
+import android.app.BackgroundStartPrivileges;
 import android.app.IActivityManager;
 import android.app.job.JobInfo;
 import android.content.ComponentName;
@@ -63,6 +64,7 @@
 import android.provider.DeviceConfig;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.SparseIntArray;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -178,6 +180,8 @@
         mGracePeriodObserver = mock(GracePeriodObserver.class);
         mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+        doReturn(BackgroundStartPrivileges.NONE)
+                .when(mActivityManagerInternal).getBackgroundStartPrivileges(anyInt());
         mDefaultUserId = mNextUserId;
         createCurrentUser(true);
         mNextUserId = 10;
@@ -601,34 +605,75 @@
 
     @Test
     public void testHasImmediacyPrivilege() {
-        JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE, 0);
+        final int uid = mDefaultUserId * UserHandle.PER_USER_RANGE;
+        JobStatus job = createJob(uid, 0);
         spyOn(job);
-        assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job));
+        doReturn(BackgroundStartPrivileges.NONE)
+                .when(mActivityManagerInternal).getBackgroundStartPrivileges(uid);
+
+        assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
 
         doReturn(false).when(job).shouldTreatAsExpeditedJob();
         doReturn(false).when(job).shouldTreatAsUserInitiatedJob();
         job.lastEvaluatedBias = JobInfo.BIAS_TOP_APP;
-        assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job));
+        assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
 
         doReturn(true).when(job).shouldTreatAsExpeditedJob();
         doReturn(false).when(job).shouldTreatAsUserInitiatedJob();
         job.lastEvaluatedBias = JobInfo.BIAS_DEFAULT;
-        assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job));
+        assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
 
         doReturn(false).when(job).shouldTreatAsExpeditedJob();
         doReturn(true).when(job).shouldTreatAsUserInitiatedJob();
         job.lastEvaluatedBias = JobInfo.BIAS_DEFAULT;
-        assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job));
+        assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
 
         doReturn(false).when(job).shouldTreatAsExpeditedJob();
         doReturn(true).when(job).shouldTreatAsUserInitiatedJob();
         job.lastEvaluatedBias = JobInfo.BIAS_TOP_APP;
-        assertTrue(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job));
+        assertTrue(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
 
         doReturn(true).when(job).shouldTreatAsExpeditedJob();
         doReturn(false).when(job).shouldTreatAsUserInitiatedJob();
         job.lastEvaluatedBias = JobInfo.BIAS_TOP_APP;
-        assertTrue(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job));
+        assertTrue(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job,
+                new SparseIntArray()));
+
+        doReturn(BackgroundStartPrivileges.ALLOW_FGS)
+                .when(mActivityManagerInternal).getBackgroundStartPrivileges(uid);
+
+        doReturn(false).when(job).shouldTreatAsExpeditedJob();
+        doReturn(false).when(job).shouldTreatAsUserInitiatedJob();
+        job.lastEvaluatedBias = JobInfo.BIAS_DEFAULT;
+        assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
+
+        doReturn(true).when(job).shouldTreatAsExpeditedJob();
+        doReturn(false).when(job).shouldTreatAsUserInitiatedJob();
+        job.lastEvaluatedBias = JobInfo.BIAS_DEFAULT;
+        assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
+
+        doReturn(false).when(job).shouldTreatAsExpeditedJob();
+        doReturn(true).when(job).shouldTreatAsUserInitiatedJob();
+        job.lastEvaluatedBias = JobInfo.BIAS_DEFAULT;
+        assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
+
+        doReturn(BackgroundStartPrivileges.ALLOW_BAL)
+                .when(mActivityManagerInternal).getBackgroundStartPrivileges(uid);
+
+        doReturn(false).when(job).shouldTreatAsExpeditedJob();
+        doReturn(false).when(job).shouldTreatAsUserInitiatedJob();
+        job.lastEvaluatedBias = JobInfo.BIAS_DEFAULT;
+        assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
+
+        doReturn(true).when(job).shouldTreatAsExpeditedJob();
+        doReturn(false).when(job).shouldTreatAsUserInitiatedJob();
+        job.lastEvaluatedBias = JobInfo.BIAS_DEFAULT;
+        assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
+
+        doReturn(false).when(job).shouldTreatAsExpeditedJob();
+        doReturn(true).when(job).shouldTreatAsUserInitiatedJob();
+        job.lastEvaluatedBias = JobInfo.BIAS_DEFAULT;
+        assertTrue(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
     }
 
     @Test
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/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
index b5c5582..120ddf6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -49,6 +49,7 @@
 import com.android.server.SystemService;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -156,6 +157,7 @@
 
     @SmallTest
     @Test
+    @Ignore("b/269249457")
     public void testCompMigrationAffiliated() throws Exception {
         prepareAdmin1AsDo();
         prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.R);
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/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
index 0d6bb8a..566c6b0 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
@@ -570,7 +570,7 @@
                     .setAutoDetectionEnabledSetting(false)
                     .build();
             assertFalse(config.getAutoDetectionEnabledBehavior());
-            assertTrue(config.isGeoDetectionExecutionEnabled());
+            assertFalse(config.isGeoDetectionExecutionEnabled());
             assertEquals(DETECTION_MODE_MANUAL, config.getDetectionMode());
         }
     }
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/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java
index 7b1db95..aeb8ec8 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java
@@ -24,6 +24,7 @@
 import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_UNKNOWN;
 
 import static com.android.server.timezonedetector.ConfigurationInternal.DETECTION_MODE_MANUAL;
+import static com.android.server.timezonedetector.ConfigurationInternal.DETECTION_MODE_TELEPHONY;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DESTROYED;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_CERTAIN;
@@ -1385,6 +1386,37 @@
     }
 
     /**
+     * A controller-state-only test to prove that "run in background" doesn't enable the
+     * location-based time zone detection algorithm to run when auto detection is disabled.
+     */
+    @Test
+    public void geoDetectionRunInBackground_obeysAutoDetectionDisabled() {
+        LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
+                mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+                mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
+
+        // A configuration where the user has auto detection disabled.
+        ConfigurationInternal autoTimeZoneDisabledConfig =
+                new ConfigurationInternal.Builder(USER1_CONFIG_GEO_DETECTION_DISABLED)
+                        .setLocationEnabledSetting(true)
+                        .setAutoDetectionEnabledSetting(false)
+                        .setGeoDetectionEnabledSetting(true)
+                        .setGeoDetectionRunInBackgroundEnabled(true)
+                        .build();
+        assertEquals(DETECTION_MODE_MANUAL, autoTimeZoneDisabledConfig.getDetectionMode());
+        assertFalse(autoTimeZoneDisabledConfig.isGeoDetectionExecutionEnabled());
+
+        TestEnvironment testEnvironment = new TestEnvironment(
+                mTestThreadingDomain, controller, autoTimeZoneDisabledConfig);
+
+        // Initialize and check initial state.
+        controller.initialize(testEnvironment, mTestCallback);
+
+        assertControllerState(controller, STATE_STOPPED);
+        mTestMetricsLogger.assertStateChangesAndCommit(STATE_PROVIDERS_INITIALIZING, STATE_STOPPED);
+    }
+
+    /**
      * A controller-state-only test to prove that "run in background" configuration behaves as
      * intended. Provider states are well covered by other "enabled" tests.
      */
@@ -1398,7 +1430,7 @@
         ConfigurationInternal runInBackgroundDisabledConfig =
                 new ConfigurationInternal.Builder(USER1_CONFIG_GEO_DETECTION_DISABLED)
                         .setLocationEnabledSetting(true)
-                        .setAutoDetectionEnabledSetting(false)
+                        .setAutoDetectionEnabledSetting(true)
                         .setGeoDetectionEnabledSetting(false)
                         .setGeoDetectionRunInBackgroundEnabled(false)
                         .build();
@@ -1408,7 +1440,7 @@
                 new ConfigurationInternal.Builder(runInBackgroundDisabledConfig)
                         .setGeoDetectionRunInBackgroundEnabled(true)
                         .build();
-        assertEquals(DETECTION_MODE_MANUAL, runInBackgroundEnabledConfig.getDetectionMode());
+        assertEquals(DETECTION_MODE_TELEPHONY, runInBackgroundEnabledConfig.getDetectionMode());
         assertTrue(runInBackgroundEnabledConfig.isGeoDetectionExecutionEnabled());
 
         TestEnvironment testEnvironment = new TestEnvironment(
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 009b259..687696a 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -203,6 +203,7 @@
 
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.internal.config.sysui.TestableFlagResolver;
 import com.android.internal.logging.InstanceIdSequence;
 import com.android.internal.logging.InstanceIdSequenceFake;
 import com.android.internal.messages.nano.SystemMessageProto;
@@ -376,7 +377,7 @@
     NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
     TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker;
 
-    TestFlagResolver mTestFlagResolver = new TestFlagResolver();
+    TestableFlagResolver mTestFlagResolver = new TestableFlagResolver();
 
     private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
             1 << 30);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index 6f2627a..a3977ba 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -64,6 +64,7 @@
 import androidx.test.InstrumentationRegistry;
 
 import com.android.internal.app.IAppOpsService;
+import com.android.internal.config.sysui.TestableFlagResolver;
 import com.android.internal.logging.InstanceIdSequence;
 import com.android.internal.logging.InstanceIdSequenceFake;
 import com.android.server.LocalServices;
@@ -168,7 +169,7 @@
                     mock(ActivityManagerInternal.class),
                     mock(MultiRateLimiter.class), mock(PermissionHelper.class),
                     mock(UsageStatsManagerInternal.class), mock (TelecomManager.class),
-                    mock(NotificationChannelLogger.class), new TestFlagResolver());
+                    mock(NotificationChannelLogger.class), new TestableFlagResolver());
         } catch (SecurityException e) {
             if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
                 throw e;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 3344bdb..1d0715a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -222,7 +222,7 @@
     }
 
     @Override
-    public void onKeyguardOccludedChangedLw(boolean occluded) {
+    public void onKeyguardOccludedChangedLw(boolean occluded, boolean waitAppTransition) {
     }
 
     public void setSafeMode(boolean safeMode) {
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/ISatelliteStateListener.aidl b/telephony/java/android/telephony/satellite/ISatelliteStateListener.aidl
index 0ce9c98..cc4c543 100644
--- a/telephony/java/android/telephony/satellite/ISatelliteStateListener.aidl
+++ b/telephony/java/android/telephony/satellite/ISatelliteStateListener.aidl
@@ -26,7 +26,8 @@
 oneway interface ISatelliteStateListener {
     void onSatelliteProvisionStateChanged(in boolean provisioned);
     void onSatellitePositionUpdate(in PointingInfo pointingInfo);
-    void onMessageTransferStateUpdate(in int state);
+    void onMessageTransferStateUpdate(in int state, in int sendPendingCount,
+            in int receivePendingCount, in int errorCode);
     void onSatelliteModemStateChange(in int state);
     void onPendingMessageCount(in int count);
     void onSatelliteDatagrams(in SatelliteDatagram[] datagrams);
diff --git a/telephony/java/android/telephony/satellite/SatelliteCallback.java b/telephony/java/android/telephony/satellite/SatelliteCallback.java
index 5250562..7f24a2f 100644
--- a/telephony/java/android/telephony/satellite/SatelliteCallback.java
+++ b/telephony/java/android/telephony/satellite/SatelliteCallback.java
@@ -20,7 +20,6 @@
 import android.os.Binder;
 
 import java.lang.ref.WeakReference;
-import java.util.List;
 import java.util.concurrent.Executor;
 
 /**
@@ -70,7 +69,7 @@
     }
 
     /**
-     * Interface for position update change listener.
+     * Interface for position update and message transfer state change listener.
      */
     public interface SatellitePositionUpdateListener {
         /**
@@ -84,9 +83,13 @@
          * Called when satellite message transfer state changes.
          *
          * @param state The new message transfer state.
+         * @param sendPendingCount The number of messages that are currently being sent.
+         * @param receivePendingCount The number of messages that are currently being received.
+         * @param errorCode If message transfer failed, the reason for failure.
          */
         void onMessageTransferStateUpdate(
-                @SatelliteManager.SatelliteMessageTransferState int state);
+                @SatelliteManager.SatelliteMessageTransferState int state, int sendPendingCount,
+                int receivePendingCount, @SatelliteManager.SatelliteError int errorCode);
     }
 
     /**
@@ -95,13 +98,13 @@
     public interface SatelliteStateListener {
         /**
          * Called when satellite state changes.
-         * @param state - The new satellite state.
+         * @param state The new satellite state.
          */
         void onSatelliteModemStateChange(@SatelliteManager.SatelliteModemState int state);
 
         /**
          * Called when there are pending messages to be received from satellite.
-         * @param count - pending message count.
+         * @param count Pending message count.
          */
         void onPendingMessageCount(int count);
     }
@@ -112,7 +115,7 @@
     public interface SatelliteDatagramListener {
         /**
          * Called when there are incoming datagrams to be received.
-         * @param datagrams - datagrams to be received over satellite.
+         * @param datagrams Datagrams to be received over satellite.
          */
         void onSatelliteDatagrams(SatelliteDatagram[] datagrams);
     }
@@ -145,13 +148,15 @@
         }
 
         public void onMessageTransferStateUpdate(
-                @SatelliteManager.SatelliteMessageTransferState int state) {
+                @SatelliteManager.SatelliteMessageTransferState int state, int sendPendingCount,
+                int receivePendingCount, @SatelliteManager.SatelliteError int errorCode) {
             SatellitePositionUpdateListener listener =
                     (SatellitePositionUpdateListener) mSatelliteCallbackWeakRef.get();
             if (listener == null) return;
 
             Binder.withCleanCallingIdentity(() -> mExecutor.execute(
-                    () -> listener.onMessageTransferStateUpdate(state)));
+                    () -> listener.onMessageTransferStateUpdate(
+                            state, sendPendingCount, receivePendingCount, errorCode)));
         }
 
 
diff --git a/telephony/java/android/telephony/satellite/SatelliteCapabilities.java b/telephony/java/android/telephony/satellite/SatelliteCapabilities.java
index c5ae4db..74f6f57 100644
--- a/telephony/java/android/telephony/satellite/SatelliteCapabilities.java
+++ b/telephony/java/android/telephony/satellite/SatelliteCapabilities.java
@@ -33,8 +33,8 @@
     private Set<Integer> mSupportedRadioTechnologies;
 
     /**
-     * Whether satellite mode is always on (this to indicate power impact of keeping it on is
-     * very minimal).
+     * Whether satellite modem is always on.
+     * This indicates the power impact of keeping it on is very minimal.
      */
     private boolean mIsAlwaysOn;
 
@@ -44,12 +44,7 @@
     private boolean mNeedsPointingToSatellite;
 
     /**
-     * List of features supported by the Satellite modem.
-     */
-    private Set<Integer> mSupportedFeatures;
-
-    /**
-     * Whether UE needs a separate SIM profile to communicate with the Satellite network.
+     * Whether UE needs a separate SIM profile to communicate with the satellite network.
      */
     private boolean mNeedsSeparateSimProfile;
 
@@ -57,12 +52,10 @@
      * @hide
      */
     public SatelliteCapabilities(Set<Integer> supportedRadioTechnologies, boolean isAlwaysOn,
-            boolean needsPointingToSatellite, Set<Integer> supportedFeatures,
-            boolean needsSeparateSimProfile) {
+            boolean needsPointingToSatellite, boolean needsSeparateSimProfile) {
         mSupportedRadioTechnologies = supportedRadioTechnologies;
         mIsAlwaysOn = isAlwaysOn;
         mNeedsPointingToSatellite = needsPointingToSatellite;
-        mSupportedFeatures = supportedFeatures;
         mNeedsSeparateSimProfile = needsSeparateSimProfile;
     }
 
@@ -88,35 +81,23 @@
 
         out.writeBoolean(mIsAlwaysOn);
         out.writeBoolean(mNeedsPointingToSatellite);
-
-        if (mSupportedFeatures != null && !mSupportedFeatures.isEmpty()) {
-            out.writeInt(mSupportedFeatures.size());
-            for (int feature : mSupportedFeatures) {
-                out.writeInt(feature);
-            }
-        } else {
-            out.writeInt(0);
-        }
-
         out.writeBoolean(mNeedsSeparateSimProfile);
     }
 
-    public static final @android.annotation.NonNull Creator<SatelliteCapabilities> CREATOR =
-            new Creator<SatelliteCapabilities>() {
-                @Override
-                public SatelliteCapabilities createFromParcel(Parcel in) {
-                    return new SatelliteCapabilities(in);
-                }
+    @NonNull public static final Creator<SatelliteCapabilities> CREATOR = new Creator<>() {
+        @Override
+        public SatelliteCapabilities createFromParcel(Parcel in) {
+            return new SatelliteCapabilities(in);
+        }
 
-                @Override
-                public SatelliteCapabilities[] newArray(int size) {
-                    return new SatelliteCapabilities[size];
-                }
-            };
+        @Override
+        public SatelliteCapabilities[] newArray(int size) {
+            return new SatelliteCapabilities[size];
+        }
+    };
 
-    @NonNull
     @Override
-    public String toString() {
+    @NonNull public String toString() {
         StringBuilder sb = new StringBuilder();
 
         sb.append("SupportedRadioTechnology:");
@@ -129,16 +110,6 @@
             sb.append("none,");
         }
 
-        sb.append("SupportedFeatures:");
-        if (mSupportedFeatures != null && !mSupportedFeatures.isEmpty()) {
-            for (int feature : mSupportedFeatures) {
-                sb.append(feature);
-                sb.append(",");
-            }
-        } else {
-            sb.append("none,");
-        }
-
         sb.append("isAlwaysOn:");
         sb.append(mIsAlwaysOn);
         sb.append(",");
@@ -152,26 +123,39 @@
         return sb.toString();
     }
 
-    @NonNull
-    public Set<Integer> getSupportedRadioTechnologies() {
+    /**
+     * @return The list of technologies supported by the satellite modem.
+     */
+    @NonNull public Set<Integer> getSupportedRadioTechnologies() {
         return mSupportedRadioTechnologies;
     }
 
+    /**
+     * Get whether the satellite modem is always on.
+     * This indicates the power impact of keeping it on is very minimal.
+     *
+     * @return {@code true} if the satellite modem is always on and {@code false} otherwise.
+     */
     public boolean isAlwaysOn() {
         return mIsAlwaysOn;
     }
 
-    /** Get function for mNeedsPointingToSatellite */
+    /**
+     * Get whether UE needs to point to a satellite to send and receive data.
+     *
+     * @return {@code true} if UE needs to pointing to a satellite to send and receive data and
+     *         {@code false} otherwise.
+     */
     public boolean needsPointingToSatellite() {
         return mNeedsPointingToSatellite;
     }
 
-    @NonNull
-    public Set<Integer> getSupportedFeatures() {
-        return mSupportedFeatures;
-    }
-
-    /** Get function for mNeedsSeparateSimProfile */
+    /**
+     * Get whether UE needs a separate SIM profile to communicate with the satellite network.
+     *
+     * @return {@code true} if UE needs a separate SIM profile to comunicate with the satellite
+     *         network and {@code false} otherwise.
+     */
     public boolean needsSeparateSimProfile() {
         return mNeedsSeparateSimProfile;
     }
@@ -187,15 +171,6 @@
 
         mIsAlwaysOn = in.readBoolean();
         mNeedsPointingToSatellite = in.readBoolean();
-
-        mSupportedFeatures = new HashSet<>();
-        int numSupportedFeatures = in.readInt();
-        if (numSupportedFeatures > 0) {
-            for (int i = 0; i < numSupportedFeatures; i++) {
-                mSupportedFeatures.add(in.readInt());
-            }
-        }
-
         mNeedsSeparateSimProfile = in.readBoolean();
     }
 }
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 5f6218d..9ce4310 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -144,6 +144,21 @@
     public static final String KEY_SATELLITE_PROVISIONED = "satellite_provisioned";
 
     /**
+     * Bundle key to get the response from
+     * {@link #requestIsSatelliteCommunicationAllowedForCurrentLocation(Executor, OutcomeReceiver)}.
+     * @hide
+     */
+    public static final String KEY_SATELLITE_COMMUNICATION_ALLOWED =
+            "satellite_communication_allowed";
+
+    /**
+     * Bundle key to get the response from
+     * {@link #requestTimeForNextSatelliteVisibility(Executor, OutcomeReceiver)}.
+     * @hide
+     */
+    public static final String KEY_SATELLITE_NEXT_VISIBILITY = "satellite_next_visibility";
+
+    /**
      * The request was successfully processed.
      */
     public static final int SATELLITE_ERROR_NONE = 0;
@@ -294,7 +309,7 @@
                 throw new IllegalStateException("telephony service is null.");
             }
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "setSatelliteEnabled RemoteException: ", ex);
+            Rlog.e(TAG, "setSatelliteEnabled() RemoteException: ", ex);
             ex.rethrowFromSystemServer();
         }
     }
@@ -460,33 +475,45 @@
     }
 
     /**
-     * Message transfer is waiting to acquire.
+     * The default state indicating that message transfer is idle.
+     * This should be sent immediately after either
+     * {@link #SATELLITE_MESSAGE_TRANSFER_STATE_SUCCESS} or
+     * {@link #SATELLITE_MESSAGE_TRANSFER_STATE_FAILED}.
      */
-    public static final int SATELLITE_MESSAGE_TRANSFER_STATE_WAITING_TO_ACQUIRE = 0;
+    public static final int SATELLITE_MESSAGE_TRANSFER_STATE_IDLE = 0;
     /**
-     * Message is being sent.
+     * A transition state indicating that a message is being sent.
      */
     public static final int SATELLITE_MESSAGE_TRANSFER_STATE_SENDING = 1;
     /**
-     * Message is being received.
+     * A transition state indicating that a message is being received.
      */
     public static final int SATELLITE_MESSAGE_TRANSFER_STATE_RECEIVING = 2;
     /**
-     * Message transfer is being retried.
+     * A transition state indicating that message transfer is being retried.
      */
     public static final int SATELLITE_MESSAGE_TRANSFER_STATE_RETRYING = 3;
     /**
-     * Message transfer is complete.
+     * An end state indicating that message transfer completed successfully.
+     * After message transfer completes, {@link #SATELLITE_MESSAGE_TRANSFER_STATE_IDLE}
+     * must be sent before reporting any additional message transfer state changes.
      */
-    public static final int SATELLITE_MESSAGE_TRANSFER_STATE_COMPLETE = 4;
+    public static final int SATELLITE_MESSAGE_TRANSFER_STATE_SUCCESS = 4;
+    /**
+     * An end state indicating that message transfer completed with a failure.
+     * After message transfer completes, {@link #SATELLITE_MESSAGE_TRANSFER_STATE_IDLE}
+     * must be sent before reporting any additional message transfer state changes.
+     */
+    public static final int SATELLITE_MESSAGE_TRANSFER_STATE_FAILED = 5;
 
     /** @hide */
     @IntDef(prefix = {"SATELLITE_MESSAGE_TRANSFER_STATE_"}, value = {
-            SATELLITE_MESSAGE_TRANSFER_STATE_WAITING_TO_ACQUIRE,
+            SATELLITE_MESSAGE_TRANSFER_STATE_IDLE,
             SATELLITE_MESSAGE_TRANSFER_STATE_SENDING,
             SATELLITE_MESSAGE_TRANSFER_STATE_RECEIVING,
             SATELLITE_MESSAGE_TRANSFER_STATE_RETRYING,
-            SATELLITE_MESSAGE_TRANSFER_STATE_COMPLETE
+            SATELLITE_MESSAGE_TRANSFER_STATE_SUCCESS,
+            SATELLITE_MESSAGE_TRANSFER_STATE_FAILED
     })
     public @interface SatelliteMessageTransferState {}
 
@@ -534,6 +561,11 @@
      * Modem should continue to report the pointing input as the device or satellite moves.
      * Satellite position updates are started only on {@link #SATELLITE_ERROR_NONE}.
      * All other results indicate that this operation failed.
+     * Once satellite position updates begin, message transfer state updates will be sent
+     * through {@link SatelliteCallback.SatellitePositionUpdateListener}.
+     * Modem should report any changes in message transfer state and indicate success or failure
+     * by reporting {@link #SATELLITE_MESSAGE_TRANSFER_STATE_SUCCESS} or
+     * {@link #SATELLITE_MESSAGE_TRANSFER_STATE_FAILED}.
      *
      * @param executor The executor on which the callback and error code listener will be called.
      * @param errorCodeListener Listener for the {@link SatelliteError} result of the operation.
@@ -568,7 +600,7 @@
                 throw new IllegalStateException("telephony service is null.");
             }
         } catch (RemoteException ex) {
-            loge("startSatellitePositionUpdates RemoteException: " + ex);
+            loge("startSatellitePositionUpdates() RemoteException: " + ex);
             ex.rethrowFromSystemServer();
         }
     }
@@ -576,8 +608,8 @@
     /**
      * Stop receiving satellite position updates.
      * This can be called by the pointing UI when the user stops pointing to the satellite.
-     * Satellite position updates are stopped only on {@link #SATELLITE_ERROR_NONE}.
-     * All other results indicate that this operation failed.
+     * Satellite position updates are stopped and the callback is unregistered only on
+     * {@link #SATELLITE_ERROR_NONE}. All other results that this operation failed.
      *
      * @param callback The callback that was passed to
      *       {@link #startSatellitePositionUpdates(Executor, Consumer, SatelliteCallback)}.
@@ -585,7 +617,6 @@
      * @param errorCodeListener Listener for the {@link SatelliteError} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
-     * @throws IllegalArgumentException if the callback is invalid.
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@@ -613,7 +644,7 @@
                 throw new IllegalStateException("telephony service is null.");
             }
         } catch (RemoteException ex) {
-            loge("stopSatellitePositionUpdates RemoteException: " + ex);
+            loge("stopSatellitePositionUpdates() RemoteException: " + ex);
             ex.rethrowFromSystemServer();
         }
     }
@@ -671,7 +702,6 @@
         }
     }
 
-
     /**
      * Provision the device with a satellite provider.
      * This is needed if the provider allows dynamic registration.
@@ -712,7 +742,7 @@
                 throw new IllegalStateException("telephony service is null.");
             }
         } catch (RemoteException ex) {
-            loge("provisionSatelliteService RemoteException=" + ex);
+            loge("provisionSatelliteService() RemoteException=" + ex);
             ex.rethrowFromSystemServer();
         }
         if (cancellationSignal != null) {
@@ -757,7 +787,7 @@
                 throw new IllegalStateException("telephony service is null.");
             }
         } catch (RemoteException ex) {
-            loge("deprovisionSatelliteService RemoteException=" + ex);
+            loge("deprovisionSatelliteService() RemoteException=" + ex);
             ex.rethrowFromSystemServer();
         }
     }
@@ -765,90 +795,72 @@
     /**
      * Register for the satellite provision state change.
      *
-     * @param executor The executor on which the callback and error code listener will be called.
-     * @param errorCodeListener Listener for the {@link SatelliteError} result of the operation.
-     * @param callback The callback to handle the satellite provision state changed event. This
-     *                 SatelliteCallback should implement the interface
+     * @param executor The executor on which the callback will be called.
+     * @param callback The callback to handle the satellite provision state changed event.
+     *                 This SatelliteCallback should implement the interface
      *                 {@link SatelliteCallback.SatelliteProvisionStateListener}.
      *
+     * @return The {@link SatelliteError} 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 registerForSatelliteProvisionStateChanged(
-            @NonNull @CallbackExecutor Executor executor,
-            @NonNull Consumer<Integer> errorCodeListener, @NonNull SatelliteCallback callback) {
+    @SatelliteError public int registerForSatelliteProvisionStateChanged(
+            @NonNull @CallbackExecutor Executor executor, @NonNull SatelliteCallback callback) {
         Objects.requireNonNull(executor);
-        Objects.requireNonNull(errorCodeListener);
         Objects.requireNonNull(callback);
 
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 callback.init(executor);
-                IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
-                    @Override
-                    public void accept(int result) {
-                        executor.execute(() -> Binder.withCleanCallingIdentity(
-                                () -> errorCodeListener.accept(result)));
-                    }
-                };
-                telephony.registerForSatelliteProvisionStateChanged(
-                        mSubId, errorCallback, callback.getCallbackStub());
+                return telephony.registerForSatelliteProvisionStateChanged(
+                        mSubId, callback.getCallbackStub());
             } else {
                 throw new IllegalStateException("telephony service is null.");
             }
         } catch (RemoteException ex) {
-            loge("registerForSatelliteProvisionStateChanged RemoteException: " + ex);
+            loge("registerForSatelliteProvisionStateChanged() RemoteException: " + ex);
             ex.rethrowFromSystemServer();
         }
+        return SATELLITE_REQUEST_FAILED;
     }
 
     /**
      * Unregister for the satellite provision state change.
      *
-     * @param callback The callback that was passed to
-     * {@link #registerForSatelliteProvisionStateChanged(Executor, Consumer, SatelliteCallback)}.
-     * @param executor The executor on which the error code listener will be called.
-     * @param errorCodeListener Listener for the {@link SatelliteError} result of the operation.
+     * @param callback The callback that was passed to {@link
+     *                 #registerForSatelliteProvisionStateChanged(Executor, SatelliteCallback)}.
+     *
+     * @return The {@link SatelliteError} 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 unregisterForSatelliteProvisionStateChanged(@NonNull SatelliteCallback callback,
-            @NonNull @CallbackExecutor Executor executor,
-            @NonNull Consumer<Integer> errorCodeListener) {
+    @SatelliteError public int unregisterForSatelliteProvisionStateChanged(
+            @NonNull SatelliteCallback callback) {
         Objects.requireNonNull(callback);
-        Objects.requireNonNull(executor);
-        Objects.requireNonNull(errorCodeListener);
 
         if (callback.getCallbackStub() == null) {
             loge("unregisterForSatelliteProvisionStateChanged: callbackStub is null");
-            executor.execute(() -> Binder.withCleanCallingIdentity(
-                    () -> errorCodeListener.accept(SATELLITE_INVALID_ARGUMENTS)));
-            return;
+            return SATELLITE_INVALID_ARGUMENTS;
         }
 
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
-                    @Override
-                    public void accept(int result) {
-                        executor.execute(() -> Binder.withCleanCallingIdentity(
-                                () -> errorCodeListener.accept(result)));
-                    }
-                };
-                telephony.unregisterForSatelliteProvisionStateChanged(mSubId, errorCallback,
+                return telephony.unregisterForSatelliteProvisionStateChanged(mSubId,
                         callback.getCallbackStub());
             } else {
                 throw new IllegalStateException("telephony service is null.");
             }
         } catch (RemoteException ex) {
-            loge("unregisterForSatelliteProvisionStateChanged RemoteException: " + ex);
+            loge("unregisterForSatelliteProvisionStateChanged() RemoteException: " + ex);
             ex.rethrowFromSystemServer();
         }
+        return SATELLITE_REQUEST_FAILED;
     }
 
     /**
@@ -908,19 +920,19 @@
     /**
      * Register for listening to satellite modem state changes.
      *
-     * @param executor - The executor on which the callback will be called.
-     * @param callback - The callback to handle the satellite state change event. This
-     *                 SatelliteCallback should implement the interface
+     * @param executor The executor on which the callback will be called.
+     * @param callback The callback to handle the satellite state change event.
+     *                 This SatelliteCallback should implement the interface
      *                 {@link SatelliteCallback.SatelliteStateListener}.
      *
-     * @return The error code of the request.
+     * @return The {@link SatelliteError} 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)
-    @SatelliteError
-    public int registerForSatelliteModemStateChange(@NonNull @CallbackExecutor Executor executor,
-            @NonNull SatelliteCallback callback) {
+    @SatelliteError public int registerForSatelliteModemStateChange(
+            @NonNull @CallbackExecutor Executor executor, @NonNull SatelliteCallback callback) {
         Objects.requireNonNull(executor);
         Objects.requireNonNull(callback);
 
@@ -943,10 +955,11 @@
     /**
      * Unregister to stop listening to satellite modem state changes.
      *
-     * @param callback - The callback that was passed to
-     * {@link #registerForSatelliteModemStateChange(Executor, SatelliteCallback)}
+     * @param callback The callback that was passed to
+     *                 {@link #registerForSatelliteModemStateChange(Executor, SatelliteCallback)}.
      *
-     * @return The error code of the request.
+     * @return The {@link SatelliteError} result of the operation.
+     *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
@@ -978,19 +991,19 @@
     /**
      * Register to receive incoming datagrams over satellite.
      *
-     * @param datagramType - type of datagram
-     * @param executor - The executor on which the callback will be called.
-     * @param callback - The callback to handle incoming datagrams over satellite. This
-     *                 SatelliteCallback should implement the interface
+     * @param datagramType Type of datagram.
+     * @param executor The executor on which the callback will be called.
+     * @param callback The callback to handle incoming datagrams over satellite.
+     *                 This SatelliteCallback should implement the interface
      *                 {@link SatelliteCallback.SatelliteDatagramListener}.
      *
-     * @return The error code of the request.
+     * @return The {@link SatelliteError} 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)
-    @SatelliteError
-    public int registerForSatelliteDatagram(@DatagramType int datagramType,
+    @SatelliteError public int registerForSatelliteDatagram(@DatagramType int datagramType,
             @NonNull @CallbackExecutor Executor executor, @NonNull SatelliteCallback callback) {
         Objects.requireNonNull(executor);
         Objects.requireNonNull(callback);
@@ -1014,16 +1027,16 @@
     /**
      * Unregister to stop receiving incoming datagrams over satellite.
      *
-     * @param callback - The callback that was passed to
-     * {@link #registerForSatelliteDatagram(int, Executor, SatelliteCallback)}
+     * @param callback The callback that was passed to
+     *                 {@link #registerForSatelliteDatagram(int, Executor, SatelliteCallback)}.
      *
-     * @return The error code of the request.
+     * @return The {@link SatelliteError} 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)
-    @SatelliteError
-    public int unregisterForSatelliteDatagram(@NonNull SatelliteCallback callback) {
+    @SatelliteError public int unregisterForSatelliteDatagram(@NonNull SatelliteCallback callback) {
         Objects.requireNonNull(callback);
 
         if (callback.getCallbackStub() == null) {
@@ -1034,8 +1047,7 @@
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.unregisterForSatelliteDatagram(mSubId,
-                        callback.getCallbackStub());
+                return telephony.unregisterForSatelliteDatagram(mSubId, callback.getCallbackStub());
             } else {
                 throw new IllegalStateException("telephony service is null.");
             }
@@ -1054,8 +1066,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-    @SatelliteError
-    public int pollPendingSatelliteDatagrams() {
+    @SatelliteError public int pollPendingSatelliteDatagrams() {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
@@ -1070,6 +1081,158 @@
         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 error code listener will be called.
+     * @param errorCodeListener Listener for the {@link SatelliteError} 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> errorCodeListener) {
+        Objects.requireNonNull(datagram);
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(errorCodeListener);
+
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
+                    @Override
+                    public void accept(int result) {
+                        executor.execute(() -> Binder.withCleanCallingIdentity(
+                                () -> errorCodeListener.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();
+        }
+    }
+
+    /**
+     * Request to get whether satellite communication is allowed for the current location.
+     *
+     * @param executor The executor on which the callback will be called.
+     * @param callback The callback object to which the result will be delivered.
+     *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
+     *                 will return a {@code boolean} with value {@code true} if satellite
+     *                 communication is allowed for the current location and
+     *                 {@code false} otherwise.
+     *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
+     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *
+     * @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 requestIsSatelliteCommunicationAllowedForCurrentLocation(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                ResultReceiver receiver = new ResultReceiver(null) {
+                    @Override
+                    protected void onReceiveResult(int resultCode, Bundle resultData) {
+                        if (resultCode == SATELLITE_ERROR_NONE) {
+                            if (resultData.containsKey(KEY_SATELLITE_COMMUNICATION_ALLOWED)) {
+                                boolean isSatelliteCommunicationAllowed =
+                                        resultData.getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED);
+                                executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+                                        callback.onResult(isSatelliteCommunicationAllowed)));
+                            } else {
+                                loge("KEY_SATELLITE_COMMUNICATION_ALLOWED does not exist.");
+                                executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+                                        callback.onError(
+                                                new SatelliteException(SATELLITE_REQUEST_FAILED))));
+                            }
+                        } else {
+                            executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+                                    callback.onError(new SatelliteException(resultCode))));
+                        }
+                    }
+                };
+                telephony.requestIsSatelliteCommunicationAllowedForCurrentLocation(mSubId,
+                        receiver);
+            } else {
+                throw new IllegalStateException("telephony service is null.");
+            }
+        } catch (RemoteException ex) {
+            loge("requestIsSatelliteCommunicationAllowedForCurrentLocation() RemoteException: "
+                    + ex);
+            ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Request to get the time after which the satellite will next be visible. This is an
+     * {@code int} representing the duration in seconds after which the satellite will be visible.
+     * This will return {@code 0} if the satellite is currently visible.
+     *
+     * @param executor The executor on which the callback will be called.
+     * @param callback The callback object to which the result will be delivered.
+     *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
+     *                 will return the time after which the satellite will next be visible.
+     *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
+     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *
+     * @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 requestTimeForNextSatelliteVisibility(@NonNull @CallbackExecutor Executor executor,
+            @NonNull OutcomeReceiver<Integer, SatelliteException> callback) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                ResultReceiver receiver = new ResultReceiver(null) {
+                    @Override
+                    protected void onReceiveResult(int resultCode, Bundle resultData) {
+                        if (resultCode == SATELLITE_ERROR_NONE) {
+                            if (resultData.containsKey(KEY_SATELLITE_NEXT_VISIBILITY)) {
+                                int nextVisibilityDuration =
+                                        resultData.getInt(KEY_SATELLITE_NEXT_VISIBILITY);
+                                executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+                                        callback.onResult(nextVisibilityDuration)));
+                            } else {
+                                loge("KEY_SATELLITE_NEXT_VISIBILITY does not exist.");
+                                executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+                                        callback.onError(
+                                                new SatelliteException(SATELLITE_REQUEST_FAILED))));
+                            }
+                        } else {
+                            executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+                                    callback.onError(new SatelliteException(resultCode))));
+                        }
+                    }
+                };
+                telephony.requestTimeForNextSatelliteVisibility(mSubId, receiver);
+            } else {
+                throw new IllegalStateException("telephony service is null.");
+            }
+        } catch (RemoteException ex) {
+            loge("requestTimeForNextSatelliteVisibility() 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..ec8dafb 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;
@@ -2770,7 +2771,7 @@
     /**
      * Request to get the maximum number of characters per text message on satellite.
      *
-     * @param subId The subId to get the maximum number of characters for.
+     * @param subId The subId of the subscription to get the maximum number of characters for.
      * @param receiver Result receiver to get the error code of the request and the requested
      *                 maximum number of characters per text message on satellite.
      */
@@ -2813,26 +2814,26 @@
     /**
      * Register for the satellite provision state change.
      *
-     * @param subId The subId of the subscription to register for provision state changes for.
-     * @param errorCallback The callback to get the error code of the request.
+     * @param subId The subId of the subscription to register for provision state changes.
      * @param callback The callback to handle the satellite provision state changed event.
+     *
+     * @return The {@link SatelliteError} result of the operation.
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
-    void registerForSatelliteProvisionStateChanged(int subId,
-            in IIntegerConsumer errorCallback, in ISatelliteStateListener callback);
+    int registerForSatelliteProvisionStateChanged(int subId, in ISatelliteStateListener callback);
 
     /**
      * Unregister for the satellite provision state change.
      *
-     * @param subId The subId of the subscription associated with the satellite service.
-     * @param errorCallback The callback to get the error code of the request.
+     * @param subId The subId of the subscription to unregister for provision state changes.
      * @param callback The callback that was passed to registerForSatelliteProvisionStateChanged.
+     *
+     * @return The {@link SatelliteError} result of the operation.
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
-    void unregisterForSatelliteProvisionStateChanged(int subId,
-            in IIntegerConsumer errorCallback, in ISatelliteStateListener callback);
+    int unregisterForSatelliteProvisionStateChanged(int subId, in ISatelliteStateListener callback);
 
     /**
      * Request to get whether the device is provisioned with a satellite provider.
@@ -2848,8 +2849,10 @@
     /**
      * Register for listening to satellite modem state changes.
      *
-     * @param subId - The subId of the subscription used for listening to satellite state changes.
-     * @param callback - The callback to handle the satellite state changed event.
+     * @param subId The subId of the subscription to register for satellite modem state changes.
+     * @param callback The callback to handle the satellite modem state changed event.
+     *
+     * @return The {@link SatelliteError} result of the operation.
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
@@ -2858,8 +2861,10 @@
     /**
      * Unregister to stop listening to satellite modem state changes.
      *
-     * @param subId - The subId of the subscription associated with the satellite service.
-     * @param callback - The callback that was passed to registerForSatelliteStateChange.
+     * @param subId The subId of the subscription to unregister for satellite modem state changes.
+     * @param callback The callback that was passed to registerForSatelliteStateChange.
+     *
+     * @return The {@link SatelliteError} result of the operation.
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
@@ -2868,30 +2873,73 @@
    /**
      * Register to receive incoming datagrams over satellite.
      *
-     * @param subId - The subId of the subscription used for receiving datagrams.
-     * @param datagramType - type of datagram
-     * @param callback - The callback to receive incoming datagrams.
+     * @param subId The subId of the subscription to register for incoming satellite datagrams.
+     * @param datagramType Type of datagram.
+     * @param callback The callback to handle receiving incoming datagrams.
+     *
+     * @return The {@link SatelliteError} result of the operation.
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
-                + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+            + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
     int registerForSatelliteDatagram(int subId, int datagramType, ISatelliteStateListener callback);
 
    /**
      * Unregister to stop receiving incoming datagrams over satellite.
      *
-     * @param subId - The subId of the subscription associated with the satellite service.
-     * @param callback - The callback that was passed to registerForSatelliteDatagram.
+     * @param subId The subId of the subscription to unregister for incoming satellite datagrams.
+     * @param callback The callback that was passed to registerForSatelliteDatagram.
+     *
+     * @return The {@link SatelliteError} result of the operation.
      */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
-                + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+            + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
     int unregisterForSatelliteDatagram(int subId, ISatelliteStateListener callback);
 
    /**
     * Poll pending satellite datagrams over satellite.
     *
-    * @param subId - The subId of the subscription used for receiving datagrams.
+    * @param subId The subId of the subscription to poll pending satellite datagrams for.
+    *
+    * @return The {@link SatelliteError} result of the operation.
     */
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
-                + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+            + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
     int pollPendingSatelliteDatagrams(int subId);
+
+   /**
+    * Send datagram over satellite.
+    *
+    * @param subId The subId of the subscription to send satellite datagrams for.
+    * @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);
+
+    /**
+     * Request to get whether satellite communication is allowed for the current location.
+     *
+     * @param subId The subId of the subscription to get whether satellite communication is allowed
+     *              for the current location for.
+     * @param receiver Result receiver to get the error code of the request and whether satellite
+     *                 communication is allowed for the current location.
+     */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+            + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+    void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId,
+            in ResultReceiver receiver);
+
+    /**
+     * Request to get the time after which the satellite will next be visible.
+     *
+     * @param subId The subId to get the time after which the satellite will next be visible for.
+     * @param receiver Result receiver to get the error code of the request and the requested
+     *                 time after which the satellite will next be visible.
+     */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+            + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+    void requestTimeForNextSatelliteVisibility(int subId, in ResultReceiver receiver);
 }
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/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
index 046174c..1bd8f6a 100644
--- a/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
+++ b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
@@ -20,12 +20,15 @@
 import android.content.pm.ActivityInfo
 import android.hardware.display.DisplayManager
 import android.util.AttributeSet
+import android.util.Log
+import android.view.Display
 import android.view.Window
 import android.widget.Button
 import android.widget.LinearLayout
 import android.widget.TextView
 import com.android.test.silkfx.R
 import com.android.test.silkfx.app.WindowObserver
+import java.util.function.Consumer
 
 class ColorModeControls : LinearLayout, WindowObserver {
     private val COLOR_MODE_HDR10 = 3
@@ -66,6 +69,38 @@
         }
     }
 
+    private val hdrsdrListener = Consumer<Display> { display ->
+        Log.d("SilkFX", "HDR/SDR changed ${display.hdrSdrRatio}")
+    }
+
+    private val displayChangedListener = object : DisplayManager.DisplayListener {
+        override fun onDisplayAdded(displayId: Int) {
+            Log.d("SilkFX", "onDisplayAdded")
+        }
+
+        override fun onDisplayRemoved(displayId: Int) {
+            Log.d("SilkFX", "onDisplayRemoved")
+        }
+
+        override fun onDisplayChanged(displayId: Int) {
+            Log.d("SilkFX", "onDisplayChanged")
+        }
+    }
+
+    override fun onAttachedToWindow() {
+        super.onAttachedToWindow()
+        Log.d("SilkFX", "is hdr/sdr available: ${display.isHdrSdrRatioAvailable}; " +
+                "current ration = ${display.hdrSdrRatio}")
+        display.registerHdrSdrRatioChangedListener({ it.run() }, hdrsdrListener)
+        displayManager.registerDisplayListener(displayChangedListener, handler)
+    }
+
+    override fun onDetachedFromWindow() {
+        super.onDetachedFromWindow()
+        display.unregisterHdrSdrRatioChangedListener(hdrsdrListener)
+        displayManager.unregisterDisplayListener(displayChangedListener)
+    }
+
     private fun setColorMode(newMode: Int) {
         val window = window!!
         var sdrWhitepointChanged = false
diff --git a/tests/testables/src/com/android/internal/config/sysui/OWNERS b/tests/testables/src/com/android/internal/config/sysui/OWNERS
new file mode 100644
index 0000000..2e96c97
--- /dev/null
+++ b/tests/testables/src/com/android/internal/config/sysui/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/OWNERS
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/TestFlagResolver.java b/tests/testables/src/com/android/internal/config/sysui/TestableFlagResolver.java
similarity index 68%
rename from services/tests/uiservicestests/src/com/android/server/notification/TestFlagResolver.java
rename to tests/testables/src/com/android/internal/config/sysui/TestableFlagResolver.java
index 3b9726e..a8815dc 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/TestFlagResolver.java
+++ b/tests/testables/src/com/android/internal/config/sysui/TestableFlagResolver.java
@@ -14,22 +14,20 @@
  * limitations under the License.
  */
 
-package com.android.server.notification;
-
-import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
+package com.android.internal.config.sysui;
 
 import java.util.HashMap;
 import java.util.Map;
 
-public class TestFlagResolver implements SystemUiSystemPropertiesFlags.FlagResolver {
-    private Map<SystemUiSystemPropertiesFlags.Flag, Boolean> mOverrides = new HashMap<>();
+public class TestableFlagResolver implements SystemUiSystemPropertiesFlags.FlagResolver {
+    private Map<String, Boolean> mOverrides = new HashMap<>();
 
     @Override
     public boolean isEnabled(SystemUiSystemPropertiesFlags.Flag flag) {
-        return mOverrides.getOrDefault(flag, flag.mDefaultValue);
+        return mOverrides.getOrDefault(flag.mSysPropKey, flag.mDefaultValue);
     }
 
     public void setFlagOverride(SystemUiSystemPropertiesFlags.Flag flag, boolean isEnabled) {
-        mOverrides.put(flag, isEnabled);
+        mOverrides.put(flag.mSysPropKey, isEnabled);
     }
 }
diff --git a/tests/testables/tests/com/android/internal/config/sysui/OWNERS b/tests/testables/tests/com/android/internal/config/sysui/OWNERS
new file mode 100644
index 0000000..2e96c97
--- /dev/null
+++ b/tests/testables/tests/com/android/internal/config/sysui/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/OWNERS