Merge "Add new Wear setting for Lockscreen"
diff --git a/Android.bp b/Android.bp
index ea7ced9..effd7ce 100644
--- a/Android.bp
+++ b/Android.bp
@@ -235,6 +235,7 @@
         "android.hardware.usb-V1.0-java-constants",
         "android.hardware.usb-V1.1-java-constants",
         "android.hardware.usb-V1.2-java-constants",
+        "android.hardware.usb.gadget-V1-java",
         "android.hardware.usb.gadget-V1.0-java",
         "android.hardware.usb.gadget-V1.1-java",
         "android.hardware.usb.gadget-V1.2-java",
diff --git a/apex/jobscheduler/framework/java/android/app/job/UserVisibleJobSummary.java b/apex/jobscheduler/framework/java/android/app/job/UserVisibleJobSummary.java
index 311a9b2..ba79c30 100644
--- a/apex/jobscheduler/framework/java/android/app/job/UserVisibleJobSummary.java
+++ b/apex/jobscheduler/framework/java/android/app/job/UserVisibleJobSummary.java
@@ -30,6 +30,8 @@
  */
 public class UserVisibleJobSummary implements Parcelable {
     private final int mCallingUid;
+    @NonNull
+    private final String mCallingPackageName;
     private final int mSourceUserId;
     @NonNull
     private final String mSourcePackageName;
@@ -37,9 +39,11 @@
     private final String mNamespace;
     private final int mJobId;
 
-    public UserVisibleJobSummary(int callingUid, int sourceUserId,
-            @NonNull String sourcePackageName, String namespace, int jobId) {
+    public UserVisibleJobSummary(int callingUid, @NonNull String callingPackageName,
+            int sourceUserId, @NonNull String sourcePackageName,
+            @Nullable String namespace, int jobId) {
         mCallingUid = callingUid;
+        mCallingPackageName = callingPackageName;
         mSourceUserId = sourceUserId;
         mSourcePackageName = sourcePackageName;
         mNamespace = namespace;
@@ -48,12 +52,18 @@
 
     protected UserVisibleJobSummary(Parcel in) {
         mCallingUid = in.readInt();
+        mCallingPackageName = in.readString();
         mSourceUserId = in.readInt();
         mSourcePackageName = in.readString();
         mNamespace = in.readString();
         mJobId = in.readInt();
     }
 
+    @NonNull
+    public String getCallingPackageName() {
+        return mCallingPackageName;
+    }
+
     public int getCallingUid() {
         return mCallingUid;
     }
@@ -62,6 +72,7 @@
         return mJobId;
     }
 
+    @Nullable
     public String getNamespace() {
         return mNamespace;
     }
@@ -70,6 +81,7 @@
         return mSourceUserId;
     }
 
+    @NonNull
     public String getSourcePackageName() {
         return mSourcePackageName;
     }
@@ -80,6 +92,7 @@
         if (!(o instanceof UserVisibleJobSummary)) return false;
         UserVisibleJobSummary that = (UserVisibleJobSummary) o;
         return mCallingUid == that.mCallingUid
+                && mCallingPackageName.equals(that.mCallingPackageName)
                 && mSourceUserId == that.mSourceUserId
                 && mSourcePackageName.equals(that.mSourcePackageName)
                 && Objects.equals(mNamespace, that.mNamespace)
@@ -90,6 +103,7 @@
     public int hashCode() {
         int result = 0;
         result = 31 * result + mCallingUid;
+        result = 31 * result + mCallingPackageName.hashCode();
         result = 31 * result + mSourceUserId;
         result = 31 * result + mSourcePackageName.hashCode();
         if (mNamespace != null) {
@@ -103,6 +117,7 @@
     public String toString() {
         return "UserVisibleJobSummary{"
                 + "callingUid=" + mCallingUid
+                + ", callingPackageName='" + mCallingPackageName + "'"
                 + ", sourceUserId=" + mSourceUserId
                 + ", sourcePackageName='" + mSourcePackageName + "'"
                 + ", namespace=" + mNamespace
@@ -118,6 +133,7 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mCallingUid);
+        dest.writeString(mCallingPackageName);
         dest.writeInt(mSourceUserId);
         dest.writeString(mSourcePackageName);
         dest.writeString(mNamespace);
diff --git a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
index 95d6f850..581ea7a 100644
--- a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
+++ b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
@@ -126,7 +126,7 @@
     public static final String KEY_ENABLE_TARE_MODE = "enable_tare_mode";
     public static final String KEY_ENABLE_POLICY_ALARM = "enable_policy_alarm";
     public static final String KEY_ENABLE_POLICY_JOB_SCHEDULER = "enable_policy_job";
-    public static final int DEFAULT_ENABLE_TARE_MODE = ENABLED_MODE_ON;
+    public static final int DEFAULT_ENABLE_TARE_MODE = ENABLED_MODE_OFF;
     public static final boolean DEFAULT_ENABLE_POLICY_ALARM = true;
     public static final boolean DEFAULT_ENABLE_POLICY_JOB_SCHEDULER = true;
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobCompletedListener.java b/apex/jobscheduler/service/java/com/android/server/job/JobCompletedListener.java
index 862d8b7..3f46cc4 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobCompletedListener.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobCompletedListener.java
@@ -16,6 +16,8 @@
 
 package com.android.server.job;
 
+import android.app.job.JobParameters;
+
 import com.android.server.job.controllers.JobStatus;
 
 /**
@@ -26,8 +28,12 @@
     /**
      * Callback for when a job is completed.
      *
-     * @param stopReason      The stop reason provided to JobParameters.
-     * @param needsReschedule Whether the implementing class should reschedule this job.
+     * @param stopReason         The stop reason returned from
+     *                           {@link JobParameters#getStopReason()}.
+     * @param internalStopReason The stop reason returned from
+     *                           {@link JobParameters#getInternalStopReasonCode()}.
+     * @param needsReschedule    Whether the implementing class should reschedule this job.
      */
-    void onJobCompletedLocked(JobStatus jobStatus, int stopReason, boolean needsReschedule);
+    void onJobCompletedLocked(JobStatus jobStatus, int stopReason, int internalStopReason,
+            boolean needsReschedule);
 }
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 5e4d000..299cb6c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1695,10 +1695,28 @@
     }
 
     private void stopUserVisibleJobsInternal(@NonNull String packageName, int userId) {
+        final int packageUid = mLocalPM.getPackageUid(packageName, 0, userId);
+        if (packageUid < 0) {
+            Slog.wtf(TAG, "Asked to stop jobs of an unknown package");
+            return;
+        }
         synchronized (mLock) {
             mConcurrencyManager.stopUserVisibleJobsLocked(userId, packageName,
                     JobParameters.STOP_REASON_USER,
                     JobParameters.INTERNAL_STOP_REASON_USER_UI_STOP);
+            final ArraySet<JobStatus> jobs = mJobs.getJobsByUid(packageUid);
+            for (int i = jobs.size() - 1; i >= 0; i--) {
+                final JobStatus job = jobs.valueAt(i);
+
+                // For now, demote all jobs of the app. However, if the app was only doing work
+                // on behalf of another app and the user wanted just that work to stop, this
+                // unfairly penalizes any other jobs that may be scheduled.
+                // For example, if apps A & B ask app C to do something (thus A & B are "source"
+                // and C is "calling"), but only A's work was under way and the user wanted
+                // to stop only that work, B's jobs would be demoted as well.
+                // TODO(255768978): make it possible to demote only the relevant subset of jobs
+                job.addInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER);
+            }
         }
     }
 
@@ -2352,7 +2370,7 @@
      */
     @VisibleForTesting
     JobStatus getRescheduleJobForFailureLocked(JobStatus failureToReschedule,
-            int internalStopReason) {
+            @JobParameters.StopReason int stopReason, int internalStopReason) {
         final long elapsedNowMillis = sElapsedRealtimeClock.millis();
         final JobInfo job = failureToReschedule.getJob();
 
@@ -2360,9 +2378,11 @@
         int numFailures = failureToReschedule.getNumFailures();
         int numSystemStops = failureToReschedule.getNumSystemStops();
         // We should back off slowly if JobScheduler keeps stopping the job,
-        // but back off immediately if the issue appeared to be the app's fault.
+        // but back off immediately if the issue appeared to be the app's fault
+        // or the user stopped the job somehow.
         if (internalStopReason == JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH
-                || internalStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT) {
+                || internalStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT
+                || stopReason == JobParameters.STOP_REASON_USER) {
             numFailures++;
         } else {
             numSystemStops++;
@@ -2393,11 +2413,14 @@
         }
         delayMillis =
                 Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
-        // TODO(255767350): demote all jobs to regular for user stops so they don't keep privileges
         JobStatus newJob = new JobStatus(failureToReschedule,
                 elapsedNowMillis + delayMillis,
                 JobStatus.NO_LATEST_RUNTIME, numFailures, numSystemStops,
                 failureToReschedule.getLastSuccessfulRunTime(), sSystemClock.millis());
+        if (stopReason == JobParameters.STOP_REASON_USER) {
+            // Demote all jobs to regular for user stops so they don't keep privileges.
+            newJob.addInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER);
+        }
         if (job.isPeriodic()) {
             newJob.setOriginalLatestRunTimeElapsed(
                     failureToReschedule.getOriginalLatestRunTimeElapsed());
@@ -2518,8 +2541,8 @@
      * @param needsReschedule Whether the implementing class should reschedule this job.
      */
     @Override
-    public void onJobCompletedLocked(JobStatus jobStatus, int debugStopReason,
-            boolean needsReschedule) {
+    public void onJobCompletedLocked(JobStatus jobStatus, @JobParameters.StopReason int stopReason,
+            int debugStopReason, boolean needsReschedule) {
         if (DEBUG) {
             Slog.d(TAG, "Completed " + jobStatus + ", reason=" + debugStopReason
                     + ", reschedule=" + needsReschedule);
@@ -2546,7 +2569,7 @@
         // job so we can transfer any appropriate state over from the previous job when
         // we stop it.
         final JobStatus rescheduledJob = needsReschedule
-                ? getRescheduleJobForFailureLocked(jobStatus, debugStopReason) : null;
+                ? getRescheduleJobForFailureLocked(jobStatus, stopReason, debugStopReason) : null;
         if (rescheduledJob != null
                 && !rescheduledJob.shouldTreatAsUserInitiatedJob()
                 && (debugStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index c2168d2..911744f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -1194,6 +1194,7 @@
         applyStoppedReasonLocked(reason);
         completedJob = mRunningJob;
         final int internalStopReason = mParams.getInternalStopReasonCode();
+        final int stopReason = mParams.getStopReason();
         mPreviousJobHadSuccessfulFinish =
                 (internalStopReason == JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
         if (!mPreviousJobHadSuccessfulFinish) {
@@ -1214,7 +1215,7 @@
                 completedJob.hasContentTriggerConstraint(),
                 completedJob.isRequestedExpeditedJob(),
                 completedJob.startedAsExpeditedJob,
-                mParams.getStopReason(),
+                stopReason,
                 completedJob.getJob().isPrefetch(),
                 completedJob.getJob().getPriority(),
                 completedJob.getEffectivePriority(),
@@ -1267,7 +1268,8 @@
         if (completedJob.isUserVisibleJob()) {
             mService.informObserversOfUserVisibleJobChange(this, completedJob, false);
         }
-        mCompletedListener.onJobCompletedLocked(completedJob, internalStopReason, reschedule);
+        mCompletedListener.onJobCompletedLocked(completedJob, stopReason, internalStopReason,
+                reschedule);
         mJobConcurrencyManager.onJobCompletedLocked(this, completedJob, workType);
     }
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/PendingJobQueue.java b/apex/jobscheduler/service/java/com/android/server/job/PendingJobQueue.java
index 0a305a2..4f4096f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/PendingJobQueue.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/PendingJobQueue.java
@@ -219,6 +219,8 @@
             ajq.clear();
             mAppJobQueuePool.release(ajq);
         } else if (prevTimestamp != ajq.peekNextTimestamp()) {
+            // Removing the job changed the "next timestamp" in the queue, so we need to reinsert
+            // it to fix the ordering.
             mOrderedQueues.remove(ajq);
             mOrderedQueues.offer(ajq);
         }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 9a69fdf..ce33a8e 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -373,6 +373,11 @@
      * @hide
      */
     public static final int INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION = 1 << 0;
+    /**
+     * Flag for {@link #mInternalFlags}: this job was stopped by the user for some reason
+     * and is thus considered demoted from whatever privileged state it had in the past.
+     */
+    public static final int INTERNAL_FLAG_DEMOTED_BY_USER = 1 << 1;
 
     /** Minimum difference between start and end time to have flexible constraint */
     @VisibleForTesting
@@ -1380,8 +1385,8 @@
      * for any reason.
      */
     public boolean shouldTreatAsUserInitiatedJob() {
-        // TODO(248386641): update implementation to handle loss of privilege
-        return getJob().isUserInitiated();
+        return getJob().isUserInitiated()
+                && (getInternalFlags() & INTERNAL_FLAG_DEMOTED_BY_USER) == 0;
     }
 
     /**
@@ -1391,7 +1396,8 @@
     public UserVisibleJobSummary getUserVisibleJobSummary() {
         if (mUserVisibleJobSummary == null) {
             mUserVisibleJobSummary = new UserVisibleJobSummary(
-                    callingUid, getSourceUserId(), getSourcePackageName(),
+                    callingUid, getServiceComponent().getPackageName(),
+                    getSourceUserId(), getSourcePackageName(),
                     getNamespace(), getJobId());
         }
         return mUserVisibleJobSummary;
diff --git a/core/api/current.txt b/core/api/current.txt
index 7bdbd7b..e87487a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1900,6 +1900,18 @@
     field public static final int system_accent3_700 = 17170522; // 0x106005a
     field public static final int system_accent3_800 = 17170523; // 0x106005b
     field public static final int system_accent3_900 = 17170524; // 0x106005c
+    field public static final int system_background_dark;
+    field public static final int system_background_light;
+    field public static final int system_control_activated_dark;
+    field public static final int system_control_activated_light;
+    field public static final int system_control_highlight_dark;
+    field public static final int system_control_highlight_light;
+    field public static final int system_control_normal_dark;
+    field public static final int system_control_normal_light;
+    field public static final int system_error_container_dark;
+    field public static final int system_error_container_light;
+    field public static final int system_error_dark;
+    field public static final int system_error_light;
     field public static final int system_neutral1_0 = 17170461; // 0x106001d
     field public static final int system_neutral1_10 = 17170462; // 0x106001e
     field public static final int system_neutral1_100 = 17170464; // 0x1060020
@@ -1926,6 +1938,104 @@
     field public static final int system_neutral2_700 = 17170483; // 0x1060033
     field public static final int system_neutral2_800 = 17170484; // 0x1060034
     field public static final int system_neutral2_900 = 17170485; // 0x1060035
+    field public static final int system_on_background_dark;
+    field public static final int system_on_background_light;
+    field public static final int system_on_error_container_dark;
+    field public static final int system_on_error_container_light;
+    field public static final int system_on_error_dark;
+    field public static final int system_on_error_light;
+    field public static final int system_on_primary_container_dark;
+    field public static final int system_on_primary_container_light;
+    field public static final int system_on_primary_dark;
+    field public static final int system_on_primary_fixed_dark;
+    field public static final int system_on_primary_fixed_light;
+    field public static final int system_on_primary_fixed_variant_dark;
+    field public static final int system_on_primary_fixed_variant_light;
+    field public static final int system_on_primary_light;
+    field public static final int system_on_secondary_container_dark;
+    field public static final int system_on_secondary_container_light;
+    field public static final int system_on_secondary_dark;
+    field public static final int system_on_secondary_fixed_dark;
+    field public static final int system_on_secondary_fixed_light;
+    field public static final int system_on_secondary_fixed_variant_dark;
+    field public static final int system_on_secondary_fixed_variant_light;
+    field public static final int system_on_secondary_light;
+    field public static final int system_on_surface_dark;
+    field public static final int system_on_surface_light;
+    field public static final int system_on_surface_variant_dark;
+    field public static final int system_on_surface_variant_light;
+    field public static final int system_on_tertiary_container_dark;
+    field public static final int system_on_tertiary_container_light;
+    field public static final int system_on_tertiary_dark;
+    field public static final int system_on_tertiary_fixed_dark;
+    field public static final int system_on_tertiary_fixed_light;
+    field public static final int system_on_tertiary_fixed_variant_dark;
+    field public static final int system_on_tertiary_fixed_variant_light;
+    field public static final int system_on_tertiary_light;
+    field public static final int system_outline_dark;
+    field public static final int system_outline_light;
+    field public static final int system_palette_key_color_neutral_dark;
+    field public static final int system_palette_key_color_neutral_light;
+    field public static final int system_palette_key_color_neutral_variant_dark;
+    field public static final int system_palette_key_color_neutral_variant_light;
+    field public static final int system_palette_key_color_primary_dark;
+    field public static final int system_palette_key_color_primary_light;
+    field public static final int system_palette_key_color_secondary_dark;
+    field public static final int system_palette_key_color_secondary_light;
+    field public static final int system_palette_key_color_tertiary_dark;
+    field public static final int system_palette_key_color_tertiary_light;
+    field public static final int system_primary_container_dark;
+    field public static final int system_primary_container_light;
+    field public static final int system_primary_dark;
+    field public static final int system_primary_fixed_dark;
+    field public static final int system_primary_fixed_darker_light;
+    field public static final int system_primary_fixed_light;
+    field public static final int system_primary_fixeder_dark;
+    field public static final int system_primary_light;
+    field public static final int system_secondary_container_dark;
+    field public static final int system_secondary_container_light;
+    field public static final int system_secondary_dark;
+    field public static final int system_secondary_fixed_dark;
+    field public static final int system_secondary_fixed_darker_light;
+    field public static final int system_secondary_fixed_light;
+    field public static final int system_secondary_fixeder_dark;
+    field public static final int system_secondary_light;
+    field public static final int system_surface_bright_dark;
+    field public static final int system_surface_bright_light;
+    field public static final int system_surface_container_dark;
+    field public static final int system_surface_container_high_dark;
+    field public static final int system_surface_container_high_light;
+    field public static final int system_surface_container_highest_dark;
+    field public static final int system_surface_container_highest_light;
+    field public static final int system_surface_container_light;
+    field public static final int system_surface_container_low_dark;
+    field public static final int system_surface_container_low_light;
+    field public static final int system_surface_container_lowest_dark;
+    field public static final int system_surface_container_lowest_light;
+    field public static final int system_surface_dark;
+    field public static final int system_surface_dim_dark;
+    field public static final int system_surface_dim_light;
+    field public static final int system_surface_light;
+    field public static final int system_surface_variant_dark;
+    field public static final int system_surface_variant_light;
+    field public static final int system_tertiary_container_dark;
+    field public static final int system_tertiary_container_light;
+    field public static final int system_tertiary_dark;
+    field public static final int system_tertiary_fixed_dark;
+    field public static final int system_tertiary_fixed_darker_light;
+    field public static final int system_tertiary_fixed_light;
+    field public static final int system_tertiary_fixeder_dark;
+    field public static final int system_tertiary_light;
+    field public static final int system_text_hint_inverse_dark;
+    field public static final int system_text_hint_inverse_light;
+    field public static final int system_text_primary_inverse_dark;
+    field public static final int system_text_primary_inverse_disable_only_dark;
+    field public static final int system_text_primary_inverse_disable_only_light;
+    field public static final int system_text_primary_inverse_light;
+    field public static final int system_text_secondary_and_tertiary_inverse_dark;
+    field public static final int system_text_secondary_and_tertiary_inverse_disabled_dark;
+    field public static final int system_text_secondary_and_tertiary_inverse_disabled_light;
+    field public static final int system_text_secondary_and_tertiary_inverse_light;
     field public static final int tab_indicator_text = 17170441; // 0x1060009
     field @Deprecated public static final int tertiary_text_dark = 17170448; // 0x1060010
     field @Deprecated public static final int tertiary_text_light = 17170449; // 0x1060011
@@ -13431,9 +13541,9 @@
 
   public final class UnregisterCredentialDescriptionRequest implements android.os.Parcelable {
     ctor public UnregisterCredentialDescriptionRequest(@NonNull android.credentials.CredentialDescription);
-    ctor public UnregisterCredentialDescriptionRequest(@NonNull java.util.List<android.credentials.CredentialDescription>);
+    ctor public UnregisterCredentialDescriptionRequest(@NonNull java.util.Set<android.credentials.CredentialDescription>);
     method public int describeContents();
-    method @NonNull public java.util.List<android.credentials.CredentialDescription> getCredentialDescriptions();
+    method @NonNull public java.util.Set<android.credentials.CredentialDescription> getCredentialDescriptions();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.credentials.UnregisterCredentialDescriptionRequest> CREATOR;
   }
@@ -27020,6 +27130,39 @@
     method public void onTuned(android.net.Uri);
   }
 
+  public final class TvRecordingInfo implements android.os.Parcelable {
+    ctor public TvRecordingInfo(@NonNull String, long, long, int, @NonNull String, @NonNull String, long, long, @NonNull android.net.Uri, @Nullable android.net.Uri, @NonNull java.util.List<android.media.tv.TvContentRating>, @Nullable android.net.Uri, long, long);
+    method public int describeContents();
+    method @NonNull public android.net.Uri getChannelUri();
+    method @NonNull public java.util.List<android.media.tv.TvContentRating> getContentRatings();
+    method @NonNull public String getDescription();
+    method @NonNull public long getEndPaddingMillis();
+    method @NonNull public String getName();
+    method @Nullable public android.net.Uri getProgramUri();
+    method @IntRange(from=0xffffffff) @NonNull public long getRecordingDurationMillis();
+    method @NonNull public String getRecordingId();
+    method @IntRange(from=0xffffffff) @NonNull public long getRecordingStartTimeMillis();
+    method @Nullable public android.net.Uri getRecordingUri();
+    method @NonNull public int getRepeatDays();
+    method @IntRange(from=0) @NonNull public long getScheduledDurationMillis();
+    method @IntRange(from=0) @NonNull public long getScheduledStartTimeMillis();
+    method @NonNull public long getStartPaddingMillis();
+    method public void setDescription(@NonNull String);
+    method public void setName(@NonNull String);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.TvRecordingInfo> CREATOR;
+    field public static final int FRIDAY = 32; // 0x20
+    field public static final int MONDAY = 2; // 0x2
+    field public static final int RECORDING_ALL = 3; // 0x3
+    field public static final int RECORDING_IN_PROGRESS = 2; // 0x2
+    field public static final int RECORDING_SCHEDULED = 1; // 0x1
+    field public static final int SATURDAY = 64; // 0x40
+    field public static final int SUNDAY = 1; // 0x1
+    field public static final int THURSDAY = 16; // 0x10
+    field public static final int TUESDAY = 4; // 0x4
+    field public static final int WEDNESDAY = 8; // 0x8
+  }
+
   public final class TvTrackInfo implements android.os.Parcelable {
     method public int describeContents();
     method public int getAudioChannelCount();
@@ -27261,8 +27404,11 @@
     method @CallSuper public void requestStopRecording(@NonNull String);
     method @CallSuper public void requestStreamVolume();
     method @CallSuper public void requestTrackInfoList();
+    method @CallSuper public void requestTvRecordingInfo(@NonNull String);
+    method @CallSuper public void requestTvRecordingInfoList(@NonNull int);
     method @CallSuper public void sendPlaybackCommandRequest(@NonNull String, @Nullable android.os.Bundle);
     method @CallSuper public void setMediaViewEnabled(boolean);
+    method @CallSuper public void setTvRecordingInfo(@NonNull String, @NonNull android.media.tv.TvRecordingInfo);
     method @CallSuper public void setVideoBounds(@NonNull android.graphics.Rect);
   }
 
@@ -27337,6 +27483,9 @@
     method public void onRequestStopRecording(@NonNull String, @NonNull String);
     method public void onRequestStreamVolume(@NonNull String);
     method public void onRequestTrackInfoList(@NonNull String);
+    method public void onRequestTvRecordingInfo(@NonNull String, @NonNull String);
+    method public void onRequestTvRecordingInfoList(@NonNull String, @NonNull int);
+    method public void onSetTvRecordingInfo(@NonNull String, @NonNull String, @NonNull android.media.tv.TvRecordingInfo);
     method public void onSetVideoBounds(@NonNull String, @NonNull android.graphics.Rect);
     method public void onStateChanged(@NonNull String, int, int);
     method public void onTeletextAppStateChanged(@NonNull String, int);
@@ -49224,6 +49373,8 @@
     method public static int complexToDimensionPixelSize(int, android.util.DisplayMetrics);
     method public static float complexToFloat(int);
     method public static float complexToFraction(int, float, float);
+    method public static float convertDimensionToPixels(int, float, @NonNull android.util.DisplayMetrics);
+    method public static float convertPixelsToDimension(int, float, @NonNull android.util.DisplayMetrics);
     method public static float deriveDimension(int, float, @NonNull android.util.DisplayMetrics);
     method public int getComplexUnit();
     method public float getDimension(android.util.DisplayMetrics);
@@ -52207,6 +52358,7 @@
 
   public static interface View.OnLongClickListener {
     method public boolean onLongClick(android.view.View);
+    method public default boolean onLongClickUseDefaultHapticFeedback(@NonNull android.view.View);
   }
 
   public static interface View.OnScrollChangeListener {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 46ac819..a40d97e 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -5807,14 +5807,19 @@
   public final class DisplayPortAltModeInfo implements android.os.Parcelable {
     method public int describeContents();
     method public int getCableStatus();
+    method public int getLinkTrainingStatus();
     method public int getNumberOfLanes();
     method public int getPartnerSinkStatus();
+    method public boolean isHotPlugDetectActive();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.hardware.usb.DisplayPortAltModeInfo> CREATOR;
     field public static final int DISPLAYPORT_ALT_MODE_STATUS_CAPABLE = 2; // 0x2
     field public static final int DISPLAYPORT_ALT_MODE_STATUS_ENABLED = 3; // 0x3
     field public static final int DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE = 1; // 0x1
     field public static final int DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN = 0; // 0x0
+    field public static final int LINK_TRAINING_STATUS_FAILURE = 2; // 0x2
+    field public static final int LINK_TRAINING_STATUS_SUCCESS = 1; // 0x1
+    field public static final int LINK_TRAINING_STATUS_UNKNOWN = 0; // 0x0
   }
 
   public class UsbDeviceConnection {
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 57214e0..2a390a7 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -1997,10 +1997,12 @@
 
     /**
      * Sets background activity launch logic won't use pending intent creator foreground state.
+     *
      * @hide
      */
-    public void setIgnorePendingIntentCreatorForegroundState(boolean state) {
+    public ActivityOptions setIgnorePendingIntentCreatorForegroundState(boolean state) {
         mIgnorePendingIntentCreatorForegroundState = state;
+        return this;
     }
 
     /**
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 44bfbf6..25b395b 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1408,14 +1408,16 @@
             AppProtoEnums.APP_OP_FOREGROUND_SERVICE_SPECIAL_USE;
 
     /**
-     * Exempt from start foreground service from background restriction.
+     * Exempt an app from all power-related restrictions, including app standby and doze.
+     * In addition, the app will be able to start foreground services from the background, and the
+     * user will not be able to stop foreground services run by the app.
      *
      * Only to be used by the system.
      *
      * @hide
      */
-    public static final int OP_SYSTEM_EXEMPT_FROM_FGS_BG_START_RESTRICTION =
-            AppProtoEnums.APP_OP_SYSTEM_EXEMPT_FROM_FGS_BG_START_RESTRICTION;
+    public static final int OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS =
+            AppProtoEnums.APP_OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS;
 
     /**
      * Exempt from start foreground service from background with while in user permission
@@ -1994,14 +1996,16 @@
             "android:foreground_service_special_use";
 
     /**
-     * Exempt from start foreground service from background restriction.
+     * Exempt an app from all power-related restrictions, including app standby and doze.
+     * In addition, the app will be able to start foreground services from the background, and the
+     * user will not be able to stop foreground services run by the app.
      *
      * Only to be used by the system.
      *
      * @hide
      */
-    public static final String OPSTR_SYSTEM_EXEMPT_FROM_FGS_BG_START_RESTRICTION =
-            "android:system_exempt_from_fgs_bg_start_restriction";
+    public static final String OPSTR_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS =
+            "android:system_exempt_from_power_restrictions";
 
     /**
      * Exempt from start foreground service from background with while in user permission
@@ -2535,9 +2539,9 @@
         new AppOpInfo.Builder(OP_FOREGROUND_SERVICE_SPECIAL_USE,
                 OPSTR_FOREGROUND_SERVICE_SPECIAL_USE, "FOREGROUND_SERVICE_SPECIAL_USE")
                 .setPermission(Manifest.permission.FOREGROUND_SERVICE_SPECIAL_USE).build(),
-        new AppOpInfo.Builder(OP_SYSTEM_EXEMPT_FROM_FGS_BG_START_RESTRICTION,
-                OPSTR_SYSTEM_EXEMPT_FROM_FGS_BG_START_RESTRICTION,
-                "SYSTEM_EXEMPT_FROM_FGS_BG_START_RESTRICTION").build(),
+        new AppOpInfo.Builder(OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS,
+                OPSTR_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS,
+                "SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS").build(),
         new AppOpInfo.Builder(
                 OP_SYSTEM_EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION,
                 OPSTR_SYSTEM_EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION,
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index c11961e..fc4e2db 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -3289,6 +3289,20 @@
      * @hide
      */
     @Override
+    public boolean removeCrossProfileIntentFilter(IntentFilter filter, int sourceUserId,
+            int targetUserId, int flags) {
+        try {
+            return mPM.removeCrossProfileIntentFilter(filter, mContext.getOpPackageName(),
+                    sourceUserId, targetUserId, flags);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @Override
     public void clearCrossProfileIntentFilters(int sourceUserId) {
         try {
             mPM.clearCrossProfileIntentFilters(sourceUserId, mContext.getOpPackageName());
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index dd44531..e1ee3e0 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -57,7 +57,6 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Pair;
-import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
@@ -430,10 +429,9 @@
         }
 
         // Whenever creation or retrieval of a mutable implicit PendingIntent occurs:
-        // - For apps with target SDK >= U, Log.wtfStack() that it is blocked for security reasons.
-        //   This will be changed to a throw of an exception on the server side once we finish
-        //   migrating to safer PendingIntents b/262253127.
-        // - Otherwise, warn that it will be blocked from target SDK U.
+        // - For apps with target SDK >= U, throw an IllegalArgumentException for
+        //   security reasons.
+        // - Otherwise, warn that it will be blocked from target SDK U onwards.
         if (isNewMutableDisallowedImplicitPendingIntent(flags, intent)) {
             if (Compatibility.isChangeEnabled(BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT)) {
                 String msg = packageName + ": Targeting U+ (version "
@@ -445,7 +443,7 @@
                         + " PendingIntent, use FLAG_NO_CREATE, however, to create a"
                         + " new PendingIntent with an implicit Intent use"
                         + " FLAG_IMMUTABLE.";
-                Slog.wtfStack(TAG, msg);
+                throw new IllegalArgumentException(msg);
             } else {
                 String msg = "New mutable implicit PendingIntent: pkg=" + packageName
                         + ", action=" + intent.getAction()
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 1f5182a..52d1d68 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -510,11 +510,12 @@
                 return new BinaryTransparencyManager(ctx, service);
             }});
 
+        // InputManager stores its own static instance for historical purposes.
         registerService(Context.INPUT_SERVICE, InputManager.class,
-                new StaticServiceFetcher<InputManager>() {
+                new ServiceFetcher<InputManager>() {
             @Override
-            public InputManager createService() {
-                return InputManager.getInstance();
+            public InputManager getService(ContextImpl ctx) {
+                return InputManager.getInstance(ctx);
             }});
 
         registerService(Context.DISPLAY_SERVICE, DisplayManager.class,
diff --git a/core/java/android/app/admin/DevicePolicyCache.java b/core/java/android/app/admin/DevicePolicyCache.java
index 4a329a9..3957732 100644
--- a/core/java/android/app/admin/DevicePolicyCache.java
+++ b/core/java/android/app/admin/DevicePolicyCache.java
@@ -56,10 +56,9 @@
     public abstract int getPermissionPolicy(@UserIdInt int userHandle);
 
     /**
-     * Caches {@link DevicePolicyManager#canAdminGrantSensorsPermissionsForUser(int)} for the
-     * given user.
+     * True if there is an admin on the device who can grant sensor permissions.
      */
-    public abstract boolean canAdminGrantSensorsPermissionsForUser(@UserIdInt int userHandle);
+    public abstract boolean canAdminGrantSensorsPermissions();
 
     /**
      * Empty implementation.
@@ -83,7 +82,7 @@
         }
 
         @Override
-        public boolean canAdminGrantSensorsPermissionsForUser(int userHandle) {
+        public boolean canAdminGrantSensorsPermissions() {
             return false;
         }
     }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 239111e..6e6d4e3 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -16,12 +16,14 @@
 
 package android.app.admin;
 
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.Manifest.permission.QUERY_ADMIN_POLICY;
 import static android.Manifest.permission.SET_TIME;
 import static android.Manifest.permission.SET_TIME_ZONE;
 import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
 import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
@@ -13546,11 +13548,14 @@
             android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS
     })
     @UserProvisioningState
+    @UserHandleAware(
+            enabledSinceTargetSdkVersion = UPSIDE_DOWN_CAKE,
+            requiresPermissionIfNotCaller = INTERACT_ACROSS_USERS)
     public int getUserProvisioningState() {
         throwIfParentInstance("getUserProvisioningState");
         if (mService != null) {
             try {
-                return mService.getUserProvisioningState();
+                return mService.getUserProvisioningState(mContext.getUserId());
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -15776,7 +15781,7 @@
     }
 
     /**
-     * Returns true if the caller is running on a device where the admin can grant
+     * Returns true if the caller is running on a device where an admin can grant
      * permissions related to device sensors.
      * This is a signal that the device is a fully-managed device where personal usage is
      * discouraged.
@@ -15784,7 +15789,7 @@
      * {@link #setPermissionGrantState(ComponentName, String, String, int)}.
      *
      * May be called by any app.
-     * @return true if the app can grant device sensors-related permissions, false otherwise.
+     * @return true if an admin can grant device sensors-related permissions, false otherwise.
      */
     public boolean canAdminGrantSensorsPermissions() {
         throwIfParentInstance("canAdminGrantSensorsPermissions");
@@ -15792,7 +15797,7 @@
             return false;
         }
         try {
-            return mService.canAdminGrantSensorsPermissionsForUser(myUserId());
+            return mService.canAdminGrantSensorsPermissions();
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 70b63e4..1ed39c5 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -415,7 +415,7 @@
     CharSequence getDeviceOwnerOrganizationName();
     CharSequence getOrganizationNameForUser(int userHandle);
 
-    int getUserProvisioningState();
+    int getUserProvisioningState(int userHandle);
     void setUserProvisioningState(int state, int userHandle);
 
     void setAffiliationIds(in ComponentName admin, in List<String> ids);
@@ -553,7 +553,7 @@
     int getDeviceOwnerType(in ComponentName admin);
 
     void resetDefaultCrossProfileIntentFilters(int userId);
-    boolean canAdminGrantSensorsPermissionsForUser(int userId);
+    boolean canAdminGrantSensorsPermissions();
 
     void setUsbDataSignalingEnabled(String callerPackage, boolean enabled);
     boolean isUsbDataSignalingEnabled(String callerPackage);
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index e803084..68b0631 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1234,6 +1234,79 @@
     @Overridable
     public static final long OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS = 263259275L;
 
+    // Compat framework that per-app overrides rely on only supports booleans. That's why we have
+    // multiple OVERRIDE_*_ORIENTATION_* change ids below instead of just one override with
+    // the integer value.
+
+    /**
+     * Enables {@link #SCREEN_ORIENTATION_PORTRAIT}. Unless OVERRIDE_ANY_ORIENTATION
+     * is enabled, this override is used only when no other fixed orientation was specified by the
+     * activity.
+     * @hide
+     */
+    @ChangeId
+    @Disabled
+    @Overridable
+    public static final long OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT = 265452344L;
+
+    /**
+     * Enables {@link #SCREEN_ORIENTATION_NOSENSOR}. Unless OVERRIDE_ANY_ORIENTATION
+     * is enabled, this override is used only when no other fixed orientation was specified by the
+     * activity.
+     * @hide
+     */
+    @ChangeId
+    @Disabled
+    @Overridable
+    public static final long OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR = 265451093L;
+
+    /**
+     * Enables {@link #SCREEN_ORIENTATION_REVERSE_LANDSCAPE}. Unless OVERRIDE_ANY_ORIENTATION
+     * is enabled, this override is used only when activity specify landscape orientation.
+     * This can help apps that assume that landscape display orientation corresponds to {@link
+     * android.view.Surface#ROTATION_90}, while on some devices it can be {@link
+     * android.view.Surface#ROTATION_270}.
+     * @hide
+     */
+    @ChangeId
+    @Disabled
+    @Overridable
+    public static final long OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE = 266124927L;
+
+    /**
+     * When enabled, allows OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE,
+     * OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR and OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT
+     * to override any orientation requested by the activity.
+     * @hide
+     */
+    @ChangeId
+    @Disabled
+    @Overridable
+    public static final long OVERRIDE_ANY_ORIENTATION = 265464455L;
+
+    /**
+     * This override fixes display orientation to landscape natural orientation when a task is
+     * fullscreen. While display rotation is fixed to landscape, the orientation requested by the
+     * activity will be still respected by bounds resolution logic. For instance, if an activity
+     * requests portrait orientation and this override is set, then activity will appear in the
+     * letterbox mode for fixed orientation with the display rotated to the lanscape natural
+     * orientation.
+     *
+     * <p>This override is applicable only when natural orientation of the device is
+     * landscape and display ignores orientation requestes.
+     *
+     * <p>Main use case for this override are camera-using activities that are portrait-only and
+     * assume alignment with natural device orientation. Such activities can automatically be
+     * rotated with com.android.server.wm.DisplayRotationCompatPolicy but not all of them can
+     * handle dynamic rotation and thus can benefit from this override.
+     *
+     * @hide
+     */
+    @ChangeId
+    @Disabled
+    @Overridable
+    public static final long OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION = 255940284L;
+
     /**
      * Compares activity window layout min width/height with require space for multi window to
      * determine if it can be put into multi window mode.
@@ -1453,8 +1526,19 @@
      * @hide
      */
     public boolean isFixedOrientation() {
-        return isFixedOrientationLandscape() || isFixedOrientationPortrait()
-                || screenOrientation == SCREEN_ORIENTATION_LOCKED;
+        return isFixedOrientation(screenOrientation);
+    }
+
+    /**
+     * Returns true if the passed activity's orientation is fixed.
+     * @hide
+     */
+    public static boolean isFixedOrientation(@ScreenOrientation int orientation) {
+        return orientation == SCREEN_ORIENTATION_LOCKED
+                // Orientation is fixed to natural display orientation
+                || orientation == SCREEN_ORIENTATION_NOSENSOR
+                || isFixedOrientationLandscape(orientation)
+                || isFixedOrientationPortrait(orientation);
     }
 
     /**
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index 66c6c81..d6951ee 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -15,6 +15,7 @@
  */
 package android.content.pm;
 
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.app.admin.DevicePolicyResources.Strings.Core.SWITCH_TO_PERSONAL_LABEL;
 import static android.app.admin.DevicePolicyResources.Strings.Core.SWITCH_TO_WORK_LABEL;
 
@@ -23,6 +24,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.annotation.UserHandleAware;
 import android.app.Activity;
 import android.app.AppOpsManager.Mode;
 import android.app.admin.DevicePolicyManager;
@@ -32,6 +34,7 @@
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -167,7 +170,7 @@
      */
     @RequiresPermission(anyOf = {
             android.Manifest.permission.INTERACT_ACROSS_PROFILES,
-            android.Manifest.permission.INTERACT_ACROSS_USERS})
+            INTERACT_ACROSS_USERS})
     public void startActivity(
             @NonNull Intent intent,
             @NonNull UserHandle targetUser,
@@ -196,7 +199,7 @@
      */
     @RequiresPermission(anyOf = {
             android.Manifest.permission.INTERACT_ACROSS_PROFILES,
-            android.Manifest.permission.INTERACT_ACROSS_USERS})
+            INTERACT_ACROSS_USERS})
     public void startActivity(
             @NonNull Intent intent,
             @NonNull UserHandle targetUser,
@@ -500,10 +503,13 @@
      */
     @RequiresPermission(
             allOf={android.Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
-                    android.Manifest.permission.INTERACT_ACROSS_USERS})
+                    INTERACT_ACROSS_USERS})
+    @UserHandleAware(
+            enabledSinceTargetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
+            requiresPermissionIfNotCaller = INTERACT_ACROSS_USERS)
     public void setInteractAcrossProfilesAppOp(@NonNull String packageName, @Mode int newMode) {
         try {
-            mService.setInteractAcrossProfilesAppOp(packageName, newMode);
+            mService.setInteractAcrossProfilesAppOp(mContext.getUserId(), packageName, newMode);
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
         }
@@ -519,9 +525,12 @@
      * @hide
      */
     @TestApi
+    @UserHandleAware(
+            enabledSinceTargetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
+            requiresPermissionIfNotCaller = INTERACT_ACROSS_USERS)
     public boolean canConfigureInteractAcrossProfiles(@NonNull String packageName) {
         try {
-            return mService.canConfigureInteractAcrossProfiles(packageName);
+            return mService.canConfigureInteractAcrossProfiles(mContext.getUserId(), packageName);
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
         }
@@ -540,9 +549,13 @@
      *
      * @hide
      */
+    @UserHandleAware(
+            enabledSinceTargetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
+            requiresPermissionIfNotCaller = INTERACT_ACROSS_USERS)
     public boolean canUserAttemptToConfigureInteractAcrossProfiles(String packageName) {
         try {
-            return mService.canUserAttemptToConfigureInteractAcrossProfiles(packageName);
+            return mService.canUserAttemptToConfigureInteractAcrossProfiles(
+                    mContext.getUserId(), packageName);
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
         }
@@ -569,7 +582,10 @@
      */
     @RequiresPermission(
             allOf={android.Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
-                    android.Manifest.permission.INTERACT_ACROSS_USERS})
+                    INTERACT_ACROSS_USERS})
+    @UserHandleAware(
+            enabledSinceTargetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
+            requiresPermissionIfNotCaller = INTERACT_ACROSS_USERS)
     public void resetInteractAcrossProfilesAppOps(
             @NonNull Collection<String> previousCrossProfilePackages,
             @NonNull Set<String> newCrossProfilePackages) {
@@ -584,7 +600,8 @@
             return;
         }
         try {
-            mService.resetInteractAcrossProfilesAppOps(unsetCrossProfilePackages);
+            mService.resetInteractAcrossProfilesAppOps(
+                    mContext.getUserId(), unsetCrossProfilePackages);
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
         }
@@ -609,10 +626,13 @@
      */
     @RequiresPermission(
             allOf={android.Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
-                    android.Manifest.permission.INTERACT_ACROSS_USERS})
+                    INTERACT_ACROSS_USERS})
+    @UserHandleAware(
+            enabledSinceTargetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
+            requiresPermissionIfNotCaller = INTERACT_ACROSS_USERS)
     public void clearInteractAcrossProfilesAppOps() {
         try {
-            mService.clearInteractAcrossProfilesAppOps();
+            mService.clearInteractAcrossProfilesAppOps(mContext.getUserId());
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
         }
diff --git a/core/java/android/content/pm/ICrossProfileApps.aidl b/core/java/android/content/pm/ICrossProfileApps.aidl
index 4f2c106..716ce30 100644
--- a/core/java/android/content/pm/ICrossProfileApps.aidl
+++ b/core/java/android/content/pm/ICrossProfileApps.aidl
@@ -36,9 +36,9 @@
     List<UserHandle> getTargetUserProfiles(in String callingPackage);
     boolean canInteractAcrossProfiles(in String callingPackage);
     boolean canRequestInteractAcrossProfiles(in String callingPackage);
-    void setInteractAcrossProfilesAppOp(in String packageName, int newMode);
-    boolean canConfigureInteractAcrossProfiles(in String packageName);
-    boolean canUserAttemptToConfigureInteractAcrossProfiles(in String packageName);
-    void resetInteractAcrossProfilesAppOps(in List<String> packageNames);
-    void clearInteractAcrossProfilesAppOps();
+    void setInteractAcrossProfilesAppOp(int userId, in String packageName, int newMode);
+    boolean canConfigureInteractAcrossProfiles(int userId, in String packageName);
+    boolean canUserAttemptToConfigureInteractAcrossProfiles(int userId, in String packageName);
+    void resetInteractAcrossProfilesAppOps(int userId, in List<String> packageNames);
+    void clearInteractAcrossProfilesAppOps(int userId);
 }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 3430a61..dfaa065 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -281,6 +281,9 @@
     void addCrossProfileIntentFilter(in IntentFilter intentFilter, String ownerPackage,
             int sourceUserId, int targetUserId, int flags);
 
+    boolean removeCrossProfileIntentFilter(in IntentFilter intentFilter, String ownerPackage,
+                int sourceUserId, int targetUserId, int flags);
+
     void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
 
     String[] setDistractingPackageRestrictionsAsUser(in String[] packageNames, int restrictionFlags,
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 5209c14..dc8c0ab 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -9633,6 +9633,23 @@
             @UserIdInt int sourceUserId, @UserIdInt int targetUserId, int flags);
 
     /**
+     * Removes all {@code CrossProfileIntentFilter}s which matches the specified intent filer,
+     * source, target and flag.
+     *
+     * @param filter       The {@link IntentFilter} the intent has to match
+     * @param sourceUserId The source user id.
+     * @param targetUserId The target user id.
+     * @param flags        The possible values are {@link #SKIP_CURRENT_PROFILE} and
+     *                     {@link #ONLY_IF_NO_MATCH_FOUND}.
+     * @hide
+     */
+    public boolean removeCrossProfileIntentFilter(@NonNull IntentFilter filter,
+            @UserIdInt int sourceUserId, @UserIdInt int targetUserId, int flags) {
+        throw new UnsupportedOperationException(
+                "removeCrossProfileIntentFilter not implemented in subclass");
+    }
+
+    /**
      * Clearing {@code CrossProfileIntentFilter}s which have the specified user
      * as their source, and have been set by the app calling this method.
      *
diff --git a/core/java/android/credentials/CredentialDescription.java b/core/java/android/credentials/CredentialDescription.java
index 1a2a0e5..c67d37e 100644
--- a/core/java/android/credentials/CredentialDescription.java
+++ b/core/java/android/credentials/CredentialDescription.java
@@ -33,6 +33,8 @@
  */
 public final class CredentialDescription implements Parcelable {
 
+    private static final int MAX_ALLOWED_ENTRIES_PER_DESCRIPTION = 16;
+
     /**
      * The credential type.
      */
@@ -70,6 +72,11 @@
         mType = Preconditions.checkStringNotEmpty(type, "type must not be empty");
         mFlattenedRequestString = Preconditions.checkStringNotEmpty(flattenedRequestString);
         mCredentialEntries = Objects.requireNonNull(credentialEntries);
+        Preconditions.checkArgument(credentialEntries.size()
+                        <= MAX_ALLOWED_ENTRIES_PER_DESCRIPTION,
+                "The number of Credential Entries exceed 16.");
+        Preconditions.checkArgument(compareEntryTypes(type, credentialEntries) == 0,
+                "Credential Entry type(s) do not match the request type.");
     }
 
     private CredentialDescription(@NonNull Parcel in) {
@@ -88,6 +95,14 @@
                 mCredentialEntries);
     }
 
+    private static int compareEntryTypes(@NonNull String type,
+            @NonNull List<CredentialEntry> credentialEntries) {
+        return credentialEntries.stream()
+                .filter(credentialEntry ->
+                        !credentialEntry.getType().equals(type)).toList().size();
+
+    }
+
     public static final @NonNull Parcelable.Creator<CredentialDescription> CREATOR =
             new Parcelable.Creator<CredentialDescription>() {
                 @Override
diff --git a/core/java/android/credentials/UnregisterCredentialDescriptionRequest.java b/core/java/android/credentials/UnregisterCredentialDescriptionRequest.java
index cfda474..f175ba4 100644
--- a/core/java/android/credentials/UnregisterCredentialDescriptionRequest.java
+++ b/core/java/android/credentials/UnregisterCredentialDescriptionRequest.java
@@ -27,7 +27,9 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 
 /**
@@ -46,7 +48,7 @@
     }
 
     public UnregisterCredentialDescriptionRequest(
-            @NonNull List<CredentialDescription> credentialDescriptions) {
+            @NonNull Set<CredentialDescription> credentialDescriptions) {
         mCredentialDescriptions = new ArrayList<>(requireNonNull(credentialDescriptions));
     }
 
@@ -84,7 +86,7 @@
     }
 
     @NonNull
-    public List<CredentialDescription> getCredentialDescriptions() {
-        return mCredentialDescriptions;
+    public Set<CredentialDescription> getCredentialDescriptions() {
+        return new HashSet<>(mCredentialDescriptions);
     }
 }
diff --git a/core/java/android/credentials/ui/BaseDialogResult.java b/core/java/android/credentials/ui/BaseDialogResult.java
index 5223314..f0442de 100644
--- a/core/java/android/credentials/ui/BaseDialogResult.java
+++ b/core/java/android/credentials/ui/BaseDialogResult.java
@@ -56,14 +56,14 @@
      * The intent extra key for the {@code BaseDialogResult} object when the credential
      * selector activity finishes.
      */
-    private static final String EXTRA_BASE_RESULT =
-            "android.credentials.ui.extra.BASE_RESULT";
+    private static final String EXTRA_BASE_RESULT = "android.credentials.ui.extra.BASE_RESULT";
 
     /** @hide **/
     @IntDef(prefix = {"RESULT_CODE_"}, value = {
             RESULT_CODE_DIALOG_USER_CANCELED,
             RESULT_CODE_CANCELED_AND_LAUNCHED_SETTINGS,
             RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION,
+            RESULT_CODE_DATA_PARSING_FAILURE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ResultCode {}
@@ -80,6 +80,10 @@
      * {@code resultData}.
      */
     public static final int RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION = 2;
+    /**
+     * The UI was canceled because it failed to parse the incoming data.
+     */
+    public static final int RESULT_CODE_DATA_PARSING_FAILURE = 3;
 
     @NonNull
     private final IBinder mRequestToken;
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 7409187..9a092a5 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -21,6 +21,7 @@
 import android.companion.virtual.IVirtualDevice;
 import android.graphics.Point;
 import android.hardware.SensorManager;
+import android.hardware.input.HostUsiVersion;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.util.IntArray;
@@ -403,6 +404,14 @@
     public abstract SurfaceControl.DisplayPrimaries getDisplayNativePrimaries(int displayId);
 
     /**
+     * Get the version of the Universal Stylus Initiative (USI) Protocol supported by the display.
+     * @param displayId The id of the display.
+     * @return The USI version, or null if not supported
+     */
+    @Nullable
+    public abstract HostUsiVersion getHostUsiVersion(int displayId);
+
+    /**
      * Describes the requested power state of the display.
      *
      * This object is intended to describe the general characteristics of the
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 197739b..96098f8 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -26,6 +26,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.BiometricFaceConstants;
@@ -87,6 +88,7 @@
     private CryptoObject mCryptoObject;
     private Face mRemovalFace;
     private Handler mHandler;
+    private List<FaceSensorPropertiesInternal> mProps = new ArrayList<>();
 
     private final IFaceServiceReceiver mServiceReceiver = new IFaceServiceReceiver.Stub() {
 
@@ -168,6 +170,16 @@
             Slog.v(TAG, "FaceAuthenticationManagerService was null");
         }
         mHandler = new MyHandler(context);
+        if (context.checkCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL)
+                == PackageManager.PERMISSION_GRANTED) {
+            addAuthenticatorsRegisteredCallback(new IFaceAuthenticatorsRegisteredCallback.Stub() {
+                @Override
+                public void onAllAuthenticatorsRegistered(
+                        @NonNull List<FaceSensorPropertiesInternal> sensors) {
+                    mProps = sensors;
+                }
+            });
+        }
     }
 
     /**
@@ -664,14 +676,14 @@
     @NonNull
     public List<FaceSensorPropertiesInternal> getSensorPropertiesInternal() {
         try {
-            if (mService == null) {
-                return new ArrayList<>();
+            if (!mProps.isEmpty() || mService == null) {
+                return mProps;
             }
             return mService.getSensorPropertiesInternal(mContext.getOpPackageName());
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
-        return new ArrayList<>();
+        return mProps;
     }
 
     /**
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index b24b30e..d9f8f8e 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -153,6 +153,7 @@
     @Nullable private RemoveTracker mRemoveTracker;
     private Handler mHandler;
     @Nullable private float[] mEnrollStageThresholds;
+    private List<FingerprintSensorPropertiesInternal> mProps = new ArrayList<>();
 
     /**
      * Retrieves a list of properties for all fingerprint sensors on the device.
@@ -1185,8 +1186,8 @@
     @NonNull
     public List<FingerprintSensorPropertiesInternal> getSensorPropertiesInternal() {
         try {
-            if (mService == null) {
-                return new ArrayList<>();
+            if (!mProps.isEmpty() || mService == null) {
+                return mProps;
             }
             return mService.getSensorPropertiesInternal(mContext.getOpPackageName());
         } catch (RemoteException e) {
@@ -1502,6 +1503,17 @@
             Slog.v(TAG, "FingerprintService was null");
         }
         mHandler = new MyHandler(context);
+        if (context.checkCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL)
+                == PackageManager.PERMISSION_GRANTED) {
+            addAuthenticatorsRegisteredCallback(
+                    new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
+                        @Override
+                        public void onAllAuthenticatorsRegistered(
+                                @NonNull List<FingerprintSensorPropertiesInternal> sensors) {
+                            mProps = sensors;
+                        }
+                    });
+        }
     }
 
     private int getCurrentUserId() {
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 222cf08..c3fae55 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -17,6 +17,7 @@
 package android.hardware.input;
 
 import android.graphics.Rect;
+import android.hardware.input.HostUsiVersion;
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.KeyboardLayout;
 import android.hardware.input.IInputDevicesChangedListener;
@@ -233,4 +234,6 @@
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
             + "android.Manifest.permission.MONITOR_KEYBOARD_BACKLIGHT)")
     void unregisterKeyboardBacklightListener(IKeyboardBacklightListener listener);
+
+    HostUsiVersion getHostUsiVersionFromDisplayConfig(int displayId);
 }
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index f27c34c..3ccc940 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -55,8 +55,6 @@
 import android.os.Vibrator;
 import android.os.VibratorManager;
 import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
-import android.util.DisplayUtils;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.Display;
@@ -71,7 +69,6 @@
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
 
-import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
@@ -102,19 +99,33 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final IInputManager mIm;
 
-    private final boolean mIsStylusPointerIconEnabled;
+    /**
+     * InputManager has historically used its own static getter {@link #getInstance()} that doesn't
+     * provide a context. We provide a Context to the InputManager instance through the
+     * {@link android.app.SystemServiceRegistry}. Methods that need a Context must use
+     * {@link #getContext()} to obtain it.
+     */
+    @Nullable
+    private Context mLateInitContext;
+
+    /**
+     * Whether a PointerIcon is shown for stylus pointers.
+     * Obtain using {@link #isStylusPointerIconEnabled()}.
+     */
+    @Nullable
+    private Boolean mIsStylusPointerIconEnabled = null;
 
     // Guarded by mInputDevicesLock
     private final Object mInputDevicesLock = new Object();
     private SparseArray<InputDevice> mInputDevices;
     private InputDevicesChangedListener mInputDevicesChangedListener;
-    private final ArrayList<InputDeviceListenerDelegate> mInputDeviceListeners =
-            new ArrayList<InputDeviceListenerDelegate>();
+    private final ArrayList<InputDeviceListenerDelegate> mInputDeviceListeners = new ArrayList<>();
 
     // Guarded by mTabletModeLock
     private final Object mTabletModeLock = new Object();
+    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
     private TabletModeChangedListener mTabletModeChangedListener;
-    private List<OnTabletModeChangedListenerDelegate> mOnTabletModeChangedListeners;
+    private ArrayList<OnTabletModeChangedListenerDelegate> mOnTabletModeChangedListeners;
 
     private final Object mBatteryListenersLock = new Object();
     // Maps a deviceId whose battery is currently being monitored to an entry containing the
@@ -126,7 +137,7 @@
 
     private final Object mKeyboardBacklightListenerLock = new Object();
     @GuardedBy("mKeyboardBacklightListenerLock")
-    private List<KeyboardBacklightListenerDelegate> mKeyboardBacklightListeners;
+    private ArrayList<KeyboardBacklightListenerDelegate> mKeyboardBacklightListeners;
     @GuardedBy("mKeyboardBacklightListenerLock")
     private IKeyboardBacklightListener mKeyboardBacklightListener;
 
@@ -326,15 +337,6 @@
         } catch (RemoteException ex) {
             Log.w(TAG, "Could not get VelocityTracker strategy: " + ex);
         }
-
-        // TODO(b/266013036): Pass a Context into InputManager constructor.
-        final Context context = ActivityThread.currentApplication();
-        if (context != null) {
-            mIsStylusPointerIconEnabled = context.getResources()
-                    .getBoolean(com.android.internal.R.bool.config_enableStylusPointerIcon);
-        } else {
-            mIsStylusPointerIconEnabled = false;
-        }
     }
 
     /**
@@ -368,24 +370,47 @@
      * Gets an instance of the input manager.
      *
      * @return The input manager instance.
-     *
+     * @deprecated Use {@link Context#getSystemService(Class)} or {@link #getInstance(Context)}
+     * to obtain the InputManager instance.
      * @hide
      */
+    @Deprecated
     @UnsupportedAppUsage
     public static InputManager getInstance() {
+        return getInstance(ActivityThread.currentApplication());
+    }
+
+    /**
+     * Gets an instance of the input manager.
+     *
+     * @return The input manager instance.
+     * @hide
+     */
+    public static InputManager getInstance(Context context) {
         synchronized (InputManager.class) {
             if (sInstance == null) {
                 try {
                     sInstance = new InputManager(IInputManager.Stub
                             .asInterface(ServiceManager.getServiceOrThrow(Context.INPUT_SERVICE)));
+
                 } catch (ServiceNotFoundException e) {
                     throw new IllegalStateException(e);
                 }
             }
+            if (sInstance.mLateInitContext == null) {
+                sInstance.mLateInitContext = context;
+            }
             return sInstance;
         }
     }
 
+    @NonNull
+    private Context getContext() {
+        return Objects.requireNonNull(mLateInitContext,
+                "A context is required for InputManager. Get the InputManager instance using "
+                        + "Context#getSystemService before calling this method.");
+    }
+
     /**
      * Get the current VelocityTracker strategy. Only works when the system has fully booted up.
      * @hide
@@ -499,7 +524,7 @@
     /**
      * Enables an InputDevice.
      * <p>
-     * Requires {@link android.Manifest.permission.DISABLE_INPUT_DEVICE}.
+     * Requires {@link android.Manifest.permission#DISABLE_INPUT_DEVICE}.
      * </p>
      *
      * @param id The input device Id.
@@ -518,7 +543,7 @@
     /**
      * Disables an InputDevice.
      * <p>
-     * Requires {@link android.Manifest.permission.DISABLE_INPUT_DEVICE}.
+     * Requires {@link android.Manifest.permission#DISABLE_INPUT_DEVICE}.
      * </p>
      *
      * @param id The input device Id.
@@ -975,6 +1000,7 @@
      */
     @TestApi
     @NonNull
+    @SuppressWarnings("unchecked")
     @RequiresPermission(Manifest.permission.REMAP_MODIFIER_KEYS)
     public Map<Integer, Integer> getModifierKeyRemapping() {
         try {
@@ -1005,7 +1031,7 @@
      * Sets the TouchCalibration to apply to the specified input device's coordinates.
      * <p>
      * This method may have the side-effect of causing the input device in question
-     * to be reconfigured. Requires {@link android.Manifest.permission.SET_INPUT_CALIBRATION}.
+     * to be reconfigured. Requires {@link android.Manifest.permission#SET_INPUT_CALIBRATION}.
      * </p>
      *
      * @param inputDeviceDescriptor The input device descriptor.
@@ -1121,19 +1147,14 @@
      * @hide
      */
     public int getPointerSpeed(Context context) {
-        int speed = DEFAULT_POINTER_SPEED;
-        try {
-            speed = Settings.System.getInt(context.getContentResolver(),
-                    Settings.System.POINTER_SPEED);
-        } catch (SettingNotFoundException snfe) {
-        }
-        return speed;
+        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}.
+     * Requires {@link android.Manifest.permission#WRITE_SETTINGS}.
      * </p>
      *
      * @param context The application context.
@@ -1154,7 +1175,7 @@
     /**
      * Changes the mouse pointer speed temporarily, but does not save the setting.
      * <p>
-     * Requires {@link android.Manifest.permission.SET_POINTER_SPEED}.
+     * Requires {@link android.Manifest.permission#SET_POINTER_SPEED}.
      * </p>
      *
      * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
@@ -1188,8 +1209,7 @@
      */
     @FloatRange(from = 0, to = 1)
     public float getMaximumObscuringOpacityForTouch() {
-        Context context = ActivityThread.currentApplication();
-        return Settings.Global.getFloat(context.getContentResolver(),
+        return Settings.Global.getFloat(getContext().getContentResolver(),
                 Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH,
                 DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH);
     }
@@ -1225,8 +1245,7 @@
             throw new IllegalArgumentException(
                     "Maximum obscuring opacity for touch should be >= 0 and <= 1");
         }
-        Context context = ActivityThread.currentApplication();
-        Settings.Global.putFloat(context.getContentResolver(),
+        Settings.Global.putFloat(getContext().getContentResolver(),
                 Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH, opacity);
     }
 
@@ -1307,7 +1326,7 @@
      * The synchronization mode determines whether the method blocks while waiting for
      * input injection to proceed.
      * <p>
-     * Requires the {@link android.Manifest.permission.INJECT_EVENTS} permission.
+     * Requires the {@link android.Manifest.permission#INJECT_EVENTS} permission.
      * </p><p>
      * Make sure you correctly set the event time and input source of the event
      * before calling this method.
@@ -1315,9 +1334,9 @@
      *
      * @param event The event to inject.
      * @param mode The synchronization mode.  One of:
-     * {@link android.os.InputEventInjectionSync.NONE},
-     * {@link android.os.InputEventInjectionSync.WAIT_FOR_RESULT}, or
-     * {@link android.os.InputEventInjectionSync.WAIT_FOR_FINISHED}.
+     * {@link android.os.InputEventInjectionSync#NONE},
+     * {@link android.os.InputEventInjectionSync#WAIT_FOR_RESULT}, or
+     * {@link android.os.InputEventInjectionSync#WAIT_FOR_FINISHED}.
      * @param targetUid The uid to target, or {@link android.os.Process#INVALID_UID} to target all
      *                 windows.
      * @return True if input event injection succeeded.
@@ -1347,7 +1366,7 @@
      * The synchronization mode determines whether the method blocks while waiting for
      * input injection to proceed.
      * <p>
-     * Requires the {@link android.Manifest.permission.INJECT_EVENTS} permission.
+     * Requires the {@link android.Manifest.permission#INJECT_EVENTS} permission.
      * </p><p>
      * Make sure you correctly set the event time and input source of the event
      * before calling this method.
@@ -1355,9 +1374,9 @@
      *
      * @param event The event to inject.
      * @param mode The synchronization mode.  One of:
-     * {@link android.os.InputEventInjectionSync.NONE},
-     * {@link android.os.InputEventInjectionSync.WAIT_FOR_RESULT}, or
-     * {@link android.os.InputEventInjectionSync.WAIT_FOR_FINISHED}.
+     * {@link android.os.InputEventInjectionSync#NONE},
+     * {@link android.os.InputEventInjectionSync#WAIT_FOR_RESULT}, or
+     * {@link android.os.InputEventInjectionSync#WAIT_FOR_FINISHED}.
      * @return True if input event injection succeeded.
      *
      * @hide
@@ -1381,7 +1400,8 @@
      * {@link android.view.InputEvent}
      *         {@code null} if the event could not be verified.
      */
-    public @Nullable VerifiedInputEvent verifyInputEvent(@NonNull InputEvent event) {
+    @Nullable
+    public VerifiedInputEvent verifyInputEvent(@NonNull InputEvent event) {
         try {
             return mIm.verifyInputEvent(event);
         } catch (RemoteException ex) {
@@ -1393,7 +1413,7 @@
      * Changes the mouse pointer's icon shape into the specified id.
      *
      * @param iconId The id of the pointer graphic, as a value between
-     * {@link PointerIcon.TYPE_ARROW} and {@link PointerIcon.TYPE_HANDWRITING}.
+     * {@link PointerIcon#TYPE_ARROW} and {@link PointerIcon#TYPE_HANDWRITING}.
      *
      * @hide
      */
@@ -1422,6 +1442,10 @@
      * stylus pointer, false if there is no pointer icon shown for styluses.
      */
     public boolean isStylusPointerIconEnabled() {
+        if (mIsStylusPointerIconEnabled == null) {
+            mIsStylusPointerIconEnabled = getContext().getResources()
+                    .getBoolean(com.android.internal.R.bool.config_enableStylusPointerIcon);
+        }
         return mIsStylusPointerIconEnabled;
     }
 
@@ -1543,7 +1567,7 @@
      * @param inputPort The port of the input device.
      * @param displayPort The physical port of the associated display.
      * <p>
-     * Requires {@link android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
+     * Requires {@link android.Manifest.permission#ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
      * </p>
      * @hide
      */
@@ -1560,7 +1584,7 @@
      * static association for the cleared input port will be restored.
      * @param inputPort The port of the input device to be cleared.
      * <p>
-     * Requires {@link android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
+     * Requires {@link android.Manifest.permission#ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
      * </p>
      * @hide
      */
@@ -1578,7 +1602,7 @@
      * @param inputPort The port of the input device.
      * @param displayUniqueId The unique id of the associated display.
      * <p>
-     * Requires {@link android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
+     * Requires {@link android.Manifest.permission#ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
      * </p>
      * @hide
      */
@@ -1595,7 +1619,7 @@
      * Removes a runtime association between the input device and display.
      * @param inputPort The port of the input device.
      * <p>
-     * Requires {@link android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
+     * Requires {@link android.Manifest.permission#ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
      * </p>
      * @hide
      */
@@ -1637,35 +1661,11 @@
         // If there are no input devices that report a valid USI version, see if there is a config
         // that specifies the USI version for the display. This is to handle cases where the USI
         // input device is not registered by the kernel/driver all the time.
-        return findConfigUsiVersionForDisplay(display);
-    }
-
-    private HostUsiVersion findConfigUsiVersionForDisplay(@NonNull Display display) {
-        final Context context = Objects.requireNonNull(ActivityThread.currentApplication());
-        final String[] displayUniqueIds = context.getResources().getStringArray(
-                R.array.config_displayUniqueIdArray);
-        final int index;
-        if (displayUniqueIds.length == 0 && display.getDisplayId() == context.getDisplayId()) {
-            index = 0;
-        } else {
-            index = DisplayUtils.getDisplayUniqueIdConfigIndex(context.getResources(),
-                    display.getUniqueId());
+        try {
+            return mIm.getHostUsiVersionFromDisplayConfig(display.getDisplayId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-
-        final String[] versions = context.getResources().getStringArray(
-                R.array.config_displayUsiVersionArray);
-        if (index < 0 || index >= versions.length) {
-            return null;
-        }
-        final String version = versions[index];
-        if (version == null || version.isEmpty()) {
-            return null;
-        }
-        final String[] majorMinor = version.split("\\.");
-        if (majorMinor.length != 2) {
-            throw new IllegalStateException("Failed to parse USI version: " + version);
-        }
-        return new HostUsiVersion(Integer.parseInt(majorMinor[0]), Integer.parseInt(majorMinor[1]));
     }
 
     private void populateInputDevicesLocked() {
@@ -1687,9 +1687,9 @@
                 throw ex.rethrowFromSystemServer();
             }
 
-            mInputDevices = new SparseArray<InputDevice>();
-            for (int i = 0; i < ids.length; i++) {
-                mInputDevices.put(ids[i], null);
+            mInputDevices = new SparseArray<>();
+            for (int id : ids) {
+                mInputDevices.put(id, null);
             }
         }
     }
@@ -1761,8 +1761,8 @@
                     + "whenNanos=" + whenNanos + ", inTabletMode=" + inTabletMode);
         }
         synchronized (mTabletModeLock) {
-            final int N = mOnTabletModeChangedListeners.size();
-            for (int i = 0; i < N; i++) {
+            final int numListeners = mOnTabletModeChangedListeners.size();
+            for (int i = 0; i < numListeners; i++) {
                 OnTabletModeChangedListenerDelegate listener =
                         mOnTabletModeChangedListeners.get(i);
                 listener.sendTabletModeChanged(whenNanos, inTabletMode);
@@ -1965,7 +1965,7 @@
             }
             List<LightState> lightStateList = request.getLightStates();
             mIm.setLightStates(deviceId, lightIds,
-                    lightStateList.toArray(new LightState[lightStateList.size()]),
+                    lightStateList.toArray(new LightState[0]),
                     token);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -2072,8 +2072,11 @@
             } else {
                 // The deviceId is already being monitored for battery changes.
                 // Ensure that the listener is not already registered.
-                for (InputDeviceBatteryListenerDelegate delegate : listenersForDevice.mDelegates) {
-                    if (Objects.equals(listener, delegate.mListener)) {
+                final int numDelegates = listenersForDevice.mDelegates.size();
+                for (int i = 0; i < numDelegates; i++) {
+                    InputDeviceBatteryListener registeredListener =
+                            listenersForDevice.mDelegates.get(i).mListener;
+                    if (Objects.equals(listener, registeredListener)) {
                         throw new IllegalArgumentException(
                                 "Attempting to register an InputDeviceBatteryListener that has "
                                         + "already been registered for deviceId: "
@@ -2208,7 +2211,7 @@
      * Changes the touchpad pointer speed temporarily, but does not save the setting.
      *
      * The new speed will only apply to gesture-compatible touchpads.
-     * Requires {@link android.Manifest.permission.SET_POINTER_SPEED}.
+     * Requires {@link android.Manifest.permission#SET_POINTER_SPEED}.
      *
      * @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}.
@@ -2398,8 +2401,9 @@
                     throw e.rethrowFromSystemServer();
                 }
             }
-            for (KeyboardBacklightListenerDelegate delegate : mKeyboardBacklightListeners) {
-                if (delegate.mListener == listener) {
+            final int numListeners = mKeyboardBacklightListeners.size();
+            for (int i = 0; i < numListeners; i++) {
+                if (mKeyboardBacklightListeners.get(i).mListener == listener) {
                     throw new IllegalArgumentException("Listener has already been registered!");
                 }
             }
@@ -2572,21 +2576,19 @@
 
         public void sendTabletModeChanged(long whenNanos, boolean inTabletMode) {
             SomeArgs args = SomeArgs.obtain();
-            args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
+            args.argi1 = (int) whenNanos;
             args.argi2 = (int) (whenNanos >> 32);
-            args.arg1 = (Boolean) inTabletMode;
+            args.arg1 = inTabletMode;
             obtainMessage(MSG_TABLET_MODE_CHANGED, args).sendToTarget();
         }
 
         @Override
         public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_TABLET_MODE_CHANGED:
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
-                    boolean inTabletMode = (boolean) args.arg1;
-                    mListener.onTabletModeChanged(whenNanos, inTabletMode);
-                    break;
+            if (msg.what == MSG_TABLET_MODE_CHANGED) {
+                SomeArgs args = (SomeArgs) msg.obj;
+                long whenNanos = (args.argi1 & 0xFFFFFFFFL) | ((long) args.argi2 << 32);
+                boolean inTabletMode = (boolean) args.arg1;
+                mListener.onTabletModeChanged(whenNanos, inTabletMode);
             }
         }
     }
@@ -2654,8 +2656,10 @@
                 if (entry == null) return;
 
                 entry.mInputDeviceBatteryState = state;
-                for (InputDeviceBatteryListenerDelegate delegate : entry.mDelegates) {
-                    delegate.notifyBatteryStateChanged(entry.mInputDeviceBatteryState);
+                final int numDelegates = entry.mDelegates.size();
+                for (int i = 0; i < numDelegates; i++) {
+                    entry.mDelegates.get(i)
+                            .notifyBatteryStateChanged(entry.mInputDeviceBatteryState);
                 }
             }
         }
@@ -2668,8 +2672,8 @@
         private final int mBrightnessLevel;
         private final int mMaxBrightnessLevel;
 
-        LocalKeyboardBacklightState(int brightnesslevel, int maxBrightnessLevel) {
-            mBrightnessLevel = brightnesslevel;
+        LocalKeyboardBacklightState(int brightnessLevel, int maxBrightnessLevel) {
+            mBrightnessLevel = brightnessLevel;
             mMaxBrightnessLevel = maxBrightnessLevel;
         }
 
@@ -2709,8 +2713,10 @@
                 boolean isTriggeredByKeyPress) {
             synchronized (mKeyboardBacklightListenerLock) {
                 if (mKeyboardBacklightListeners == null) return;
-                for (KeyboardBacklightListenerDelegate delegate : mKeyboardBacklightListeners) {
-                    delegate.notifyKeyboardBacklightChange(deviceId, state, isTriggeredByKeyPress);
+                final int numListeners = mKeyboardBacklightListeners.size();
+                for (int i = 0; i < numListeners; i++) {
+                    mKeyboardBacklightListeners.get(i)
+                            .notifyKeyboardBacklightChange(deviceId, state, isTriggeredByKeyPress);
                 }
             }
         }
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index 621eab5..b7a694c 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -2017,26 +2017,14 @@
      *         - {@link #STATUS_BAD_VALUE} if modules is null
      *         - {@link #STATUS_DEAD_OBJECT} if the binder transaction to the native service fails
      *
-     * @deprecated Please use {@link #listModulesAsOriginator(ArrayList, Identity)} or
+     * @removed Please use {@link #listModulesAsOriginator(ArrayList, Identity)} or
      * {@link #listModulesAsMiddleman(ArrayList, Identity, Identity)}, based on whether the
      * client is acting on behalf of its own identity or a separate identity.
      * @hide
      */
     @UnsupportedAppUsage
     public static int listModules(@NonNull ArrayList<ModuleProperties> modules) {
-        // TODO(ytai): This is a temporary hack to retain prior behavior, which makes
-        //  assumptions about process affinity and Binder context, namely that the binder calling ID
-        //  reliably reflects the originator identity.
-        Identity middlemanIdentity = new Identity();
-        middlemanIdentity.packageName = ActivityThread.currentOpPackageName();
-
-        Identity originatorIdentity = new Identity();
-        originatorIdentity.pid = Binder.getCallingPid();
-        originatorIdentity.uid = Binder.getCallingUid();
-
-        try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
-            return listModulesAsMiddleman(modules, middlemanIdentity, originatorIdentity);
-        }
+        return STATUS_OK;
     }
 
     /**
@@ -2051,10 +2039,11 @@
      *         - {@link #STATUS_NO_INIT} if the native service cannot be reached
      *         - {@link #STATUS_BAD_VALUE} if modules is null
      *         - {@link #STATUS_DEAD_OBJECT} if the binder transaction to the native service fails
-     *
+     * @deprecated Use {@link android.media.soundtrigger.SoundTriggerManager} instead.
      * @hide
      */
     @RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
+    @Deprecated
     public static int listModulesAsOriginator(@NonNull ArrayList<ModuleProperties> modules,
             @NonNull Identity originatorIdentity) {
         try {
@@ -2082,9 +2071,11 @@
      *         - {@link #STATUS_BAD_VALUE} if modules is null
      *         - {@link #STATUS_DEAD_OBJECT} if the binder transaction to the native service fails
      *
+     * @deprecated Use {@link android.media.soundtrigger.SoundTriggerManager} instead.
      * @hide
      */
     @RequiresPermission(SOUNDTRIGGER_DELEGATE_IDENTITY)
+    @Deprecated
     public static int listModulesAsMiddleman(@NonNull ArrayList<ModuleProperties> modules,
             @NonNull Identity middlemanIdentity,
             @NonNull Identity originatorIdentity) {
@@ -2123,30 +2114,14 @@
      *                is OK.
      * @return a valid sound module in case of success or null in case of error.
      *
-     * @deprecated Please use
-     * {@link #attachModuleAsOriginator(int, StatusListener, Handler, Identity)} or
-     * {@link #attachModuleAsMiddleman(int, StatusListener, Handler, Identity, Identity)}, based
-     * on whether the client is acting on behalf of its own identity or a separate identity.
+     * @removed Use {@link android.media.soundtrigger.SoundTriggerManager} instead.
      * @hide
      */
     @UnsupportedAppUsage
     private static SoundTriggerModule attachModule(int moduleId,
             @NonNull StatusListener listener,
             @Nullable Handler handler) {
-        // TODO(ytai): This is a temporary hack to retain prior behavior, which makes
-        //  assumptions about process affinity and Binder context, namely that the binder calling ID
-        //  reliably reflects the originator identity.
-        Identity middlemanIdentity = new Identity();
-        middlemanIdentity.packageName = ActivityThread.currentOpPackageName();
-
-        Identity originatorIdentity = new Identity();
-        originatorIdentity.pid = Binder.getCallingPid();
-        originatorIdentity.uid = Binder.getCallingUid();
-
-        try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
-            return attachModuleAsMiddleman(moduleId, listener, handler, middlemanIdentity,
-                    originatorIdentity);
-        }
+            return null;
     }
 
     /**
@@ -2162,10 +2137,11 @@
      * @param originatorIdentity The identity of the originator, which will be used for permission
      *                           purposes.
      * @return a valid sound module in case of success or null in case of error.
-     *
+     * @deprecated Use {@link android.media.soundtrigger.SoundTriggerManager} instead.
      * @hide
      */
     @RequiresPermission(SOUNDTRIGGER_DELEGATE_IDENTITY)
+    @Deprecated
     public static SoundTriggerModule attachModuleAsMiddleman(int moduleId,
             @NonNull SoundTrigger.StatusListener listener,
             @Nullable Handler handler, Identity middlemanIdentity,
diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
index eed92c1..a1d74df 100644
--- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
+++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
@@ -102,7 +102,9 @@
      * Detach from this module. The {@link SoundTrigger.StatusListener} callback will not be called
      * anymore and associated resources will be released.
      * All models must have been unloaded prior to detaching.
+     * @deprecated Use {@link android.media.soundtrigger.SoundTriggerManager} instead.
      */
+    @Deprecated
     @UnsupportedAppUsage
     public synchronized void detach() {
         try {
@@ -131,7 +133,9 @@
      *         - {@link SoundTrigger#STATUS_DEAD_OBJECT} if the binder transaction to the native
      *         service fails
      *         - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence
+     * @deprecated Use {@link android.media.soundtrigger.SoundTriggerManager} instead.
      */
+    @Deprecated
     @UnsupportedAppUsage
     public synchronized int loadSoundModel(@NonNull SoundTrigger.SoundModel model,
             @NonNull int[] soundModelHandle) {
@@ -191,8 +195,10 @@
      *         - {@link SoundTrigger#STATUS_BAD_VALUE} if the sound model handle is invalid
      *         - {@link SoundTrigger#STATUS_DEAD_OBJECT} if the binder transaction to the native
      *         service fails
+     * @deprecated Use {@link android.media.soundtrigger.SoundTriggerManager} instead.
      */
     @UnsupportedAppUsage
+    @Deprecated
     public synchronized int unloadSoundModel(int soundModelHandle) {
         try {
             mService.unloadModel(soundModelHandle);
@@ -219,8 +225,10 @@
      *         - {@link SoundTrigger#STATUS_DEAD_OBJECT} if the binder transaction to the native
      *         service fails
      *         - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence
+     * @deprecated Use {@link android.media.soundtrigger.SoundTriggerManager} instead.
      */
     @UnsupportedAppUsage
+    @Deprecated
     public synchronized int startRecognition(int soundModelHandle,
             SoundTrigger.RecognitionConfig config) {
         try {
@@ -244,8 +252,10 @@
      *         - {@link SoundTrigger#STATUS_DEAD_OBJECT} if the binder transaction to the native
      *         service fails
      *         - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence
+     * @deprecated Use {@link android.media.soundtrigger.SoundTriggerManager} instead.
      */
     @UnsupportedAppUsage
+    @Deprecated
     public synchronized int stopRecognition(int soundModelHandle) {
         try {
             mService.stopRecognition(soundModelHandle);
diff --git a/core/java/android/hardware/usb/DisplayPortAltModeInfo.java b/core/java/android/hardware/usb/DisplayPortAltModeInfo.java
index ef2fefc..7c62373 100644
--- a/core/java/android/hardware/usb/DisplayPortAltModeInfo.java
+++ b/core/java/android/hardware/usb/DisplayPortAltModeInfo.java
@@ -39,8 +39,8 @@
     private final @DisplayPortAltModeStatus int mPartnerSinkStatus;
     private final @DisplayPortAltModeStatus int mCableStatus;
     private final int mNumLanes;
-    private final boolean mHpd;
-    private final int mLinkTrainingStatus;
+    private final boolean mHotPlugDetect;
+    private final @LinkTrainingStatus int mLinkTrainingStatus;
 
     /**
      * Port Partners:
@@ -90,6 +90,25 @@
      */
     public static final int DISPLAYPORT_ALT_MODE_STATUS_ENABLED = 3;
 
+    /*
+     * Indicates that DisplayPort Alt Mode link training has not initiated or completed.
+     */
+    public static final int LINK_TRAINING_STATUS_UNKNOWN = 0;
+
+    /*
+     * Indicates that DisplayPort Alt Mode link training has completed and the optimal data
+     * transmission settings between the device and the connected port partner have successfully
+     * been negotiated.
+     */
+    public static final int LINK_TRAINING_STATUS_SUCCESS = 1;
+
+    /*
+     * Indicates that DisplayPort Alt Mode link training has completed but no data transmission
+     * settings between the device and the connected port partner could be established, and that the
+     * link initialization has terminated.
+     */
+    public static final int LINK_TRAINING_STATUS_FAILURE = 2;
+
     /** @hide */
     @IntDef(prefix = { "DISPLAYPORT_ALT_MODE_STATUS_" }, value = {
             DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN,
@@ -101,21 +120,30 @@
     public @interface DisplayPortAltModeStatus {}
 
     /** @hide */
+    @IntDef(prefix = { "LINK_TRAINING_STATUS_" }, value = {
+            LINK_TRAINING_STATUS_UNKNOWN,
+            LINK_TRAINING_STATUS_SUCCESS,
+            LINK_TRAINING_STATUS_FAILURE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LinkTrainingStatus {}
+
+    /** @hide */
     public DisplayPortAltModeInfo() {
         mPartnerSinkStatus = DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN;
         mCableStatus = DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN;
         mNumLanes = 0;
-        mHpd = false;
-        mLinkTrainingStatus = 0;
+        mHotPlugDetect = false;
+        mLinkTrainingStatus = LINK_TRAINING_STATUS_UNKNOWN;
     }
 
     /** @hide */
     public DisplayPortAltModeInfo(int partnerSinkStatus, int cableStatus,
-            int numLanes, boolean hpd, int linkTrainingStatus) {
+            int numLanes, boolean hotPlugDetect, int linkTrainingStatus) {
         mPartnerSinkStatus = partnerSinkStatus;
         mCableStatus = cableStatus;
         mNumLanes = numLanes;
-        mHpd = hpd;
+        mHotPlugDetect = hotPlugDetect;
         mLinkTrainingStatus = linkTrainingStatus;
     }
 
@@ -151,6 +179,21 @@
         return mNumLanes;
     }
 
+    /**
+     * Returns whether or not the Hot Plug Detect (HPD) value of the connected DisplayPort Alt Mode
+     * partner sink is active.
+     */
+    public boolean isHotPlugDetectActive() {
+        return mHotPlugDetect;
+    }
+
+    /**
+     * Returns the DisplayPort Alt Mode link training status.
+     */
+    public @LinkTrainingStatus int getLinkTrainingStatus() {
+        return mLinkTrainingStatus;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -161,7 +204,7 @@
         dest.writeInt(mPartnerSinkStatus);
         dest.writeInt(mCableStatus);
         dest.writeInt(mNumLanes);
-        dest.writeBoolean(mHpd);
+        dest.writeBoolean(mHotPlugDetect);
         dest.writeInt(mLinkTrainingStatus);
     }
 
@@ -174,8 +217,8 @@
                 + mCableStatus
                 + " numLanes="
                 + mNumLanes
-                + " hpd="
-                + mHpd
+                + " hotPlugDetect="
+                + mHotPlugDetect
                 + " linkTrainingStatus="
                 + mLinkTrainingStatus
                 + "}";
@@ -192,12 +235,15 @@
         DisplayPortAltModeInfo other = (DisplayPortAltModeInfo) o;
         return this.mPartnerSinkStatus == other.mPartnerSinkStatus
                 && this.mCableStatus == other.mCableStatus
-                && this.mNumLanes == other.mNumLanes;
+                && this.mNumLanes == other.mNumLanes
+                && this.mHotPlugDetect == other.mHotPlugDetect
+                && this.mLinkTrainingStatus == other.mLinkTrainingStatus;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mPartnerSinkStatus, mCableStatus, mNumLanes);
+        return Objects.hash(mPartnerSinkStatus, mCableStatus, mNumLanes, mHotPlugDetect,
+                mLinkTrainingStatus);
     }
 
     public static final @NonNull Parcelable.Creator<DisplayPortAltModeInfo> CREATOR =
@@ -207,10 +253,10 @@
             int partnerSinkStatus = in.readInt();
             int cableStatus = in.readInt();
             int numLanes = in.readInt();
-            boolean hpd = in.readBoolean();
+            boolean hotPlugDetect = in.readBoolean();
             int linkTrainingStatus = in.readInt();
-            return new DisplayPortAltModeInfo(partnerSinkStatus, cableStatus, numLanes, hpd,
-                    linkTrainingStatus);
+            return new DisplayPortAltModeInfo(partnerSinkStatus, cableStatus, numLanes,
+                    hotPlugDetect, linkTrainingStatus);
         }
 
         @Override
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 909d147..0483b71 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -37,8 +37,8 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.hardware.usb.gadget.V1_0.GadgetFunction;
-import android.hardware.usb.gadget.V1_2.UsbSpeed;
+import android.hardware.usb.gadget.GadgetFunction;
+import android.hardware.usb.gadget.UsbSpeed;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -54,15 +54,12 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.StringJoiner;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.Executor;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * This class allows you to access the state of USB and communicate with USB devices.
@@ -78,7 +75,7 @@
 public class UsbManager {
     private static final String TAG = "UsbManager";
 
-   /**
+    /**
      * Broadcast Action:  A sticky broadcast for USB state change events when in device mode.
      *
      * This is a sticky broadcast for clients that includes USB connected/disconnected state,
@@ -104,7 +101,7 @@
      * MIDI function is enabled
      * </ul>
      * If the sticky intent has not been found, that indicates USB is disconnected,
-     * USB is not configued, MTP function is enabled, and all the other functions are disabled.
+     * USB is not configured, MTP function is enabled, and all the other functions are disabled.
      *
      * @hide
      */
@@ -124,7 +121,7 @@
     public static final String ACTION_USB_PORT_CHANGED =
             "android.hardware.usb.action.USB_PORT_CHANGED";
 
-     /**
+    /**
      * Broadcast Action: A broadcast for USB compliance warning changes.
      *
      * This intent is sent when a port partner's
@@ -137,7 +134,7 @@
     public static final String ACTION_USB_PORT_COMPLIANCE_CHANGED =
             "android.hardware.usb.action.USB_PORT_COMPLIANCE_CHANGED";
 
-   /**
+    /**
      * Activity intent sent when user attaches a USB device.
      *
      * This intent is sent when a USB device is attached to the USB bus when in host mode.
@@ -150,7 +147,7 @@
     public static final String ACTION_USB_DEVICE_ATTACHED =
             "android.hardware.usb.action.USB_DEVICE_ATTACHED";
 
-   /**
+    /**
      * Broadcast Action:  A broadcast for USB device detached event.
      *
      * This intent is sent when a USB device is detached from the USB bus when in host mode.
@@ -163,7 +160,7 @@
     public static final String ACTION_USB_DEVICE_DETACHED =
             "android.hardware.usb.action.USB_DEVICE_DETACHED";
 
-   /**
+    /**
      * Activity intent sent when user attaches a USB accessory.
      *
      * <ul>
@@ -175,7 +172,7 @@
     public static final String ACTION_USB_ACCESSORY_ATTACHED =
             "android.hardware.usb.action.USB_ACCESSORY_ATTACHED";
 
-   /**
+    /**
      * Broadcast Action:  A broadcast for USB accessory detached event.
      *
      * This intent is sent when a USB accessory is detached.
@@ -616,6 +613,7 @@
 
     /**
      * Code for the charging usb function. Passed into {@link #setCurrentFunctions(long)}
+     * Must be equal to {@link GadgetFunction#NONE}
      * @hide
      */
     @SystemApi
@@ -623,55 +621,63 @@
 
     /**
      * Code for the mtp usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
+     * Must be equal to {@link GadgetFunction#MTP}
      * @hide
      */
     @SystemApi
-    public static final long FUNCTION_MTP = GadgetFunction.MTP;
+    public static final long FUNCTION_MTP = 1 << 2;
 
     /**
      * Code for the ptp usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
+     * Must be equal to {@link GadgetFunction#PTP}
      * @hide
      */
     @SystemApi
-    public static final long FUNCTION_PTP = GadgetFunction.PTP;
+    public static final long FUNCTION_PTP = 1 << 4;
 
     /**
      * Code for the rndis usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
+     * Must be equal to {@link GadgetFunction#RNDIS}
      * @hide
      */
     @SystemApi
-    public static final long FUNCTION_RNDIS = GadgetFunction.RNDIS;
+    public static final long FUNCTION_RNDIS = 1 << 5;
 
     /**
      * Code for the midi usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
+     * Must be equal to {@link GadgetFunction#MIDI}
      * @hide
      */
     @SystemApi
-    public static final long FUNCTION_MIDI = GadgetFunction.MIDI;
+    public static final long FUNCTION_MIDI = 1 << 3;
 
     /**
      * Code for the accessory usb function.
+     * Must be equal to {@link GadgetFunction#ACCESSORY}
      * @hide
      */
     @SystemApi
-    public static final long FUNCTION_ACCESSORY = GadgetFunction.ACCESSORY;
+    public static final long FUNCTION_ACCESSORY = 1 << 1;
 
     /**
      * Code for the audio source usb function.
+     * Must be equal to {@link GadgetFunction#AUDIO_SOURCE}
      * @hide
      */
     @SystemApi
-    public static final long FUNCTION_AUDIO_SOURCE = GadgetFunction.AUDIO_SOURCE;
+    public static final long FUNCTION_AUDIO_SOURCE = 1 << 6;
 
     /**
      * Code for the adb usb function.
+     * Must be equal to {@link GadgetFunction#ADB}
      * @hide
      */
     @SystemApi
-    public static final long FUNCTION_ADB = GadgetFunction.ADB;
+    public static final long FUNCTION_ADB = 1;
 
     /**
      * Code for the ncm source usb function.
+     * Must be equal to {@link GadgetFunction#NCM}
      * @hide
      */
     @SystemApi
@@ -998,7 +1004,7 @@
         }
     }
 
-   /**
+    /**
      * Requests temporary permission for the given package to access the device.
      * This may result in a system dialog being displayed to the user
      * if permission had not already been granted.
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 083b4f6..a35b088 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2425,8 +2425,9 @@
     public abstract int getHistoryTagPoolUid(int index);
 
     /**
-     * Returns a BatteryStatsHistoryIterator. Battery history will remain immutable until the
-     * {@link BatteryStatsHistoryIterator#close()} method is invoked.
+     * Returns a BatteryStatsHistoryIterator. Battery history will continue being writable,
+     * but the iterator will continue iterating over the snapshot taken at the time this method
+     * is called.
      */
     public abstract BatteryStatsHistoryIterator iterateBatteryStatsHistory();
 
@@ -5120,14 +5121,6 @@
         sb.append(formatCharge(power));
     }
 
-    /**
-     * Temporary for settings.
-     */
-    public final void dumpLocked(Context context, PrintWriter pw, String prefix, int which,
-            int reqUid) {
-        dumpLocked(context, pw, prefix, which, reqUid, checkWifiOnly(context));
-    }
-
     @SuppressWarnings("unused")
     public final void dumpLocked(Context context, PrintWriter pw, String prefix, final int which,
             int reqUid, boolean wifiOnly) {
@@ -7483,7 +7476,25 @@
     public static final int DUMP_VERBOSE = 1<<5;
     public static final int DUMP_DEVICE_WIFI_ONLY = 1<<6;
 
-    private void dumpHistoryLocked(PrintWriter pw, int flags, long histStart, boolean checkin) {
+    private void dumpHistory(PrintWriter pw, int flags, long histStart, boolean checkin) {
+        if (!checkin) {
+            synchronized (this) {
+                final long historyTotalSize = getHistoryTotalSize();
+                final long historyUsedSize = getHistoryUsedSize();
+                pw.print("Battery History (");
+                pw.print((100 * historyUsedSize) / historyTotalSize);
+                pw.print("% used, ");
+                printSizeValue(pw, historyUsedSize);
+                pw.print(" used of ");
+                printSizeValue(pw, historyTotalSize);
+                pw.print(", ");
+                pw.print(getHistoryStringPoolSize());
+                pw.print(" strings using ");
+                printSizeValue(pw, getHistoryStringPoolBytes());
+                pw.println("):");
+            }
+        }
+
         final HistoryPrinter hprinter = new HistoryPrinter();
         long lastTime = -1;
         long baseTime = -1;
@@ -7628,27 +7639,14 @@
      * @param pw a Printer to receive the dump output.
      */
     @SuppressWarnings("unused")
-    public void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
+    public void dump(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
         prepareForDumpLocked();
 
         final boolean filtering = (flags
                 & (DUMP_HISTORY_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
 
         if ((flags&DUMP_HISTORY_ONLY) != 0 || !filtering) {
-            final long historyTotalSize = getHistoryTotalSize();
-            final long historyUsedSize = getHistoryUsedSize();
-            pw.print("Battery History (");
-            pw.print((100 * historyUsedSize) / historyTotalSize);
-            pw.print("% used, ");
-            printSizeValue(pw, historyUsedSize);
-            pw.print(" used of ");
-            printSizeValue(pw, historyTotalSize);
-            pw.print(", ");
-            pw.print(getHistoryStringPoolSize());
-            pw.print(" strings using ");
-            printSizeValue(pw, getHistoryStringPoolBytes());
-            pw.println("):");
-            dumpHistoryLocked(pw, flags, histStart, false);
+            dumpHistory(pw, flags, histStart, false);
             pw.println();
         }
 
@@ -7656,6 +7654,13 @@
             return;
         }
 
+        synchronized (this) {
+            dumpLocked(context, pw, flags, reqUid, filtering);
+        }
+    }
+
+    private void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid,
+            boolean filtering) {
         if (!filtering) {
             SparseArray<? extends Uid> uidStats = getUidStats();
             final int NU = uidStats.size();
@@ -7823,7 +7828,7 @@
                 }
                 pw.print("\"");
                 pw.println();
-                dumpHistoryLocked(pw, flags, histStart, true);
+                dumpHistory(pw, flags, histStart, true);
             }
         }
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3902a15..07212a2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -40,6 +40,7 @@
 import android.app.NotificationManager;
 import android.app.SearchManager;
 import android.app.WallpaperManager;
+import android.app.tare.EconomyManager;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -14682,7 +14683,7 @@
          *
          * @hide
          */
-        public static final int DEFAULT_ENABLE_TARE = 1;
+        public static final int DEFAULT_ENABLE_TARE = EconomyManager.DEFAULT_ENABLE_TARE_MODE;
 
         /**
          * Whether to enable the TARE AlarmManager economic policy or not.
@@ -14697,7 +14698,8 @@
          *
          * @hide
          */
-        public static final int DEFAULT_ENABLE_TARE_ALARM_MANAGER = 0;
+        public static final int DEFAULT_ENABLE_TARE_ALARM_MANAGER =
+                        EconomyManager.DEFAULT_ENABLE_POLICY_ALARM ? 1 : 0;
 
         /**
          * Settings for AlarmManager's TARE EconomicPolicy (list of its economic factors).
@@ -14721,7 +14723,8 @@
          *
          * @hide
          */
-        public static final int DEFAULT_ENABLE_TARE_JOB_SCHEDULER = 0;
+        public static final int DEFAULT_ENABLE_TARE_JOB_SCHEDULER =
+                EconomyManager.DEFAULT_ENABLE_POLICY_JOB_SCHEDULER ? 1 : 0;
 
         /**
          * Settings for JobScheduler's TARE EconomicPolicy (list of its economic factors).
diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java
index 09545fc..b93e338 100644
--- a/core/java/android/util/TypedValue.java
+++ b/core/java/android/util/TypedValue.java
@@ -495,6 +495,48 @@
     }
 
     /**
+     * Converts a pixel value to the given dimension, e.g. PX to DP.
+     *
+     * <p>This is just an alias of {@link #deriveDimension(int, float, DisplayMetrics)} with an
+     * easier-to-find name.
+     *
+     * @param unitToConvertTo The unit to convert to.
+     * @param pixelValue The raw pixels value to convert from.
+     * @param metrics Current display metrics to use in the conversion --
+     *                supplies display density and scaling information.
+     *
+     * @return A dimension value equivalent to the given number of pixels
+     * @throws IllegalArgumentException if unitToConvertTo is not valid.
+     */
+    public static float convertPixelsToDimension(
+            @ComplexDimensionUnit int unitToConvertTo,
+            float pixelValue,
+            @NonNull DisplayMetrics metrics) {
+        return deriveDimension(unitToConvertTo, pixelValue, metrics);
+    }
+
+    /**
+     * Converts a dimension value to raw pixels, e.g. DP to PX.
+     *
+     * <p>This is just an alias of {@link #applyDimension(int, float, DisplayMetrics)} with an
+     * easier-to-find name.
+     *
+     * @param unitToConvertFrom The unit to convert from.
+     * @param value The dimension value to apply the unit to.
+     * @param metrics Current display metrics to use in the conversion --
+     *                supplies display density and scaling information.
+     *
+     * @return The equivalent pixel value—i.e. the complex floating point value multiplied by the
+     * appropriate metrics depending on its unit—or zero if unit is not valid.
+     */
+    public static float convertDimensionToPixels(
+            @ComplexDimensionUnit int unitToConvertFrom,
+            float value,
+            @NonNull DisplayMetrics metrics) {
+        return applyDimension(unitToConvertFrom, value, metrics);
+    }
+
+    /**
      * Return the data for this value as a dimension.  Only use for values 
      * whose type is {@link #TYPE_DIMENSION}. 
      * 
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 47da3f6..b22a43e 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -561,6 +561,7 @@
         private String mKeyboardLayoutType = null;
         private int mUsiVersionMajor = -1;
         private int mUsiVersionMinor = -1;
+        private int mAssociatedDisplayId = Display.INVALID_DISPLAY;
         private List<MotionRange> mMotionRanges = new ArrayList<>();
 
         /** @see InputDevice#getId() */
@@ -678,6 +679,12 @@
             return this;
         }
 
+        /** @see InputDevice#getAssociatedDisplayId() */
+        public Builder setAssociatedDisplayId(int displayId) {
+            mAssociatedDisplayId = displayId;
+            return this;
+        }
+
         /** @see InputDevice#getMotionRanges() */
         public Builder addMotionRange(int axis, int source,
                 float min, float max, float flat, float fuzz, float resolution) {
@@ -708,7 +715,7 @@
                     mHasBattery,
                     mUsiVersionMajor,
                     mUsiVersionMinor,
-                    Display.INVALID_DISPLAY);
+                    mAssociatedDisplayId);
 
             final int numRanges = mMotionRanges.size();
             for (int i = 0; i < numRanges; i++) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 5c23c31..fedb098 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -222,6 +222,8 @@
             int transform);
     private static native void nativeSetDataSpace(long transactionObj, long nativeObject,
             @DataSpace.NamedDataSpace int dataSpace);
+    private static native void nativeSetExtendedRangeBrightness(long transactionObj,
+            long nativeObject, float currentBufferRatio, float desiredRatio);
     private static native void nativeSetDamageRegion(long transactionObj, long nativeObject,
             Region region);
     private static native void nativeSetDimmingEnabled(long transactionObj, long nativeObject,
@@ -3610,6 +3612,46 @@
         }
 
         /**
+         * Sets the desired extended range brightness for the layer. This only applies for layers
+         * whose dataspace has RANGE_EXTENDED.
+         *
+         * @param sc The layer whose extended range brightness is being specified
+         * @param currentBufferRatio The current sdr/hdr ratio of the current buffer. For example
+         *                           if the buffer was rendered with a target SDR whitepoint of
+         *                           100 nits and a max display brightness of 200 nits, this should
+         *                           be set to 2.0f.
+         *
+         *                           Default value is 1.0f.
+         *
+         *                           Transfer functions that encode their own brightness ranges,
+         *                           such as HLG or PQ, should also set this to 1.0f and instead
+         *                           communicate extended content brightness information via
+         *                           metadata such as CTA861_3 or SMPTE2086.
+         *
+         * @param desiredRatio The desired sdr/hdr ratio. This can be used to communicate the max
+         *                     desired brightness range. This is similar to the "max luminance"
+         *                     value in other HDR metadata formats, but represented as a ratio of
+         *                     the target SDR whitepoint to the max display brightness. The system
+         *                     may not be able to, or may choose not to, deliver the
+         *                     requested range.
+         *
+         *                     If unspecified, the system will attempt to provide the best range
+         *                     it can for the given ambient conditions & device state. However,
+         *                     voluntarily reducing the requested range can help improve battery
+         *                     life as well as can improve quality by ensuring greater bit depth
+         *                     is allocated to the luminance range in use.
+         * @return this
+         * @hide
+         **/
+        public @NonNull Transaction setExtendedRangeBrightness(@NonNull SurfaceControl sc,
+                float currentBufferRatio, float desiredRatio) {
+            checkPreconditions(sc);
+            nativeSetExtendedRangeBrightness(mNativeObject, sc.mNativeObject, currentBufferRatio,
+                    desiredRatio);
+            return this;
+        }
+
+        /**
          * Sets the trusted overlay state on this SurfaceControl and it is inherited to all the
          * children. The caller must hold the ACCESS_SURFACE_FLINGER permission.
          * @hide
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 508c6bd..7b53843 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7698,8 +7698,13 @@
 
         boolean handled = false;
         final ListenerInfo li = mListenerInfo;
+        boolean shouldPerformHapticFeedback = true;
         if (li != null && li.mOnLongClickListener != null) {
             handled = li.mOnLongClickListener.onLongClick(View.this);
+            if (handled) {
+                shouldPerformHapticFeedback =
+                        li.mOnLongClickListener.onLongClickUseDefaultHapticFeedback(View.this);
+            }
         }
         if (!handled) {
             final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y);
@@ -7710,7 +7715,7 @@
                 handled = showLongClickTooltip((int) x, (int) y);
             }
         }
-        if (handled) {
+        if (handled && shouldPerformHapticFeedback) {
             performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
         }
         return handled;
@@ -29922,6 +29927,19 @@
          * @return true if the callback consumed the long click, false otherwise.
          */
         boolean onLongClick(View v);
+
+        /**
+         * Returns whether the default {@link HapticFeedbackConstants#LONG_PRESS} haptic feedback
+         * is performed when this listener has consumed the long click. This method is called
+         * immediately after {@link #onLongClick} has returned true.
+         *
+         * @param v The view that was clicked and held.
+         * @return true to perform the default {@link HapticFeedbackConstants#LONG_PRESS} haptic
+         * feedback, or false if the handler manages all haptics itself.
+         */
+        default boolean onLongClickUseDefaultHapticFeedback(@NonNull View v) {
+            return true;
+        }
     }
 
     /**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 6eb932e..84ed845 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -75,7 +75,6 @@
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
@@ -440,6 +439,7 @@
     @NonNull Display mDisplay;
     final DisplayManager mDisplayManager;
     final String mBasePackageName;
+    final InputManager mInputManager;
 
     final int[] mTmpLocation = new int[2];
 
@@ -968,6 +968,7 @@
         // TODO(b/222696368): remove getSfInstance usage and use vsyncId for transactions
         mChoreographer = Choreographer.getInstance();
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
+        mInputManager = context.getSystemService(InputManager.class);
         mInsetsController = new InsetsController(new ViewRootInsetsControllerHost(this));
         mHandwritingInitiator = new HandwritingInitiator(
                 mViewConfiguration,
@@ -5337,7 +5338,7 @@
             Log.e(mTag, "No input channel to request Pointer Capture.");
             return;
         }
-        InputManager.getInstance().requestPointerCapture(inputToken, enabled);
+        mInputManager.requestPointerCapture(inputToken, enabled);
     }
 
     private void handlePointerCaptureChanged(boolean hasCapture) {
@@ -6860,9 +6861,8 @@
             if (event.getPointerCount() != 1) {
                 return;
             }
-            final boolean needsStylusPointerIcon =
-                    InputManager.getInstance().isStylusPointerIconEnabled()
-                            && event.isStylusPointer();
+            final boolean needsStylusPointerIcon = event.isStylusPointer()
+                    && mInputManager.isStylusPointerIconEnabled();
             if (needsStylusPointerIcon || event.isFromSource(InputDevice.SOURCE_MOUSE)) {
                 if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER
                         || event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
@@ -6934,7 +6934,7 @@
 
         PointerIcon pointerIcon = null;
 
-        if (event.isStylusPointer() && InputManager.getInstance().isStylusPointerIconEnabled()) {
+        if (event.isStylusPointer() && mInputManager.isStylusPointerIconEnabled()) {
             pointerIcon = mHandwritingInitiator.onResolvePointerIcon(mContext, event);
         }
 
@@ -6949,14 +6949,14 @@
             mPointerIconType = pointerType;
             mCustomPointerIcon = null;
             if (mPointerIconType != PointerIcon.TYPE_CUSTOM) {
-                InputManager.getInstance().setPointerIconType(pointerType);
+                mInputManager.setPointerIconType(pointerType);
                 return true;
             }
         }
         if (mPointerIconType == PointerIcon.TYPE_CUSTOM &&
                 !pointerIcon.equals(mCustomPointerIcon)) {
             mCustomPointerIcon = pointerIcon;
-            InputManager.getInstance().setCustomPointerIcon(mCustomPointerIcon);
+            mInputManager.setCustomPointerIcon(mCustomPointerIcon);
         }
         return true;
     }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 5144f3a..40898d0 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1099,6 +1099,77 @@
             "android.window.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE";
 
     /**
+     * Activity level {@link android.content.pm.PackageManager.Property PackageManager
+     * .Property} for an app to inform the system that the activity should be excluded from the
+     * compatibility override for orientation set by the device manufacturer.
+     *
+     * <p>With this property set to {@code true} or unset, device manufacturers can override
+     * orientation for the activity using their discretion to improve display compatibility.
+     *
+     * <p>With this property set to {@code false}, device manufactured per-app override for
+     * orientation won't be applied.
+     *
+     * <p><b>Syntax:</b>
+     * <pre>
+     * &lt;activity&gt;
+     *   &lt;property
+     *     android:name="android.window.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE"
+     *     android:value="true|false"/&gt;
+     * &lt;/activity&gt;
+     * </pre>
+     *
+     * @hide
+     */
+    // TODO(b/263984287): Make this public API.
+    String PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE =
+            "android.window.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE";
+
+    /**
+     * Activity level {@link android.content.pm.PackageManager.Property PackageManager
+     * .Property} for an app to inform the system that the activity should be opted-out from the
+     * compatibility override that fixes display orientation to landscape natural orientation when
+     * an activity is fullscreen.
+     *
+     * <p>When this compat override is enabled and while display is fixed to the landscape natural
+     * orientation, the orientation requested by the activity will be still respected by bounds
+     * resolution logic. For instance, if an activity requests portrait orientation, then activity
+     * will appear in the letterbox mode for fixed orientation with the display rotated to the
+     * lanscape natural orientation.
+     *
+     * <p>The treatment is disabled by default but device manufacturers can enable the treatment
+     * using their discretion to improve display compatibility on the displays that have
+     * ignoreOrientationRequest display setting enabled (enables compatibility mode for fixed
+     * orientation, see <a href="https://developer.android.com/guide/practices/enhanced-letterboxing">Enhanced letterboxing</a>
+     * for more details).
+     *
+     * <p>With this property set to {@code true} or unset, the system wiil use landscape display
+     * orientation when the following conditions are met:
+     * <ul>
+     *     <li>Natural orientation of the display is landscape
+     *     <li>ignoreOrientationRequest display setting is enabled
+     *     <li>Activity is fullscreen.
+     *     <li>Device manufacturer enabled the treatment.
+     * </ul>
+     *
+     * <p>With this property set to {@code false}, device manufactured per-app override for
+     * display orientation won't be applied.
+     *
+     * <p><b>Syntax:</b>
+     * <pre>
+     * &lt;activity&gt;
+     *   &lt;property
+     *     android:name="android.window.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE"
+     *     android:value="true|false"/&gt;
+     * &lt;/activity&gt;
+     * </pre>
+     *
+     * @hide
+     */
+    // TODO(b/263984287): Make this public API.
+    String PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE =
+            "android.window.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE";
+
+    /**
      * @hide
      */
     public static final String PARCEL_KEY_SHORTCUTS_ARRAY = "shortcuts_array";
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 21d22f2..b157ea0 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -361,7 +361,6 @@
         }
 
         t.setPosition(leash, frames.frame.left, frames.frame.top);
-        t.setWindowCrop(leash, frames.frame.width(), frames.frame.height());
 
         if (viewFlags == View.VISIBLE) {
             // TODO(b/262892794) ViewRootImpl modifies the app's rendering SurfaceControl
diff --git a/core/java/android/window/TaskFragmentCreationParams.java b/core/java/android/window/TaskFragmentCreationParams.java
index 203d79a..c19abf9 100644
--- a/core/java/android/window/TaskFragmentCreationParams.java
+++ b/core/java/android/window/TaskFragmentCreationParams.java
@@ -52,10 +52,26 @@
     @NonNull
     private final IBinder mOwnerToken;
 
-    /** The initial bounds of the TaskFragment. Fills parent if empty. */
+    /**
+     * The initial bounds of the TaskFragment. Fills parent if empty.
+     * TODO(b/232476698): cleanup with update CTS.
+     */
     @NonNull
     private final Rect mInitialBounds = new Rect();
 
+    /**
+     * The initial relative bounds of the TaskFragment in parent coordinate.
+     * Fills parent if empty.
+     */
+    @NonNull
+    private final Rect mInitialRelativeBounds = new Rect();
+
+    /**
+     * Whether the params are using {@link Builder#setInitialRelativeBounds(Rect)}.
+     * TODO(b/232476698): remove after remove mInitialBounds
+     */
+    private final boolean mAreInitialRelativeBoundsSet;
+
     /** The initial windowing mode of the TaskFragment. Inherits from parent if not set. */
     @WindowingMode
     private final int mWindowingMode;
@@ -94,6 +110,7 @@
     private TaskFragmentCreationParams(
             @NonNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken,
             @NonNull IBinder ownerToken, @NonNull Rect initialBounds,
+            @NonNull Rect initialRelativeBounds, boolean areInitialRelativeBoundsSet,
             @WindowingMode int windowingMode, @Nullable IBinder pairedPrimaryFragmentToken,
             @Nullable IBinder pairedActivityToken) {
         if (pairedPrimaryFragmentToken != null && pairedActivityToken != null) {
@@ -104,6 +121,8 @@
         mFragmentToken = fragmentToken;
         mOwnerToken = ownerToken;
         mInitialBounds.set(initialBounds);
+        mInitialRelativeBounds.set(initialRelativeBounds);
+        mAreInitialRelativeBoundsSet = areInitialRelativeBoundsSet;
         mWindowingMode = windowingMode;
         mPairedPrimaryFragmentToken = pairedPrimaryFragmentToken;
         mPairedActivityToken = pairedActivityToken;
@@ -129,6 +148,23 @@
         return mInitialBounds;
     }
 
+    /**
+     * TODO(b/232476698): remove the hide with adding CTS for this in next release.
+     * @hide
+     */
+    @NonNull
+    public Rect getInitialRelativeBounds() {
+        return mInitialRelativeBounds;
+    }
+
+    /**
+     * TODO(b/232476698): remove after remove mInitialBounds.
+     * @hide
+     */
+    public boolean areInitialRelativeBoundsSet() {
+        return mAreInitialRelativeBoundsSet;
+    }
+
     @WindowingMode
     public int getWindowingMode() {
         return mWindowingMode;
@@ -157,6 +193,8 @@
         mFragmentToken = in.readStrongBinder();
         mOwnerToken = in.readStrongBinder();
         mInitialBounds.readFromParcel(in);
+        mInitialRelativeBounds.readFromParcel(in);
+        mAreInitialRelativeBoundsSet = in.readBoolean();
         mWindowingMode = in.readInt();
         mPairedPrimaryFragmentToken = in.readStrongBinder();
         mPairedActivityToken = in.readStrongBinder();
@@ -169,6 +207,8 @@
         dest.writeStrongBinder(mFragmentToken);
         dest.writeStrongBinder(mOwnerToken);
         mInitialBounds.writeToParcel(dest, flags);
+        mInitialRelativeBounds.writeToParcel(dest, flags);
+        dest.writeBoolean(mAreInitialRelativeBoundsSet);
         dest.writeInt(mWindowingMode);
         dest.writeStrongBinder(mPairedPrimaryFragmentToken);
         dest.writeStrongBinder(mPairedActivityToken);
@@ -195,6 +235,7 @@
                 + " fragmentToken=" + mFragmentToken
                 + " ownerToken=" + mOwnerToken
                 + " initialBounds=" + mInitialBounds
+                + " initialRelativeBounds=" + mInitialRelativeBounds
                 + " windowingMode=" + mWindowingMode
                 + " pairedFragmentToken=" + mPairedPrimaryFragmentToken
                 + " pairedActivityToken=" + mPairedActivityToken
@@ -222,6 +263,11 @@
         @NonNull
         private final Rect mInitialBounds = new Rect();
 
+        @NonNull
+        private final Rect mInitialRelativeBounds = new Rect();
+
+        private boolean mAreInitialRelativeBoundsSet;
+
         @WindowingMode
         private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
 
@@ -245,6 +291,19 @@
             return this;
         }
 
+        /**
+         * Sets the initial relative bounds for the TaskFragment in parent coordinate.
+         * Set to empty to fill parent.
+         * TODO(b/232476698): remove the hide with adding CTS for this in next release.
+         * @hide
+         */
+        @NonNull
+        public Builder setInitialRelativeBounds(@NonNull Rect bounds) {
+            mInitialRelativeBounds.set(bounds);
+            mAreInitialRelativeBoundsSet = true;
+            return this;
+        }
+
         /** Sets the initial windowing mode for the TaskFragment. */
         @NonNull
         public Builder setWindowingMode(@WindowingMode int windowingMode) {
@@ -296,8 +355,8 @@
         @NonNull
         public TaskFragmentCreationParams build() {
             return new TaskFragmentCreationParams(mOrganizer, mFragmentToken, mOwnerToken,
-                    mInitialBounds, mWindowingMode, mPairedPrimaryFragmentToken,
-                    mPairedActivityToken);
+                    mInitialBounds, mInitialRelativeBounds, mAreInitialRelativeBoundsSet,
+                    mWindowingMode, mPairedPrimaryFragmentToken, mPairedActivityToken);
         }
     }
 }
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index cc48d46..a2fa162 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -306,6 +306,26 @@
     }
 
     /**
+     * Resizes a container by providing a bounds in its parent coordinate.
+     * This is only used by {@link TaskFragmentOrganizer}.
+     * @hide
+     */
+    @NonNull
+    public WindowContainerTransaction setRelativeBounds(
+            @NonNull WindowContainerToken container, @NonNull Rect relBounds) {
+        Change chg = getOrCreateChange(container.asBinder());
+        if (chg.mRelativeBounds == null) {
+            chg.mRelativeBounds = new Rect();
+        }
+        chg.mRelativeBounds.set(relBounds);
+        chg.mChangeMask |= Change.CHANGE_RELATIVE_BOUNDS;
+        // Bounds will be overridden.
+        chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
+        chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_BOUNDS;
+        return this;
+    }
+
+    /**
      * Reparents a container into another one. The effect of a {@code null} parent can vary. For
      * example, reparenting a stack to {@code null} will reparent it to its display.
      *
@@ -979,6 +999,7 @@
         public static final int CHANGE_FORCE_NO_PIP = 1 << 6;
         public static final int CHANGE_FORCE_TRANSLUCENT = 1 << 7;
         public static final int CHANGE_DRAG_RESIZING = 1 << 8;
+        public static final int CHANGE_RELATIVE_BOUNDS = 1 << 9;
 
         private final Configuration mConfiguration = new Configuration();
         private boolean mFocusable = true;
@@ -994,6 +1015,8 @@
         private Rect mPinnedBounds = null;
         private SurfaceControl.Transaction mBoundsChangeTransaction = null;
         private Rect mBoundsChangeSurfaceBounds = null;
+        @Nullable
+        private Rect mRelativeBounds = null;
 
         private int mActivityWindowingMode = -1;
         private int mWindowingMode = -1;
@@ -1022,6 +1045,10 @@
                 mBoundsChangeSurfaceBounds = new Rect();
                 mBoundsChangeSurfaceBounds.readFromParcel(in);
             }
+            if ((mChangeMask & Change.CHANGE_RELATIVE_BOUNDS) != 0) {
+                mRelativeBounds = new Rect();
+                mRelativeBounds.readFromParcel(in);
+            }
 
             mWindowingMode = in.readInt();
             mActivityWindowingMode = in.readInt();
@@ -1069,6 +1096,11 @@
                 mBoundsChangeSurfaceBounds = transfer ? other.mBoundsChangeSurfaceBounds
                         : new Rect(other.mBoundsChangeSurfaceBounds);
             }
+            if (other.mRelativeBounds != null) {
+                mRelativeBounds = transfer
+                        ? other.mRelativeBounds
+                        : new Rect(other.mRelativeBounds);
+            }
         }
 
         public int getWindowingMode() {
@@ -1156,6 +1188,11 @@
             return mBoundsChangeSurfaceBounds;
         }
 
+        @Nullable
+        public Rect getRelativeBounds() {
+            return mRelativeBounds;
+        }
+
         @Override
         public String toString() {
             final boolean changesBounds =
@@ -1196,6 +1233,9 @@
             if ((mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
                 sb.append("ignoreOrientationRequest:" + mIgnoreOrientationRequest + ",");
             }
+            if ((mChangeMask & CHANGE_RELATIVE_BOUNDS) != 0) {
+                sb.append("relativeBounds:").append(mRelativeBounds).append(",");
+            }
             sb.append("}");
             return sb.toString();
         }
@@ -1221,6 +1261,9 @@
             if (mBoundsChangeSurfaceBounds != null) {
                 mBoundsChangeSurfaceBounds.writeToParcel(dest, flags);
             }
+            if (mRelativeBounds != null) {
+                mRelativeBounds.writeToParcel(dest, flags);
+            }
 
             dest.writeInt(mWindowingMode);
             dest.writeInt(mActivityWindowingMode);
diff --git a/core/java/com/android/internal/app/ChooserActivityLoggerImpl.java b/core/java/com/android/internal/app/ChooserActivityLoggerImpl.java
index e3cc4f1..d0b5811 100644
--- a/core/java/com/android/internal/app/ChooserActivityLoggerImpl.java
+++ b/core/java/com/android/internal/app/ChooserActivityLoggerImpl.java
@@ -47,7 +47,9 @@
                 /* num_app_provided_app_targets = 6 */ appProvidedApp,
                 /* is_workprofile = 7 */ isWorkprofile,
                 /* previewType = 8 */ typeFromPreviewInt(previewType),
-                /* intentType = 9 */ typeFromIntentString(intent));
+                /* intentType = 9 */ typeFromIntentString(intent),
+                /* num_provided_custom_actions = 10 */ 0,
+                /* reselection_action_provided = 11 */ false);
     }
 
     @Override
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index f56f818..7beb059 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -163,6 +163,9 @@
     @Override
     @Nullable
     public ChooserListAdapter getWorkListAdapter() {
+        if (getCount() == 1) {
+            return null;
+        }
         return getAdapterForIndex(PROFILE_WORK).getListAdapter();
     }
 
diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
index 1ecaf21..7677912 100644
--- a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
@@ -142,6 +142,9 @@
     @Override
     @Nullable
     public ResolverListAdapter getWorkListAdapter() {
+        if (getCount() == 1) {
+            return null;
+        }
         return getAdapterForIndex(PROFILE_WORK);
     }
 
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 4f7f8ba..b9373be 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -567,11 +567,6 @@
     public static final String VOLUME_SEPARATE_NOTIFICATION = "volume_separate_notification";
 
     /**
-     * (boolean) Whether the clipboard overlay is enabled.
-     */
-    public static final String CLIPBOARD_OVERLAY_ENABLED = "clipboard_overlay_enabled";
-
-    /**
      * (boolean) Whether widget provider info would be saved to / loaded from system persistence
      * layer as opposed to individual manifests in respective apps.
      */
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index ddc0c0c..9e176e3 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -40,12 +40,12 @@
 import android.util.SparseArray;
 import android.util.TimeUtils;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ParseUtils;
 
 import java.io.File;
 import java.io.FileOutputStream;
-import java.io.FilenameFilter;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -198,6 +198,8 @@
     private final VarintParceler mVarintParceler = new VarintParceler();
     private byte mLastHistoryStepLevel = 0;
     private boolean mMutable = true;
+    private final BatteryStatsHistory mWritableHistory;
+    private boolean mCleanupEnabled = true;
 
     /**
      * A delegate responsible for computing additional details for a step in battery history.
@@ -272,10 +274,32 @@
         initHistoryBuffer();
     }
 
+    /**
+     * Creates a read-only wrapper for the supplied writable history.
+     */
+    public BatteryStatsHistory(BatteryStatsHistory writableHistory) {
+        this(Parcel.obtain(), writableHistory.mSystemDir, 0, 0, null, null, null, writableHistory);
+        mMutable = false;
+
+        synchronized (mWritableHistory) {
+            // Make a copy of battery history to avoid concurrent modification.
+            mHistoryBuffer.appendFrom(mWritableHistory.mHistoryBuffer, 0,
+                    mWritableHistory.mHistoryBuffer.dataSize());
+        }
+    }
+
     @VisibleForTesting
     public BatteryStatsHistory(Parcel historyBuffer, File systemDir,
             int maxHistoryFiles, int maxHistoryBufferSize,
             HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, TraceDelegate tracer) {
+        this(historyBuffer, systemDir, maxHistoryFiles, maxHistoryBufferSize, stepDetailsCalculator,
+                clock, tracer, null);
+    }
+
+    private BatteryStatsHistory(Parcel historyBuffer, File systemDir,
+            int maxHistoryFiles, int maxHistoryBufferSize,
+            HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, TraceDelegate tracer,
+            BatteryStatsHistory writableHistory) {
         mHistoryBuffer = historyBuffer;
         mSystemDir = systemDir;
         mMaxHistoryFiles = maxHistoryFiles;
@@ -283,6 +307,7 @@
         mStepDetailsCalculator = stepDetailsCalculator;
         mTracer = tracer;
         mClock = clock;
+        mWritableHistory = writableHistory;
 
         mHistoryDir = new File(systemDir, HISTORY_DIR);
         mHistoryDir.mkdirs();
@@ -292,21 +317,17 @@
 
         final Set<Integer> dedup = new ArraySet<>();
         // scan directory, fill mFileNumbers and mActiveFile.
-        mHistoryDir.listFiles(new FilenameFilter() {
-            @Override
-            public boolean accept(File dir, String name) {
-                final int b = name.lastIndexOf(FILE_SUFFIX);
-                if (b <= 0) {
-                    return false;
-                }
-                final Integer c =
-                        ParseUtils.parseInt(name.substring(0, b), -1);
-                if (c != -1) {
-                    dedup.add(c);
-                    return true;
-                } else {
-                    return false;
-                }
+        mHistoryDir.listFiles((dir, name) -> {
+            final int b = name.lastIndexOf(FILE_SUFFIX);
+            if (b <= 0) {
+                return false;
+            }
+            final int c = ParseUtils.parseInt(name.substring(0, b), -1);
+            if (c != -1) {
+                dedup.add(c);
+                return true;
+            } else {
+                return false;
             }
         });
         if (!dedup.isEmpty()) {
@@ -328,21 +349,29 @@
         mHistoryBuffer = Parcel.obtain();
         mSystemDir = null;
         mHistoryDir = null;
+        mWritableHistory = null;
         initHistoryBuffer();
     }
 
     /**
-     * Used when BatteryStatsImpl object is created from deserialization of a parcel,
-     * such as a checkin file.
+     * Used when BatteryStatsHistory object is created from deserialization of a BatteryUsageStats
+     * parcel.
      */
-    private BatteryStatsHistory(Parcel historyBuffer,
-            HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) {
-        mHistoryBuffer = historyBuffer;
-        mTracer = new TraceDelegate();
-        mClock = clock;
+    private BatteryStatsHistory(Parcel parcel) {
+        mClock = Clock.SYSTEM_CLOCK;
+        mTracer = null;
         mSystemDir = null;
         mHistoryDir = null;
-        mStepDetailsCalculator = stepDetailsCalculator;
+        mStepDetailsCalculator = null;
+        mWritableHistory = null;
+        mMutable = false;
+
+        final byte[] historyBlob = parcel.readBlob();
+
+        mHistoryBuffer = Parcel.obtain();
+        mHistoryBuffer.unmarshall(historyBlob, 0, historyBlob.length);
+
+        readFromParcel(parcel, true /* useBlobs */);
     }
 
     private void initHistoryBuffer() {
@@ -386,10 +415,7 @@
      * in the system directory, so it is not safe while actively writing history.
      */
     public BatteryStatsHistory copy() {
-        // Make a copy of battery history to avoid concurrent modification.
-        Parcel historyBuffer = Parcel.obtain();
-        historyBuffer.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
-        return new BatteryStatsHistory(historyBuffer, mSystemDir, 0, 0, null, null, mTracer);
+        return new BatteryStatsHistory(this);
     }
 
     /**
@@ -448,6 +474,25 @@
             Slog.e(TAG, "Could not create history file: " + mActiveFile.getBaseFile());
         }
 
+        synchronized (this) {
+            cleanupLocked();
+        }
+    }
+
+    @GuardedBy("this")
+    private void setCleanupEnabledLocked(boolean enabled) {
+        mCleanupEnabled = enabled;
+        if (mCleanupEnabled) {
+            cleanupLocked();
+        }
+    }
+
+    @GuardedBy("this")
+    private void cleanupLocked() {
+        if (!mCleanupEnabled || mHistoryDir == null) {
+            return;
+        }
+
         // if free disk space is less than 100MB, delete oldest history file.
         if (!hasFreeDiskSpace()) {
             int oldest = mFileNumbers.remove(0);
@@ -465,6 +510,16 @@
     }
 
     /**
+     * Returns true if it is safe to reset history. It will return false if the history is
+     * currently being read.
+     */
+    public boolean isResetEnabled() {
+        synchronized (this) {
+            return mCleanupEnabled;
+        }
+    }
+
+    /**
      * Clear history buffer and delete all existing history files. Active history file start from
      * number 0 again.
      */
@@ -491,6 +546,11 @@
         mCurrentParcelEnd = 0;
         mParcelIndex = 0;
         mMutable = false;
+        if (mWritableHistory != null) {
+            synchronized (mWritableHistory) {
+                mWritableHistory.setCleanupEnabledLocked(false);
+            }
+        }
         return new BatteryStatsHistoryIterator(this);
     }
 
@@ -500,7 +560,13 @@
     void iteratorFinished() {
         // setDataPosition so mHistoryBuffer Parcel can be written.
         mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
-        mMutable = true;
+        if (mWritableHistory != null) {
+            synchronized (mWritableHistory) {
+                mWritableHistory.setCleanupEnabledLocked(true);
+            }
+        } else {
+            mMutable = true;
+        }
     }
 
     /**
@@ -717,15 +783,7 @@
      * the {@link #writeToBatteryUsageStatsParcel} method.
      */
     public static BatteryStatsHistory createFromBatteryUsageStatsParcel(Parcel in) {
-        final byte[] historyBlob = in.readBlob();
-
-        Parcel historyBuffer = Parcel.obtain();
-        historyBuffer.unmarshall(historyBlob, 0, historyBlob.length);
-
-        BatteryStatsHistory history = new BatteryStatsHistory(historyBuffer, null,
-                Clock.SYSTEM_CLOCK);
-        history.readFromParcel(in, true /* useBlobs */);
-        return history;
+        return new BatteryStatsHistory(in);
     }
 
     /**
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index ae45a0e..1557f9e 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -19,18 +19,18 @@
 
 #include "android_media_AudioTrack.h"
 
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedUtfChars.h>
-#include "core_jni_helpers.h"
-
-#include <utils/Log.h>
+#include <android-base/macros.h>
+#include <android_os_Parcel.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
 #include <media/AudioParameter.h>
 #include <media/AudioSystem.h>
 #include <media/AudioTrack.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedUtfChars.h>
+#include <utils/Log.h>
 
-#include <android-base/macros.h>
-#include <binder/MemoryHeapBase.h>
-#include <binder/MemoryBase.h>
+#include <cinttypes>
 
 #include "android_media_AudioAttributes.h"
 #include "android_media_AudioErrors.h"
@@ -41,8 +41,7 @@
 #include "android_media_MediaMetricsJNI.h"
 #include "android_media_PlaybackParams.h"
 #include "android_media_VolumeShaper.h"
-
-#include <cinttypes>
+#include "core_jni_helpers.h"
 
 // ----------------------------------------------------------------------------
 
@@ -245,9 +244,10 @@
                                            jobject jaa, jintArray jSampleRate,
                                            jint channelPositionMask, jint channelIndexMask,
                                            jint audioFormat, jint buffSizeInBytes, jint memoryMode,
-                                           jintArray jSession, jlong nativeAudioTrack,
-                                           jboolean offload, jint encapsulationMode,
-                                           jobject tunerConfiguration, jstring opPackageName) {
+                                           jintArray jSession, jobject jAttributionSource,
+                                           jlong nativeAudioTrack, jboolean offload,
+                                           jint encapsulationMode, jobject tunerConfiguration,
+                                           jstring opPackageName) {
     ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d,"
           " nativeAudioTrack=0x%" PRIX64 ", offload=%d encapsulationMode=%d tuner=%p",
           jSampleRate, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes,
@@ -323,10 +323,9 @@
 
         // create the native AudioTrack object
         ScopedUtfChars opPackageNameStr(env, opPackageName);
-        // TODO b/182469354: make consistent with AudioRecord
-        AttributionSourceState attributionSource;
-        attributionSource.packageName = std::string(opPackageNameStr.c_str());
-        attributionSource.token = sp<BBinder>::make();
+
+        android::content::AttributionSourceState attributionSource;
+        attributionSource.readFromParcel(parcelForJavaObject(env, jAttributionSource));
         lpTrack = sp<AudioTrack>::make(attributionSource);
 
         // read the AudioAttributes values
@@ -382,7 +381,7 @@
                                   offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK
                                           : AudioTrack::TRANSFER_SYNC,
                                   (offload || encapsulationMode) ? &offloadInfo : NULL,
-                                  AttributionSourceState(), // default uid, pid values
+                                  attributionSource, // Passed from Java
                                   paa.get());
             break;
 
@@ -401,14 +400,14 @@
                                   format, // word length, PCM
                                   nativeChannelMask, frameCount, AUDIO_OUTPUT_FLAG_NONE,
                                   lpJniStorage,
-                                  0, // notificationFrames == 0 since not using EVENT_MORE_DATA
-                                     // to feed the AudioTrack
-                                  iMem,                   // shared mem
-                                  true,                   // thread can call Java
-                                  sessionId,              // audio session ID
+                                  0,    // notificationFrames == 0 since not using EVENT_MORE_DATA
+                                        // to feed the AudioTrack
+                                  iMem, // shared mem
+                                  true, // thread can call Java
+                                  sessionId, // audio session ID
                                   AudioTrack::TRANSFER_SHARED,
-                                  nullptr ,               // default offloadInfo
-                                  AttributionSourceState(), // default uid, pid values
+                                  nullptr,           // default offloadInfo
+                                  attributionSource, // Passed from Java
                                   paa.get());
             break;
         }
@@ -1456,7 +1455,8 @@
         {"native_pause", "()V", (void *)android_media_AudioTrack_pause},
         {"native_flush", "()V", (void *)android_media_AudioTrack_flush},
         {"native_setup",
-         "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZILjava/lang/Object;Ljava/lang/String;)I",
+         "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[ILandroid/os/Parcel;"
+         "JZILjava/lang/Object;Ljava/lang/String;)I",
          (void *)android_media_AudioTrack_setup},
         {"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
         {"native_release", "()V", (void *)android_media_AudioTrack_release},
diff --git a/core/jni/android_os_PerformanceHintManager.cpp b/core/jni/android_os_PerformanceHintManager.cpp
index 0223b96..d8a2497 100644
--- a/core/jni/android_os_PerformanceHintManager.cpp
+++ b/core/jni/android_os_PerformanceHintManager.cpp
@@ -41,7 +41,7 @@
 typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t);
 typedef void (*APH_closeSession)(APerformanceHintSession* session);
 typedef void (*APH_sendHint)(APerformanceHintSession*, int32_t);
-typedef void (*APH_setThreads)(APerformanceHintSession*, const int32_t*, size_t);
+typedef void (*APH_setThreads)(APerformanceHintSession*, const pid_t*, size_t);
 typedef void (*APH_getThreadIds)(APerformanceHintSession*, int32_t* const, size_t* const);
 
 bool gAPerformanceHintBindingInitialized = false;
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 34589b7..225ed2c 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -579,6 +579,14 @@
     transaction->setDataspace(ctrl, dataspace);
 }
 
+static void nativeSetExtendedRangeBrightness(JNIEnv* env, jclass clazz, jlong transactionObj,
+                                             jlong nativeObject, float currentBufferRatio,
+                                             float desiredRatio) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
+    transaction->setExtendedRangeBrightness(ctrl, currentBufferRatio, desiredRatio);
+}
+
 static void nativeSetBlurRegions(JNIEnv* env, jclass clazz, jlong transactionObj,
                                  jlong nativeObject, jobjectArray regions, jint regionsLength) {
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
@@ -2086,6 +2094,8 @@
     {"nativeSetBufferTransform", "(JJI)V", (void*) nativeSetBufferTransform},
     {"nativeSetDataSpace", "(JJI)V",
             (void*)nativeSetDataSpace },
+    {"nativeSetExtendedRangeBrightness", "(JJFF)V",
+            (void*)nativeSetExtendedRangeBrightness },
     {"nativeAddWindowInfosReportedListener", "(JLjava/lang/Runnable;)V",
             (void*)nativeAddWindowInfosReportedListener },
     {"nativeGetDisplayBrightnessSupport", "(Landroid/os/IBinder;)Z",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 07aefbd..7d69d56 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4153,7 +4153,7 @@
          <p>Should only be requested by the System, should be required by
          TileService declarations.-->
     <permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signature|recents" />
 
     <!-- Allows SystemUI to request third party controls.
          <p>Should only be requested by the System and required by
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index fa77c45..e242e20 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -435,6 +435,119 @@
      This value can be overlaid at runtime by OverlayManager RROs. -->
     <color name="system_neutral2_1000">#000000</color>
 
+    <!-- Colors used in Android system, from Material design system.
+     These values can be overlaid at runtime by OverlayManager RROs. -->
+    <color name="system_primary_container_light">#D8E2FF</color>
+    <color name="system_on_primary_container_light">#001A41</color>
+    <color name="system_primary_light">#445E91</color>
+    <color name="system_on_primary_light">#FFFFFF</color>
+    <color name="system_secondary_container_light">#DBE2F9</color>
+    <color name="system_on_secondary_container_light">#141B2C</color>
+    <color name="system_secondary_light">#575E71</color>
+    <color name="system_on_secondary_light">#FFFFFF</color>
+    <color name="system_tertiary_container_light">#FBD7FC</color>
+    <color name="system_on_tertiary_container_light">#29132D</color>
+    <color name="system_tertiary_light">#715573</color>
+    <color name="system_on_tertiary_light">#FFFFFF</color>
+    <color name="system_background_light">#FAF9FD</color>
+    <color name="system_on_background_light">#1B1B1F</color>
+    <color name="system_surface_light">#FAF9FD</color>
+    <color name="system_on_surface_light">#1B1B1F</color>
+    <color name="system_surface_container_low_light">#F5F3F7</color>
+    <color name="system_surface_container_lowest_light">#FFFFFF</color>
+    <color name="system_surface_container_light">#EFEDF1</color>
+    <color name="system_surface_container_high_light">#E9E7EC</color>
+    <color name="system_surface_container_highest_light">#E3E2E6</color>
+    <color name="system_surface_bright_light">#FAF9FD</color>
+    <color name="system_surface_dim_light">#DBD9DD</color>
+    <color name="system_surface_variant_light">#E1E2EC</color>
+    <color name="system_on_surface_variant_light">#44474F</color>
+    <color name="system_outline_light">#72747D</color>
+    <color name="system_error_light">#C00003</color>
+    <color name="system_on_error_light">#FFFFFF</color>
+    <color name="system_error_container_light">#FFDAD5</color>
+    <color name="system_on_error_container_light">#410000</color>
+    <color name="system_primary_fixed_light">#D8E2FF</color>
+    <color name="system_primary_fixed_darker_light">#ADC6FF</color>
+    <color name="system_on_primary_fixed_light">#001A41</color>
+    <color name="system_on_primary_fixed_variant_light">#2B4678</color>
+    <color name="system_secondary_fixed_light">#DBE2F9</color>
+    <color name="system_secondary_fixed_darker_light">#BFC6DC</color>
+    <color name="system_on_secondary_fixed_light">#141B2C</color>
+    <color name="system_on_secondary_fixed_variant_light">#3F4759</color>
+    <color name="system_tertiary_fixed_light">#FBD7FC</color>
+    <color name="system_tertiary_fixed_darker_light">#DEBCDF</color>
+    <color name="system_on_tertiary_fixed_light">#29132D</color>
+    <color name="system_on_tertiary_fixed_variant_light">#583E5B</color>
+    <color name="system_control_activated_light">#D8E2FF</color>
+    <color name="system_control_normal_light">#44474F</color>
+    <color name="system_control_highlight_light">#1F000000</color>
+    <color name="system_text_primary_inverse_light">#E3E2E6</color>
+    <color name="system_text_secondary_and_tertiary_inverse_light">#C4C6D0</color>
+    <color name="system_text_primary_inverse_disable_only_light">#E3E2E6</color>
+    <color name="system_text_secondary_and_tertiary_inverse_disabled_light">#E3E2E6</color>
+    <color name="system_text_hint_inverse_light">#E3E2E6</color>
+    <color name="system_palette_key_color_primary_light">#5D77AC</color>
+    <color name="system_palette_key_color_secondary_light">#6C7488</color>
+    <color name="system_palette_key_color_tertiary_light">#907292</color>
+    <color name="system_palette_key_color_neutral_light">#838387</color>
+    <color name="system_palette_key_color_neutral_variant_light">#777982</color>
+    <color name="system_primary_container_dark">#2B4678</color>
+    <color name="system_on_primary_container_dark">#D8E2FF</color>
+    <color name="system_primary_dark">#ADC6FF</color>
+    <color name="system_on_primary_dark">#102F60</color>
+    <color name="system_secondary_container_dark">#3F4759</color>
+    <color name="system_on_secondary_container_dark">#DBE2F9</color>
+    <color name="system_secondary_dark">#BFC6DC</color>
+    <color name="system_on_secondary_dark">#293041</color>
+    <color name="system_tertiary_container_dark">#583E5B</color>
+    <color name="system_on_tertiary_container_dark">#FBD7FC</color>
+    <color name="system_tertiary_dark">#DEBCDF</color>
+    <color name="system_on_tertiary_dark">#402843</color>
+    <color name="system_background_dark">#121316</color>
+    <color name="system_on_background_dark">#E3E2E6</color>
+    <color name="system_surface_dark">#121316</color>
+    <color name="system_on_surface_dark">#E3E2E6</color>
+    <color name="system_surface_container_low_dark">#1B1B1F</color>
+    <color name="system_surface_container_lowest_dark">#0D0E11</color>
+    <color name="system_surface_container_dark">#1F1F23</color>
+    <color name="system_surface_container_high_dark">#292A2D</color>
+    <color name="system_surface_container_highest_dark">#343538</color>
+    <color name="system_surface_bright_dark">#38393C</color>
+    <color name="system_surface_dim_dark">#121316</color>
+    <color name="system_surface_variant_dark">#44474F</color>
+    <color name="system_on_surface_variant_dark">#C4C6D0</color>
+    <color name="system_outline_dark">#72747D</color>
+    <color name="system_error_dark">#FFB4A8</color>
+    <color name="system_on_error_dark">#690001</color>
+    <color name="system_error_container_dark">#930001</color>
+    <color name="system_on_error_container_dark">#FFDAD5</color>
+    <color name="system_primary_fixed_dark">#D8E2FF</color>
+    <color name="system_primary_fixeder_dark">#ADC6FF</color>
+    <color name="system_on_primary_fixed_dark">#001A41</color>
+    <color name="system_on_primary_fixed_variant_dark">#2B4678</color>
+    <color name="system_secondary_fixed_dark">#DBE2F9</color>
+    <color name="system_secondary_fixeder_dark">#BFC6DC</color>
+    <color name="system_on_secondary_fixed_dark">#141B2C</color>
+    <color name="system_on_secondary_fixed_variant_dark">#3F4759</color>
+    <color name="system_tertiary_fixed_dark">#FBD7FC</color>
+    <color name="system_tertiary_fixeder_dark">#DEBCDF</color>
+    <color name="system_on_tertiary_fixed_dark">#29132D</color>
+    <color name="system_on_tertiary_fixed_variant_dark">#583E5B</color>
+    <color name="system_control_activated_dark">#2B4678</color>
+    <color name="system_control_normal_dark">#C4C6D0</color>
+    <color name="system_control_highlight_dark">#33FFFFFF</color>
+    <color name="system_text_primary_inverse_dark">#1B1B1F</color>
+    <color name="system_text_secondary_and_tertiary_inverse_dark">#44474F</color>
+    <color name="system_text_primary_inverse_disable_only_dark">#1B1B1F</color>
+    <color name="system_text_secondary_and_tertiary_inverse_disabled_dark">#1B1B1F</color>
+    <color name="system_text_hint_inverse_dark">#1B1B1F</color>
+    <color name="system_palette_key_color_primary_dark">#5D77AC</color>
+    <color name="system_palette_key_color_secondary_dark">#6C7488</color>
+    <color name="system_palette_key_color_tertiary_dark">#907292</color>
+    <color name="system_palette_key_color_neutral_dark">#838387</color>
+    <color name="system_palette_key_color_neutral_variant_dark">#777982</color>
+
     <!-- Accessibility shortcut icon background color -->
     <color name="accessibility_feature_background">#5F6368</color> <!-- Google grey 700 -->
     <color name="accessibility_magnification_background">#F50D60</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f544feb..d3aee43 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -642,6 +642,16 @@
          The default is false. -->
     <bool name="config_lidControlsSleep">false</bool>
 
+    <!-- The device states (supplied by DeviceStateManager) that should be treated as open by the
+         device fold controller. Default is empty. -->
+    <integer-array name="config_openDeviceStates">
+        <!-- Example:
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+        -->
+    </integer-array>
+
     <!-- The device states (supplied by DeviceStateManager) that should be treated as folded by the
          display fold controller. Default is empty. -->
     <integer-array name="config_foldedDeviceStates">
@@ -662,6 +672,16 @@
         -->
     </integer-array>
 
+    <!-- The device states (supplied by DeviceStateManager) that should be treated as a rear display
+     state. Default is empty. -->
+    <integer-array name="config_rearDisplayDeviceStates">
+        <!-- Example:
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+        -->
+    </integer-array>
+
     <!-- Indicates whether the window manager reacts to half-fold device states by overriding
      rotation. -->
     <bool name="config_windowManagerHalfFoldAutoRotateOverride">false</bool>
@@ -954,6 +974,12 @@
     <!-- Boolean indicating whether light mode is allowed when DWB is turned on. -->
     <bool name="config_displayWhiteBalanceLightModeAllowed">true</bool>
 
+    <!-- Device states where the sensor based rotation values should be reversed around the Z axis
+         for the default display.
+         TODO(b/265312193): Remove this workaround when this bug is fixed.-->
+    <integer-array name="config_deviceStatesToReverseDefaultDisplayRotationAroundZAxis">
+    </integer-array>
+
     <!-- Indicate available ColorDisplayManager.COLOR_MODE_xxx. -->
     <integer-array name="config_availableColorModes">
         <!-- Example:
@@ -5820,7 +5846,6 @@
            - config_roundedCornerDrawableArray (config in SystemUI resource)
            - config_roundedCornerTopDrawableArray (config in SystemUI resource)
            - config_roundedCornerBottomDrawableArray (config in SystemUI resource)
-           - config_displayUsiVersionArray
 
          Leave this array empty for single display device and the system will load the default main
          built-in related configs.
@@ -6189,21 +6214,4 @@
         trusted certificate using the SHA-256 digest algorithm. -->
     <string-array name="config_healthConnectMigrationKnownSigners">
     </string-array>
-
-    <!-- The Universal Stylus Initiative (USI) protocol version supported by each display.
-         (@see https://universalstylus.org/).
-
-         The i-th value in this array corresponds to the supported USI version of the i-th display
-         listed in config_displayUniqueIdArray. On a single-display device, the
-         config_displayUniqueIdArray may be empty, in which case the only value in this array should
-         be the USI version for the main built-in display.
-
-         If the display does not support USI, the version value should be an empty string. If the
-         display supports USI, the version must be in the following format:
-           "<major-version>.<minor-version>"
-
-         For example, "", "1.0", and "2.0" are valid values. -->
-    <string-array name="config_displayUsiVersionArray" translatable="false">
-        <item>""</item>
-    </string-array>
 </resources>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index 58b8601..f7ed38c 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -154,6 +154,116 @@
   </staging-public-group>
 
   <staging-public-group type="color" first-id="0x01c90000">
+    <public name="system_primary_container_light" />
+    <public name="system_on_primary_container_light" />
+    <public name="system_primary_light" />
+    <public name="system_on_primary_light" />
+    <public name="system_secondary_container_light" />
+    <public name="system_on_secondary_container_light" />
+    <public name="system_secondary_light" />
+    <public name="system_on_secondary_light" />
+    <public name="system_tertiary_container_light" />
+    <public name="system_on_tertiary_container_light" />
+    <public name="system_tertiary_light" />
+    <public name="system_on_tertiary_light" />
+    <public name="system_background_light" />
+    <public name="system_on_background_light" />
+    <public name="system_surface_light" />
+    <public name="system_on_surface_light" />
+    <public name="system_surface_container_low_light" />
+    <public name="system_surface_container_lowest_light" />
+    <public name="system_surface_container_light" />
+    <public name="system_surface_container_high_light" />
+    <public name="system_surface_container_highest_light" />
+    <public name="system_surface_bright_light" />
+    <public name="system_surface_dim_light" />
+    <public name="system_surface_variant_light" />
+    <public name="system_on_surface_variant_light" />
+    <public name="system_outline_light" />
+    <public name="system_error_light" />
+    <public name="system_on_error_light" />
+    <public name="system_error_container_light" />
+    <public name="system_on_error_container_light" />
+    <public name="system_primary_fixed_light" />
+    <public name="system_primary_fixed_darker_light" />
+    <public name="system_on_primary_fixed_light" />
+    <public name="system_on_primary_fixed_variant_light" />
+    <public name="system_secondary_fixed_light" />
+    <public name="system_secondary_fixed_darker_light" />
+    <public name="system_on_secondary_fixed_light" />
+    <public name="system_on_secondary_fixed_variant_light" />
+    <public name="system_tertiary_fixed_light" />
+    <public name="system_tertiary_fixed_darker_light" />
+    <public name="system_on_tertiary_fixed_light" />
+    <public name="system_on_tertiary_fixed_variant_light" />
+    <public name="system_control_activated_light" />
+    <public name="system_control_normal_light" />
+    <public name="system_control_highlight_light" />
+    <public name="system_text_primary_inverse_light" />
+    <public name="system_text_secondary_and_tertiary_inverse_light" />
+    <public name="system_text_primary_inverse_disable_only_light" />
+    <public name="system_text_secondary_and_tertiary_inverse_disabled_light" />
+    <public name="system_text_hint_inverse_light" />
+    <public name="system_palette_key_color_primary_light" />
+    <public name="system_palette_key_color_secondary_light" />
+    <public name="system_palette_key_color_tertiary_light" />
+    <public name="system_palette_key_color_neutral_light" />
+    <public name="system_palette_key_color_neutral_variant_light" />
+    <public name="system_primary_container_dark"/>
+    <public name="system_on_primary_container_dark"/>
+    <public name="system_primary_dark"/>
+    <public name="system_on_primary_dark"/>
+    <public name="system_secondary_container_dark"/>
+    <public name="system_on_secondary_container_dark"/>
+    <public name="system_secondary_dark"/>
+    <public name="system_on_secondary_dark"/>
+    <public name="system_tertiary_container_dark"/>
+    <public name="system_on_tertiary_container_dark"/>
+    <public name="system_tertiary_dark"/>
+    <public name="system_on_tertiary_dark"/>
+    <public name="system_background_dark"/>
+    <public name="system_on_background_dark"/>
+    <public name="system_surface_dark"/>
+    <public name="system_on_surface_dark"/>
+    <public name="system_surface_container_low_dark"/>
+    <public name="system_surface_container_lowest_dark"/>
+    <public name="system_surface_container_dark"/>
+    <public name="system_surface_container_high_dark"/>
+    <public name="system_surface_container_highest_dark"/>
+    <public name="system_surface_bright_dark"/>
+    <public name="system_surface_dim_dark"/>
+    <public name="system_surface_variant_dark"/>
+    <public name="system_on_surface_variant_dark"/>
+    <public name="system_outline_dark"/>
+    <public name="system_error_dark"/>
+    <public name="system_on_error_dark"/>
+    <public name="system_error_container_dark"/>
+    <public name="system_on_error_container_dark"/>
+    <public name="system_primary_fixed_dark"/>
+    <public name="system_primary_fixeder_dark"/>
+    <public name="system_on_primary_fixed_dark"/>
+    <public name="system_on_primary_fixed_variant_dark"/>
+    <public name="system_secondary_fixed_dark"/>
+    <public name="system_secondary_fixeder_dark"/>
+    <public name="system_on_secondary_fixed_dark"/>
+    <public name="system_on_secondary_fixed_variant_dark"/>
+    <public name="system_tertiary_fixed_dark"/>
+    <public name="system_tertiary_fixeder_dark"/>
+    <public name="system_on_tertiary_fixed_dark"/>
+    <public name="system_on_tertiary_fixed_variant_dark"/>
+    <public name="system_control_activated_dark"/>
+    <public name="system_control_normal_dark"/>
+    <public name="system_control_highlight_dark"/>
+    <public name="system_text_primary_inverse_dark"/>
+    <public name="system_text_secondary_and_tertiary_inverse_dark"/>
+    <public name="system_text_primary_inverse_disable_only_dark"/>
+    <public name="system_text_secondary_and_tertiary_inverse_disabled_dark"/>
+    <public name="system_text_hint_inverse_dark"/>
+    <public name="system_palette_key_color_primary_dark"/>
+    <public name="system_palette_key_color_secondary_dark"/>
+    <public name="system_palette_key_color_tertiary_dark"/>
+    <public name="system_palette_key_color_neutral_dark"/>
+    <public name="system_palette_key_color_neutral_variant_dark"/>
   </staging-public-group>
 
   <staging-public-group type="array" first-id="0x01c80000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index fa8ba9d..e330ee3 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5024,6 +5024,14 @@
     <!-- Cling help message confirmation button when hiding the navigation bar entering immersive mode [CHAR LIMIT=30] -->
     <string name="immersive_cling_positive">Got it</string>
 
+    <!-- Text on a toast shown after the system rotates the screen for camera app
+         compatibility. [CHAR LIMIT=NONE] -->
+    <string name="display_rotation_camera_compat_toast_after_rotation">Rotate for a better view</string>
+
+    <!-- Text on a toast shown when a camera view is started within the app that may not be able
+         to display the camera preview correctly while in split screen. [CHAR LIMIT=NONE] -->
+    <string name="display_rotation_camera_compat_toast_in_split_screen">Exit split screen for a better view</string>
+
     <!-- Label for button to confirm chosen date or time [CHAR LIMIT=30] -->
     <string name="done_label">Done</string>
     <!--
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9dc7835..f1b8cca 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3385,6 +3385,11 @@
   <java-symbol type="array" name="config_displayWhiteBalanceDisplayNominalWhite" />
   <java-symbol type="bool" name="config_displayWhiteBalanceLightModeAllowed" />
 
+  <!-- Device states where the sensor based rotation values should be reversed around the Z axis
+       for the default display.
+       TODO(b/265312193): Remove this workaround when this bug is fixed.-->
+  <java-symbol type="array" name="config_deviceStatesToReverseDefaultDisplayRotationAroundZAxis" />
+
   <!-- Default user restrictions for the SYSTEM user -->
   <java-symbol type="array" name="config_defaultFirstUserRestrictions" />
 
@@ -3960,8 +3965,10 @@
   <java-symbol type="integer" name="config_maxScanTasksForHomeVisibility" />
 
   <!-- For Foldables -->
+  <java-symbol type="array" name="config_openDeviceStates" />
   <java-symbol type="array" name="config_foldedDeviceStates" />
   <java-symbol type="array" name="config_halfFoldedDeviceStates" />
+  <java-symbol type="array" name="config_rearDisplayDeviceStates" />
   <java-symbol type="bool" name="config_windowManagerHalfFoldAutoRotateOverride" />
   <java-symbol type="array" name="config_deviceStatesOnWhichToWakeUp" />
   <java-symbol type="array" name="config_deviceStatesOnWhichToSleep" />
@@ -4781,7 +4788,6 @@
   <java-symbol type="array" name="config_mainBuiltInDisplayWaterfallCutout" />
   <java-symbol type="array" name="config_secondaryBuiltInDisplayWaterfallCutout" />
   <java-symbol type="array" name="config_waterfallCutoutArray" />
-  <java-symbol type="array" name="config_displayUsiVersionArray" />
 
   <java-symbol type="fraction" name="global_actions_vertical_padding_percentage" />
   <java-symbol type="fraction" name="global_actions_horizontal_padding_percentage" />
diff --git a/core/tests/coretests/src/android/hardware/input/InputManagerTest.kt b/core/tests/coretests/src/android/hardware/input/InputManagerTest.kt
new file mode 100644
index 0000000..ee7a608
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/input/InputManagerTest.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.input
+
+import android.content.res.Resources
+import android.platform.test.annotations.Presubmit
+import android.view.Display
+import android.view.DisplayInfo
+import android.view.InputDevice
+import org.junit.After
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.`when`
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoJUnitRunner
+
+/**
+ * Tests for [InputManager].
+ *
+ * Build/Install/Run:
+ * atest FrameworksCoreTests:InputManagerTest
+ */
+@Presubmit
+@RunWith(MockitoJUnitRunner::class)
+class InputManagerTest {
+
+    companion object {
+        const val DEVICE_ID = 42
+        const val SECOND_DEVICE_ID = 96
+        const val THIRD_DEVICE_ID = 99
+    }
+
+    @get:Rule
+    val rule = MockitoJUnit.rule()!!
+
+    private lateinit var inputManager: InputManager
+
+    private lateinit var devicesChangedListener: IInputDevicesChangedListener
+    private val deviceGenerationMap = mutableMapOf<Int /*deviceId*/, Int /*generation*/>()
+
+    @Mock
+    private lateinit var iInputManager: IInputManager
+
+    @Before
+    fun setUp() {
+        inputManager = InputManager.resetInstance(iInputManager)
+        `when`(iInputManager.inputDeviceIds).then {
+            deviceGenerationMap.keys.toIntArray()
+        }
+    }
+
+    @After
+    fun tearDown() {
+        InputManager.clearInstance()
+    }
+
+    private fun notifyDeviceChanged(
+        deviceId: Int,
+        associatedDisplayId: Int,
+        usiVersion: HostUsiVersion?,
+    ) {
+        val generation = deviceGenerationMap[deviceId]?.plus(1)
+            ?: throw IllegalArgumentException("Device $deviceId was never added!")
+        deviceGenerationMap[deviceId] = generation
+
+        `when`(iInputManager.getInputDevice(deviceId))
+            .thenReturn(createInputDevice(deviceId, associatedDisplayId, usiVersion, generation))
+        val list = deviceGenerationMap.flatMap { listOf(it.key, it.value) }
+        if (::devicesChangedListener.isInitialized) {
+            devicesChangedListener.onInputDevicesChanged(list.toIntArray())
+        }
+    }
+
+    private fun addInputDevice(
+        deviceId: Int,
+        associatedDisplayId: Int,
+        usiVersion: HostUsiVersion?,
+    ) {
+        deviceGenerationMap[deviceId] = 0
+        notifyDeviceChanged(deviceId, associatedDisplayId, usiVersion)
+    }
+
+    @Test
+    fun testUsiVersionDisplayAssociation() {
+        addInputDevice(DEVICE_ID, Display.DEFAULT_DISPLAY, null)
+        addInputDevice(SECOND_DEVICE_ID, Display.INVALID_DISPLAY, HostUsiVersion(9, 8))
+        addInputDevice(THIRD_DEVICE_ID, 42, HostUsiVersion(3, 1))
+
+        val usiVersion = inputManager.getHostUsiVersion(createDisplay(42))
+        assertNotNull(usiVersion)
+        assertEquals(3, usiVersion!!.majorVersion)
+        assertEquals(1, usiVersion.minorVersion)
+    }
+
+    @Test
+    fun testUsiVersionFallBackToDisplayConfig() {
+        addInputDevice(DEVICE_ID, Display.DEFAULT_DISPLAY, null)
+
+        `when`(iInputManager.getHostUsiVersionFromDisplayConfig(eq(42)))
+            .thenReturn(HostUsiVersion(9, 8))
+        val usiVersion = inputManager.getHostUsiVersion(createDisplay(42))
+        assertEquals(HostUsiVersion(9, 8), usiVersion)
+    }
+}
+
+private fun createInputDevice(
+    deviceId: Int,
+    associatedDisplayId: Int,
+    usiVersion: HostUsiVersion? = null,
+    generation: Int = -1,
+): InputDevice =
+    InputDevice.Builder()
+        .setId(deviceId)
+        .setName("Device $deviceId")
+        .setDescriptor("descriptor $deviceId")
+        .setAssociatedDisplayId(associatedDisplayId)
+        .setUsiVersion(usiVersion)
+        .setGeneration(generation)
+        .build()
+
+private fun createDisplay(displayId: Int): Display {
+    val res: Resources? = null
+    return Display(null /* global */, displayId, DisplayInfo(), res)
+}
diff --git a/core/tests/coretests/src/android/util/TypedValueTest.kt b/core/tests/coretests/src/android/util/TypedValueTest.kt
index af01447..d4e77b5 100644
--- a/core/tests/coretests/src/android/util/TypedValueTest.kt
+++ b/core/tests/coretests/src/android/util/TypedValueTest.kt
@@ -276,5 +276,13 @@
         assertThat(dimenValueToTest)
             .isWithin(0.05f)
             .of(actualDimenValue)
+
+        // Also test the alias functions
+        assertThat(TypedValue.convertDimensionToPixels(dimenType, dimenValueToTest, metrics))
+            .isWithin(0.05f)
+            .of(actualPx)
+        assertThat(TypedValue.convertPixelsToDimension(dimenType, actualPx, metrics))
+            .isWithin(0.05f)
+            .of(actualDimenValue)
     }
 }
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 8b7265e..bccf283 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -3391,6 +3391,12 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/TaskFragment.java"
     },
+    "1015746067": {
+      "message": "Display id=%d is ignoring orientation request for %d, return %d following a per-app override for %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "1022095595": {
       "message": "TaskFragment info changed name=%s",
       "level": "VERBOSE",
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
index ee8ec1d..67963a3 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
@@ -109,38 +109,38 @@
      *                                  be resized based on {@param launchingFragmentBounds}.
      *                                  Otherwise, we will create a new TaskFragment with the given
      *                                  token for the {@param launchingActivity}.
-     * @param launchingFragmentBounds   the initial bounds for the launching TaskFragment.
+     * @param launchingRelBounds    the initial relative bounds for the launching TaskFragment.
      * @param launchingActivity the Activity to put on the left hand side of the split as the
      *                          primary.
      * @param secondaryFragmentToken    token to create the secondary TaskFragment with.
-     * @param secondaryFragmentBounds   the initial bounds for the secondary TaskFragment
+     * @param secondaryRelBounds    the initial relative bounds for the secondary TaskFragment
      * @param activityIntent    Intent to start the secondary Activity with.
      * @param activityOptions   ActivityOptions to start the secondary Activity with.
      * @param windowingMode     the windowing mode to set for the TaskFragments.
      * @param splitAttributes   the {@link SplitAttributes} to represent the split.
      */
     void startActivityToSide(@NonNull WindowContainerTransaction wct,
-            @NonNull IBinder launchingFragmentToken, @NonNull Rect launchingFragmentBounds,
+            @NonNull IBinder launchingFragmentToken, @NonNull Rect launchingRelBounds,
             @NonNull Activity launchingActivity, @NonNull IBinder secondaryFragmentToken,
-            @NonNull Rect secondaryFragmentBounds, @NonNull Intent activityIntent,
+            @NonNull Rect secondaryRelBounds, @NonNull Intent activityIntent,
             @Nullable Bundle activityOptions, @NonNull SplitRule rule,
             @WindowingMode int windowingMode, @NonNull SplitAttributes splitAttributes) {
         final IBinder ownerToken = launchingActivity.getActivityToken();
 
         // Create or resize the launching TaskFragment.
         if (mFragmentInfos.containsKey(launchingFragmentToken)) {
-            resizeTaskFragment(wct, launchingFragmentToken, launchingFragmentBounds);
+            resizeTaskFragment(wct, launchingFragmentToken, launchingRelBounds);
             updateWindowingMode(wct, launchingFragmentToken, windowingMode);
         } else {
             createTaskFragmentAndReparentActivity(wct, launchingFragmentToken, ownerToken,
-                    launchingFragmentBounds, windowingMode, launchingActivity);
+                    launchingRelBounds, windowingMode, launchingActivity);
         }
         updateAnimationParams(wct, launchingFragmentToken, splitAttributes);
 
         // Create a TaskFragment for the secondary activity.
         final TaskFragmentCreationParams fragmentOptions = new TaskFragmentCreationParams.Builder(
                 getOrganizerToken(), secondaryFragmentToken, ownerToken)
-                .setInitialBounds(secondaryFragmentBounds)
+                .setInitialRelativeBounds(secondaryRelBounds)
                 .setWindowingMode(windowingMode)
                 // Make sure to set the paired fragment token so that the new TaskFragment will be
                 // positioned right above the paired TaskFragment.
@@ -190,8 +190,9 @@
      *                   have to be a child of this task fragment, but must belong to the same task.
      */
     void createTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken,
-            @NonNull IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode) {
-        createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode,
+            @NonNull IBinder ownerToken, @NonNull Rect relBounds,
+            @WindowingMode int windowingMode) {
+        createTaskFragment(wct, fragmentToken, ownerToken, relBounds, windowingMode,
                 null /* pairedActivityToken */);
     }
 
@@ -203,11 +204,11 @@
      *                            positioned right above it.
      */
     void createTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken,
-            @NonNull IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode,
+            @NonNull IBinder ownerToken, @NonNull Rect relBounds, @WindowingMode int windowingMode,
             @Nullable IBinder pairedActivityToken) {
         final TaskFragmentCreationParams fragmentOptions = new TaskFragmentCreationParams.Builder(
                 getOrganizerToken(), fragmentToken, ownerToken)
-                .setInitialBounds(bounds)
+                .setInitialRelativeBounds(relBounds)
                 .setWindowingMode(windowingMode)
                 .setPairedActivityToken(pairedActivityToken)
                 .build();
@@ -229,10 +230,10 @@
      *                   have to be a child of this task fragment, but must belong to the same task.
      */
     private void createTaskFragmentAndReparentActivity(@NonNull WindowContainerTransaction wct,
-            @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect bounds,
+            @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect relBounds,
             @WindowingMode int windowingMode, @NonNull Activity activity) {
         final IBinder reparentActivityToken = activity.getActivityToken();
-        createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode,
+        createTaskFragment(wct, fragmentToken, ownerToken, relBounds, windowingMode,
                 reparentActivityToken);
         wct.reparentActivityToTaskFragment(fragmentToken, reparentActivityToken);
     }
@@ -280,15 +281,15 @@
     }
 
     void resizeTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken,
-            @Nullable Rect bounds) {
+            @Nullable Rect relBounds) {
         if (!mFragmentInfos.containsKey(fragmentToken)) {
             throw new IllegalArgumentException(
                     "Can't find an existing TaskFragment with fragmentToken=" + fragmentToken);
         }
-        if (bounds == null) {
-            bounds = new Rect();
+        if (relBounds == null) {
+            relBounds = new Rect();
         }
-        wct.setBounds(mFragmentInfos.get(fragmentToken).getToken(), bounds);
+        wct.setRelativeBounds(mFragmentInfos.get(fragmentToken).getToken(), relBounds);
     }
 
     void updateWindowingMode(@NonNull WindowContainerTransaction wct,
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index 85a00df..2b93682 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -180,22 +180,21 @@
                 primaryActivity, secondaryIntent);
         final SplitAttributes splitAttributes = computeSplitAttributes(taskProperties, rule,
                 minDimensionsPair);
-        final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, taskProperties,
+        final Rect primaryRelBounds = getRelBoundsForPosition(POSITION_START, taskProperties,
                 splitAttributes);
         final TaskFragmentContainer primaryContainer = prepareContainerForActivity(wct,
-                primaryActivity, primaryRectBounds, splitAttributes, null /* containerToAvoid */);
+                primaryActivity, primaryRelBounds, splitAttributes, null /* containerToAvoid */);
 
         // Create new empty task fragment
         final int taskId = primaryContainer.getTaskId();
         final TaskFragmentContainer secondaryContainer = mController.newContainer(
                 secondaryIntent, primaryActivity, taskId);
-        final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, taskProperties,
+        final Rect secondaryRelBounds = getRelBoundsForPosition(POSITION_END, taskProperties,
                 splitAttributes);
         final int windowingMode = mController.getTaskContainer(taskId)
-                .getWindowingModeForSplitTaskFragment(secondaryRectBounds);
+                .getWindowingModeForSplitTaskFragment(secondaryRelBounds);
         createTaskFragment(wct, secondaryContainer.getTaskFragmentToken(),
-                primaryActivity.getActivityToken(), secondaryRectBounds,
-                windowingMode);
+                primaryActivity.getActivityToken(), secondaryRelBounds, windowingMode);
         updateAnimationParams(wct, secondaryContainer.getTaskFragmentToken(), splitAttributes);
 
         // Set adjacent to each other so that the containers below will be invisible.
@@ -227,12 +226,12 @@
                 secondaryActivity);
         final SplitAttributes splitAttributes = computeSplitAttributes(taskProperties, rule,
                 minDimensionsPair);
-        final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, taskProperties,
+        final Rect primaryRelBounds = getRelBoundsForPosition(POSITION_START, taskProperties,
                 splitAttributes);
         final TaskFragmentContainer primaryContainer = prepareContainerForActivity(wct,
-                primaryActivity, primaryRectBounds, splitAttributes, null /* containerToAvoid */);
+                primaryActivity, primaryRelBounds, splitAttributes, null /* containerToAvoid */);
 
-        final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, taskProperties,
+        final Rect secondaryRelBounds = getRelBoundsForPosition(POSITION_END, taskProperties,
                 splitAttributes);
         final TaskFragmentContainer curSecondaryContainer = mController.getContainerWithActivity(
                 secondaryActivity);
@@ -244,7 +243,7 @@
             containerToAvoid = curSecondaryContainer;
         }
         final TaskFragmentContainer secondaryContainer = prepareContainerForActivity(wct,
-                secondaryActivity, secondaryRectBounds, splitAttributes, containerToAvoid);
+                secondaryActivity, secondaryRelBounds, splitAttributes, containerToAvoid);
 
         // Set adjacent to each other so that the containers below will be invisible.
         setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule,
@@ -261,23 +260,23 @@
      */
     private TaskFragmentContainer prepareContainerForActivity(
             @NonNull WindowContainerTransaction wct, @NonNull Activity activity,
-            @NonNull Rect bounds, @NonNull SplitAttributes splitAttributes,
+            @NonNull Rect relBounds, @NonNull SplitAttributes splitAttributes,
             @Nullable TaskFragmentContainer containerToAvoid) {
         TaskFragmentContainer container = mController.getContainerWithActivity(activity);
         final int taskId = container != null ? container.getTaskId() : activity.getTaskId();
         if (container == null || container == containerToAvoid) {
             container = mController.newContainer(activity, taskId);
             final int windowingMode = mController.getTaskContainer(taskId)
-                    .getWindowingModeForSplitTaskFragment(bounds);
+                    .getWindowingModeForSplitTaskFragment(relBounds);
             final IBinder reparentActivityToken = activity.getActivityToken();
             createTaskFragment(wct, container.getTaskFragmentToken(), reparentActivityToken,
-                    bounds, windowingMode, reparentActivityToken);
+                    relBounds, windowingMode, reparentActivityToken);
             wct.reparentActivityToTaskFragment(container.getTaskFragmentToken(),
                     reparentActivityToken);
         } else {
-            resizeTaskFragmentIfRegistered(wct, container, bounds);
+            resizeTaskFragmentIfRegistered(wct, container, relBounds);
             final int windowingMode = mController.getTaskContainer(taskId)
-                    .getWindowingModeForSplitTaskFragment(bounds);
+                    .getWindowingModeForSplitTaskFragment(relBounds);
             updateTaskFragmentWindowingModeIfRegistered(wct, container, windowingMode);
         }
         updateAnimationParams(wct, container.getTaskFragmentToken(), splitAttributes);
@@ -301,9 +300,9 @@
             @Nullable Bundle activityOptions, @NonNull SplitRule rule,
             @NonNull SplitAttributes splitAttributes, boolean isPlaceholder) {
         final TaskProperties taskProperties = getTaskProperties(launchingActivity);
-        final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, taskProperties,
+        final Rect primaryRelBounds = getRelBoundsForPosition(POSITION_START, taskProperties,
                 splitAttributes);
-        final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, taskProperties,
+        final Rect secondaryRelBounds = getRelBoundsForPosition(POSITION_END, taskProperties,
                 splitAttributes);
 
         TaskFragmentContainer primaryContainer = mController.getContainerWithActivity(
@@ -320,11 +319,11 @@
                 primaryContainer);
         final TaskContainer taskContainer = mController.getTaskContainer(taskId);
         final int windowingMode = taskContainer.getWindowingModeForSplitTaskFragment(
-                primaryRectBounds);
+                primaryRelBounds);
         mController.registerSplit(wct, primaryContainer, launchingActivity, secondaryContainer,
                 rule, splitAttributes);
-        startActivityToSide(wct, primaryContainer.getTaskFragmentToken(), primaryRectBounds,
-                launchingActivity, secondaryContainer.getTaskFragmentToken(), secondaryRectBounds,
+        startActivityToSide(wct, primaryContainer.getTaskFragmentToken(), primaryRelBounds,
+                launchingActivity, secondaryContainer.getTaskFragmentToken(), secondaryRelBounds,
                 activityIntent, activityOptions, rule, windowingMode, splitAttributes);
         if (isPlaceholder) {
             // When placeholder is launched in split, we should keep the focus on the primary.
@@ -351,20 +350,20 @@
         }
         final TaskProperties taskProperties = getTaskProperties(updatedContainer);
         final SplitAttributes splitAttributes = splitContainer.getSplitAttributes();
-        final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, taskProperties,
+        final Rect primaryRelBounds = getRelBoundsForPosition(POSITION_START, taskProperties,
                 splitAttributes);
-        final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, taskProperties,
+        final Rect secondaryRelBounds = getRelBoundsForPosition(POSITION_END, taskProperties,
                 splitAttributes);
         final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
         // Whether the placeholder is becoming side-by-side with the primary from fullscreen.
         final boolean isPlaceholderBecomingSplit = splitContainer.isPlaceholderContainer()
                 && secondaryContainer.areLastRequestedBoundsEqual(null /* bounds */)
-                && !secondaryRectBounds.isEmpty();
+                && !secondaryRelBounds.isEmpty();
 
         // If the task fragments are not registered yet, the positions will be updated after they
         // are created again.
-        resizeTaskFragmentIfRegistered(wct, primaryContainer, primaryRectBounds);
-        resizeTaskFragmentIfRegistered(wct, secondaryContainer, secondaryRectBounds);
+        resizeTaskFragmentIfRegistered(wct, primaryContainer, primaryRelBounds);
+        resizeTaskFragmentIfRegistered(wct, secondaryContainer, secondaryRelBounds);
         setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule,
                 splitAttributes);
         if (isPlaceholderBecomingSplit) {
@@ -373,7 +372,7 @@
         }
         final TaskContainer taskContainer = updatedContainer.getTaskContainer();
         final int windowingMode = taskContainer.getWindowingModeForSplitTaskFragment(
-                primaryRectBounds);
+                primaryRelBounds);
         updateTaskFragmentWindowingModeIfRegistered(wct, primaryContainer, windowingMode);
         updateTaskFragmentWindowingModeIfRegistered(wct, secondaryContainer, windowingMode);
         updateAnimationParams(wct, primaryContainer.getTaskFragmentToken(), splitAttributes);
@@ -405,11 +404,11 @@
     // TODO(b/190433398): Handle resize if the fragment hasn't appeared yet.
     private void resizeTaskFragmentIfRegistered(@NonNull WindowContainerTransaction wct,
             @NonNull TaskFragmentContainer container,
-            @Nullable Rect bounds) {
+            @Nullable Rect relBounds) {
         if (container.getInfo() == null) {
             return;
         }
-        resizeTaskFragment(wct, container.getTaskFragmentToken(), bounds);
+        resizeTaskFragment(wct, container.getTaskFragmentToken(), relBounds);
     }
 
     private void updateTaskFragmentWindowingModeIfRegistered(
@@ -431,27 +430,27 @@
                     "Creating a task fragment that is not registered with controller.");
         }
 
-        container.setLastRequestedBounds(fragmentOptions.getInitialBounds());
+        container.setLastRequestedBounds(fragmentOptions.getInitialRelativeBounds());
         container.setLastRequestedWindowingMode(fragmentOptions.getWindowingMode());
         super.createTaskFragment(wct, fragmentOptions);
     }
 
     @Override
     void resizeTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken,
-            @Nullable Rect bounds) {
+            @Nullable Rect relBounds) {
         TaskFragmentContainer container = mController.getContainer(fragmentToken);
         if (container == null) {
             throw new IllegalStateException(
                     "Resizing a task fragment that is not registered with controller.");
         }
 
-        if (container.areLastRequestedBoundsEqual(bounds)) {
+        if (container.areLastRequestedBoundsEqual(relBounds)) {
             // Return early if the provided bounds were already requested
             return;
         }
 
-        container.setLastRequestedBounds(bounds);
-        super.resizeTaskFragment(wct, fragmentToken, bounds);
+        container.setLastRequestedBounds(relBounds);
+        super.resizeTaskFragment(wct, fragmentToken, relBounds);
     }
 
     @Override
@@ -658,7 +657,7 @@
 
     @VisibleForTesting
     @NonNull
-    Rect getBoundsForPosition(@Position int position, @NonNull TaskProperties taskProperties,
+    Rect getRelBoundsForPosition(@Position int position, @NonNull TaskProperties taskProperties,
             @NonNull SplitAttributes splitAttributes) {
         final Configuration taskConfiguration = taskProperties.getConfiguration();
         final FoldingFeature foldingFeature = getFoldingFeature(taskProperties);
@@ -671,16 +670,24 @@
         if (!shouldShowSplit(computedSplitAttributes)) {
             return new Rect();
         }
+        final Rect bounds;
         switch (position) {
             case POSITION_START:
-                return getPrimaryBounds(taskConfiguration, computedSplitAttributes, foldingFeature);
-            case POSITION_END:
-                return getSecondaryBounds(taskConfiguration, computedSplitAttributes,
+                bounds = getPrimaryBounds(taskConfiguration, computedSplitAttributes,
                         foldingFeature);
+                break;
+            case POSITION_END:
+                bounds = getSecondaryBounds(taskConfiguration, computedSplitAttributes,
+                        foldingFeature);
+                break;
             case POSITION_FILL:
             default:
-                return new Rect();
+                bounds = new Rect();
         }
+        // Convert to relative bounds in parent coordinate. This is to avoid flicker when the Task
+        // resized before organizer requests have been applied.
+        taskProperties.translateAbsoluteBoundsToRelativeBounds(bounds);
+        return bounds;
     }
 
     @NonNull
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index 03f4dc9..f41295b 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -243,6 +243,15 @@
             return mConfiguration;
         }
 
+        /** Translates the given absolute bounds to relative bounds in this Task coordinate. */
+        void translateAbsoluteBoundsToRelativeBounds(@NonNull Rect inOutBounds) {
+            if (inOutBounds.isEmpty()) {
+                return;
+            }
+            final Rect taskBounds = mConfiguration.windowConfiguration.getBounds();
+            inOutBounds.offset(-taskBounds.left, -taskBounds.top);
+        }
+
         /**
          * Obtains the {@link TaskProperties} for the task that the provided {@link Activity} is
          * associated with.
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 17814c6..861cb49 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -570,20 +570,22 @@
 
     /**
      * Checks if last requested bounds are equal to the provided value.
+     * The requested bounds are relative bounds in parent coordinate.
      */
-    boolean areLastRequestedBoundsEqual(@Nullable Rect bounds) {
-        return (bounds == null && mLastRequestedBounds.isEmpty())
-                || mLastRequestedBounds.equals(bounds);
+    boolean areLastRequestedBoundsEqual(@Nullable Rect relBounds) {
+        return (relBounds == null && mLastRequestedBounds.isEmpty())
+                || mLastRequestedBounds.equals(relBounds);
     }
 
     /**
      * Updates the last requested bounds.
+     * The requested bounds are relative bounds in parent coordinate.
      */
-    void setLastRequestedBounds(@Nullable Rect bounds) {
-        if (bounds == null) {
+    void setLastRequestedBounds(@Nullable Rect relBounds) {
+        if (relBounds == null) {
             mLastRequestedBounds.setEmpty();
         } else {
-            mLastRequestedBounds.set(bounds);
+            mLastRequestedBounds.set(relBounds);
         }
     }
 
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
index c5d932e..a41e63f 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
@@ -75,6 +75,7 @@
 import android.window.TaskFragmentOperation;
 import android.window.WindowContainerTransaction;
 
+import androidx.annotation.NonNull;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
@@ -148,13 +149,13 @@
         mPresenter.resizeTaskFragment(mTransaction, container.getTaskFragmentToken(), TASK_BOUNDS);
 
         assertTrue(container.areLastRequestedBoundsEqual(TASK_BOUNDS));
-        verify(mTransaction).setBounds(any(), eq(TASK_BOUNDS));
+        verify(mTransaction).setRelativeBounds(any(), eq(TASK_BOUNDS));
 
         // No request to set the same bounds.
         clearInvocations(mTransaction);
         mPresenter.resizeTaskFragment(mTransaction, container.getTaskFragmentToken(), TASK_BOUNDS);
 
-        verify(mTransaction, never()).setBounds(any(), any());
+        verify(mTransaction, never()).setRelativeBounds(any(), any());
     }
 
     @Test
@@ -226,7 +227,7 @@
     }
 
     @Test
-    public void testGetBoundsForPosition_expandContainers() {
+    public void testGetRelBoundsForPosition_expandContainers() {
         final TaskContainer.TaskProperties taskProperties = getTaskProperty();
         final SplitAttributes splitAttributes = new SplitAttributes.Builder()
                 .setSplitType(new SplitAttributes.SplitType.ExpandContainersSplitType())
@@ -234,18 +235,40 @@
 
         assertEquals("Task bounds must be reported.",
                 new Rect(),
-                mPresenter.getBoundsForPosition(POSITION_START, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_START, taskProperties,
+                        splitAttributes));
 
         assertEquals("Task bounds must be reported.",
                 new Rect(),
-                mPresenter.getBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
         assertEquals("Task bounds must be reported.",
                 new Rect(),
-                mPresenter.getBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
     }
 
     @Test
-    public void testGetBoundsForPosition_splitVertically() {
+    public void testGetRelBoundsForPosition_expandContainers_isRelativeToParent() {
+        final TaskContainer.TaskProperties taskProperties = getTaskProperty(
+                new Rect(100, 100, 500, 1000));
+        final SplitAttributes splitAttributes = new SplitAttributes.Builder()
+                .setSplitType(new SplitAttributes.SplitType.ExpandContainersSplitType())
+                .build();
+
+        assertEquals("Task bounds must be reported.",
+                new Rect(),
+                mPresenter.getRelBoundsForPosition(POSITION_START, taskProperties,
+                        splitAttributes));
+
+        assertEquals("Task bounds must be reported.",
+                new Rect(),
+                mPresenter.getRelBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
+        assertEquals("Task bounds must be reported.",
+                new Rect(),
+                mPresenter.getRelBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
+    }
+
+    @Test
+    public void testGetRelBoundsForPosition_splitVertically() {
         final Rect primaryBounds = getSplitBounds(true /* isPrimary */,
                 false /* splitHorizontally */);
         final Rect secondaryBounds = getSplitBounds(false /* isPrimary */,
@@ -258,14 +281,15 @@
 
         assertEquals("Primary bounds must be reported.",
                 primaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_START, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_START, taskProperties,
+                        splitAttributes));
 
         assertEquals("Secondary bounds must be reported.",
                 secondaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
         assertEquals("Task bounds must be reported.",
                 new Rect(),
-                mPresenter.getBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
 
         splitAttributes = new SplitAttributes.Builder()
                 .setSplitType(SplitAttributes.SplitType.RatioSplitType.splitEqually())
@@ -274,14 +298,15 @@
 
         assertEquals("Secondary bounds must be reported.",
                 secondaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_START, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_START, taskProperties,
+                        splitAttributes));
 
         assertEquals("Primary bounds must be reported.",
                 primaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
         assertEquals("Task bounds must be reported.",
                 new Rect(),
-                mPresenter.getBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
 
         splitAttributes = new SplitAttributes.Builder()
                 .setSplitType(SplitAttributes.SplitType.RatioSplitType.splitEqually())
@@ -292,18 +317,85 @@
 
         assertEquals("Secondary bounds must be reported.",
                 secondaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_START, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_START, taskProperties,
+                        splitAttributes));
 
         assertEquals("Primary bounds must be reported.",
                 primaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
         assertEquals("Task bounds must be reported.",
                 new Rect(),
-                mPresenter.getBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
     }
 
     @Test
-    public void testGetBoundsForPosition_splitHorizontally() {
+    public void testGetRelBoundsForPosition_splitVertically_isRelativeToParent() {
+        // Calculate based on TASK_BOUNDS.
+        final Rect primaryBounds = getSplitBounds(true /* isPrimary */,
+                false /* splitHorizontally */);
+        final Rect secondaryBounds = getSplitBounds(false /* isPrimary */,
+                false /* splitHorizontally */);
+
+        // Offset TaskBounds to 100, 100. The returned rel bounds shouldn't be affected.
+        final Rect taskBounds = new Rect(TASK_BOUNDS);
+        taskBounds.offset(100, 100);
+        final TaskContainer.TaskProperties taskProperties = getTaskProperty(taskBounds);
+        SplitAttributes splitAttributes = new SplitAttributes.Builder()
+                .setSplitType(SplitAttributes.SplitType.RatioSplitType.splitEqually())
+                .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT)
+                .build();
+
+        assertEquals("Primary bounds must be reported.",
+                primaryBounds,
+                mPresenter.getRelBoundsForPosition(POSITION_START, taskProperties,
+                        splitAttributes));
+
+        assertEquals("Secondary bounds must be reported.",
+                secondaryBounds,
+                mPresenter.getRelBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
+        assertEquals("Task bounds must be reported.",
+                new Rect(),
+                mPresenter.getRelBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
+
+        splitAttributes = new SplitAttributes.Builder()
+                .setSplitType(SplitAttributes.SplitType.RatioSplitType.splitEqually())
+                .setLayoutDirection(SplitAttributes.LayoutDirection.RIGHT_TO_LEFT)
+                .build();
+
+        assertEquals("Secondary bounds must be reported.",
+                secondaryBounds,
+                mPresenter.getRelBoundsForPosition(POSITION_START, taskProperties,
+                        splitAttributes));
+
+        assertEquals("Primary bounds must be reported.",
+                primaryBounds,
+                mPresenter.getRelBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
+        assertEquals("Task bounds must be reported.",
+                new Rect(),
+                mPresenter.getRelBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
+
+        splitAttributes = new SplitAttributes.Builder()
+                .setSplitType(SplitAttributes.SplitType.RatioSplitType.splitEqually())
+                .setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE)
+                .build();
+        // Layout direction should follow screen layout for SplitAttributes.LayoutDirection.LOCALE.
+        taskProperties.getConfiguration().screenLayout |= Configuration.SCREENLAYOUT_LAYOUTDIR_RTL;
+
+        assertEquals("Secondary bounds must be reported.",
+                secondaryBounds,
+                mPresenter.getRelBoundsForPosition(POSITION_START, taskProperties,
+                        splitAttributes));
+
+        assertEquals("Primary bounds must be reported.",
+                primaryBounds,
+                mPresenter.getRelBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
+        assertEquals("Task bounds must be reported.",
+                new Rect(),
+                mPresenter.getRelBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
+    }
+
+    @Test
+    public void testGetRelBoundsForPosition_splitHorizontally() {
         final Rect primaryBounds = getSplitBounds(true /* isPrimary */,
                 true /* splitHorizontally */);
         final Rect secondaryBounds = getSplitBounds(false /* isPrimary */,
@@ -316,14 +408,15 @@
 
         assertEquals("Primary bounds must be reported.",
                 primaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_START, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_START, taskProperties,
+                        splitAttributes));
 
         assertEquals("Secondary bounds must be reported.",
                 secondaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
         assertEquals("Task bounds must be reported.",
                 new Rect(),
-                mPresenter.getBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
 
         splitAttributes = new SplitAttributes.Builder()
                 .setSplitType(SplitAttributes.SplitType.RatioSplitType.splitEqually())
@@ -332,18 +425,19 @@
 
         assertEquals("Secondary bounds must be reported.",
                 secondaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_START, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_START, taskProperties,
+                        splitAttributes));
 
         assertEquals("Primary bounds must be reported.",
                 primaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
         assertEquals("Task bounds must be reported.",
                 new Rect(),
-                mPresenter.getBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
     }
 
     @Test
-    public void testGetBoundsForPosition_useHingeFallback() {
+    public void testGetRelBoundsForPosition_useHingeFallback() {
         final Rect primaryBounds = getSplitBounds(true /* isPrimary */,
                 false /* splitHorizontally */);
         final Rect secondaryBounds = getSplitBounds(false /* isPrimary */,
@@ -361,14 +455,15 @@
 
         assertEquals("PrimaryBounds must be reported.",
                 primaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_START, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_START, taskProperties,
+                        splitAttributes));
 
         assertEquals("SecondaryBounds must be reported.",
                 secondaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
         assertEquals("Task bounds must be reported.",
                 new Rect(),
-                mPresenter.getBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
 
         // Hinge is reported, but the host task is in multi-window mode. Still use fallback
         // splitType.
@@ -379,14 +474,15 @@
 
         assertEquals("PrimaryBounds must be reported.",
                 primaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_START, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_START, taskProperties,
+                        splitAttributes));
 
         assertEquals("SecondaryBounds must be reported.",
                 secondaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
         assertEquals("Task bounds must be reported.",
                 new Rect(),
-                mPresenter.getBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
 
         // Hinge is reported, and the host task is in fullscreen, but layout direction doesn't match
         // folding area orientation. Still use fallback splitType.
@@ -397,18 +493,19 @@
 
         assertEquals("PrimaryBounds must be reported.",
                 primaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_START, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_START, taskProperties,
+                        splitAttributes));
 
         assertEquals("SecondaryBounds must be reported.",
                 secondaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
         assertEquals("Task bounds must be reported.",
                 new Rect(),
-                mPresenter.getBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
     }
 
     @Test
-    public void testGetBoundsForPosition_fallbackToExpandContainers() {
+    public void testGetRelBoundsForPosition_fallbackToExpandContainers() {
         final TaskContainer.TaskProperties taskProperties = getTaskProperty();
         final SplitAttributes splitAttributes = new SplitAttributes.Builder()
                 .setSplitType(new SplitAttributes.SplitType.HingeSplitType(
@@ -418,18 +515,19 @@
 
         assertEquals("Task bounds must be reported.",
                 new Rect(),
-                mPresenter.getBoundsForPosition(POSITION_START, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_START, taskProperties,
+                        splitAttributes));
 
         assertEquals("Task bounds must be reported.",
                 new Rect(),
-                mPresenter.getBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
         assertEquals("Task bounds must be reported.",
                 new Rect(),
-                mPresenter.getBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
     }
 
     @Test
-    public void testGetBoundsForPosition_useHingeSplitType() {
+    public void testGetRelBoundsForPosition_useHingeSplitType() {
         final TaskContainer.TaskProperties taskProperties = getTaskProperty();
         final SplitAttributes splitAttributes = new SplitAttributes.Builder()
                 .setSplitType(new SplitAttributes.SplitType.HingeSplitType(
@@ -455,14 +553,15 @@
 
         assertEquals("PrimaryBounds must be reported.",
                 primaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_START, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_START, taskProperties,
+                        splitAttributes));
 
         assertEquals("SecondaryBounds must be reported.",
                 secondaryBounds,
-                mPresenter.getBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_END, taskProperties, splitAttributes));
         assertEquals("Task bounds must be reported.",
                 new Rect(),
-                mPresenter.getBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
+                mPresenter.getRelBoundsForPosition(POSITION_FILL, taskProperties, splitAttributes));
     }
 
     @Test
@@ -601,8 +700,12 @@
     }
 
     private static TaskContainer.TaskProperties getTaskProperty() {
+        return getTaskProperty(TASK_BOUNDS);
+    }
+
+    private static TaskContainer.TaskProperties getTaskProperty(@NonNull Rect taskBounds) {
         final Configuration configuration = new Configuration();
-        configuration.windowConfiguration.setBounds(TASK_BOUNDS);
+        configuration.windowConfiguration.setBounds(taskBounds);
         return new TaskContainer.TaskProperties(DEFAULT_DISPLAY, configuration);
     }
 }
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index 774f6c6..76eb094 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -105,6 +105,10 @@
         1.777778
     </item>
 
+    <!-- The aspect ratio that by which optimizations to large screen sizes are made.
+         Needs to be less that or equal to 1. -->
+    <item name="config_pipLargeScreenOptimizedAspectRatio" format="float" type="dimen">0.5625</item>
+
     <!-- The default gravity for the picture-in-picture window.
          Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
     <integer name="config_defaultPictureInPictureGravity">0x55</integer>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
index b144d22..be3e0a1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
@@ -39,6 +39,7 @@
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.pip.PipTransitionState;
 import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
 import com.android.wm.shell.pip.tv.TvPipBoundsAlgorithm;
 import com.android.wm.shell.pip.tv.TvPipBoundsController;
 import com.android.wm.shell.pip.tv.TvPipBoundsState;
@@ -52,11 +53,11 @@
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
 
-import java.util.Optional;
-
 import dagger.Module;
 import dagger.Provides;
 
+import java.util.Optional;
+
 /**
  * Provides TV specific dependencies for Pip.
  */
@@ -69,6 +70,7 @@
             ShellInit shellInit,
             ShellController shellController,
             TvPipBoundsState tvPipBoundsState,
+            PipSizeSpecHandler pipSizeSpecHandler,
             TvPipBoundsAlgorithm tvPipBoundsAlgorithm,
             TvPipBoundsController tvPipBoundsController,
             PipAppOpsListener pipAppOpsListener,
@@ -89,6 +91,7 @@
                         shellInit,
                         shellController,
                         tvPipBoundsState,
+                        pipSizeSpecHandler,
                         tvPipBoundsAlgorithm,
                         tvPipBoundsController,
                         pipAppOpsListener,
@@ -129,14 +132,23 @@
     @WMSingleton
     @Provides
     static TvPipBoundsAlgorithm provideTvPipBoundsAlgorithm(Context context,
-            TvPipBoundsState tvPipBoundsState, PipSnapAlgorithm pipSnapAlgorithm) {
-        return new TvPipBoundsAlgorithm(context, tvPipBoundsState, pipSnapAlgorithm);
+            TvPipBoundsState tvPipBoundsState, PipSnapAlgorithm pipSnapAlgorithm,
+            PipSizeSpecHandler pipSizeSpecHandler) {
+        return new TvPipBoundsAlgorithm(context, tvPipBoundsState, pipSnapAlgorithm,
+                pipSizeSpecHandler);
     }
 
     @WMSingleton
     @Provides
-    static TvPipBoundsState provideTvPipBoundsState(Context context) {
-        return new TvPipBoundsState(context);
+    static TvPipBoundsState provideTvPipBoundsState(Context context,
+            PipSizeSpecHandler pipSizeSpecHandler) {
+        return new TvPipBoundsState(context, pipSizeSpecHandler);
+    }
+
+    @WMSingleton
+    @Provides
+    static PipSizeSpecHandler providePipSizeSpecHelper(Context context) {
+        return new PipSizeSpecHandler(context);
     }
 
     // Handler needed for loadDrawableAsync() in PipControlsViewController
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 512a4ef..4879d86 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -77,6 +77,7 @@
 import com.android.wm.shell.pip.phone.PhonePipMenuController;
 import com.android.wm.shell.pip.phone.PipController;
 import com.android.wm.shell.pip.phone.PipMotionHelper;
+import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
 import com.android.wm.shell.pip.phone.PipTouchHandler;
 import com.android.wm.shell.recents.RecentTasksController;
 import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -98,15 +99,15 @@
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel;
 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-
 import dagger.Binds;
 import dagger.Lazy;
 import dagger.Module;
 import dagger.Provides;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
 /**
  * Provides dependencies from {@link com.android.wm.shell}, these dependencies are only
  * accessible from components within the WM subcomponent (can be explicitly exposed to the
@@ -338,6 +339,7 @@
             PipBoundsAlgorithm pipBoundsAlgorithm,
             PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
             PipBoundsState pipBoundsState,
+            PipSizeSpecHandler pipSizeSpecHandler,
             PipMotionHelper pipMotionHelper,
             PipMediaController pipMediaController,
             PhonePipMenuController phonePipMenuController,
@@ -354,17 +356,18 @@
         return Optional.ofNullable(PipController.create(
                 context, shellInit, shellCommandHandler, shellController,
                 displayController, pipAnimationController, pipAppOpsListener, pipBoundsAlgorithm,
-                pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper, pipMediaController,
-                phonePipMenuController, pipTaskOrganizer, pipTransitionState, pipTouchHandler,
-                pipTransitionController, windowManagerShellWrapper, taskStackListener,
-                pipParamsChangedForwarder, displayInsetsController, oneHandedController,
-                mainExecutor));
+                pipKeepClearAlgorithm, pipBoundsState, pipSizeSpecHandler, pipMotionHelper,
+                pipMediaController, phonePipMenuController, pipTaskOrganizer, pipTransitionState,
+                pipTouchHandler, pipTransitionController, windowManagerShellWrapper,
+                taskStackListener, pipParamsChangedForwarder, displayInsetsController,
+                oneHandedController, mainExecutor));
     }
 
     @WMSingleton
     @Provides
-    static PipBoundsState providePipBoundsState(Context context) {
-        return new PipBoundsState(context);
+    static PipBoundsState providePipBoundsState(Context context,
+            PipSizeSpecHandler pipSizeSpecHandler) {
+        return new PipBoundsState(context, pipSizeSpecHandler);
     }
 
     @WMSingleton
@@ -381,11 +384,18 @@
 
     @WMSingleton
     @Provides
+    static PipSizeSpecHandler providePipSizeSpecHelper(Context context) {
+        return new PipSizeSpecHandler(context);
+    }
+
+    @WMSingleton
+    @Provides
     static PipBoundsAlgorithm providesPipBoundsAlgorithm(Context context,
             PipBoundsState pipBoundsState, PipSnapAlgorithm pipSnapAlgorithm,
-            PhonePipKeepClearAlgorithm pipKeepClearAlgorithm) {
+            PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
+            PipSizeSpecHandler pipSizeSpecHandler) {
         return new PipBoundsAlgorithm(context, pipBoundsState, pipSnapAlgorithm,
-                pipKeepClearAlgorithm);
+                pipKeepClearAlgorithm, pipSizeSpecHandler);
     }
 
     // Handler is used by Icon.loadDrawableAsync
@@ -409,13 +419,14 @@
             PhonePipMenuController menuPhoneController,
             PipBoundsAlgorithm pipBoundsAlgorithm,
             PipBoundsState pipBoundsState,
+            PipSizeSpecHandler pipSizeSpecHandler,
             PipTaskOrganizer pipTaskOrganizer,
             PipMotionHelper pipMotionHelper,
             FloatingContentCoordinator floatingContentCoordinator,
             PipUiEventLogger pipUiEventLogger,
             @ShellMainThread ShellExecutor mainExecutor) {
         return new PipTouchHandler(context, shellInit, menuPhoneController, pipBoundsAlgorithm,
-                pipBoundsState, pipTaskOrganizer, pipMotionHelper,
+                pipBoundsState, pipSizeSpecHandler, pipTaskOrganizer, pipMotionHelper,
                 floatingContentCoordinator, pipUiEventLogger, mainExecutor);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index f6d67d8..867162b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -16,24 +16,19 @@
 
 package com.android.wm.shell.pip;
 
-import static android.util.TypedValue.COMPLEX_UNIT_DIP;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.PictureInPictureParams;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
-import android.graphics.Point;
-import android.graphics.PointF;
 import android.graphics.Rect;
 import android.util.DisplayMetrics;
 import android.util.Size;
-import android.util.TypedValue;
 import android.view.Gravity;
 
 import com.android.wm.shell.R;
-import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
 
 import java.io.PrintWriter;
 
@@ -45,33 +40,29 @@
     private static final String TAG = PipBoundsAlgorithm.class.getSimpleName();
     private static final float INVALID_SNAP_FRACTION = -1f;
 
-    private final @NonNull PipBoundsState mPipBoundsState;
+    @NonNull private final PipBoundsState mPipBoundsState;
+    @NonNull protected final PipSizeSpecHandler mPipSizeSpecHandler;
     private final PipSnapAlgorithm mSnapAlgorithm;
     private final PipKeepClearAlgorithmInterface mPipKeepClearAlgorithm;
 
-    private float mDefaultSizePercent;
-    private float mMinAspectRatioForMinSize;
-    private float mMaxAspectRatioForMinSize;
     private float mDefaultAspectRatio;
     private float mMinAspectRatio;
     private float mMaxAspectRatio;
     private int mDefaultStackGravity;
-    private int mDefaultMinSize;
-    private int mOverridableMinSize;
-    protected Point mScreenEdgeInsets;
 
     public PipBoundsAlgorithm(Context context, @NonNull PipBoundsState pipBoundsState,
             @NonNull PipSnapAlgorithm pipSnapAlgorithm,
-            @NonNull PipKeepClearAlgorithmInterface pipKeepClearAlgorithm) {
+            @NonNull PipKeepClearAlgorithmInterface pipKeepClearAlgorithm,
+            @NonNull PipSizeSpecHandler pipSizeSpecHandler) {
         mPipBoundsState = pipBoundsState;
         mSnapAlgorithm = pipSnapAlgorithm;
         mPipKeepClearAlgorithm = pipKeepClearAlgorithm;
+        mPipSizeSpecHandler = pipSizeSpecHandler;
         reloadResources(context);
         // Initialize the aspect ratio to the default aspect ratio.  Don't do this in reload
         // resources as it would clobber mAspectRatio when entering PiP from fullscreen which
         // triggers a configuration change and the resources to be reloaded.
         mPipBoundsState.setAspectRatio(mDefaultAspectRatio);
-        mPipBoundsState.setMinEdgeSize(mDefaultMinSize);
     }
 
     /**
@@ -83,27 +74,15 @@
                 R.dimen.config_pictureInPictureDefaultAspectRatio);
         mDefaultStackGravity = res.getInteger(
                 R.integer.config_defaultPictureInPictureGravity);
-        mDefaultMinSize = res.getDimensionPixelSize(
-                R.dimen.default_minimal_size_pip_resizable_task);
-        mOverridableMinSize = res.getDimensionPixelSize(
-                R.dimen.overridable_minimal_size_pip_resizable_task);
         final String screenEdgeInsetsDpString = res.getString(
                 R.string.config_defaultPictureInPictureScreenEdgeInsets);
         final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
                 ? Size.parseSize(screenEdgeInsetsDpString)
                 : null;
-        mScreenEdgeInsets = screenEdgeInsetsDp == null ? new Point()
-                : new Point(dpToPx(screenEdgeInsetsDp.getWidth(), res.getDisplayMetrics()),
-                        dpToPx(screenEdgeInsetsDp.getHeight(), res.getDisplayMetrics()));
         mMinAspectRatio = res.getFloat(
                 com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
         mMaxAspectRatio = res.getFloat(
                 com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
-        mDefaultSizePercent = res.getFloat(
-                R.dimen.config_pictureInPictureDefaultSizePercent);
-        mMaxAspectRatioForMinSize = res.getFloat(
-                R.dimen.config_pictureInPictureAspectRatioLimitForMinSize);
-        mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize;
     }
 
     /**
@@ -180,8 +159,9 @@
         if (windowLayout.minWidth > 0 && windowLayout.minHeight > 0) {
             // If either dimension is smaller than the allowed minimum, adjust them
             // according to mOverridableMinSize
-            return new Size(Math.max(windowLayout.minWidth, mOverridableMinSize),
-                    Math.max(windowLayout.minHeight, mOverridableMinSize));
+            return new Size(
+                    Math.max(windowLayout.minWidth, mPipSizeSpecHandler.getOverrideMinEdgeSize()),
+                    Math.max(windowLayout.minHeight, mPipSizeSpecHandler.getOverrideMinEdgeSize()));
         }
         return null;
     }
@@ -243,28 +223,13 @@
         final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
                 getMovementBounds(stackBounds), mPipBoundsState.getStashedState());
 
-        final Size overrideMinSize = mPipBoundsState.getOverrideMinSize();
         final Size size;
         if (useCurrentMinEdgeSize || useCurrentSize) {
-            // The default minimum edge size, or the override min edge size if set.
-            final int defaultMinEdgeSize = overrideMinSize == null ? mDefaultMinSize
-                    : mPipBoundsState.getOverrideMinEdgeSize();
-            final int minEdgeSize = useCurrentMinEdgeSize ? mPipBoundsState.getMinEdgeSize()
-                    : defaultMinEdgeSize;
-            // Use the existing size but adjusted to the aspect ratio and min edge size.
-            size = getSizeForAspectRatio(
-                    new Size(stackBounds.width(), stackBounds.height()), aspectRatio, minEdgeSize);
+            // Use the existing size but adjusted to the new aspect ratio.
+            size = mPipSizeSpecHandler.getSizeForAspectRatio(
+                    new Size(stackBounds.width(), stackBounds.height()), aspectRatio);
         } else {
-            if (overrideMinSize != null) {
-                // The override minimal size is set, use that as the default size making sure it's
-                // adjusted to the aspect ratio.
-                size = adjustSizeToAspectRatio(overrideMinSize, aspectRatio);
-            } else {
-                // Calculate the default size using the display size and default min edge size.
-                final DisplayLayout displayLayout = mPipBoundsState.getDisplayLayout();
-                size = getSizeForAspectRatio(aspectRatio, mDefaultMinSize,
-                        displayLayout.width(), displayLayout.height());
-            }
+            size = mPipSizeSpecHandler.getDefaultSize(aspectRatio);
         }
 
         final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f);
@@ -273,18 +238,6 @@
         mSnapAlgorithm.applySnapFraction(stackBounds, getMovementBounds(stackBounds), snapFraction);
     }
 
-    /** Adjusts the given size to conform to the given aspect ratio. */
-    private Size adjustSizeToAspectRatio(@NonNull Size size, float aspectRatio) {
-        final float sizeAspectRatio = size.getWidth() / (float) size.getHeight();
-        if (sizeAspectRatio > aspectRatio) {
-            // Size is wider, fix the width and increase the height
-            return new Size(size.getWidth(), (int) (size.getWidth() / aspectRatio));
-        } else {
-            // Size is taller, fix the height and adjust the width.
-            return new Size((int) (size.getHeight() * aspectRatio), size.getHeight());
-        }
-    }
-
     /**
      * @return the default bounds to show the PIP, if a {@param snapFraction} and {@param size} are
      * provided, then it will apply the default bounds to the provided snap fraction and size.
@@ -303,17 +256,9 @@
         final Size defaultSize;
         final Rect insetBounds = new Rect();
         getInsetBounds(insetBounds);
-        final DisplayLayout displayLayout = mPipBoundsState.getDisplayLayout();
-        final Size overrideMinSize = mPipBoundsState.getOverrideMinSize();
-        if (overrideMinSize != null) {
-            // The override minimal size is set, use that as the default size making sure it's
-            // adjusted to the aspect ratio.
-            defaultSize = adjustSizeToAspectRatio(overrideMinSize, mDefaultAspectRatio);
-        } else {
-            // Calculate the default size using the display size and default min edge size.
-            defaultSize = getSizeForAspectRatio(mDefaultAspectRatio,
-                    mDefaultMinSize, displayLayout.width(), displayLayout.height());
-        }
+
+        // Calculate the default size
+        defaultSize = mPipSizeSpecHandler.getDefaultSize(mDefaultAspectRatio);
 
         // Now that we have the default size, apply the snap fraction if valid or position the
         // bounds using the default gravity.
@@ -335,12 +280,7 @@
      * Populates the bounds on the screen that the PIP can be visible in.
      */
     public void getInsetBounds(Rect outRect) {
-        final DisplayLayout displayLayout = mPipBoundsState.getDisplayLayout();
-        Rect insets = mPipBoundsState.getDisplayLayout().stableInsets();
-        outRect.set(insets.left + mScreenEdgeInsets.x,
-                insets.top + mScreenEdgeInsets.y,
-                displayLayout.width() - insets.right - mScreenEdgeInsets.x,
-                displayLayout.height() - insets.bottom - mScreenEdgeInsets.y);
+        outRect.set(mPipSizeSpecHandler.getInsetBounds());
     }
 
     /**
@@ -405,71 +345,11 @@
         mSnapAlgorithm.applySnapFraction(stackBounds, movementBounds, snapFraction);
     }
 
-    public int getDefaultMinSize() {
-        return mDefaultMinSize;
-    }
-
     /**
      * @return the pixels for a given dp value.
      */
     private int dpToPx(float dpValue, DisplayMetrics dm) {
-        return (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, dpValue, dm);
-    }
-
-    /**
-     * @return the size of the PiP at the given aspectRatio, ensuring that the minimum edge
-     * is at least minEdgeSize.
-     */
-    public Size getSizeForAspectRatio(float aspectRatio, float minEdgeSize, int displayWidth,
-            int displayHeight) {
-        final int smallestDisplaySize = Math.min(displayWidth, displayHeight);
-        final int minSize = (int) Math.max(minEdgeSize, smallestDisplaySize * mDefaultSizePercent);
-
-        final int width;
-        final int height;
-        if (aspectRatio <= mMinAspectRatioForMinSize || aspectRatio > mMaxAspectRatioForMinSize) {
-            // Beyond these points, we can just use the min size as the shorter edge
-            if (aspectRatio <= 1) {
-                // Portrait, width is the minimum size
-                width = minSize;
-                height = Math.round(width / aspectRatio);
-            } else {
-                // Landscape, height is the minimum size
-                height = minSize;
-                width = Math.round(height * aspectRatio);
-            }
-        } else {
-            // Within these points, we ensure that the bounds fit within the radius of the limits
-            // at the points
-            final float widthAtMaxAspectRatioForMinSize = mMaxAspectRatioForMinSize * minSize;
-            final float radius = PointF.length(widthAtMaxAspectRatioForMinSize, minSize);
-            height = (int) Math.round(Math.sqrt((radius * radius)
-                    / (aspectRatio * aspectRatio + 1)));
-            width = Math.round(height * aspectRatio);
-        }
-        return new Size(width, height);
-    }
-
-    /**
-     * @return the adjusted size so that it conforms to the given aspectRatio, ensuring that the
-     * minimum edge is at least minEdgeSize.
-     */
-    public Size getSizeForAspectRatio(Size size, float aspectRatio, float minEdgeSize) {
-        final int smallestSize = Math.min(size.getWidth(), size.getHeight());
-        final int minSize = (int) Math.max(minEdgeSize, smallestSize);
-
-        final int width;
-        final int height;
-        if (aspectRatio <= 1) {
-            // Portrait, width is the minimum size.
-            width = minSize;
-            height = Math.round(width / aspectRatio);
-        } else {
-            // Landscape, height is the minimum size
-            height = minSize;
-            width = Math.round(height * aspectRatio);
-        }
-        return new Size(width, height);
+        return PipUtils.dpToPx(dpValue, dm);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
index 5376ae3..61da10b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
@@ -37,6 +37,7 @@
 import com.android.internal.util.function.TriConsumer;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 
 import java.io.PrintWriter;
@@ -83,13 +84,10 @@
     private int mStashedState = STASH_TYPE_NONE;
     private int mStashOffset;
     private @Nullable PipReentryState mPipReentryState;
+    private final @Nullable PipSizeSpecHandler mPipSizeSpecHandler;
     private @Nullable ComponentName mLastPipComponentName;
     private int mDisplayId = Display.DEFAULT_DISPLAY;
     private final @NonNull DisplayLayout mDisplayLayout = new DisplayLayout();
-    /** The current minimum edge size of PIP. */
-    private int mMinEdgeSize;
-    /** The preferred minimum (and default) size specified by apps. */
-    private @Nullable Size mOverrideMinSize;
     private final @NonNull MotionBoundsState mMotionBoundsState = new MotionBoundsState();
     private boolean mIsImeShowing;
     private int mImeHeight;
@@ -122,9 +120,10 @@
     private @Nullable TriConsumer<Boolean, Integer, Boolean> mOnShelfVisibilityChangeCallback;
     private List<Consumer<Rect>> mOnPipExclusionBoundsChangeCallbacks = new ArrayList<>();
 
-    public PipBoundsState(@NonNull Context context) {
+    public PipBoundsState(@NonNull Context context, PipSizeSpecHandler pipSizeSpecHandler) {
         mContext = context;
         reloadResources();
+        mPipSizeSpecHandler = pipSizeSpecHandler;
     }
 
     /** Reloads the resources. */
@@ -323,20 +322,10 @@
         mPipReentryState = null;
     }
 
-    /** Set the PIP minimum edge size. */
-    public void setMinEdgeSize(int minEdgeSize) {
-        mMinEdgeSize = minEdgeSize;
-    }
-
-    /** Returns the PIP's current minimum edge size. */
-    public int getMinEdgeSize() {
-        return mMinEdgeSize;
-    }
-
     /** Sets the preferred size of PIP as specified by the activity in PIP mode. */
     public void setOverrideMinSize(@Nullable Size overrideMinSize) {
-        final boolean changed = !Objects.equals(overrideMinSize, mOverrideMinSize);
-        mOverrideMinSize = overrideMinSize;
+        final boolean changed = !Objects.equals(overrideMinSize, getOverrideMinSize());
+        mPipSizeSpecHandler.setOverrideMinSize(overrideMinSize);
         if (changed && mOnMinimalSizeChangeCallback != null) {
             mOnMinimalSizeChangeCallback.run();
         }
@@ -345,13 +334,12 @@
     /** Returns the preferred minimal size specified by the activity in PIP. */
     @Nullable
     public Size getOverrideMinSize() {
-        return mOverrideMinSize;
+        return mPipSizeSpecHandler.getOverrideMinSize();
     }
 
     /** Returns the minimum edge size of the override minimum size, or 0 if not set. */
     public int getOverrideMinEdgeSize() {
-        if (mOverrideMinSize == null) return 0;
-        return Math.min(mOverrideMinSize.getWidth(), mOverrideMinSize.getHeight());
+        return mPipSizeSpecHandler.getOverrideMinEdgeSize();
     }
 
     /** Get the state of the bounds in motion. */
@@ -581,11 +569,8 @@
         pw.println(innerPrefix + "mLastPipComponentName=" + mLastPipComponentName);
         pw.println(innerPrefix + "mAspectRatio=" + mAspectRatio);
         pw.println(innerPrefix + "mDisplayId=" + mDisplayId);
-        pw.println(innerPrefix + "mDisplayLayout=" + mDisplayLayout);
         pw.println(innerPrefix + "mStashedState=" + mStashedState);
         pw.println(innerPrefix + "mStashOffset=" + mStashOffset);
-        pw.println(innerPrefix + "mMinEdgeSize=" + mMinEdgeSize);
-        pw.println(innerPrefix + "mOverrideMinSize=" + mOverrideMinSize);
         pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing);
         pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
         pw.println(innerPrefix + "mIsShelfShowing=" + mIsShelfShowing);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java
index fa00619..8b98790 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java
@@ -18,6 +18,7 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.util.TypedValue.COMPLEX_UNIT_DIP;
 
 import android.annotation.Nullable;
 import android.app.ActivityTaskManager;
@@ -26,8 +27,10 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.RemoteException;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Pair;
+import android.util.TypedValue;
 import android.window.TaskSnapshot;
 
 import com.android.internal.protolog.common.ProtoLog;
@@ -70,6 +73,13 @@
     }
 
     /**
+     * @return the pixels for a given dp value.
+     */
+    public static int dpToPx(float dpValue, DisplayMetrics dm) {
+        return (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, dpValue, dm);
+    }
+
+    /**
      * @return true if the aspect ratios differ
      */
     public static boolean aspectRatioChanged(float aspectRatio1, float aspectRatio2) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 525beb1..d86468a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -137,6 +137,7 @@
     private PipBoundsAlgorithm mPipBoundsAlgorithm;
     private PipKeepClearAlgorithmInterface mPipKeepClearAlgorithm;
     private PipBoundsState mPipBoundsState;
+    private PipSizeSpecHandler mPipSizeSpecHandler;
     private PipMotionHelper mPipMotionHelper;
     private PipTouchHandler mTouchHandler;
     private PipTransitionController mPipTransitionController;
@@ -380,6 +381,7 @@
             PipBoundsAlgorithm pipBoundsAlgorithm,
             PipKeepClearAlgorithmInterface pipKeepClearAlgorithm,
             PipBoundsState pipBoundsState,
+            PipSizeSpecHandler pipSizeSpecHandler,
             PipMotionHelper pipMotionHelper,
             PipMediaController pipMediaController,
             PhonePipMenuController phonePipMenuController,
@@ -401,11 +403,11 @@
 
         return new PipController(context, shellInit, shellCommandHandler, shellController,
                 displayController, pipAnimationController, pipAppOpsListener,
-                pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper,
-                pipMediaController, phonePipMenuController, pipTaskOrganizer, pipTransitionState,
-                pipTouchHandler, pipTransitionController, windowManagerShellWrapper,
-                taskStackListener, pipParamsChangedForwarder, displayInsetsController,
-                oneHandedController, mainExecutor)
+                pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState, pipSizeSpecHandler,
+                pipMotionHelper, pipMediaController, phonePipMenuController, pipTaskOrganizer,
+                pipTransitionState, pipTouchHandler, pipTransitionController,
+                windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
+                displayInsetsController, oneHandedController, mainExecutor)
                 .mImpl;
     }
 
@@ -419,6 +421,7 @@
             PipBoundsAlgorithm pipBoundsAlgorithm,
             PipKeepClearAlgorithmInterface pipKeepClearAlgorithm,
             @NonNull PipBoundsState pipBoundsState,
+            PipSizeSpecHandler pipSizeSpecHandler,
             PipMotionHelper pipMotionHelper,
             PipMediaController pipMediaController,
             PhonePipMenuController phonePipMenuController,
@@ -444,6 +447,7 @@
         mPipBoundsAlgorithm = pipBoundsAlgorithm;
         mPipKeepClearAlgorithm = pipKeepClearAlgorithm;
         mPipBoundsState = pipBoundsState;
+        mPipSizeSpecHandler = pipSizeSpecHandler;
         mPipMotionHelper = pipMotionHelper;
         mPipTaskOrganizer = pipTaskOrganizer;
         mPipTransitionState = pipTransitionState;
@@ -512,7 +516,10 @@
         // Ensure that we have the display info in case we get calls to update the bounds before the
         // listener calls back
         mPipBoundsState.setDisplayId(mContext.getDisplayId());
-        mPipBoundsState.setDisplayLayout(new DisplayLayout(mContext, mContext.getDisplay()));
+
+        DisplayLayout layout = new DisplayLayout(mContext, mContext.getDisplay());
+        mPipSizeSpecHandler.setDisplayLayout(layout);
+        mPipBoundsState.setDisplayLayout(layout);
 
         try {
             mWindowManagerShellWrapper.addPinnedStackListener(mPinnedTaskListener);
@@ -686,6 +693,7 @@
         mPipBoundsAlgorithm.onConfigurationChanged(mContext);
         mTouchHandler.onConfigurationChanged();
         mPipBoundsState.onConfigurationChanged();
+        mPipSizeSpecHandler.onConfigurationChanged();
     }
 
     @Override
@@ -711,7 +719,11 @@
         Runnable updateDisplayLayout = () -> {
             final boolean fromRotation = Transitions.ENABLE_SHELL_TRANSITIONS
                     && mPipBoundsState.getDisplayLayout().rotation() != layout.rotation();
+
+            // update the internal state of objects subscribed to display changes
+            mPipSizeSpecHandler.setDisplayLayout(layout);
             mPipBoundsState.setDisplayLayout(layout);
+
             final WindowContainerTransaction wct =
                     fromRotation ? new WindowContainerTransaction() : null;
             updateMovementBounds(null /* toBounds */,
@@ -1083,6 +1095,7 @@
         mPipTaskOrganizer.dump(pw, innerPrefix);
         mPipBoundsState.dump(pw, innerPrefix);
         mPipInputConsumer.dump(pw, innerPrefix);
+        mPipSizeSpecHandler.dump(pw, innerPrefix);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
new file mode 100644
index 0000000..a906522
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
@@ -0,0 +1,527 @@
+/*
+ * 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.wm.shell.pip.phone;
+
+import static com.android.wm.shell.pip.PipUtils.dpToPx;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.os.SystemProperties;
+import android.util.Size;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.wm.shell.R;
+import com.android.wm.shell.common.DisplayLayout;
+
+import java.io.PrintWriter;
+
+/**
+ * Acts as a source of truth for appropriate size spec for PIP.
+ */
+public class PipSizeSpecHandler {
+    private static final String TAG = PipSizeSpecHandler.class.getSimpleName();
+
+    @NonNull private final DisplayLayout mDisplayLayout = new DisplayLayout();
+
+    @VisibleForTesting
+    final SizeSpecSource mSizeSpecSourceImpl;
+
+    /** The preferred minimum (and default) size specified by apps. */
+    @Nullable private Size mOverrideMinSize;
+
+    /** Used to store values obtained from resource files. */
+    private Point mScreenEdgeInsets;
+    private float mMinAspectRatioForMinSize;
+    private float mMaxAspectRatioForMinSize;
+    private int mDefaultMinSize;
+
+    @NonNull private final Context mContext;
+
+    private interface SizeSpecSource {
+        /** Returns max size allowed for the PIP window */
+        Size getMaxSize(float aspectRatio);
+
+        /** Returns default size for the PIP window */
+        Size getDefaultSize(float aspectRatio);
+
+        /** Returns min size allowed for the PIP window */
+        Size getMinSize(float aspectRatio);
+
+        /** Returns the adjusted size based on current size and target aspect ratio */
+        Size getSizeForAspectRatio(Size size, float aspectRatio);
+
+        /** Updates internal resources on configuration changes */
+        default void reloadResources() {}
+    }
+
+    /**
+     * Determines PIP window size optimized for large screens and aspect ratios close to 1:1
+     */
+    private class SizeSpecLargeScreenOptimizedImpl implements SizeSpecSource {
+        private static final float DEFAULT_OPTIMIZED_ASPECT_RATIO = 9f / 16;
+
+        /** Default and minimum percentages for the PIP size logic. */
+        private final float mDefaultSizePercent;
+        private final float mMinimumSizePercent;
+
+        /** Aspect ratio that the PIP size spec logic optimizes for. */
+        private float mOptimizedAspectRatio;
+
+        private SizeSpecLargeScreenOptimizedImpl() {
+            mDefaultSizePercent = Float.parseFloat(SystemProperties
+                    .get("com.android.wm.shell.pip.phone.def_percentage", "0.6"));
+            mMinimumSizePercent = Float.parseFloat(SystemProperties
+                    .get("com.android.wm.shell.pip.phone.min_percentage", "0.5"));
+        }
+
+        @Override
+        public void reloadResources() {
+            final Resources res = mContext.getResources();
+
+            mOptimizedAspectRatio = res.getFloat(R.dimen.config_pipLargeScreenOptimizedAspectRatio);
+            // make sure the optimized aspect ratio is valid with a default value to fall back to
+            if (mOptimizedAspectRatio > 1) {
+                mOptimizedAspectRatio = DEFAULT_OPTIMIZED_ASPECT_RATIO;
+            }
+        }
+
+        /**
+         * Calculates the max size of PIP.
+         *
+         * Optimizes for 16:9 aspect ratios, making them take full length of shortest display edge.
+         * As aspect ratio approaches values close to 1:1, the logic does not let PIP occupy the
+         * whole screen. A linear function is used to calculate these sizes.
+         *
+         * @param aspectRatio aspect ratio of the PIP window
+         * @return dimensions of the max size of the PIP
+         */
+        @Override
+        public Size getMaxSize(float aspectRatio) {
+            final int totalHorizontalPadding = getInsetBounds().left
+                    + (getDisplayBounds().width() - getInsetBounds().right);
+            final int totalVerticalPadding = getInsetBounds().top
+                    + (getDisplayBounds().height() - getInsetBounds().bottom);
+
+            final int shorterLength = (int) (1f * Math.min(
+                    getDisplayBounds().width() - totalHorizontalPadding,
+                    getDisplayBounds().height() - totalVerticalPadding));
+
+            int maxWidth, maxHeight;
+
+            // use the optimized max sizing logic only within a certain aspect ratio range
+            if (aspectRatio >= mOptimizedAspectRatio && aspectRatio <= 1 / mOptimizedAspectRatio) {
+                // this formula and its derivation is explained in b/198643358#comment16
+                maxWidth = (int) (mOptimizedAspectRatio * shorterLength
+                        + shorterLength * (aspectRatio - mOptimizedAspectRatio) / (1
+                        + aspectRatio));
+                maxHeight = (int) (maxWidth / aspectRatio);
+            } else {
+                if (aspectRatio > 1f) {
+                    maxWidth = shorterLength;
+                    maxHeight = (int) (maxWidth / aspectRatio);
+                } else {
+                    maxHeight = shorterLength;
+                    maxWidth = (int) (maxHeight * aspectRatio);
+                }
+            }
+
+            return new Size(maxWidth, maxHeight);
+        }
+
+        /**
+         * Decreases the dimensions by a percentage relative to max size to get default size.
+         *
+         * @param aspectRatio aspect ratio of the PIP window
+         * @return dimensions of the default size of the PIP
+         */
+        @Override
+        public Size getDefaultSize(float aspectRatio) {
+            Size minSize = this.getMinSize(aspectRatio);
+
+            if (mOverrideMinSize != null) {
+                return minSize;
+            }
+
+            Size maxSize = this.getMaxSize(aspectRatio);
+
+            int defaultWidth = Math.max((int) (maxSize.getWidth() * mDefaultSizePercent),
+                    minSize.getWidth());
+            int defaultHeight = Math.max((int) (maxSize.getHeight() * mDefaultSizePercent),
+                    minSize.getHeight());
+
+            return new Size(defaultWidth, defaultHeight);
+        }
+
+        /**
+         * Decreases the dimensions by a certain percentage relative to max size to get min size.
+         *
+         * @param aspectRatio aspect ratio of the PIP window
+         * @return dimensions of the min size of the PIP
+         */
+        @Override
+        public Size getMinSize(float aspectRatio) {
+            // if there is an overridden min size provided, return that
+            if (mOverrideMinSize != null) {
+                return adjustOverrideMinSizeToAspectRatio(aspectRatio);
+            }
+
+            Size maxSize = this.getMaxSize(aspectRatio);
+
+            int minWidth = (int) (maxSize.getWidth() * mMinimumSizePercent);
+            int minHeight = (int) (maxSize.getHeight() * mMinimumSizePercent);
+
+            // make sure the calculated min size is not smaller than the allowed default min size
+            if (aspectRatio > 1f) {
+                minHeight = (int) Math.max(minHeight, mDefaultMinSize);
+                minWidth = (int) (minHeight * aspectRatio);
+            } else {
+                minWidth = (int) Math.max(minWidth, mDefaultMinSize);
+                minHeight = (int) (minWidth / aspectRatio);
+            }
+            return new Size(minWidth, minHeight);
+        }
+
+        /**
+         * Returns the size for target aspect ratio making sure new size conforms with the rules.
+         *
+         * <p>Recalculates the dimensions such that the target aspect ratio is achieved, while
+         * maintaining the same maximum size to current size ratio.
+         *
+         * @param size current size
+         * @param aspectRatio target aspect ratio
+         */
+        @Override
+        public Size getSizeForAspectRatio(Size size, float aspectRatio) {
+            // getting the percentage of the max size that current size takes
+            float currAspectRatio = (float) size.getWidth() / size.getHeight();
+            Size currentMaxSize = getMaxSize(currAspectRatio);
+            float currentPercent = (float) size.getWidth() / currentMaxSize.getWidth();
+
+            // getting the max size for the target aspect ratio
+            Size updatedMaxSize = getMaxSize(aspectRatio);
+
+            int width = (int) (updatedMaxSize.getWidth() * currentPercent);
+            int height = (int) (updatedMaxSize.getHeight() * currentPercent);
+
+            // adjust the dimensions if below allowed min edge size
+            if (width < getMinEdgeSize() && aspectRatio <= 1) {
+                width = getMinEdgeSize();
+                height = (int) (width / aspectRatio);
+            } else if (height < getMinEdgeSize() && aspectRatio > 1) {
+                height = getMinEdgeSize();
+                width = (int) (height * aspectRatio);
+            }
+
+            // reduce the dimensions of the updated size to the calculated percentage
+            return new Size(width, height);
+        }
+    }
+
+    private class SizeSpecDefaultImpl implements SizeSpecSource {
+        private float mDefaultSizePercent;
+        private float mMinimumSizePercent;
+
+        @Override
+        public void reloadResources() {
+            final Resources res = mContext.getResources();
+
+            mMaxAspectRatioForMinSize = res.getFloat(
+                    R.dimen.config_pictureInPictureAspectRatioLimitForMinSize);
+            mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize;
+
+            mDefaultSizePercent = res.getFloat(R.dimen.config_pictureInPictureDefaultSizePercent);
+            mMinimumSizePercent = res.getFraction(R.fraction.config_pipShortestEdgePercent, 1, 1);
+        }
+
+        @Override
+        public Size getMaxSize(float aspectRatio) {
+            final int shorterLength = Math.min(getDisplayBounds().width(),
+                    getDisplayBounds().height());
+
+            final int totalHorizontalPadding = getInsetBounds().left
+                    + (getDisplayBounds().width() - getInsetBounds().right);
+            final int totalVerticalPadding = getInsetBounds().top
+                    + (getDisplayBounds().height() - getInsetBounds().bottom);
+
+            final int maxWidth, maxHeight;
+
+            if (aspectRatio > 1f) {
+                maxWidth = (int) Math.max(getDefaultSize(aspectRatio).getWidth(),
+                        shorterLength - totalHorizontalPadding);
+                maxHeight = (int) (maxWidth / aspectRatio);
+            } else {
+                maxHeight = (int) Math.max(getDefaultSize(aspectRatio).getHeight(),
+                        shorterLength - totalVerticalPadding);
+                maxWidth = (int) (maxHeight * aspectRatio);
+            }
+
+            return new Size(maxWidth, maxHeight);
+        }
+
+        @Override
+        public Size getDefaultSize(float aspectRatio) {
+            if (mOverrideMinSize != null) {
+                return this.getMinSize(aspectRatio);
+            }
+
+            final int smallestDisplaySize = Math.min(getDisplayBounds().width(),
+                    getDisplayBounds().height());
+            final int minSize = (int) Math.max(getMinEdgeSize(),
+                    smallestDisplaySize * mDefaultSizePercent);
+
+            final int width;
+            final int height;
+
+            if (aspectRatio <= mMinAspectRatioForMinSize
+                    || aspectRatio > mMaxAspectRatioForMinSize) {
+                // Beyond these points, we can just use the min size as the shorter edge
+                if (aspectRatio <= 1) {
+                    // Portrait, width is the minimum size
+                    width = minSize;
+                    height = Math.round(width / aspectRatio);
+                } else {
+                    // Landscape, height is the minimum size
+                    height = minSize;
+                    width = Math.round(height * aspectRatio);
+                }
+            } else {
+                // Within these points, ensure that the bounds fit within the radius of the limits
+                // at the points
+                final float widthAtMaxAspectRatioForMinSize = mMaxAspectRatioForMinSize * minSize;
+                final float radius = PointF.length(widthAtMaxAspectRatioForMinSize, minSize);
+                height = (int) Math.round(Math.sqrt((radius * radius)
+                        / (aspectRatio * aspectRatio + 1)));
+                width = Math.round(height * aspectRatio);
+            }
+
+            return new Size(width, height);
+        }
+
+        @Override
+        public Size getMinSize(float aspectRatio) {
+            if (mOverrideMinSize != null) {
+                return adjustOverrideMinSizeToAspectRatio(aspectRatio);
+            }
+
+            final int shorterLength = Math.min(getDisplayBounds().width(),
+                    getDisplayBounds().height());
+            final int minWidth, minHeight;
+
+            if (aspectRatio > 1f) {
+                minWidth = (int) Math.min(getDefaultSize(aspectRatio).getWidth(),
+                        shorterLength * mMinimumSizePercent);
+                minHeight = (int) (minWidth / aspectRatio);
+            } else {
+                minHeight = (int) Math.min(getDefaultSize(aspectRatio).getHeight(),
+                        shorterLength * mMinimumSizePercent);
+                minWidth = (int) (minHeight * aspectRatio);
+            }
+
+            return new Size(minWidth, minHeight);
+        }
+
+        @Override
+        public Size getSizeForAspectRatio(Size size, float aspectRatio) {
+            final int smallestSize = Math.min(size.getWidth(), size.getHeight());
+            final int minSize = Math.max(getMinEdgeSize(), smallestSize);
+
+            final int width;
+            final int height;
+            if (aspectRatio <= 1) {
+                // Portrait, width is the minimum size.
+                width = minSize;
+                height = Math.round(width / aspectRatio);
+            } else {
+                // Landscape, height is the minimum size
+                height = minSize;
+                width = Math.round(height * aspectRatio);
+            }
+
+            return new Size(width, height);
+        }
+    }
+
+    public PipSizeSpecHandler(Context context) {
+        mContext = context;
+
+        boolean enablePipSizeLargeScreen = SystemProperties
+                .getBoolean("persist.wm.debug.enable_pip_size_large_screen", false);
+
+        // choose between two implementations of size spec logic
+        if (enablePipSizeLargeScreen) {
+            mSizeSpecSourceImpl = new SizeSpecLargeScreenOptimizedImpl();
+        } else {
+            mSizeSpecSourceImpl = new SizeSpecDefaultImpl();
+        }
+
+        reloadResources();
+    }
+
+    /** Reloads the resources */
+    public void onConfigurationChanged() {
+        reloadResources();
+    }
+
+    private void reloadResources() {
+        final Resources res = mContext.getResources();
+
+        mDefaultMinSize = res.getDimensionPixelSize(
+                R.dimen.default_minimal_size_pip_resizable_task);
+
+        final String screenEdgeInsetsDpString = res.getString(
+                R.string.config_defaultPictureInPictureScreenEdgeInsets);
+        final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
+                ? Size.parseSize(screenEdgeInsetsDpString)
+                : null;
+        mScreenEdgeInsets = screenEdgeInsetsDp == null ? new Point()
+                : new Point(dpToPx(screenEdgeInsetsDp.getWidth(), res.getDisplayMetrics()),
+                        dpToPx(screenEdgeInsetsDp.getHeight(), res.getDisplayMetrics()));
+
+        // update the internal resources of the size spec source's stub
+        mSizeSpecSourceImpl.reloadResources();
+    }
+
+    /** Returns the display's bounds. */
+    @NonNull
+    public Rect getDisplayBounds() {
+        return new Rect(0, 0, mDisplayLayout.width(), mDisplayLayout.height());
+    }
+
+    /** Get the display layout. */
+    @NonNull
+    public DisplayLayout getDisplayLayout() {
+        return mDisplayLayout;
+    }
+
+    /** Update the display layout. */
+    public void setDisplayLayout(@NonNull DisplayLayout displayLayout) {
+        mDisplayLayout.set(displayLayout);
+    }
+
+    public Point getScreenEdgeInsets() {
+        return mScreenEdgeInsets;
+    }
+
+    /**
+     * Returns the inset bounds the PIP window can be visible in.
+     */
+    public Rect getInsetBounds() {
+        Rect insetBounds = new Rect();
+        final DisplayLayout displayLayout = getDisplayLayout();
+        Rect insets = getDisplayLayout().stableInsets();
+        insetBounds.set(insets.left + mScreenEdgeInsets.x,
+                insets.top + mScreenEdgeInsets.y,
+                displayLayout.width() - insets.right - mScreenEdgeInsets.x,
+                displayLayout.height() - insets.bottom - mScreenEdgeInsets.y);
+        return insetBounds;
+    }
+
+    /** Sets the preferred size of PIP as specified by the activity in PIP mode. */
+    public void setOverrideMinSize(@Nullable Size overrideMinSize) {
+        mOverrideMinSize = overrideMinSize;
+    }
+
+    /** Returns the preferred minimal size specified by the activity in PIP. */
+    @Nullable
+    public Size getOverrideMinSize() {
+        return mOverrideMinSize;
+    }
+
+    /** Returns the minimum edge size of the override minimum size, or 0 if not set. */
+    public int getOverrideMinEdgeSize() {
+        if (mOverrideMinSize == null) return 0;
+        return Math.min(mOverrideMinSize.getWidth(), mOverrideMinSize.getHeight());
+    }
+
+    public int getMinEdgeSize() {
+        return mOverrideMinSize == null ? mDefaultMinSize : getOverrideMinEdgeSize();
+    }
+
+    /**
+     * Returns the size for the max size spec.
+     */
+    public Size getMaxSize(float aspectRatio) {
+        return mSizeSpecSourceImpl.getMaxSize(aspectRatio);
+    }
+
+    /**
+     * Returns the size for the default size spec.
+     */
+    public Size getDefaultSize(float aspectRatio) {
+        return mSizeSpecSourceImpl.getDefaultSize(aspectRatio);
+    }
+
+    /**
+     * Returns the size for the min size spec.
+     */
+    public Size getMinSize(float aspectRatio) {
+        return mSizeSpecSourceImpl.getMinSize(aspectRatio);
+    }
+
+    /**
+     * Returns the adjusted size so that it conforms to the given aspectRatio.
+     *
+     * @param size current size
+     * @param aspectRatio target aspect ratio
+     */
+    public Size getSizeForAspectRatio(@NonNull Size size, float aspectRatio) {
+        if (size.equals(mOverrideMinSize)) {
+            return adjustOverrideMinSizeToAspectRatio(aspectRatio);
+        }
+
+        return mSizeSpecSourceImpl.getSizeForAspectRatio(size, aspectRatio);
+    }
+
+    /**
+     * Returns the adjusted overridden min size if it is set; otherwise, returns null.
+     *
+     * <p>Overridden min size needs to be adjusted in its own way while making sure that the target
+     * aspect ratio is maintained
+     *
+     * @param aspectRatio target aspect ratio
+     */
+    @Nullable
+    @VisibleForTesting
+    Size adjustOverrideMinSizeToAspectRatio(float aspectRatio) {
+        if (mOverrideMinSize == null) {
+            return null;
+        }
+        final Size size = mOverrideMinSize;
+        final float sizeAspectRatio = size.getWidth() / (float) size.getHeight();
+        if (sizeAspectRatio > aspectRatio) {
+            // Size is wider, fix the width and increase the height
+            return new Size(size.getWidth(), (int) (size.getWidth() / aspectRatio));
+        } else {
+            // Size is taller, fix the height and adjust the width.
+            return new Size((int) (size.getHeight() * aspectRatio), size.getHeight());
+        }
+    }
+
+    /** Dumps internal state. */
+    public void dump(PrintWriter pw, String prefix) {
+        final String innerPrefix = prefix + "  ";
+        pw.println(prefix + TAG);
+        pw.println(innerPrefix + "mSizeSpecSourceImpl=" + mSizeSpecSourceImpl.toString());
+        pw.println(innerPrefix + "mDisplayLayout=" + mDisplayLayout);
+        pw.println(innerPrefix + "mOverrideMinSize=" + mOverrideMinSize);
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 850c561..0e8d13d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -78,7 +78,8 @@
     private boolean mEnableResize;
     private final Context mContext;
     private final PipBoundsAlgorithm mPipBoundsAlgorithm;
-    private final @NonNull PipBoundsState mPipBoundsState;
+    @NonNull private final PipBoundsState mPipBoundsState;
+    @NonNull private final PipSizeSpecHandler mPipSizeSpecHandler;
     private final PipUiEventLogger mPipUiEventLogger;
     private final PipDismissTargetHandler mPipDismissTargetHandler;
     private final PipTaskOrganizer mPipTaskOrganizer;
@@ -99,7 +100,6 @@
 
     // The reference inset bounds, used to determine the dismiss fraction
     private final Rect mInsetBounds = new Rect();
-    private int mExpandedShortestEdgeSize;
 
     // Used to workaround an issue where the WM rotation happens before we are notified, allowing
     // us to send stale bounds
@@ -120,7 +120,6 @@
     private float mSavedSnapFraction = -1f;
     private boolean mSendingHoverAccessibilityEvents;
     private boolean mMovementWithinDismiss;
-    private float mMinimumSizePercent;
 
     // Touch state
     private final PipTouchState mTouchState;
@@ -174,6 +173,7 @@
             PhonePipMenuController menuController,
             PipBoundsAlgorithm pipBoundsAlgorithm,
             @NonNull PipBoundsState pipBoundsState,
+            @NonNull PipSizeSpecHandler pipSizeSpecHandler,
             PipTaskOrganizer pipTaskOrganizer,
             PipMotionHelper pipMotionHelper,
             FloatingContentCoordinator floatingContentCoordinator,
@@ -184,6 +184,7 @@
         mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
         mPipBoundsAlgorithm = pipBoundsAlgorithm;
         mPipBoundsState = pipBoundsState;
+        mPipSizeSpecHandler = pipSizeSpecHandler;
         mPipTaskOrganizer = pipTaskOrganizer;
         mMenuController = menuController;
         mPipUiEventLogger = pipUiEventLogger;
@@ -271,10 +272,7 @@
     private void reloadResources() {
         final Resources res = mContext.getResources();
         mBottomOffsetBufferPx = res.getDimensionPixelSize(R.dimen.pip_bottom_offset_buffer);
-        mExpandedShortestEdgeSize = res.getDimensionPixelSize(
-                R.dimen.pip_expanded_shortest_edge_size);
         mImeOffset = res.getDimensionPixelSize(R.dimen.pip_ime_offset);
-        mMinimumSizePercent = res.getFraction(R.fraction.config_pipShortestEdgePercent, 1, 1);
         mPipDismissTargetHandler.updateMagneticTargetSize();
     }
 
@@ -407,10 +405,7 @@
 
         // Calculate the expanded size
         float aspectRatio = (float) normalBounds.width() / normalBounds.height();
-        Point displaySize = new Point();
-        mContext.getDisplay().getRealSize(displaySize);
-        Size expandedSize = mPipBoundsAlgorithm.getSizeForAspectRatio(
-                aspectRatio, mExpandedShortestEdgeSize, displaySize.x, displaySize.y);
+        Size expandedSize = mPipSizeSpecHandler.getDefaultSize(aspectRatio);
         mPipBoundsState.setExpandedBounds(
                 new Rect(0, 0, expandedSize.getWidth(), expandedSize.getHeight()));
         Rect expandedMovementBounds = new Rect();
@@ -418,7 +413,7 @@
                 mPipBoundsState.getExpandedBounds(), insetBounds, expandedMovementBounds,
                 bottomOffset);
 
-        updatePipSizeConstraints(insetBounds, normalBounds, aspectRatio);
+        updatePipSizeConstraints(normalBounds, aspectRatio);
 
         // The extra offset does not really affect the movement bounds, but are applied based on the
         // current state (ime showing, or shelf offset) when we need to actually shift
@@ -496,14 +491,14 @@
      * @param aspectRatio aspect ratio to use for the calculation of min/max size
      */
     public void updateMinMaxSize(float aspectRatio) {
-        updatePipSizeConstraints(mInsetBounds, mPipBoundsState.getNormalBounds(),
+        updatePipSizeConstraints(mPipBoundsState.getNormalBounds(),
                 aspectRatio);
     }
 
-    private void updatePipSizeConstraints(Rect insetBounds, Rect normalBounds,
+    private void updatePipSizeConstraints(Rect normalBounds,
             float aspectRatio) {
         if (mPipResizeGestureHandler.isUsingPinchToZoom()) {
-            updatePinchResizeSizeConstraints(insetBounds, normalBounds, aspectRatio);
+            updatePinchResizeSizeConstraints(aspectRatio);
         } else {
             mPipResizeGestureHandler.updateMinSize(normalBounds.width(), normalBounds.height());
             mPipResizeGestureHandler.updateMaxSize(mPipBoundsState.getExpandedBounds().width(),
@@ -511,26 +506,13 @@
         }
     }
 
-    private void updatePinchResizeSizeConstraints(Rect insetBounds, Rect normalBounds,
-            float aspectRatio) {
-        final int shorterLength = Math.min(mPipBoundsState.getDisplayBounds().width(),
-                mPipBoundsState.getDisplayBounds().height());
-        final int totalHorizontalPadding = insetBounds.left
-                + (mPipBoundsState.getDisplayBounds().width() - insetBounds.right);
-        final int totalVerticalPadding = insetBounds.top
-                + (mPipBoundsState.getDisplayBounds().height() - insetBounds.bottom);
+    private void updatePinchResizeSizeConstraints(float aspectRatio) {
         final int minWidth, minHeight, maxWidth, maxHeight;
-        if (aspectRatio > 1f) {
-            minWidth = (int) Math.min(normalBounds.width(), shorterLength * mMinimumSizePercent);
-            minHeight = (int) (minWidth / aspectRatio);
-            maxWidth = (int) Math.max(normalBounds.width(), shorterLength - totalHorizontalPadding);
-            maxHeight = (int) (maxWidth / aspectRatio);
-        } else {
-            minHeight = (int) Math.min(normalBounds.height(), shorterLength * mMinimumSizePercent);
-            minWidth = (int) (minHeight * aspectRatio);
-            maxHeight = (int) Math.max(normalBounds.height(), shorterLength - totalVerticalPadding);
-            maxWidth = (int) (maxHeight * aspectRatio);
-        }
+
+        minWidth = mPipSizeSpecHandler.getMinSize(aspectRatio).getWidth();
+        minHeight = mPipSizeSpecHandler.getMinSize(aspectRatio).getHeight();
+        maxWidth = mPipSizeSpecHandler.getMaxSize(aspectRatio).getWidth();
+        maxHeight = mPipSizeSpecHandler.getMaxSize(aspectRatio).getHeight();
 
         mPipResizeGestureHandler.updateMinSize(minWidth, minHeight);
         mPipResizeGestureHandler.updateMaxSize(maxWidth, maxHeight);
@@ -1064,11 +1046,6 @@
         mPipBoundsAlgorithm.getMovementBounds(mPipBoundsState.getBounds(),
                 mInsetBounds, mPipBoundsState.getMovementBounds(), mIsImeShowing ? mImeHeight : 0);
         mMotionHelper.onMovementBoundsChanged();
-
-        boolean isMenuExpanded = mMenuState == MENU_STATE_FULL;
-        mPipBoundsState.setMinEdgeSize(
-                isMenuExpanded && willResizeMenu() ? mExpandedShortestEdgeSize
-                        : mPipBoundsAlgorithm.getDefaultMinSize());
     }
 
     private Rect getMovementBounds(Rect curBounds) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
index b042063..825b969 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
@@ -39,6 +39,7 @@
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipKeepClearAlgorithmInterface;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
+import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
 import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 
@@ -60,10 +61,10 @@
 
     public TvPipBoundsAlgorithm(Context context,
             @NonNull TvPipBoundsState tvPipBoundsState,
-            @NonNull PipSnapAlgorithm pipSnapAlgorithm) {
+            @NonNull PipSnapAlgorithm pipSnapAlgorithm,
+            @NonNull PipSizeSpecHandler pipSizeSpecHandler) {
         super(context, tvPipBoundsState, pipSnapAlgorithm,
-                new PipKeepClearAlgorithmInterface() {
-                });
+                new PipKeepClearAlgorithmInterface() {}, pipSizeSpecHandler);
         this.mTvPipBoundsState = tvPipBoundsState;
         this.mKeepClearAlgorithm = new TvPipKeepClearAlgorithm();
         reloadResources(context);
@@ -289,7 +290,8 @@
             if (mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_HORIZONTAL) {
                 expandedSize = mTvPipBoundsState.getTvExpandedSize();
             } else {
-                int maxHeight = displayLayout.height() - (2 * mScreenEdgeInsets.y)
+                int maxHeight = displayLayout.height()
+                        - (2 * mPipSizeSpecHandler.getScreenEdgeInsets().y)
                         - pipDecorations.top - pipDecorations.bottom;
                 float aspectRatioHeight = mFixedExpandedWidthInPx / expandedRatio;
 
@@ -308,7 +310,8 @@
             if (mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_VERTICAL) {
                 expandedSize = mTvPipBoundsState.getTvExpandedSize();
             } else {
-                int maxWidth = displayLayout.width() - (2 * mScreenEdgeInsets.x)
+                int maxWidth = displayLayout.width()
+                        - (2 * mPipSizeSpecHandler.getScreenEdgeInsets().x)
                         - pipDecorations.left - pipDecorations.right;
                 float aspectRatioWidth = mFixedExpandedHeightInPx * expandedRatio;
                 if (maxWidth > aspectRatioWidth) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
index 9c7c0ae..22b3f49 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
@@ -31,6 +31,7 @@
 
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
+import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -73,8 +74,9 @@
     @NonNull
     private Insets mPipMenuTemporaryDecorInsets = Insets.NONE;
 
-    public TvPipBoundsState(@NonNull Context context) {
-        super(context);
+    public TvPipBoundsState(@NonNull Context context,
+            @NonNull PipSizeSpecHandler pipSizeSpecHandler) {
+        super(context, pipSizeSpecHandler);
         mContext = context;
         updateDefaultGravity();
         mPreviousCollapsedGravity = mDefaultGravity;
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 4426423..02b9197 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
@@ -55,6 +55,7 @@
 import com.android.wm.shell.pip.PipParamsChangedForwarder;
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.sysui.ConfigurationChangeListener;
 import com.android.wm.shell.sysui.ShellController;
@@ -118,6 +119,7 @@
 
     private final ShellController mShellController;
     private final TvPipBoundsState mTvPipBoundsState;
+    private final PipSizeSpecHandler mPipSizeSpecHandler;
     private final TvPipBoundsAlgorithm mTvPipBoundsAlgorithm;
     private final TvPipBoundsController mTvPipBoundsController;
     private final PipAppOpsListener mAppOpsListener;
@@ -152,6 +154,7 @@
             ShellInit shellInit,
             ShellController shellController,
             TvPipBoundsState tvPipBoundsState,
+            PipSizeSpecHandler pipSizeSpecHandler,
             TvPipBoundsAlgorithm tvPipBoundsAlgorithm,
             TvPipBoundsController tvPipBoundsController,
             PipAppOpsListener pipAppOpsListener,
@@ -171,6 +174,7 @@
                 shellInit,
                 shellController,
                 tvPipBoundsState,
+                pipSizeSpecHandler,
                 tvPipBoundsAlgorithm,
                 tvPipBoundsController,
                 pipAppOpsListener,
@@ -192,6 +196,7 @@
             ShellInit shellInit,
             ShellController shellController,
             TvPipBoundsState tvPipBoundsState,
+            PipSizeSpecHandler pipSizeSpecHandler,
             TvPipBoundsAlgorithm tvPipBoundsAlgorithm,
             TvPipBoundsController tvPipBoundsController,
             PipAppOpsListener pipAppOpsListener,
@@ -212,10 +217,13 @@
         mShellController = shellController;
         mDisplayController = displayController;
 
-        mTvPipBoundsState = tvPipBoundsState;
-        mTvPipBoundsState.setDisplayId(context.getDisplayId());
-        mTvPipBoundsState.setDisplayLayout(new DisplayLayout(context, context.getDisplay()));
+        DisplayLayout layout = new DisplayLayout(context, context.getDisplay());
 
+        mTvPipBoundsState = tvPipBoundsState;
+        mTvPipBoundsState.setDisplayLayout(layout);
+        mTvPipBoundsState.setDisplayId(context.getDisplayId());
+        mPipSizeSpecHandler = pipSizeSpecHandler;
+        mPipSizeSpecHandler.setDisplayLayout(layout);
         mTvPipBoundsAlgorithm = tvPipBoundsAlgorithm;
         mTvPipBoundsController = tvPipBoundsController;
         mTvPipBoundsController.setListener(this);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
index 298d0a6..3d8cd2e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
@@ -32,6 +32,7 @@
 import com.android.wm.shell.R;
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -57,17 +58,22 @@
     private PipBoundsAlgorithm mPipBoundsAlgorithm;
     private DisplayInfo mDefaultDisplayInfo;
     private PipBoundsState mPipBoundsState;
+    private PipSizeSpecHandler mPipSizeSpecHandler;
 
 
     @Before
     public void setUp() throws Exception {
         initializeMockResources();
-        mPipBoundsState = new PipBoundsState(mContext);
+        mPipSizeSpecHandler = new PipSizeSpecHandler(mContext);
+        mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler);
         mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState,
-                new PipSnapAlgorithm(), new PipKeepClearAlgorithmInterface() {});
+                new PipSnapAlgorithm(), new PipKeepClearAlgorithmInterface() {},
+                mPipSizeSpecHandler);
 
-        mPipBoundsState.setDisplayLayout(
-                new DisplayLayout(mDefaultDisplayInfo, mContext.getResources(), true, true));
+        DisplayLayout layout =
+                new DisplayLayout(mDefaultDisplayInfo, mContext.getResources(), true, true);
+        mPipBoundsState.setDisplayLayout(layout);
+        mPipSizeSpecHandler.setDisplayLayout(layout);
     }
 
     private void initializeMockResources() {
@@ -120,9 +126,7 @@
 
     @Test
     public void getDefaultBounds_noOverrideMinSize_matchesDefaultSizeAndAspectRatio() {
-        final Size defaultSize = mPipBoundsAlgorithm.getSizeForAspectRatio(DEFAULT_ASPECT_RATIO,
-                DEFAULT_MIN_EDGE_SIZE, mDefaultDisplayInfo.logicalWidth,
-                mDefaultDisplayInfo.logicalHeight);
+        final Size defaultSize = mPipSizeSpecHandler.getDefaultSize(DEFAULT_ASPECT_RATIO);
 
         mPipBoundsState.setOverrideMinSize(null);
         final Rect defaultBounds = mPipBoundsAlgorithm.getDefaultBounds();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
index 8e30f65..ede5bde 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
@@ -33,6 +33,7 @@
 
 import com.android.internal.util.function.TriConsumer;
 import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -57,7 +58,7 @@
 
     @Before
     public void setUp() {
-        mPipBoundsState = new PipBoundsState(mContext);
+        mPipBoundsState = new PipBoundsState(mContext, new PipSizeSpecHandler(mContext));
         mTestComponentName1 = new ComponentName(mContext, "component1");
         mTestComponentName2 = new ComponentName(mContext, "component2");
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 17e7d74..2da4af8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -53,6 +53,7 @@
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.pip.phone.PhonePipMenuController;
+import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 
 import org.junit.Before;
@@ -86,6 +87,7 @@
     private PipBoundsState mPipBoundsState;
     private PipTransitionState mPipTransitionState;
     private PipBoundsAlgorithm mPipBoundsAlgorithm;
+    private PipSizeSpecHandler mPipSizeSpecHandler;
 
     private ComponentName mComponent1;
     private ComponentName mComponent2;
@@ -95,10 +97,12 @@
         MockitoAnnotations.initMocks(this);
         mComponent1 = new ComponentName(mContext, "component1");
         mComponent2 = new ComponentName(mContext, "component2");
-        mPipBoundsState = new PipBoundsState(mContext);
+        mPipSizeSpecHandler = new PipSizeSpecHandler(mContext);
+        mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler);
         mPipTransitionState = new PipTransitionState();
         mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState,
-                new PipSnapAlgorithm(), new PipKeepClearAlgorithmInterface() {});
+                new PipSnapAlgorithm(), new PipKeepClearAlgorithmInterface() {},
+                mPipSizeSpecHandler);
         mMainExecutor = new TestShellExecutor();
         mPipTaskOrganizer = new PipTaskOrganizer(mContext,
                 mMockSyncTransactionQueue, mPipTransitionState, mPipBoundsState,
@@ -253,8 +257,10 @@
 
     private void preparePipTaskOrg() {
         final DisplayInfo info = new DisplayInfo();
-        mPipBoundsState.setDisplayLayout(new DisplayLayout(info,
-                mContext.getResources(), true, true));
+        DisplayLayout layout = new DisplayLayout(info,
+                mContext.getResources(), true, true);
+        mPipBoundsState.setDisplayLayout(layout);
+        mPipSizeSpecHandler.setDisplayLayout(layout);
         mPipTaskOrganizer.setOneShotAnimationType(PipAnimationController.ANIM_TYPE_ALPHA);
         mPipTaskOrganizer.setSurfaceControlTransactionFactory(
                 MockSurfaceControlHelper::createMockSurfaceControlTransaction);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 35c09a1..4a68287 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -65,7 +65,6 @@
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.pip.PipTransitionState;
-import com.android.wm.shell.recents.IRecentTasksListener;
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
@@ -108,6 +107,7 @@
     @Mock private PipMotionHelper mMockPipMotionHelper;
     @Mock private WindowManagerShellWrapper mMockWindowManagerShellWrapper;
     @Mock private PipBoundsState mMockPipBoundsState;
+    @Mock private PipSizeSpecHandler mMockPipSizeSpecHandler;
     @Mock private TaskStackListenerImpl mMockTaskStackListener;
     @Mock private ShellExecutor mMockExecutor;
     @Mock private Optional<OneHandedController> mMockOneHandedController;
@@ -130,11 +130,12 @@
         mPipController = new PipController(mContext, mShellInit, mMockShellCommandHandler,
                 mShellController, mMockDisplayController, mMockPipAnimationController,
                 mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
-                mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
-                mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState,
-                mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
-                mMockTaskStackListener, mMockPipParamsChangedForwarder,
-                mMockDisplayInsetsController, mMockOneHandedController, mMockExecutor);
+                mMockPipBoundsState, mMockPipSizeSpecHandler, mMockPipMotionHelper,
+                mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer,
+                mMockPipTransitionState, mMockPipTouchHandler, mMockPipTransitionController,
+                mMockWindowManagerShellWrapper, mMockTaskStackListener,
+                mMockPipParamsChangedForwarder, mMockDisplayInsetsController,
+                mMockOneHandedController, mMockExecutor);
         mShellInit.init();
         when(mMockPipBoundsAlgorithm.getSnapAlgorithm()).thenReturn(mMockPipSnapAlgorithm);
         when(mMockPipTouchHandler.getMotionHelper()).thenReturn(mMockPipMotionHelper);
@@ -220,11 +221,12 @@
         assertNull(PipController.create(spyContext, shellInit, mMockShellCommandHandler,
                 mShellController, mMockDisplayController, mMockPipAnimationController,
                 mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
-                mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
-                mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState,
-                mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
-                mMockTaskStackListener, mMockPipParamsChangedForwarder,
-                mMockDisplayInsetsController, mMockOneHandedController, mMockExecutor));
+                mMockPipBoundsState, mMockPipSizeSpecHandler, mMockPipMotionHelper,
+                mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer,
+                mMockPipTransitionState, mMockPipTouchHandler, mMockPipTransitionController,
+                mMockWindowManagerShellWrapper, mMockTaskStackListener,
+                mMockPipParamsChangedForwarder, mMockDisplayInsetsController,
+                mMockOneHandedController, mMockExecutor));
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
index c1993b2..c7b9eb3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
@@ -85,15 +85,18 @@
 
     private PipBoundsState mPipBoundsState;
 
+    private PipSizeSpecHandler mPipSizeSpecHandler;
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mPipBoundsState = new PipBoundsState(mContext);
+        mPipSizeSpecHandler = new PipSizeSpecHandler(mContext);
+        mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler);
         final PipSnapAlgorithm pipSnapAlgorithm = new PipSnapAlgorithm();
         final PipKeepClearAlgorithmInterface pipKeepClearAlgorithm =
                 new PipKeepClearAlgorithmInterface() {};
         final PipBoundsAlgorithm pipBoundsAlgorithm = new PipBoundsAlgorithm(mContext,
-                mPipBoundsState, pipSnapAlgorithm, pipKeepClearAlgorithm);
+                mPipBoundsState, pipSnapAlgorithm, pipKeepClearAlgorithm, mPipSizeSpecHandler);
         final PipMotionHelper motionHelper = new PipMotionHelper(mContext, mPipBoundsState,
                 mPipTaskOrganizer, mPhonePipMenuController, pipSnapAlgorithm,
                 mMockPipTransitionController, mFloatingContentCoordinator);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java
new file mode 100644
index 0000000..d9ff7d1
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java
@@ -0,0 +1,214 @@
+/*
+ * 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.wm.shell.pip.phone;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.SystemProperties;
+import android.testing.AndroidTestingRunner;
+import android.util.Size;
+import android.view.DisplayInfo;
+
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.DisplayLayout;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.exceptions.misusing.InvalidUseOfMatchersException;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ * Unit test against {@link PipSizeSpecHandler} with feature flag on.
+ */
+@RunWith(AndroidTestingRunner.class)
+public class PipSizeSpecHandlerTest extends ShellTestCase {
+    /** A sample overridden min edge size. */
+    private static final int OVERRIDE_MIN_EDGE_SIZE = 40;
+    /** A sample default min edge size */
+    private static final int DEFAULT_MIN_EDGE_SIZE = 40;
+    /** Display edge size */
+    private static final int DISPLAY_EDGE_SIZE = 1000;
+    /** Default sizing percentage */
+    private static final float DEFAULT_PERCENT = 0.6f;
+    /** Minimum sizing percentage */
+    private static final float MIN_PERCENT = 0.5f;
+    /** Aspect ratio that the new PIP size spec logic optimizes for. */
+    private static final float OPTIMIZED_ASPECT_RATIO = 9f / 16;
+
+    /** A map of aspect ratios to be tested to expected sizes */
+    private static Map<Float, Size> sExpectedMaxSizes;
+    private static Map<Float, Size> sExpectedDefaultSizes;
+    private static Map<Float, Size> sExpectedMinSizes;
+    /** A static mockito session object to mock {@link SystemProperties} */
+    private static StaticMockitoSession sStaticMockitoSession;
+
+    @Mock private Context mContext;
+    @Mock private Resources mResources;
+
+    private PipSizeSpecHandler mPipSizeSpecHandler;
+
+    /**
+     * Sets up static Mockito session for SystemProperties and mocks necessary static methods.
+     */
+    private static void setUpStaticSystemPropertiesSession() {
+        sStaticMockitoSession = mockitoSession()
+                .mockStatic(SystemProperties.class).startMocking();
+        // make sure the feature flag is on
+        when(SystemProperties.getBoolean(anyString(), anyBoolean())).thenReturn(true);
+        when(SystemProperties.get(anyString(), anyString())).thenAnswer(invocation -> {
+            String property = invocation.getArgument(0);
+            if (property.equals("com.android.wm.shell.pip.phone.def_percentage")) {
+                return Float.toString(DEFAULT_PERCENT);
+            } else if (property.equals("com.android.wm.shell.pip.phone.min_percentage")) {
+                return Float.toString(MIN_PERCENT);
+            }
+
+            // throw an exception if illegal arguments are used for these tests
+            throw new InvalidUseOfMatchersException(
+                String.format("Argument %s does not match", property)
+            );
+        });
+    }
+
+    /**
+     * Initializes the map with the aspect ratios to be tested and corresponding expected max sizes.
+     */
+    private static void initExpectedSizes() {
+        sExpectedMaxSizes = new HashMap<>();
+        sExpectedDefaultSizes = new HashMap<>();
+        sExpectedMinSizes = new HashMap<>();
+
+        sExpectedMaxSizes.put(16f / 9, new Size(1000, 562));
+        sExpectedDefaultSizes.put(16f / 9, new Size(600, 337));
+        sExpectedMinSizes.put(16f / 9, new Size(499, 281));
+
+        sExpectedMaxSizes.put(4f / 3, new Size(892, 669));
+        sExpectedDefaultSizes.put(4f / 3, new Size(535, 401));
+        sExpectedMinSizes.put(4f / 3, new Size(445, 334));
+
+        sExpectedMaxSizes.put(3f / 4, new Size(669, 892));
+        sExpectedDefaultSizes.put(3f / 4, new Size(401, 535));
+        sExpectedMinSizes.put(3f / 4, new Size(334, 445));
+
+        sExpectedMaxSizes.put(9f / 16, new Size(562, 999));
+        sExpectedDefaultSizes.put(9f / 16, new Size(337, 599));
+        sExpectedMinSizes.put(9f / 16, new Size(281, 499));
+    }
+
+    private void forEveryTestCaseCheck(Map<Float, Size> expectedSizes,
+            Function<Float, Size> callback) {
+        for (Map.Entry<Float, Size> expectedSizesEntry : expectedSizes.entrySet()) {
+            float aspectRatio = expectedSizesEntry.getKey();
+            Size expectedSize = expectedSizesEntry.getValue();
+
+            Assert.assertEquals(expectedSize, callback.apply(aspectRatio));
+        }
+    }
+
+    @Before
+    public void setUp() {
+        initExpectedSizes();
+        setUpStaticSystemPropertiesSession();
+
+        when(mResources.getDimensionPixelSize(anyInt())).thenReturn(DEFAULT_MIN_EDGE_SIZE);
+        when(mResources.getFloat(anyInt())).thenReturn(OPTIMIZED_ASPECT_RATIO);
+        when(mResources.getString(anyInt())).thenReturn("0x0");
+        when(mResources.getDisplayMetrics())
+                .thenReturn(getContext().getResources().getDisplayMetrics());
+
+        // set up the mock context for spec handler specifically
+        when(mContext.getResources()).thenReturn(mResources);
+
+        mPipSizeSpecHandler = new PipSizeSpecHandler(mContext);
+
+        // no overridden min edge size by default
+        mPipSizeSpecHandler.setOverrideMinSize(null);
+
+        DisplayInfo displayInfo = new DisplayInfo();
+        displayInfo.logicalWidth = DISPLAY_EDGE_SIZE;
+        displayInfo.logicalHeight = DISPLAY_EDGE_SIZE;
+
+        // use the parent context (not the mocked one) to obtain the display layout
+        // this is done to avoid unnecessary mocking while allowing for custom display dimensions
+        DisplayLayout displayLayout = new DisplayLayout(displayInfo, getContext().getResources(),
+                false, false);
+        mPipSizeSpecHandler.setDisplayLayout(displayLayout);
+    }
+
+    @After
+    public void cleanUp() {
+        sStaticMockitoSession.finishMocking();
+    }
+
+    @Test
+    public void testGetMaxSize() {
+        forEveryTestCaseCheck(sExpectedMaxSizes,
+                (aspectRatio) -> mPipSizeSpecHandler.getMaxSize(aspectRatio));
+    }
+
+    @Test
+    public void testGetDefaultSize() {
+        forEveryTestCaseCheck(sExpectedDefaultSizes,
+                (aspectRatio) -> mPipSizeSpecHandler.getDefaultSize(aspectRatio));
+    }
+
+    @Test
+    public void testGetMinSize() {
+        forEveryTestCaseCheck(sExpectedMinSizes,
+                (aspectRatio) -> mPipSizeSpecHandler.getMinSize(aspectRatio));
+    }
+
+    @Test
+    public void testGetSizeForAspectRatio_noOverrideMinSize() {
+        // an initial size with 16:9 aspect ratio
+        Size initSize = new Size(600, 337);
+
+        Size expectedSize = new Size(337, 599);
+        Size actualSize = mPipSizeSpecHandler.getSizeForAspectRatio(initSize, 9f / 16);
+
+        Assert.assertEquals(expectedSize, actualSize);
+    }
+
+    @Test
+    public void testGetSizeForAspectRatio_withOverrideMinSize() {
+        // an initial size with a 1:1 aspect ratio
+        mPipSizeSpecHandler.setOverrideMinSize(new Size(OVERRIDE_MIN_EDGE_SIZE,
+                OVERRIDE_MIN_EDGE_SIZE));
+        // make sure initial size is same as override min size
+        Size initSize = mPipSizeSpecHandler.getOverrideMinSize();
+
+        Size expectedSize = new Size(40, 71);
+        Size actualSize = mPipSizeSpecHandler.getSizeForAspectRatio(initSize, 9f / 16);
+
+        Assert.assertEquals(expectedSize, actualSize);
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
index 8ad2932..5c4863f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
@@ -25,6 +25,7 @@
 import android.graphics.Rect;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.util.Size;
 
 import androidx.test.filters.SmallTest;
 
@@ -90,6 +91,7 @@
     private PipSnapAlgorithm mPipSnapAlgorithm;
     private PipMotionHelper mMotionHelper;
     private PipResizeGestureHandler mPipResizeGestureHandler;
+    private PipSizeSpecHandler mPipSizeSpecHandler;
 
     private DisplayLayout mDisplayLayout;
     private Rect mInsetBounds;
@@ -103,16 +105,17 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mPipBoundsState = new PipBoundsState(mContext);
+        mPipSizeSpecHandler = new PipSizeSpecHandler(mContext);
+        mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler);
         mPipSnapAlgorithm = new PipSnapAlgorithm();
         mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState, mPipSnapAlgorithm,
-                new PipKeepClearAlgorithmInterface() {});
+                new PipKeepClearAlgorithmInterface() {}, mPipSizeSpecHandler);
         PipMotionHelper pipMotionHelper = new PipMotionHelper(mContext, mPipBoundsState,
                 mPipTaskOrganizer, mPhonePipMenuController, mPipSnapAlgorithm,
                 mMockPipTransitionController, mFloatingContentCoordinator);
         mPipTouchHandler = new PipTouchHandler(mContext, mShellInit, mPhonePipMenuController,
-                mPipBoundsAlgorithm, mPipBoundsState, mPipTaskOrganizer, pipMotionHelper,
-                mFloatingContentCoordinator, mPipUiEventLogger, mMainExecutor);
+                mPipBoundsAlgorithm, mPipBoundsState, mPipSizeSpecHandler, mPipTaskOrganizer,
+                pipMotionHelper, mFloatingContentCoordinator, mPipUiEventLogger, mMainExecutor);
         // We aren't actually using ShellInit, so just call init directly
         mPipTouchHandler.onInit();
         mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
@@ -122,6 +125,7 @@
 
         mDisplayLayout = new DisplayLayout(mContext, mContext.getDisplay());
         mPipBoundsState.setDisplayLayout(mDisplayLayout);
+        mPipSizeSpecHandler.setDisplayLayout(mDisplayLayout);
         mInsetBounds = new Rect(mPipBoundsState.getDisplayBounds().left + INSET,
                 mPipBoundsState.getDisplayBounds().top + INSET,
                 mPipBoundsState.getDisplayBounds().right - INSET,
@@ -154,13 +158,17 @@
         mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mPipBounds, mCurBounds,
                 mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation);
 
+        // getting the expected min and max size
+        float aspectRatio = (float) mPipBounds.width() / mPipBounds.height();
+        Size expectedMinSize = mPipSizeSpecHandler.getMinSize(aspectRatio);
+        Size expectedMaxSize = mPipSizeSpecHandler.getMaxSize(aspectRatio);
+
         assertEquals(expectedMovementBounds, mPipBoundsState.getNormalMovementBounds());
         verify(mPipResizeGestureHandler, times(1))
-                .updateMinSize(mPipBounds.width(), mPipBounds.height());
+                .updateMinSize(expectedMinSize.getWidth(), expectedMinSize.getHeight());
 
         verify(mPipResizeGestureHandler, times(1))
-                .updateMaxSize(shorterLength - 2 * mInsetBounds.left,
-                        shorterLength - 2 * mInsetBounds.left);
+                .updateMaxSize(expectedMaxSize.getWidth(), expectedMaxSize.getHeight());
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipGravityTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipGravityTest.java
index 51f86b8..30096cb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipGravityTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipGravityTest.java
@@ -27,6 +27,7 @@
 
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
+import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -45,6 +46,7 @@
 
     private TvPipBoundsState mTvPipBoundsState;
     private TvPipBoundsAlgorithm mTvPipBoundsAlgorithm;
+    private PipSizeSpecHandler mPipSizeSpecHandler;
 
     @Before
     public void setUp() {
@@ -52,9 +54,10 @@
             return;
         }
         MockitoAnnotations.initMocks(this);
-        mTvPipBoundsState = new TvPipBoundsState(mContext);
+        mPipSizeSpecHandler = new PipSizeSpecHandler(mContext);
+        mTvPipBoundsState = new TvPipBoundsState(mContext, mPipSizeSpecHandler);
         mTvPipBoundsAlgorithm = new TvPipBoundsAlgorithm(mContext, mTvPipBoundsState,
-                mMockPipSnapAlgorithm);
+                mMockPipSnapAlgorithm, mPipSizeSpecHandler);
 
         setRTL(false);
     }
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 8dea684..db4d1dc 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -250,6 +250,8 @@
         // Order is important when new and old surfaces are the same, because old surface has
         // its frame stats disabled automatically.
         native_window_enable_frame_timestamps(mNativeSurface->getNativeWindow(), true);
+        native_window_set_scaling_mode(mNativeSurface->getNativeWindow(),
+                                       NATIVE_WINDOW_SCALING_MODE_FREEZE);
     } else {
         mRenderThread.removeFrameCallback(this);
         mGenerationID++;
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index 3afb419..4485044 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -155,23 +155,12 @@
 
     skcms_TransferFunction fn;
     if (!colorSpace->isNumericalTransferFn(&fn)) {
-        // pq with the default white point
-        auto rec2020PQ = SkColorSpace::MakeRGB(GetPQSkTransferFunction(), SkNamedGamut::kRec2020);
-        if (SkColorSpace::Equals(colorSpace, rec2020PQ.get())) {
+        auto res = skcms_TransferFunction_getType(&fn);
+        if (res == skcms_TFType_PQish) {
             return HAL_DATASPACE_BT2020_PQ;
         }
-        // standard PQ
-        rec2020PQ = SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, SkNamedGamut::kRec2020);
-        if (SkColorSpace::Equals(colorSpace, rec2020PQ.get())) {
-            return HAL_DATASPACE_BT2020_PQ;
-        }
-        // HLG
-        const auto hlgFn = GetHLGScaleTransferFunction();
-        if (hlgFn.has_value()) {
-            auto rec2020HLG = SkColorSpace::MakeRGB(hlgFn.value(), SkNamedGamut::kRec2020);
-            if (SkColorSpace::Equals(colorSpace, rec2020HLG.get())) {
-                return static_cast<android_dataspace>(HAL_DATASPACE_BT2020_HLG);
-            }
+        if (res == skcms_TFType_HLGish) {
+            return static_cast<android_dataspace>(HAL_DATASPACE_BT2020_HLG);
         }
         LOG_ALWAYS_FATAL("Only select non-numerical transfer functions are supported");
     }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index a4d5606..0636451 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -8329,7 +8329,8 @@
         Objects.requireNonNull(device);
         try {
             if (device.getId() == 0) {
-                throw new IllegalArgumentException("In valid device: " + device);
+                Log.w(TAG, "setCommunicationDevice: device not found: " + device);
+                return false;
             }
             return getService().setCommunicationDevice(mICallBack, device.getId());
         } catch (RemoteException e) {
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 50749e7..948fef4 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -28,6 +28,8 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.content.AttributionSource;
+import android.content.AttributionSource.ScopedParcelState;
 import android.content.Context;
 import android.media.audiopolicy.AudioMix;
 import android.media.audiopolicy.AudioMixingRule;
@@ -39,6 +41,7 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Parcel;
 import android.os.PersistableBundle;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -822,15 +825,20 @@
         int[] session = new int[1];
         session[0] = resolvePlaybackSessionId(context, sessionId);
 
+        AttributionSource attributionSource = context == null
+                ? AttributionSource.myAttributionSource() : context.getAttributionSource();
+
         // native initialization
-        int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes,
-                sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
-                mNativeBufferSizeInBytes, mDataLoadMode, session, 0 /*nativeTrackInJavaObj*/,
-                offload, encapsulationMode, tunerConfiguration,
-                getCurrentOpPackageName());
-        if (initResult != SUCCESS) {
-            loge("Error code "+initResult+" when initializing AudioTrack.");
-            return; // with mState == STATE_UNINITIALIZED
+        try (ScopedParcelState attributionSourceState = attributionSource.asScopedParcelState()) {
+            int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes,
+                    sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
+                    mNativeBufferSizeInBytes, mDataLoadMode, session,
+                    attributionSourceState.getParcel(), 0 /*nativeTrackInJavaObj*/, offload,
+                    encapsulationMode, tunerConfiguration, getCurrentOpPackageName());
+            if (initResult != SUCCESS) {
+                loge("Error code " + initResult + " when initializing AudioTrack.");
+                return; // with mState == STATE_UNINITIALIZED
+            }
         }
 
         mSampleRate = sampleRate[0];
@@ -902,23 +910,27 @@
             // *Native* AudioTrack, so the attributes parameters to native_setup() are ignored.
             int[] session = { 0 };
             int[] rates = { 0 };
-            int initResult = native_setup(new WeakReference<AudioTrack>(this),
-                    null /*mAttributes - NA*/,
-                    rates /*sampleRate - NA*/,
-                    0 /*mChannelMask - NA*/,
-                    0 /*mChannelIndexMask - NA*/,
-                    0 /*mAudioFormat - NA*/,
-                    0 /*mNativeBufferSizeInBytes - NA*/,
-                    0 /*mDataLoadMode - NA*/,
-                    session,
-                    nativeTrackInJavaObj,
-                    false /*offload*/,
-                    ENCAPSULATION_MODE_NONE,
-                    null /* tunerConfiguration */,
-                    "" /* opPackagename */);
-            if (initResult != SUCCESS) {
-                loge("Error code "+initResult+" when initializing AudioTrack.");
-                return; // with mState == STATE_UNINITIALIZED
+            try (ScopedParcelState attributionSourceState =
+                         AttributionSource.myAttributionSource().asScopedParcelState()) {
+                int initResult = native_setup(new WeakReference<AudioTrack>(this),
+                        null /*mAttributes - NA*/,
+                        rates /*sampleRate - NA*/,
+                        0 /*mChannelMask - NA*/,
+                        0 /*mChannelIndexMask - NA*/,
+                        0 /*mAudioFormat - NA*/,
+                        0 /*mNativeBufferSizeInBytes - NA*/,
+                        0 /*mDataLoadMode - NA*/,
+                        session,
+                        attributionSourceState.getParcel(),
+                        nativeTrackInJavaObj,
+                        false /*offload*/,
+                        ENCAPSULATION_MODE_NONE,
+                        null /* tunerConfiguration */,
+                        "" /* opPackagename */);
+                if (initResult != SUCCESS) {
+                    loge("Error code " + initResult + " when initializing AudioTrack.");
+                    return; // with mState == STATE_UNINITIALIZED
+                }
             }
 
             mSessionId = session[0];
@@ -4371,9 +4383,9 @@
     private native final int native_setup(Object /*WeakReference<AudioTrack>*/ audiotrack_this,
             Object /*AudioAttributes*/ attributes,
             int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
-            int buffSizeInBytes, int mode, int[] sessionId, long nativeAudioTrack,
-            boolean offload, int encapsulationMode, Object tunerConfiguration,
-            @NonNull String opPackageName);
+            int buffSizeInBytes, int mode, int[] sessionId, @NonNull Parcel attributionSource,
+            long nativeAudioTrack, boolean offload, int encapsulationMode,
+            Object tunerConfiguration, @NonNull String opPackageName);
 
     private native final void native_finalize();
 
diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java
index e6d95eb6..9b238e1 100644
--- a/media/java/android/media/ThumbnailUtils.java
+++ b/media/java/android/media/ThumbnailUtils.java
@@ -236,7 +236,7 @@
      * which enables remote providers to efficiently cache and invalidate
      * thumbnails.
      *
-     * @param file The audio file.
+     * @param file The image file.
      * @param size The desired thumbnail size.
      * @throws IOException If any trouble was encountered while generating or
      *             loading the thumbnail, or if
diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java
index f84eec6..0289aa3 100644
--- a/media/java/android/media/audiopolicy/AudioProductStrategy.java
+++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java
@@ -233,7 +233,7 @@
 
     /**
      * @hide
-     * @return the product strategy ID (which is the generalisation of Car Audio Usage / legacy
+     * @return the product strategy name (which is the generalisation of Car Audio Usage / legacy
      *         routing_strategy linked to {@link AudioAttributes#getUsage()}).
      */
     @SystemApi
diff --git a/media/java/android/media/projection/IMediaProjectionManager.aidl b/media/java/android/media/projection/IMediaProjectionManager.aidl
index 99d1f8d..c259f9a 100644
--- a/media/java/android/media/projection/IMediaProjectionManager.aidl
+++ b/media/java/android/media/projection/IMediaProjectionManager.aidl
@@ -33,7 +33,7 @@
     IMediaProjection createProjection(int uid, String packageName, int type,
             boolean permanentGrant);
 
-    boolean isValidMediaProjection(IMediaProjection projection);
+    boolean isCurrentProjection(IMediaProjection projection);
 
     @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
             + ".permission.MANAGE_MEDIA_PROJECTION)")
diff --git a/media/java/android/media/tv/TvRecordingInfo.java b/media/java/android/media/tv/TvRecordingInfo.java
index 8de42f3..60ceb83 100644
--- a/media/java/android/media/tv/TvRecordingInfo.java
+++ b/media/java/android/media/tv/TvRecordingInfo.java
@@ -17,6 +17,7 @@
 package android.media.tv;
 
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.net.Uri;
@@ -25,9 +26,13 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.List;
+
 /**
-    @hide
+ * This class is used to describe the meta information for a TV recording. It can be retrieved by
+ * the {@link android.media.tv.interactive.TvInteractiveAppService} by using getTvRecordingInfo
+ * or getTvRecordingInfoList. It can then be updated to the TV app using setTvRecordingInfo.
  */
 public final class TvRecordingInfo implements Parcelable {
     /*
@@ -54,105 +59,256 @@
     })
     public @interface TvRecordingListType {}
 
+    public static final int SUNDAY = 1;
+    public static final int MONDAY = 1 << 1;
+    public static final int TUESDAY = 1 << 2;
+    public static final int WEDNESDAY = 1 << 3;
+    public static final int THURSDAY = 1 << 4;
+    public static final int FRIDAY = 1 << 5;
+    public static final int SATURDAY = 1 << 6;
+
+    /**
+     * The days of the week defined in {@link java.time.DayOfWeek} are not used here because they
+     * map to integers that increment by 1. The intended use case in {@link #getRepeatDays()} uses
+     * a bitfield, which requires integers that map to 2^n.
+     *
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, value = {SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY})
+    public @interface DaysOfWeek {}
+
     private String mRecordingId;
-    private int mStartPadding;
-    private int mEndPadding;
+    private long mStartPaddingMillis;
+    private long mEndPaddingMillis;
     private int mRepeatDays;
     private String mName;
     private String mDescription;
-    private int mScheduledStartTime;
-    private int mScheduledDuration;
+    private long mScheduledStartTimeMillis;
+    private long mScheduledDurationMillis;
     private Uri mChannelUri;
-    private Uri mProgramId;
-    private List<String> mParentalRatings;
-    private String mRecordingUri;
-    private int mRecordingStartTime;
-    private int mRecordingDuration;
+    private Uri mProgramUri;
+    private List<TvContentRating> mContentRatings;
+    private Uri mRecordingUri;
+    private long mRecordingStartTimeMillis;
+    private long mRecordingDurationMillis;
 
     public TvRecordingInfo(
-            @NonNull String recordingId, @NonNull int startPadding, @NonNull int endPadding,
-            @NonNull int repeatDays, @NonNull int scheduledStartTime,
-            @NonNull int scheduledDuration, @NonNull Uri channelUri, @Nullable Uri programId,
-            @NonNull List<String> parentalRatings, @NonNull String recordingUri,
-            @NonNull int recordingStartTime, @NonNull int recordingDuration) {
+            @NonNull String recordingId, long startPadding, long endPadding, int repeatDays,
+            @NonNull String name, @NonNull String description, long scheduledStartTime,
+            long scheduledDuration, @NonNull Uri channelUri, @Nullable Uri programUri,
+            @NonNull List<TvContentRating> contentRatings, @Nullable Uri recordingUri,
+            long recordingStartTime, long recordingDuration) {
         mRecordingId = recordingId;
-        mStartPadding = startPadding;
-        mEndPadding = endPadding;
+        mStartPaddingMillis = startPadding;
+        mEndPaddingMillis = endPadding;
         mRepeatDays = repeatDays;
-        mScheduledStartTime = scheduledStartTime;
-        mScheduledDuration = scheduledDuration;
+        mName = name;
+        mDescription = description;
+        mScheduledStartTimeMillis = scheduledStartTime;
+        mScheduledDurationMillis = scheduledDuration;
         mChannelUri = channelUri;
-        mScheduledDuration = scheduledDuration;
-        mChannelUri = channelUri;
-        mProgramId = programId;
-        mParentalRatings = parentalRatings;
+        mProgramUri = programUri;
+        mContentRatings = contentRatings;
         mRecordingUri = recordingUri;
-        mRecordingStartTime = recordingStartTime;
-        mRecordingDuration = recordingDuration;
+        mRecordingStartTimeMillis = recordingStartTime;
+        mRecordingDurationMillis = recordingDuration;
     }
+
+    /**
+     * Returns the ID of this recording. This ID is created and maintained by the TV app.
+     */
     @NonNull
     public String getRecordingId() {
         return mRecordingId;
     }
+
+    /**
+     * Returns the start padding duration of this recording in milliseconds since the epoch.
+     *
+     * <p> A positive value should cause the recording to start earlier than the specified time.
+     * This should cause the actual duration of the recording to increase. A negative value should
+     * cause the recording to start later than the specified time. This should cause the actual
+     * duration of the recording to decrease.
+     */
     @NonNull
-    public int getStartPadding() {
-        return mStartPadding;
+    public long getStartPaddingMillis() {
+        return mStartPaddingMillis;
     }
+
+    /**
+     * Returns the ending padding duration of this recording in milliseconds since the epoch.
+     *
+     * <p> A positive value should cause the recording to end later than the specified time.
+     * This should cause the actual duration of the recording to increase. A negative value should
+     * cause the recording to end earlier than the specified time. This should cause the actual
+     * duration of the recording to decrease.
+     */
     @NonNull
-    public int getEndPadding() {
-        return mEndPadding;
+    public long getEndPaddingMillis() {
+        return mEndPaddingMillis;
     }
+
+    /**
+     * Returns the days of the week for which this recording should be repeated for.
+     *
+     * <p> This information is represented in the form of a bitfield, with each bit
+     * representing the day which the recording should be repeated.
+     *
+     * <p> The bitfield corresponds to each day of the week with the following format:
+     * <ul>
+     * <li>{@link #SUNDAY}    - 0x01 (00000001)</li>
+     * <li>{@link #MONDAY}    - 0x02 (00000010)</li>
+     * <li>{@link #TUESDAY}   - 0x04 (00000100)</li>
+     * <li>{@link #WEDNESDAY} - 0x08 (00001000)</li>
+     * <li>{@link #THURSDAY}  - 0x10 (00010000)</li>
+     * <li>{@link #FRIDAY}    - 0x20 (00100000)</li>
+     * <li>{@link #SATURDAY}  - 0x40 (01000000)</li>
+     * </ul>
+     *
+     * <p> You can specify multiple days to repeat the recording by performing a bitwise 'OR' on the
+     * bitfield. For example, for a recording to repeat on Sunday and Mondays, this function should
+     * return 0x03 (00000011).
+     *
+     * <p> A value of 0x00 indicates that the recording will not be repeated.
+     *
+     * <p> This format comes from the <a href="
+     * https://www.oipf.tv/docs/OIPF-T1-R2_Specification-Volume-5-Declarative-Application-Environment-v2_3-2014-01-24.pdf
+     * ">Open IPTV Forum Release 2 Specification</a>. It is described in Volume 5, section 7.10.1.1.
+     */
     @NonNull
+    @DaysOfWeek
     public int getRepeatDays() {
         return mRepeatDays;
     }
+
+    /**
+     * Returns the name of the scheduled recording.
+     *
+     * <p> This is set with {@link TvRecordingInfo#setName(String)} and sent to tv app with
+     * {@link android.media.tv.interactive.TvInteractiveAppService.Session#setTvRecordingInfo(String, TvRecordingInfo)}
+     */
     @NonNull
     public String getName() {
         return mName;
     }
-    @NonNull
-    public void setName(String name) {
+
+    /**
+     * Sets the name of the scheduled recording.
+     *
+     * <p> Updates to the {@link TvRecordingInfo} can be sent to the TV app with
+     * {@link android.media.tv.interactive.TvInteractiveAppService.Session#setTvRecordingInfo(String, TvRecordingInfo)}
+     */
+    public void setName(@NonNull String name) {
         mName = name;
     }
+
+    /**
+     * Returns the description of the scheduled recording.
+     *
+     * <p> This is set with {@link TvRecordingInfo#setDescription(String)} and sent to tv app with
+     * {@link android.media.tv.interactive.TvInteractiveAppService.Session#setTvRecordingInfo(String, TvRecordingInfo)}
+     */
     @NonNull
     public String getDescription() {
         return mDescription;
     }
-    @NonNull
-    public void setDescription(String description) {
+
+    /**
+     * Sets the description of the scheduled recording.
+     *
+     * <p> Updates to the {@link TvRecordingInfo} can be sent to the TV app with
+     * {@link android.media.tv.interactive.TvInteractiveAppService.Session#setTvRecordingInfo(String, TvRecordingInfo)}
+     */
+    public void setDescription(@NonNull String description) {
         mDescription = description;
     }
+
+    /**
+     * Returns the scheduled start time of the recording in milliseconds since the epoch.
+     */
+    @IntRange(from = 0)
     @NonNull
-    public int getScheduledStartTime() {
-        return mScheduledStartTime;
+    public long getScheduledStartTimeMillis() {
+        return mScheduledStartTimeMillis;
     }
+
+    /**
+     * Returns the scheduled duration of the recording in milliseconds since the epoch.
+     */
+    @IntRange(from = 0)
     @NonNull
-    public int getScheduledDuration() {
-        return mScheduledDuration;
+    public long getScheduledDurationMillis() {
+        return mScheduledDurationMillis;
     }
+
+    /**
+     * Returns the uri of the broadcast channel where the recording will take place.
+     */
     @NonNull
     public Uri getChannelUri() {
         return mChannelUri;
     }
+
+    /**
+     * Returns the uri of the scheduled program or series.
+     *
+     * <p> For recordings scheduled using scheduleRecording, this value may be null. A non-null
+     * programUri implies the started recording should be of that specific program, whereas a null
+     * programUri does not impose such a requirement and the recording can span across
+     * multiple TV programs.
+     */
     @Nullable
-    public Uri getProgramId() {
-        return mProgramId;
+    public Uri getProgramUri() {
+        return mProgramUri;
     }
+
+    /**
+     * Returns a list of content ratings for the program(s) in this recording.
+     *
+     * <p> Returns an empty list if no content rating information is available.
+     */
     @NonNull
-    public List<String> getParentalRatings() {
-        return mParentalRatings;
+    public List<TvContentRating> getContentRatings() {
+        return mContentRatings;
     }
-    @NonNull
-    public String getRecordingUri() {
+
+    /**
+     * The uri of the recording in local storage.
+     *
+     * <p> Could be null in the event that the recording has not been completed.
+     */
+    @Nullable
+    public Uri getRecordingUri() {
         return mRecordingUri;
     }
+
+    /**
+     * The real start time of the recording, including any padding, in milliseconds since the epoch.
+     *
+     * <p> This may not be the same as the value of {@link #getScheduledStartTimeMillis()} due to a
+     * recording starting late, or due to start/end padding.
+     *
+     * <p> Returns -1 for recordings that have not yet started.
+     */
+    @IntRange(from = -1)
     @NonNull
-    public int getRecordingStartTime() {
-        return mRecordingStartTime;
+    public long getRecordingStartTimeMillis() {
+        return mRecordingStartTimeMillis;
     }
+
+    /**
+     * The real duration of the recording, including any padding, in milliseconds since the epoch.
+     *
+     * <p> This may not be the same as the value of {@link #getScheduledDurationMillis()} due to a
+     * recording starting late, or due to start/end padding.
+     *
+     * <p> Returns -1 for recordings that have not yet started.
+     */
+    @IntRange(from = -1)
     @NonNull
-    public int getRecordingDuration() {
-        return mRecordingDuration;
+    public long getRecordingDurationMillis() {
+        return mRecordingDurationMillis;
     }
 
     @Override
@@ -169,36 +325,42 @@
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeString(mRecordingId);
-        dest.writeInt(mStartPadding);
-        dest.writeInt(mEndPadding);
+        dest.writeLong(mStartPaddingMillis);
+        dest.writeLong(mEndPaddingMillis);
         dest.writeInt(mRepeatDays);
         dest.writeString(mName);
         dest.writeString(mDescription);
-        dest.writeInt(mScheduledStartTime);
-        dest.writeInt(mScheduledDuration);
+        dest.writeLong(mScheduledStartTimeMillis);
+        dest.writeLong(mScheduledDurationMillis);
         dest.writeString(mChannelUri == null ? null : mChannelUri.toString());
-        dest.writeString(mProgramId == null ? null : mProgramId.toString());
-        dest.writeStringList(mParentalRatings);
-        dest.writeString(mRecordingUri);
-        dest.writeInt(mRecordingDuration);
-        dest.writeInt(mRecordingStartTime);
+        dest.writeString(mProgramUri == null ? null : mProgramUri.toString());
+        List<String> flattenedContentRatings = new ArrayList<String>();
+        mContentRatings.forEach((rating) -> flattenedContentRatings.add(rating.flattenToString()));
+        dest.writeList(mContentRatings);
+        dest.writeString(mRecordingUri == null ? null : mProgramUri.toString());
+        dest.writeLong(mRecordingDurationMillis);
+        dest.writeLong(mRecordingStartTimeMillis);
     }
 
     private TvRecordingInfo(Parcel in) {
         mRecordingId = in.readString();
-        mStartPadding = in.readInt();
-        mEndPadding = in.readInt();
+        mStartPaddingMillis = in.readLong();
+        mEndPaddingMillis = in.readLong();
         mRepeatDays = in.readInt();
         mName = in.readString();
         mDescription = in.readString();
-        mScheduledStartTime = in.readInt();
-        mScheduledDuration = in.readInt();
+        mScheduledStartTimeMillis = in.readLong();
+        mScheduledDurationMillis = in.readLong();
         mChannelUri = Uri.parse(in.readString());
-        mProgramId = Uri.parse(in.readString());
-        in.readStringList(mParentalRatings);
-        mRecordingUri = in.readString();
-        mRecordingDuration = in.readInt();
-        mRecordingStartTime = in.readInt();
+        mProgramUri = Uri.parse(in.readString());
+        mContentRatings = new ArrayList<TvContentRating>();
+        List<String> flattenedContentRatings = new ArrayList<String>();
+        in.readStringList(flattenedContentRatings);
+        flattenedContentRatings.forEach((rating) ->
+                mContentRatings.add(TvContentRating.unflattenFromString(rating)));
+        mRecordingUri = Uri.parse(in.readString());
+        mRecordingDurationMillis = in.readLong();
+        mRecordingStartTimeMillis = in.readLong();
     }
 
 
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index be2c16c..d1777cc 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -1219,13 +1219,15 @@
         }
 
         /**
-         * Sets the recording info for the specified recording
+         * Sets the recording info for the specified recording.
          *
-         * @hide
+         * @param recordingId The ID of the recording to set the info for. This is provided by the
+         *     TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String)}
+         * @param recordingInfo The {@link TvRecordingInfo} to set to the recording.
          */
         @CallSuper
-        public void setTvRecordingInfo(@NonNull String recordingId,
-                @NonNull TvRecordingInfo recordingInfo) {
+        public void setTvRecordingInfo(
+                @NonNull String recordingId, @NonNull TvRecordingInfo recordingInfo) {
             executeOrPostRunnableOnMainThread(() -> {
                 try {
                     if (DEBUG) {
@@ -1242,8 +1244,8 @@
 
         /**
          * Gets the recording info for the specified recording
-         *
-         * @hide
+         * @param recordingId The ID of the recording to set the info for. This is provided by the
+         *                    TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String)}
          */
         @CallSuper
         public void requestTvRecordingInfo(@NonNull String recordingId) {
@@ -1262,9 +1264,9 @@
         }
 
         /**
-         * Gets the recording info list for the specified recording type
+         * Gets a list of {@link TvRecordingInfo} for the specified recording type.
          *
-         * @hide
+         * @param type The type of recording to retrieve.
          */
         @CallSuper
         public void requestTvRecordingInfoList(@NonNull @TvRecordingInfo.TvRecordingListType
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index af03bb8..4a01440 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -1055,6 +1055,47 @@
                 @NonNull String algorithm, @NonNull String alias, @NonNull byte[] data) {
         }
 
+        /**
+         * This is called when {@link TvInteractiveAppService.Session#setTvRecordingInfo(String,
+         * TvRecordingInfo)} is called.
+         *
+         * @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)}
+         * @param recordingInfo The {@link TvRecordingInfo} to set to the recording.
+         */
+        public void onSetTvRecordingInfo(
+                @NonNull String iAppServiceId,
+                @NonNull String recordingId,
+                @NonNull TvRecordingInfo recordingInfo) {
+        }
+
+        /**
+         * This is called when
+         * {@link TvInteractiveAppService.Session#requestTvRecordingInfo(String)} is
+         * called.
+         *
+         * @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)}
+         */
+        public void onRequestTvRecordingInfo(
+                @NonNull String iAppServiceId,
+                @NonNull String recordingId) {
+        }
+
+        /**
+         * This is called when
+         * {@link TvInteractiveAppService.Session#requestTvRecordingInfoList(int)} is
+         * called.
+         *
+         * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+         * @param type The type of recording requested to retrieve.
+         */
+        public void onRequestTvRecordingInfoList(
+                @NonNull String iAppServiceId,
+                @NonNull @TvRecordingInfo.TvRecordingListType int type) {
+        }
     }
 
     /**
@@ -1440,6 +1481,51 @@
         }
 
         @Override
+        public void onSetTvRecordingInfo(
+                Session session, String recordingId, TvRecordingInfo recordingInfo) {
+            if (DEBUG) {
+                Log.d(TAG, "onSetRecordingInfo");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onSetRecordingInfo - session not created");
+                return;
+            }
+            if (mCallback != null) {
+                mCallback.onSetTvRecordingInfo(mIAppServiceId, recordingId, recordingInfo);
+            }
+        }
+
+        @Override
+        public void onRequestTvRecordingInfo(Session session,
+                String recordingId) {
+            if (DEBUG) {
+                Log.d(TAG, "onRequestRecordingInfo");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onRequestRecordingInfo - session not created");
+                return;
+            }
+            if (mCallback != null) {
+                mCallback.onRequestTvRecordingInfo(mIAppServiceId, recordingId);
+            }
+        }
+
+        @Override
+        public void onRequestTvRecordingInfoList(Session session,
+                int type) {
+            if (DEBUG) {
+                Log.d(TAG, "onRequestRecordingInfoList");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onRequestRecordingInfoList - session not created");
+                return;
+            }
+            if (mCallback != null) {
+                mCallback.onRequestTvRecordingInfoList(mIAppServiceId, type);
+            }
+        }
+
+        @Override
         public void onRequestSigning(
                 Session session, String id, String algorithm, String alias, byte[] data) {
             if (DEBUG) {
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 681d76a..b70818d 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -1021,9 +1021,10 @@
 
 static jbyteArray android_media_MediaDrm_getSupportedCryptoSchemesNative(JNIEnv *env) {
     sp<IDrm> drm = android::DrmUtils::MakeDrm();
+    if (drm == NULL) return env->NewByteArray(0);
+
     std::vector<uint8_t> bv;
     drm->getSupportedSchemes(bv);
-
     jbyteArray jUuidBytes = env->NewByteArray(bv.size());
     env->SetByteArrayRegion(jUuidBytes, 0, bv.size(), reinterpret_cast<const jbyte *>(bv.data()));
     return jUuidBytes;
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index dfbd7b5..27666caa 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -339,7 +339,7 @@
     return reinterpret_cast<APerformanceHintSession*>(session)->sendHint(hint);
 }
 
-int APerformanceHint_setThreads(APerformanceHintSession* session, const int32_t* threadIds,
+int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
                                 size_t size) {
     if (session == nullptr) {
         return EINVAL;
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
index 0761b64..a48cd2b 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
@@ -55,422 +55,457 @@
 
 // Consider repo per screen, similar to view model?
 class CredentialManagerRepo(
-  private val context: Context,
-  intent: Intent,
+    private val context: Context,
+    intent: Intent,
 ) {
-  val requestInfo: RequestInfo
-  private val providerEnabledList: List<ProviderData>
-  private val providerDisabledList: List<DisabledProviderData>?
-  // TODO: require non-null.
-  val resultReceiver: ResultReceiver?
+    val requestInfo: RequestInfo
+    private val providerEnabledList: List<ProviderData>
+    private val providerDisabledList: List<DisabledProviderData>?
 
-  init {
-    requestInfo = intent.extras?.getParcelable(
-      RequestInfo.EXTRA_REQUEST_INFO,
-      RequestInfo::class.java
-    ) ?: testCreatePasskeyRequestInfo()
+    // TODO: require non-null.
+    val resultReceiver: ResultReceiver?
 
-    providerEnabledList = when (requestInfo.type) {
-      RequestInfo.TYPE_CREATE ->
-        intent.extras?.getParcelableArrayList(
-                ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST,
-                CreateCredentialProviderData::class.java
-        ) ?: testCreateCredentialEnabledProviderList()
-      RequestInfo.TYPE_GET ->
-        intent.extras?.getParcelableArrayList(
-          ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST,
-          GetCredentialProviderData::class.java
-        ) ?: testGetCredentialProviderList()
-      else -> {
-        // TODO: fail gracefully
-        throw IllegalStateException("Unrecognized request type: ${requestInfo.type}")
-      }
+    init {
+        requestInfo = intent.extras?.getParcelable(
+            RequestInfo.EXTRA_REQUEST_INFO,
+            RequestInfo::class.java
+        ) ?: testCreatePasskeyRequestInfo()
+
+        providerEnabledList = when (requestInfo.type) {
+            RequestInfo.TYPE_CREATE ->
+                intent.extras?.getParcelableArrayList(
+                    ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST,
+                    CreateCredentialProviderData::class.java
+                ) ?: testCreateCredentialEnabledProviderList()
+            RequestInfo.TYPE_GET ->
+                intent.extras?.getParcelableArrayList(
+                    ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST,
+                    GetCredentialProviderData::class.java
+                ) ?: testGetCredentialProviderList()
+            else -> {
+                // TODO: fail gracefully
+                throw IllegalStateException("Unrecognized request type: ${requestInfo.type}")
+            }
+        }
+
+        providerDisabledList =
+            intent.extras?.getParcelableArrayList(
+                ProviderData.EXTRA_DISABLED_PROVIDER_DATA_LIST,
+                DisabledProviderData::class.java
+            ) ?: testDisabledProviderList()
+
+        resultReceiver = intent.getParcelableExtra(
+            Constants.EXTRA_RESULT_RECEIVER,
+            ResultReceiver::class.java
+        )
     }
 
-    providerDisabledList =
-      intent.extras?.getParcelableArrayList(
-        ProviderData.EXTRA_DISABLED_PROVIDER_DATA_LIST,
-        DisabledProviderData::class.java
-      ) ?: testDisabledProviderList()
+    // The dialog is canceled by the user.
+    fun onUserCancel() {
+        onCancel(BaseDialogResult.RESULT_CODE_DIALOG_USER_CANCELED)
+    }
 
-    resultReceiver = intent.getParcelableExtra(
-      Constants.EXTRA_RESULT_RECEIVER,
-      ResultReceiver::class.java
-    )
-  }
+    // The dialog is canceled because we launched into settings.
+    fun onSettingLaunchCancel() {
+        onCancel(BaseDialogResult.RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION)
+    }
 
-  // The dialog is canceled by the user.
-  fun onUserCancel() {
-    onCancel(BaseDialogResult.RESULT_CODE_DIALOG_USER_CANCELED)
-  }
+    fun onParsingFailureCancel() {
+        onCancel(BaseDialogResult.RESULT_CODE_DATA_PARSING_FAILURE)
+    }
 
-  // The dialog is canceled because we launched into settings.
-  fun onSettingLaunchCancel() {
-    onCancel(BaseDialogResult.RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION)
-  }
+    fun onCancel(cancelCode: Int) {
+        val resultData = Bundle()
+        BaseDialogResult.addToBundle(BaseDialogResult(requestInfo.token), resultData)
+        resultReceiver?.send(cancelCode, resultData)
+    }
 
-  private fun onCancel(cancelCode: Int) {
-    val resultData = Bundle()
-    BaseDialogResult.addToBundle(BaseDialogResult(requestInfo.token), resultData)
-    resultReceiver?.send(cancelCode, resultData)
-  }
+    fun onOptionSelected(
+        providerId: String,
+        entryKey: String,
+        entrySubkey: String,
+        resultCode: Int? = null,
+        resultData: Intent? = null,
+    ) {
+        val userSelectionDialogResult = UserSelectionDialogResult(
+            requestInfo.token,
+            providerId,
+            entryKey,
+            entrySubkey,
+            if (resultCode != null) ProviderPendingIntentResponse(resultCode, resultData) else null
+        )
+        val resultData = Bundle()
+        UserSelectionDialogResult.addToBundle(userSelectionDialogResult, resultData)
+        resultReceiver?.send(
+            BaseDialogResult.RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION,
+            resultData
+        )
+    }
 
-  fun onOptionSelected(
-    providerId: String,
-    entryKey: String,
-    entrySubkey: String,
-    resultCode: Int? = null,
-    resultData: Intent? = null,
-  ) {
-    val userSelectionDialogResult = UserSelectionDialogResult(
-      requestInfo.token,
-      providerId,
-      entryKey,
-      entrySubkey,
-      if (resultCode != null) ProviderPendingIntentResponse(resultCode, resultData) else null
-    )
-    val resultData = Bundle()
-    UserSelectionDialogResult.addToBundle(userSelectionDialogResult, resultData)
-    resultReceiver?.send(BaseDialogResult.RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION, resultData)
-  }
+    fun getCredentialInitialUiState(): GetCredentialUiState? {
+        val providerEnabledList = GetFlowUtils.toProviderList(
+            // TODO: handle runtime cast error
+            providerEnabledList as List<GetCredentialProviderData>, context
+        )
+        val requestDisplayInfo = GetFlowUtils.toRequestDisplayInfo(requestInfo, context)
+        return GetCredentialUiState(
+            providerEnabledList,
+            requestDisplayInfo ?: return null,
+        )
+    }
 
-  fun getCredentialInitialUiState(): GetCredentialUiState {
-    val providerEnabledList = GetFlowUtils.toProviderList(
-    // TODO: handle runtime cast error
-      providerEnabledList as List<GetCredentialProviderData>, context)
-    val requestDisplayInfo = GetFlowUtils.toRequestDisplayInfo(requestInfo, context)
-    return GetCredentialUiState(
-      providerEnabledList,
-      requestDisplayInfo,
-    )
-  }
+    fun getCreateProviderEnableListInitialUiState(): List<EnabledProviderInfo> {
+        val providerEnabledList = CreateFlowUtils.toEnabledProviderList(
+            // Handle runtime cast error
+            providerEnabledList as List<CreateCredentialProviderData>, context
+        )
+        return providerEnabledList
+    }
 
-  fun getCreateProviderEnableListInitialUiState(): List<EnabledProviderInfo> {
-    val providerEnabledList = CreateFlowUtils.toEnabledProviderList(
-      // Handle runtime cast error
-      providerEnabledList as List<CreateCredentialProviderData>, context)
-    return providerEnabledList
-  }
+    fun getCreateProviderDisableListInitialUiState(): List<DisabledProviderInfo> {
+        return CreateFlowUtils.toDisabledProviderList(
+            // Handle runtime cast error
+            providerDisabledList, context
+        )
+    }
 
-  fun getCreateProviderDisableListInitialUiState(): List<DisabledProviderInfo>? {
-    return CreateFlowUtils.toDisabledProviderList(
-      // Handle runtime cast error
-      providerDisabledList, context)
-  }
+    fun getCreateRequestDisplayInfoInitialUiState(): RequestDisplayInfo? {
+        return CreateFlowUtils.toRequestDisplayInfo(requestInfo, context)
+    }
 
-  fun getCreateRequestDisplayInfoInitialUiState(): RequestDisplayInfo {
-    return CreateFlowUtils.toRequestDisplayInfo(requestInfo, context)
-  }
+    // TODO: below are prototype functionalities. To be removed for productionization.
+    private fun testCreateCredentialEnabledProviderList(): List<CreateCredentialProviderData> {
+        return listOf(
+            CreateCredentialProviderData
+                .Builder("io.enpass.app")
+                .setSaveEntries(
+                    listOf<Entry>(
+                        newCreateEntry(
+                            "key1", "subkey-1", "elisa.beckett@gmail.com",
+                            20, 7, 27, 10L,
+                            "Optional footer description"
+                        ),
+                        newCreateEntry(
+                            "key1", "subkey-2", "elisa.work@google.com",
+                            20, 7, 27, 12L,
+                            null
+                        ),
+                    )
+                )
+                .setRemoteEntry(
+                    newRemoteEntry("key2", "subkey-1")
+                )
+                .build(),
+            CreateCredentialProviderData
+                .Builder("com.dashlane")
+                .setSaveEntries(
+                    listOf<Entry>(
+                        newCreateEntry(
+                            "key1", "subkey-3", "elisa.beckett@dashlane.com",
+                            20, 7, 27, 11L,
+                            null
+                        ),
+                        newCreateEntry(
+                            "key1", "subkey-4", "elisa.work@dashlane.com",
+                            20, 7, 27, 14L,
+                            null
+                        ),
+                    )
+                )
+                .build(),
+        )
+    }
 
-  // TODO: below are prototype functionalities. To be removed for productionization.
-  private fun testCreateCredentialEnabledProviderList(): List<CreateCredentialProviderData> {
-      return listOf(
-          CreateCredentialProviderData
-              .Builder("io.enpass.app")
-              .setSaveEntries(
-                  listOf<Entry>(
-                      newCreateEntry("key1", "subkey-1", "elisa.beckett@gmail.com",
-                          20, 7, 27, 10L,
-                          "Optional footer description"),
-                      newCreateEntry("key1", "subkey-2", "elisa.work@google.com",
-                          20, 7, 27, 12L,
-                      null),
-                  )
-              )
-              .setRemoteEntry(
-                  newRemoteEntry("key2", "subkey-1")
-              )
-              .build(),
-          CreateCredentialProviderData
-              .Builder("com.dashlane")
-              .setSaveEntries(
-                  listOf<Entry>(
-                      newCreateEntry("key1", "subkey-3", "elisa.beckett@dashlane.com",
-                          20, 7, 27, 11L,
-                          null),
-                      newCreateEntry("key1", "subkey-4", "elisa.work@dashlane.com",
-                          20, 7, 27, 14L,
-                          null),
-                  )
-              )
-              .build(),
-      )
-  }
+    private fun testDisabledProviderList(): List<DisabledProviderData>? {
+        return listOf(
+            DisabledProviderData("com.lastpass.lpandroid"),
+            DisabledProviderData("com.google.android.youtube")
+        )
+    }
 
-  private fun testDisabledProviderList(): List<DisabledProviderData>? {
-    return listOf(
-      DisabledProviderData("com.lastpass.lpandroid"),
-      DisabledProviderData("com.google.android.youtube")
-    )
-  }
-
-  private fun testGetCredentialProviderList(): List<GetCredentialProviderData> {
-    return listOf(
-      GetCredentialProviderData.Builder("io.enpass.app")
-        .setCredentialEntries(
-          listOf<Entry>(
-              newGetEntry(
-                  "key1", "subkey-1", TYPE_PASSWORD_CREDENTIAL, "Password",
-                  "elisa.family@outlook.com", null, 3L
-              ),
-            newGetEntry(
-              "key1", "subkey-1", TYPE_PUBLIC_KEY_CREDENTIAL, "Passkey",
-              "elisa.bakery@gmail.com", "Elisa Beckett", 0L
-            ),
-            newGetEntry(
-              "key1", "subkey-2", TYPE_PASSWORD_CREDENTIAL, "Password",
-              "elisa.bakery@gmail.com", null, 10L
-            ),
-            newGetEntry(
-              "key1", "subkey-3", TYPE_PUBLIC_KEY_CREDENTIAL, "Passkey",
-              "elisa.family@outlook.com", "Elisa Beckett", 1L
-            ),
-          )
-        ).setAuthenticationEntry(
-          newAuthenticationEntry("key2", "subkey-1", TYPE_PASSWORD_CREDENTIAL)
-        ).setActionChips(
-          listOf(
-            newActionEntry(
-              "key3", "subkey-1", TYPE_PASSWORD_CREDENTIAL,
-              "Open Google Password Manager", "elisa.beckett@gmail.com"
-            ),
-            newActionEntry(
-              "key3", "subkey-2", TYPE_PASSWORD_CREDENTIAL,
-              "Open Google Password Manager", "beckett-family@gmail.com"
-            ),
-          )
-        ).setRemoteEntry(
-          newRemoteEntry("key4", "subkey-1")
-        ).build(),
-      GetCredentialProviderData.Builder("com.dashlane")
-        .setCredentialEntries(
-          listOf<Entry>(
-            newGetEntry(
-              "key1", "subkey-2", TYPE_PASSWORD_CREDENTIAL, "Password",
-              "elisa.family@outlook.com", null, 4L
-            ),
-            newGetEntry(
-                  "key1", "subkey-3", TYPE_PASSWORD_CREDENTIAL, "Password",
-                  "elisa.work@outlook.com", null, 11L
-            ),
-          )
-        ).setAuthenticationEntry(
-          newAuthenticationEntry("key2", "subkey-1", TYPE_PASSWORD_CREDENTIAL)
-        ).setActionChips(
-          listOf(
-            newActionEntry(
-              "key3", "subkey-1", TYPE_PASSWORD_CREDENTIAL,
-              "Open Enpass"
-            ),
-          )
-        ).build(),
-    )
-  }
+    private fun testGetCredentialProviderList(): List<GetCredentialProviderData> {
+        return listOf(
+            GetCredentialProviderData.Builder("io.enpass.app")
+                .setCredentialEntries(
+                    listOf<Entry>(
+                        newGetEntry(
+                            "key1", "subkey-1", TYPE_PASSWORD_CREDENTIAL, "Password",
+                            "elisa.family@outlook.com", null, 3L
+                        ),
+                        newGetEntry(
+                            "key1", "subkey-1", TYPE_PUBLIC_KEY_CREDENTIAL, "Passkey",
+                            "elisa.bakery@gmail.com", "Elisa Beckett", 0L
+                        ),
+                        newGetEntry(
+                            "key1", "subkey-2", TYPE_PASSWORD_CREDENTIAL, "Password",
+                            "elisa.bakery@gmail.com", null, 10L
+                        ),
+                        newGetEntry(
+                            "key1", "subkey-3", TYPE_PUBLIC_KEY_CREDENTIAL, "Passkey",
+                            "elisa.family@outlook.com", "Elisa Beckett", 1L
+                        ),
+                    )
+                ).setAuthenticationEntry(
+                    newAuthenticationEntry("key2", "subkey-1", TYPE_PASSWORD_CREDENTIAL)
+                ).setActionChips(
+                    listOf(
+                        newActionEntry(
+                            "key3", "subkey-1", TYPE_PASSWORD_CREDENTIAL,
+                            "Open Google Password Manager", "elisa.beckett@gmail.com"
+                        ),
+                        newActionEntry(
+                            "key3", "subkey-2", TYPE_PASSWORD_CREDENTIAL,
+                            "Open Google Password Manager", "beckett-family@gmail.com"
+                        ),
+                    )
+                ).setRemoteEntry(
+                    newRemoteEntry("key4", "subkey-1")
+                ).build(),
+            GetCredentialProviderData.Builder("com.dashlane")
+                .setCredentialEntries(
+                    listOf<Entry>(
+                        newGetEntry(
+                            "key1", "subkey-2", TYPE_PASSWORD_CREDENTIAL, "Password",
+                            "elisa.family@outlook.com", null, 4L
+                        ),
+                        newGetEntry(
+                            "key1", "subkey-3", TYPE_PASSWORD_CREDENTIAL, "Password",
+                            "elisa.work@outlook.com", null, 11L
+                        ),
+                    )
+                ).setAuthenticationEntry(
+                    newAuthenticationEntry("key2", "subkey-1", TYPE_PASSWORD_CREDENTIAL)
+                ).setActionChips(
+                    listOf(
+                        newActionEntry(
+                            "key3", "subkey-1", TYPE_PASSWORD_CREDENTIAL,
+                            "Open Enpass"
+                        ),
+                    )
+                ).build(),
+        )
+    }
 
     private fun newActionEntry(
-            key: String,
-            subkey: String,
-            credentialType: String,
-            text: String,
-            subtext: String? = null,
+        key: String,
+        subkey: String,
+        credentialType: String,
+        text: String,
+        subtext: String? = null,
     ): Entry {
         val action = Action(text, subtext, null)
 
         return Entry(
-                key,
-                subkey,
-                Action.toSlice(action)
+            key,
+            subkey,
+            Action.toSlice(action)
         )
     }
 
     private fun newAuthenticationEntry(
-            key: String,
-            subkey: String,
-            credentialType: String,
+        key: String,
+        subkey: String,
+        credentialType: String,
     ): Entry {
         val slice = Slice.Builder(
-                Uri.EMPTY, SliceSpec(credentialType, 1)
+            Uri.EMPTY, SliceSpec(credentialType, 1)
         )
         return Entry(
-                key,
-                subkey,
-                slice.build()
+            key,
+            subkey,
+            slice.build()
         )
     }
 
     private fun newGetEntry(
-            key: String,
-            subkey: String,
-            credentialType: String,
-            credentialTypeDisplayName: String,
-            userName: String,
-            userDisplayName: String?,
-            lastUsedTimeMillis: Long?,
+        key: String,
+        subkey: String,
+        credentialType: String,
+        credentialTypeDisplayName: String,
+        userName: String,
+        userDisplayName: String?,
+        lastUsedTimeMillis: Long?,
     ): Entry {
         val intent = Intent("com.androidauth.androidvault.CONFIRM_PASSWORD")
-                .setPackage("com.androidauth.androidvault")
+            .setPackage("com.androidauth.androidvault")
         intent.putExtra("provider_extra_sample", "testprovider")
 
-        val pendingIntent = PendingIntent.getActivity(context, 1,
-                intent, (PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
-                or PendingIntent.FLAG_ONE_SHOT))
+        val pendingIntent = PendingIntent.getActivity(
+            context, 1,
+            intent, (PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
+                or PendingIntent.FLAG_ONE_SHOT)
+        )
 
-        val credentialEntry = CredentialEntry(credentialType, credentialTypeDisplayName, userName,
-                userDisplayName, pendingIntent, lastUsedTimeMillis
-                ?: 0L, null, false)
+        val credentialEntry = CredentialEntry(
+            credentialType, credentialTypeDisplayName, userName,
+            userDisplayName, pendingIntent, lastUsedTimeMillis
+                ?: 0L, null, false
+        )
 
         return Entry(
-                key,
-                subkey,
-                CredentialEntry.toSlice(credentialEntry),
-                Intent()
-        )
-  }
-
-    private fun newCreateEntry(
-            key: String,
-            subkey: String,
-            providerDisplayName: String,
-            passwordCount: Int,
-            passkeyCount: Int,
-            totalCredentialCount: Int,
-            lastUsedTimeMillis: Long,
-            footerDescription: String?,
-    ): Entry {
-        val intent = Intent("com.androidauth.androidvault.CONFIRM_PASSWORD")
-                .setPackage("com.androidauth.androidvault")
-        intent.putExtra("provider_extra_sample", "testprovider")
-        val pendingIntent = PendingIntent.getActivity(context, 1,
-                intent, (PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
-                or PendingIntent.FLAG_ONE_SHOT))
-        val createPasswordRequest = android.service.credentials.CreateCredentialRequest(
-                android.service.credentials.CallingAppInfo(
-                        context.applicationInfo.packageName, SigningInfo()),
-                TYPE_PASSWORD_CREDENTIAL,
-                toCredentialDataBundle("beckett-bakert@gmail.com", "password123")
-        )
-        val fillInIntent = Intent().putExtra(
-                CredentialProviderService.EXTRA_CREATE_CREDENTIAL_REQUEST,
-                createPasswordRequest)
-
-        val createEntry = CreateEntry(
-                providerDisplayName, pendingIntent,
-                null, lastUsedTimeMillis,
-                listOf(
-                        CredentialCountInformation.createPasswordCountInformation(passwordCount),
-                        CredentialCountInformation.createPublicKeyCountInformation(passkeyCount),
-                ), footerDescription)
-        return Entry(
-                key,
-                subkey,
-                CreateEntry.toSlice(createEntry),
-                fillInIntent
+            key,
+            subkey,
+            CredentialEntry.toSlice(credentialEntry),
+            Intent()
         )
     }
 
-  private fun newRemoteEntry(
-    key: String,
-    subkey: String,
-  ): Entry {
-    return Entry(
-      key,
-      subkey,
-      Slice.Builder(
-        Uri.EMPTY, SliceSpec("type", 1)
-      ).build()
-    )
-  }
-
-  private fun testCreatePasskeyRequestInfo(): RequestInfo {
-    val request = CreatePublicKeyCredentialRequest("{\"extensions\": {\n" +
-            "                     \"webauthn.loc\": true\n" +
-            "                   },\n" +
-            "                   \"attestation\": \"direct\",\n" +
-            "                   \"challenge\": \"-rSQHXSQUdaK1N-La5bE-JPt6EVAW4SxX1K_tXhZ_Gk\",\n" +
-            "                   \"user\": {\n" +
-            "                     \"displayName\": \"testName\",\n" +
-            "                     \"name\": \"credManTesting@gmail.com\",\n" +
-            "                     \"id\": \"eD4o2KoXLpgegAtnM5cDhhUPvvk2\"\n" +
-            "                   },\n" +
-            "                   \"excludeCredentials\": [],\n" +
-            "                   \"rp\": {\n" +
-            "                     \"name\": \"Address Book\",\n" +
-            "                     \"id\": \"addressbook-c7876.uc.r.appspot.com\"\n" +
-            "                   },\n" +
-            "                   \"timeout\": 60000,\n" +
-            "                   \"pubKeyCredParams\": [\n" +
-            "                     {\n" +
-            "                       \"type\": \"public-key\",\n" +
-            "                       \"alg\": -7\n" +
-            "                     },\n" +
-            "                     {\n" +
-            "                       \"type\": \"public-key\",\n" +
-            "                       \"alg\": -257\n" +
-            "                     },\n" +
-            "                     {\n" +
-            "                       \"type\": \"public-key\",\n" +
-            "                       \"alg\": -37\n" +
-            "                     }\n" +
-            "                   ],\n" +
-            "                   \"authenticatorSelection\": {\n" +
-            "                     \"residentKey\": \"required\",\n" +
-            "                     \"requireResidentKey\": true\n" +
-            "                   }}")
-    val credentialData = request.credentialData
-    return RequestInfo.newCreateRequestInfo(
-      Binder(),
-      CreateCredentialRequest(
-        TYPE_PUBLIC_KEY_CREDENTIAL,
-        credentialData,
-        // TODO: populate with actual data
-        /*candidateQueryData=*/ Bundle(),
-        /*isSystemProviderRequired=*/ false
-      ),
-      "com.google.android.youtube"
-    )
-  }
-
-  private fun testCreatePasswordRequestInfo(): RequestInfo {
-    val data = toCredentialDataBundle("beckett-bakert@gmail.com", "password123")
-    return RequestInfo.newCreateRequestInfo(
-      Binder(),
-      CreateCredentialRequest(
-        TYPE_PASSWORD_CREDENTIAL,
-        data,
-        // TODO: populate with actual data
-        /*candidateQueryData=*/ Bundle(),
-        /*isSystemProviderRequired=*/ false
-      ),
-      "com.google.android.youtube"
-    )
-  }
-
-  private fun testCreateOtherCredentialRequestInfo(): RequestInfo {
-    val data = Bundle()
-    return RequestInfo.newCreateRequestInfo(
-      Binder(),
-      CreateCredentialRequest(
-        "other-sign-ins",
-        data,
-        /*candidateQueryData=*/ Bundle(),
-        /*isSystemProviderRequired=*/ false
-      ),
-      "com.google.android.youtube"
-    )
-  }
-
-  private fun testGetRequestInfo(): RequestInfo {
-    return RequestInfo.newGetRequestInfo(
-      Binder(),
-      GetCredentialRequest.Builder(
-        Bundle()
-      )
-        .addGetCredentialOption(
-          GetCredentialOption(
-            TYPE_PUBLIC_KEY_CREDENTIAL, Bundle(), Bundle(), /*isSystemProviderRequired=*/ false)
+    private fun newCreateEntry(
+        key: String,
+        subkey: String,
+        providerDisplayName: String,
+        passwordCount: Int,
+        passkeyCount: Int,
+        totalCredentialCount: Int,
+        lastUsedTimeMillis: Long,
+        footerDescription: String?,
+    ): Entry {
+        val intent = Intent("com.androidauth.androidvault.CONFIRM_PASSWORD")
+            .setPackage("com.androidauth.androidvault")
+        intent.putExtra("provider_extra_sample", "testprovider")
+        val pendingIntent = PendingIntent.getActivity(
+            context, 1,
+            intent, (PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
+                or PendingIntent.FLAG_ONE_SHOT)
         )
-        .build(),
-      "com.google.android.youtube"
-    )
-  }
+        val createPasswordRequest = android.service.credentials.CreateCredentialRequest(
+            android.service.credentials.CallingAppInfo(
+                context.applicationInfo.packageName, SigningInfo()
+            ),
+            TYPE_PASSWORD_CREDENTIAL,
+            toCredentialDataBundle("beckett-bakert@gmail.com", "password123")
+        )
+        val fillInIntent = Intent().putExtra(
+            CredentialProviderService.EXTRA_CREATE_CREDENTIAL_REQUEST,
+            createPasswordRequest
+        )
+
+        val createEntry = CreateEntry(
+            providerDisplayName, pendingIntent,
+            null, lastUsedTimeMillis,
+            listOf(
+                CredentialCountInformation.createPasswordCountInformation(passwordCount),
+                CredentialCountInformation.createPublicKeyCountInformation(passkeyCount),
+            ), footerDescription
+        )
+        return Entry(
+            key,
+            subkey,
+            CreateEntry.toSlice(createEntry),
+            fillInIntent
+        )
+    }
+
+    private fun newRemoteEntry(
+        key: String,
+        subkey: String,
+    ): Entry {
+        return Entry(
+            key,
+            subkey,
+            Slice.Builder(
+                Uri.EMPTY, SliceSpec("type", 1)
+            ).build()
+        )
+    }
+
+    private fun testCreatePasskeyRequestInfo(): RequestInfo {
+        val request = CreatePublicKeyCredentialRequest(
+            "{\"extensions\": {\n" +
+                "                     \"webauthn.loc\": true\n" +
+                "                   },\n" +
+                "                   \"attestation\": \"direct\",\n" +
+                "                   \"challenge\":" +
+                " \"-rSQHXSQUdaK1N-La5bE-JPt6EVAW4SxX1K_tXhZ_Gk\",\n" +
+                "                   \"user\": {\n" +
+                "                     \"displayName\": \"testName\",\n" +
+                "                     \"name\": \"credManTesting@gmail.com\",\n" +
+                "                     \"id\": \"eD4o2KoXLpgegAtnM5cDhhUPvvk2\"\n" +
+                "                   },\n" +
+                "                   \"excludeCredentials\": [],\n" +
+                "                   \"rp\": {\n" +
+                "                     \"name\": \"Address Book\",\n" +
+                "                     \"id\": \"addressbook-c7876.uc.r.appspot.com\"\n" +
+                "                   },\n" +
+                "                   \"timeout\": 60000,\n" +
+                "                   \"pubKeyCredParams\": [\n" +
+                "                     {\n" +
+                "                       \"type\": \"public-key\",\n" +
+                "                       \"alg\": -7\n" +
+                "                     },\n" +
+                "                     {\n" +
+                "                       \"type\": \"public-key\",\n" +
+                "                       \"alg\": -257\n" +
+                "                     },\n" +
+                "                     {\n" +
+                "                       \"type\": \"public-key\",\n" +
+                "                       \"alg\": -37\n" +
+                "                     }\n" +
+                "                   ],\n" +
+                "                   \"authenticatorSelection\": {\n" +
+                "                     \"residentKey\": \"required\",\n" +
+                "                     \"requireResidentKey\": true\n" +
+                "                   }}"
+        )
+        val credentialData = request.credentialData
+        return RequestInfo.newCreateRequestInfo(
+            Binder(),
+            CreateCredentialRequest(
+                TYPE_PUBLIC_KEY_CREDENTIAL,
+                credentialData,
+                // TODO: populate with actual data
+                /*candidateQueryData=*/ Bundle(),
+                /*isSystemProviderRequired=*/ false
+            ),
+            "com.google.android.youtube"
+        )
+    }
+
+    private fun testCreatePasswordRequestInfo(): RequestInfo {
+        val data = toCredentialDataBundle("beckett-bakert@gmail.com", "password123")
+        return RequestInfo.newCreateRequestInfo(
+            Binder(),
+            CreateCredentialRequest(
+                TYPE_PASSWORD_CREDENTIAL,
+                data,
+                // TODO: populate with actual data
+                /*candidateQueryData=*/ Bundle(),
+                /*isSystemProviderRequired=*/ false
+            ),
+            "com.google.android.youtube"
+        )
+    }
+
+    private fun testCreateOtherCredentialRequestInfo(): RequestInfo {
+        val data = Bundle()
+        return RequestInfo.newCreateRequestInfo(
+            Binder(),
+            CreateCredentialRequest(
+                "other-sign-ins",
+                data,
+                /*candidateQueryData=*/ Bundle(),
+                /*isSystemProviderRequired=*/ false
+            ),
+            "com.google.android.youtube"
+        )
+    }
+
+    private fun testGetRequestInfo(): RequestInfo {
+        return RequestInfo.newGetRequestInfo(
+            Binder(),
+            GetCredentialRequest.Builder(
+                Bundle()
+            )
+                .addGetCredentialOption(
+                    GetCredentialOption(
+                        TYPE_PUBLIC_KEY_CREDENTIAL,
+                        Bundle(),
+                        Bundle(), /*isSystemProviderRequired=*/
+                        false
+                    )
+                )
+                .build(),
+            "com.google.android.youtube"
+        )
+    }
 }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index df85745..3b9c02a 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -31,6 +31,7 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.lifecycle.viewmodel.compose.viewModel
+import com.android.credentialmanager.common.Constants
 import com.android.credentialmanager.common.DialogState
 import com.android.credentialmanager.common.ProviderActivityResult
 import com.android.credentialmanager.createflow.CreateCredentialScreen
@@ -45,11 +46,15 @@
         super.onCreate(savedInstanceState)
         val credManRepo = CredentialManagerRepo(this, intent)
         UserConfigRepo.setup(this)
-        val requestInfo = credManRepo.requestInfo
-        setContent {
-            CredentialSelectorTheme {
-                CredentialManagerBottomSheet(requestInfo.type, credManRepo)
+        try {
+            setContent {
+                CredentialSelectorTheme {
+                    CredentialManagerBottomSheet(credManRepo.requestInfo.type, credManRepo)
+                }
             }
+        } catch (e: Exception) {
+            Log.e(Constants.LOG_TAG, "Failed to show the credential selector", e)
+            reportInstantiationErrorAndFinishActivity(credManRepo)
         }
     }
 
@@ -65,7 +70,22 @@
         when (requestType) {
             RequestInfo.TYPE_CREATE -> {
                 val viewModel: CreateCredentialViewModel = viewModel {
-                    CreateCredentialViewModel(credManRepo)
+                    val vm = CreateCredentialViewModel.newInstance(
+                        credManRepo = credManRepo,
+                        providerEnableListUiState =
+                        credManRepo.getCreateProviderEnableListInitialUiState(),
+                        providerDisableListUiState =
+                        credManRepo.getCreateProviderDisableListInitialUiState(),
+                        requestDisplayInfoUiState =
+                        credManRepo.getCreateRequestDisplayInfoInitialUiState()
+                    )
+                    if (vm == null) {
+                        // Input parsing failed. Close the activity.
+                        reportInstantiationErrorAndFinishActivity(credManRepo)
+                        throw IllegalStateException()
+                    } else {
+                        vm
+                    }
                 }
                 LaunchedEffect(viewModel.uiState.dialogState) {
                     handleDialogState(viewModel.uiState.dialogState)
@@ -74,11 +94,21 @@
                     viewModel.onProviderActivityResult(it)
                     providerActivityResult.value = null
                 }
-                CreateCredentialScreen(viewModel = viewModel, providerActivityLauncher = launcher)
+                CreateCredentialScreen(
+                    viewModel = viewModel,
+                    providerActivityLauncher = launcher
+                )
             }
             RequestInfo.TYPE_GET -> {
                 val viewModel: GetCredentialViewModel = viewModel {
-                    GetCredentialViewModel(credManRepo)
+                    val initialUiState = credManRepo.getCredentialInitialUiState()
+                    if (initialUiState == null) {
+                        // Input parsing failed. Close the activity.
+                        reportInstantiationErrorAndFinishActivity(credManRepo)
+                        throw IllegalStateException()
+                    } else {
+                        GetCredentialViewModel(credManRepo, initialUiState)
+                    }
                 }
                 LaunchedEffect(viewModel.uiState.dialogState) {
                     handleDialogState(viewModel.uiState.dialogState)
@@ -90,18 +120,24 @@
                 GetCredentialScreen(viewModel = viewModel, providerActivityLauncher = launcher)
             }
             else -> {
-                Log.w("AccountSelector", "Unknown type, not rendering any UI")
-                this.finish()
+                Log.d(Constants.LOG_TAG, "Unknown type, not rendering any UI")
+                reportInstantiationErrorAndFinishActivity(credManRepo)
             }
         }
     }
 
+    private fun reportInstantiationErrorAndFinishActivity(credManRepo: CredentialManagerRepo) {
+        Log.w(Constants.LOG_TAG, "Finishing the activity due to instantiation failure.")
+        credManRepo.onParsingFailureCancel()
+        this@CredentialSelectorActivity.finish()
+    }
+
     private fun handleDialogState(dialogState: DialogState) {
         if (dialogState == DialogState.COMPLETE) {
-            Log.i("AccountSelector", "Received signal to finish the activity.")
+            Log.d(Constants.LOG_TAG, "Received signal to finish the activity.")
             this@CredentialSelectorActivity.finish()
         } else if (dialogState == DialogState.CANCELED_FOR_SETTINGS) {
-            Log.i("AccountSelector", "Received signal to finish the activity and launch settings.")
+            Log.d(Constants.LOG_TAG, "Received signal to finish the activity and launch settings.")
             this@CredentialSelectorActivity.startActivity(Intent(Settings.ACTION_SYNC_SETTINGS))
             this@CredentialSelectorActivity.finish()
         }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index d9e4dc8..3f705d6 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -19,21 +19,23 @@
 import android.content.ComponentName
 import android.content.Context
 import android.content.pm.PackageManager
-import android.credentials.ui.Entry
-import android.credentials.ui.GetCredentialProviderData
 import android.credentials.ui.CreateCredentialProviderData
 import android.credentials.ui.DisabledProviderData
+import android.credentials.ui.Entry
+import android.credentials.ui.GetCredentialProviderData
 import android.credentials.ui.RequestInfo
 import android.graphics.drawable.Drawable
 import android.text.TextUtils
+import android.util.Log
+import com.android.credentialmanager.common.Constants
+import com.android.credentialmanager.createflow.ActiveEntry
+import com.android.credentialmanager.createflow.CreateCredentialUiState
 import com.android.credentialmanager.createflow.CreateOptionInfo
+import com.android.credentialmanager.createflow.CreateScreenState
+import com.android.credentialmanager.createflow.DisabledProviderInfo
+import com.android.credentialmanager.createflow.EnabledProviderInfo
 import com.android.credentialmanager.createflow.RemoteInfo
 import com.android.credentialmanager.createflow.RequestDisplayInfo
-import com.android.credentialmanager.createflow.EnabledProviderInfo
-import com.android.credentialmanager.createflow.CreateScreenState
-import com.android.credentialmanager.createflow.ActiveEntry
-import com.android.credentialmanager.createflow.DisabledProviderInfo
-import com.android.credentialmanager.createflow.CreateCredentialUiState
 import com.android.credentialmanager.getflow.ActionEntryInfo
 import com.android.credentialmanager.getflow.AuthenticationEntryInfo
 import com.android.credentialmanager.getflow.CredentialEntryInfo
@@ -45,416 +47,480 @@
 import com.android.credentialmanager.jetpack.developer.PublicKeyCredential.Companion.TYPE_PUBLIC_KEY_CREDENTIAL
 import com.android.credentialmanager.jetpack.provider.Action
 import com.android.credentialmanager.jetpack.provider.AuthenticationAction
+import com.android.credentialmanager.jetpack.provider.CreateEntry
 import com.android.credentialmanager.jetpack.provider.CredentialCountInformation
 import com.android.credentialmanager.jetpack.provider.CredentialEntry
-import com.android.credentialmanager.jetpack.provider.CreateEntry
 import org.json.JSONObject
 
+private fun getAppLabel(
+    pm: PackageManager,
+    appPackageName: String
+): String? {
+    return try {
+        val pkgInfo = pm.getPackageInfo(appPackageName, PackageManager.PackageInfoFlags.of(0))
+        pkgInfo.applicationInfo.loadSafeLabel(
+            pm, 0f,
+            TextUtils.SAFE_STRING_FLAG_FIRST_LINE or TextUtils.SAFE_STRING_FLAG_TRIM
+        ).toString()
+    } catch (e: PackageManager.NameNotFoundException) {
+        Log.e(Constants.LOG_TAG, "Caller app not found", e)
+        null
+    }
+}
+
+private fun getServiceLabelAndIcon(
+    pm: PackageManager,
+    providerFlattenedComponentName: String
+): Pair<String, Drawable>? {
+    var providerLabel: String? = null
+    var providerIcon: Drawable? = null
+    val component = ComponentName.unflattenFromString(providerFlattenedComponentName)
+    if (component == null) {
+        // Test data has only package name not component name.
+        // TODO: remove once test data is removed
+        try {
+            val pkgInfo = pm.getPackageInfo(
+                providerFlattenedComponentName,
+                PackageManager.PackageInfoFlags.of(0)
+            )
+            providerLabel =
+                pkgInfo.applicationInfo.loadSafeLabel(
+                    pm, 0f,
+                    TextUtils.SAFE_STRING_FLAG_FIRST_LINE or TextUtils.SAFE_STRING_FLAG_TRIM
+                ).toString()
+            providerIcon = pkgInfo.applicationInfo.loadIcon(pm)
+        } catch (e: PackageManager.NameNotFoundException) {
+            Log.e(Constants.LOG_TAG, "Provider info not found", e)
+        }
+    } else {
+        try {
+            val si = pm.getServiceInfo(component, PackageManager.ComponentInfoFlags.of(0))
+            providerLabel = si.loadSafeLabel(
+                pm, 0f,
+                TextUtils.SAFE_STRING_FLAG_FIRST_LINE or TextUtils.SAFE_STRING_FLAG_TRIM
+            ).toString()
+            providerIcon = si.loadIcon(pm)
+        } catch (e: PackageManager.NameNotFoundException) {
+            Log.e(Constants.LOG_TAG, "Provider info not found", e)
+        }
+    }
+    return if (providerLabel == null || providerIcon == null) {
+        Log.d(
+            Constants.LOG_TAG,
+            "Failed to load provider label/icon for provider $providerFlattenedComponentName"
+        )
+        null
+    } else {
+        Pair(providerLabel, providerIcon)
+    }
+}
+
 /** Utility functions for converting CredentialManager data structures to or from UI formats. */
 class GetFlowUtils {
-  companion object {
-
-    fun toProviderList(
+    companion object {
+        // Returns the list (potentially empty) of enabled provider.
+        fun toProviderList(
             providerDataList: List<GetCredentialProviderData>,
             context: Context,
-    ): List<ProviderInfo> {
-      val packageManager = context.packageManager
-      return providerDataList.map {
-        val componentName = ComponentName.unflattenFromString(it.providerFlattenedComponentName)
-        var packageName = componentName?.packageName
-        if (componentName == null) {
-          // TODO: Remove once test data is fixed
-          packageName = it.providerFlattenedComponentName
+        ): List<ProviderInfo> {
+            val providerList: MutableList<ProviderInfo> = mutableListOf()
+            providerDataList.forEach {
+                val providerLabelAndIcon = getServiceLabelAndIcon(
+                    context.packageManager,
+                    it.providerFlattenedComponentName
+                ) ?: return@forEach
+                val (providerLabel, providerIcon) = providerLabelAndIcon
+                providerList.add(
+                    ProviderInfo(
+                        id = it.providerFlattenedComponentName,
+                        icon = providerIcon,
+                        displayName = providerLabel,
+                        credentialEntryList = getCredentialOptionInfoList(
+                            it.providerFlattenedComponentName, it.credentialEntries, context
+                        ),
+                        authenticationEntry = getAuthenticationEntry(
+                            it.providerFlattenedComponentName,
+                            providerLabel,
+                            providerIcon,
+                            it.authenticationEntry
+                        ),
+                        remoteEntry = getRemoteEntry(
+                            it.providerFlattenedComponentName,
+                            it.remoteEntry
+                        ),
+                        actionEntryList = getActionEntryList(
+                            it.providerFlattenedComponentName, it.actionChips, providerIcon
+                        ),
+                    )
+                )
+            }
+            return providerList
         }
 
-        val pkgInfo = packageManager
-                .getPackageInfo(packageName!!,
-                        PackageManager.PackageInfoFlags.of(0))
-        val providerDisplayName = pkgInfo.applicationInfo.loadLabel(packageManager).toString()
-        // TODO: decide what to do when failed to load a provider icon
-        val providerIcon = pkgInfo.applicationInfo.loadIcon(packageManager)!!
-        ProviderInfo(
-                id = it.providerFlattenedComponentName,
-                // TODO: decide what to do when failed to load a provider icon
-                icon = providerIcon,
-                displayName = providerDisplayName,
-                credentialEntryList = getCredentialOptionInfoList(
-                        it.providerFlattenedComponentName, it.credentialEntries, context),
-                authenticationEntry = getAuthenticationEntry(
-                        it.providerFlattenedComponentName,
-                        providerDisplayName,
-                        providerIcon,
-                        it.authenticationEntry),
-                remoteEntry = getRemoteEntry(it.providerFlattenedComponentName, it.remoteEntry),
-                actionEntryList = getActionEntryList(
-                        it.providerFlattenedComponentName, it.actionChips, providerIcon),
-        )
-      }
-    }
-
-    fun toRequestDisplayInfo(
+        fun toRequestDisplayInfo(
             requestInfo: RequestInfo,
             context: Context,
-    ): com.android.credentialmanager.getflow.RequestDisplayInfo {
-        val packageName = requestInfo.appPackageName
-        val pkgInfo = context.packageManager.getPackageInfo(packageName,
-                PackageManager.PackageInfoFlags.of(0))
-        val appLabel = pkgInfo.applicationInfo.loadSafeLabel(context.packageManager, 0f,
-            TextUtils.SAFE_STRING_FLAG_FIRST_LINE or TextUtils.SAFE_STRING_FLAG_TRIM)
-        return com.android.credentialmanager.getflow.RequestDisplayInfo(
-              appName = appLabel.toString()
-      )
-    }
+        ): com.android.credentialmanager.getflow.RequestDisplayInfo? {
+            return com.android.credentialmanager.getflow.RequestDisplayInfo(
+                appName = getAppLabel(context.packageManager, requestInfo.appPackageName)
+                    ?: return null
+            )
+        }
 
 
-    /* From service data structure to UI credential entry list representation. */
-    private fun getCredentialOptionInfoList(
+        /* From service data structure to UI credential entry list representation. */
+        private fun getCredentialOptionInfoList(
             providerId: String,
             credentialEntries: List<Entry>,
             context: Context,
-    ): List<CredentialEntryInfo> {
-      return credentialEntries.map {
-        // TODO: handle NPE gracefully
-        val credentialEntry = CredentialEntry.fromSlice(it.slice)!!
+        ): List<CredentialEntryInfo> {
+            return credentialEntries.map {
+                // TODO: handle NPE gracefully
+                val credentialEntry = CredentialEntry.fromSlice(it.slice)!!
 
-        // Consider directly move the UI object into the class.
-        return@map CredentialEntryInfo(
-                providerId = providerId,
-                entryKey = it.key,
-                entrySubkey = it.subkey,
-                pendingIntent = credentialEntry.pendingIntent,
-                fillInIntent = it.frameworkExtrasIntent,
-                credentialType = credentialEntry.type.toString(),
-                credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(),
-                userName = credentialEntry.username.toString(),
-                displayName = credentialEntry.displayName?.toString(),
-                // TODO: proper fallback
-                icon = credentialEntry.icon?.loadDrawable(context),
-                lastUsedTimeMillis = credentialEntry.lastUsedTimeMillis,
-        )
-      }
-    }
+                // Consider directly move the UI object into the class.
+                return@map CredentialEntryInfo(
+                    providerId = providerId,
+                    entryKey = it.key,
+                    entrySubkey = it.subkey,
+                    pendingIntent = credentialEntry.pendingIntent,
+                    fillInIntent = it.frameworkExtrasIntent,
+                    credentialType = credentialEntry.type,
+                    credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(),
+                    userName = credentialEntry.username.toString(),
+                    displayName = credentialEntry.displayName?.toString(),
+                    // TODO: proper fallback
+                    icon = credentialEntry.icon?.loadDrawable(context),
+                    lastUsedTimeMillis = credentialEntry.lastUsedTimeMillis,
+                )
+            }
+        }
 
-    private fun getAuthenticationEntry(
+        private fun getAuthenticationEntry(
             providerId: String,
             providerDisplayName: String,
             providerIcon: Drawable,
             authEntry: Entry?,
-    ): AuthenticationEntryInfo? {
-      if (authEntry == null) {
-        return null
-      }
-      val authStructuredEntry = AuthenticationAction.fromSlice(
-              authEntry!!.slice)
-      if (authStructuredEntry == null) {
-        return null
-      }
+        ): AuthenticationEntryInfo? {
+            if (authEntry == null) {
+                return null
+            }
+            val authStructuredEntry = AuthenticationAction.fromSlice(
+                authEntry!!.slice
+            )
+            if (authStructuredEntry == null) {
+                return null
+            }
 
-      return AuthenticationEntryInfo(
-              providerId = providerId,
-              entryKey = authEntry.key,
-              entrySubkey = authEntry.subkey,
-              pendingIntent = authStructuredEntry.pendingIntent,
-              fillInIntent = authEntry.frameworkExtrasIntent,
-              title = providerDisplayName,
-              icon = providerIcon,
-      )
-    }
+            return AuthenticationEntryInfo(
+                providerId = providerId,
+                entryKey = authEntry.key,
+                entrySubkey = authEntry.subkey,
+                pendingIntent = authStructuredEntry.pendingIntent,
+                fillInIntent = authEntry.frameworkExtrasIntent,
+                title = providerDisplayName,
+                icon = providerIcon,
+            )
+        }
 
-    private fun getRemoteEntry(providerId: String, remoteEntry: Entry?): RemoteEntryInfo? {
-      // TODO: should also call fromSlice after getting the official jetpack code.
-      if (remoteEntry == null) {
-        return null
-      }
-      return RemoteEntryInfo(
-              providerId = providerId,
-              entryKey = remoteEntry.key,
-              entrySubkey = remoteEntry.subkey,
-              pendingIntent = remoteEntry.pendingIntent,
-              fillInIntent = remoteEntry.frameworkExtrasIntent,
-      )
-    }
+        private fun getRemoteEntry(providerId: String, remoteEntry: Entry?): RemoteEntryInfo? {
+            // TODO: should also call fromSlice after getting the official jetpack code.
+            if (remoteEntry == null) {
+                return null
+            }
+            return RemoteEntryInfo(
+                providerId = providerId,
+                entryKey = remoteEntry.key,
+                entrySubkey = remoteEntry.subkey,
+                pendingIntent = remoteEntry.pendingIntent,
+                fillInIntent = remoteEntry.frameworkExtrasIntent,
+            )
+        }
 
-    private fun getActionEntryList(
+        private fun getActionEntryList(
             providerId: String,
             actionEntries: List<Entry>,
             providerIcon: Drawable,
-    ): List<ActionEntryInfo> {
-      return actionEntries.map {
-        // TODO: handle NPE gracefully
-        val actionEntryUi = Action.fromSlice(it.slice)!!
+        ): List<ActionEntryInfo> {
+            return actionEntries.map {
+                // TODO: handle NPE gracefully
+                val actionEntryUi = Action.fromSlice(it.slice)!!
 
-        return@map ActionEntryInfo(
-                providerId = providerId,
-                entryKey = it.key,
-                entrySubkey = it.subkey,
-                pendingIntent = actionEntryUi.pendingIntent,
-                fillInIntent = it.frameworkExtrasIntent,
-                title = actionEntryUi.title.toString(),
-                // TODO: gracefully fail
-                icon = providerIcon,
-                subTitle = actionEntryUi.subTitle?.toString(),
-        )
-      }
+                return@map ActionEntryInfo(
+                    providerId = providerId,
+                    entryKey = it.key,
+                    entrySubkey = it.subkey,
+                    pendingIntent = actionEntryUi.pendingIntent,
+                    fillInIntent = it.frameworkExtrasIntent,
+                    title = actionEntryUi.title.toString(),
+                    // TODO: gracefully fail
+                    icon = providerIcon,
+                    subTitle = actionEntryUi.subTitle?.toString(),
+                )
+            }
+        }
     }
-  }
 }
 
 class CreateFlowUtils {
-  companion object {
-
-    fun toEnabledProviderList(
+    companion object {
+        // Returns the list (potentially empty) of enabled provider.
+        fun toEnabledProviderList(
             providerDataList: List<CreateCredentialProviderData>,
             context: Context,
-    ): List<EnabledProviderInfo> {
-      // TODO: get from the actual service info
-      val packageManager = context.packageManager
-
-      return providerDataList.map {
-        val componentName = ComponentName.unflattenFromString(it.providerFlattenedComponentName)
-        var packageName = componentName?.packageName
-        if (componentName == null) {
-          // TODO: Remove once test data is fixed
-          packageName = it.providerFlattenedComponentName
+        ): List<EnabledProviderInfo> {
+            val providerList: MutableList<EnabledProviderInfo> = mutableListOf()
+            providerDataList.forEach {
+                val providerLabelAndIcon = getServiceLabelAndIcon(
+                    context.packageManager,
+                    it.providerFlattenedComponentName
+                ) ?: return@forEach
+                val (providerLabel, providerIcon) = providerLabelAndIcon
+                providerList.add(EnabledProviderInfo(
+                    id = it.providerFlattenedComponentName,
+                    displayName = providerLabel,
+                    icon = providerIcon,
+                    createOptions = toCreationOptionInfoList(
+                        it.providerFlattenedComponentName, it.saveEntries, context
+                    ),
+                    remoteEntry = toRemoteInfo(it.providerFlattenedComponentName, it.remoteEntry),
+                ))
+            }
+            return providerList
         }
 
-        val pkgInfo = packageManager
-                .getPackageInfo(packageName!!,
-                        PackageManager.PackageInfoFlags.of(0))
-        EnabledProviderInfo(
-                // TODO: decide what to do when failed to load a provider icon
-                icon = pkgInfo.applicationInfo.loadIcon(packageManager)!!,
-                name = it.providerFlattenedComponentName,
-                displayName = pkgInfo.applicationInfo.loadLabel(packageManager).toString(),
-                createOptions = toCreationOptionInfoList(
-                        it.providerFlattenedComponentName, it.saveEntries, context),
-                remoteEntry = toRemoteInfo(it.providerFlattenedComponentName, it.remoteEntry),
-        )
-      }
-    }
-
-    fun toDisabledProviderList(
+        // Returns the list (potentially empty) of disabled provider.
+        fun toDisabledProviderList(
             providerDataList: List<DisabledProviderData>?,
             context: Context,
-    ): List<DisabledProviderInfo>? {
-      // TODO: get from the actual service info
-      val packageManager = context.packageManager
-      return providerDataList?.map {
-        val componentName = ComponentName.unflattenFromString(it.providerFlattenedComponentName)
-        var packageName = componentName?.packageName
-        if (componentName == null) {
-          // TODO: Remove once test data is fixed
-          packageName = it.providerFlattenedComponentName
+        ): List<DisabledProviderInfo> {
+            val providerList: MutableList<DisabledProviderInfo> = mutableListOf()
+            providerDataList?.forEach {
+                val providerLabelAndIcon = getServiceLabelAndIcon(
+                    context.packageManager,
+                    it.providerFlattenedComponentName
+                ) ?: return@forEach
+                val (providerLabel, providerIcon) = providerLabelAndIcon
+                providerList.add(DisabledProviderInfo(
+                    icon = providerIcon,
+                    id = it.providerFlattenedComponentName,
+                    displayName = providerLabel,
+                ))
+            }
+            return providerList
         }
-        val pkgInfo = packageManager
-                .getPackageInfo(packageName!!,
-                        PackageManager.PackageInfoFlags.of(0))
-        DisabledProviderInfo(
-                icon = pkgInfo.applicationInfo.loadIcon(packageManager)!!,
-                name = it.providerFlattenedComponentName,
-                displayName = pkgInfo.applicationInfo.loadLabel(packageManager).toString(),
-        )
-      }
-    }
 
-    fun toRequestDisplayInfo(
+        fun toRequestDisplayInfo(
             requestInfo: RequestInfo,
             context: Context,
-    ): RequestDisplayInfo {
-      val packageName = requestInfo.appPackageName
-      val pkgInfo = context.packageManager.getPackageInfo(packageName,
-            PackageManager.PackageInfoFlags.of(0))
-      val appLabel = pkgInfo.applicationInfo.loadSafeLabel(context.packageManager, 0f,
-            TextUtils.SAFE_STRING_FLAG_FIRST_LINE or TextUtils.SAFE_STRING_FLAG_TRIM)
-      val createCredentialRequest = requestInfo.createCredentialRequest
-      val createCredentialRequestJetpack = createCredentialRequest?.let {
-        CreateCredentialRequest.createFrom(
-                it.type, it.credentialData, it.candidateQueryData, it.isSystemProviderRequired()
-        )
-      }
-      when (createCredentialRequestJetpack) {
-        is CreatePasswordRequest -> {
-          return RequestDisplayInfo(
-                  createCredentialRequestJetpack.id,
-                  createCredentialRequestJetpack.password,
-                  createCredentialRequestJetpack.type,
-                  appLabel.toString(),
-                  context.getDrawable(R.drawable.ic_password)!!
-          )
+        ): RequestDisplayInfo? {
+            val appLabel = getAppLabel(context.packageManager, requestInfo.appPackageName)
+                ?: return null
+            val createCredentialRequest = requestInfo.createCredentialRequest
+            val createCredentialRequestJetpack = createCredentialRequest?.let {
+                CreateCredentialRequest.createFrom(
+                    it.type, it.credentialData, it.candidateQueryData, it.isSystemProviderRequired
+                )
+            }
+            when (createCredentialRequestJetpack) {
+                is CreatePasswordRequest -> {
+                    return RequestDisplayInfo(
+                        createCredentialRequestJetpack.id,
+                        createCredentialRequestJetpack.password,
+                        createCredentialRequestJetpack.type,
+                        appLabel,
+                        context.getDrawable(R.drawable.ic_password)!!
+                    )
+                }
+                is CreatePublicKeyCredentialRequest -> {
+                    val requestJson = createCredentialRequestJetpack.requestJson
+                    val json = JSONObject(requestJson)
+                    var name = ""
+                    var displayName = ""
+                    if (json.has("user")) {
+                        val user: JSONObject = json.getJSONObject("user")
+                        name = user.getString("name")
+                        displayName = user.getString("displayName")
+                    }
+                    return RequestDisplayInfo(
+                        name,
+                        displayName,
+                        createCredentialRequestJetpack.type,
+                        appLabel,
+                        context.getDrawable(R.drawable.ic_passkey)!!
+                    )
+                }
+                // TODO: correctly parsing for other sign-ins
+                else -> {
+                    return RequestDisplayInfo(
+                        "beckett-bakert@gmail.com",
+                        "Elisa Beckett",
+                        "other-sign-ins",
+                        appLabel.toString(),
+                        context.getDrawable(R.drawable.ic_other_sign_in)!!
+                    )
+                }
+            }
         }
-        is CreatePublicKeyCredentialRequest -> {
-          val requestJson = createCredentialRequestJetpack.requestJson
-          val json = JSONObject(requestJson)
-          var name = ""
-          var displayName = ""
-          if (json.has("user")) {
-            val user: JSONObject = json.getJSONObject("user")
-            name = user.getString("name")
-            displayName = user.getString("displayName")
-          }
-          return RequestDisplayInfo(
-                  name,
-                  displayName,
-                  createCredentialRequestJetpack.type,
-                  appLabel.toString(),
-                  context.getDrawable(R.drawable.ic_passkey)!!)
-        }
-        // TODO: correctly parsing for other sign-ins
-        else -> {
-          return RequestDisplayInfo(
-                  "beckett-bakert@gmail.com",
-                  "Elisa Beckett",
-                  "other-sign-ins",
-                  appLabel.toString(),
-                  context.getDrawable(R.drawable.ic_other_sign_in)!!)
-        }
-      }
-    }
 
-    fun toCreateCredentialUiState(
+        fun toCreateCredentialUiState(
             enabledProviders: List<EnabledProviderInfo>,
             disabledProviders: List<DisabledProviderInfo>?,
             defaultProviderId: String?,
             requestDisplayInfo: RequestDisplayInfo,
             isOnPasskeyIntroStateAlready: Boolean,
             isPasskeyFirstUse: Boolean,
-    ): CreateCredentialUiState {
-      var lastSeenProviderWithNonEmptyCreateOptions: EnabledProviderInfo? = null
-      var remoteEntry: RemoteInfo? = null
-      var defaultProvider: EnabledProviderInfo? = null
-      var createOptionsPairs:
-              MutableList<Pair<CreateOptionInfo, EnabledProviderInfo>> = mutableListOf()
-      enabledProviders.forEach {
-        enabledProvider ->
-        if (defaultProviderId != null) {
-          if (enabledProvider.id == defaultProviderId) {
-            defaultProvider = enabledProvider
-          }
+        ): CreateCredentialUiState? {
+            var lastSeenProviderWithNonEmptyCreateOptions: EnabledProviderInfo? = null
+            var remoteEntry: RemoteInfo? = null
+            var defaultProvider: EnabledProviderInfo? = null
+            var createOptionsPairs:
+                MutableList<Pair<CreateOptionInfo, EnabledProviderInfo>> = mutableListOf()
+            enabledProviders.forEach { enabledProvider ->
+                if (defaultProviderId != null) {
+                    if (enabledProvider.id == defaultProviderId) {
+                        defaultProvider = enabledProvider
+                    }
+                }
+                if (enabledProvider.createOptions.isNotEmpty()) {
+                    lastSeenProviderWithNonEmptyCreateOptions = enabledProvider
+                    enabledProvider.createOptions.forEach {
+                        createOptionsPairs.add(Pair(it, enabledProvider))
+                    }
+                }
+                if (enabledProvider.remoteEntry != null) {
+                    remoteEntry = enabledProvider.remoteEntry!!
+                }
+            }
+            val initialScreenState = toCreateScreenState(
+                /*createOptionSize=*/createOptionsPairs.size,
+                /*isOnPasskeyIntroStateAlready=*/isOnPasskeyIntroStateAlready,
+                /*requestDisplayInfo=*/requestDisplayInfo,
+                /*defaultProvider=*/defaultProvider, /*remoteEntry=*/remoteEntry,
+                /*isPasskeyFirstUse=*/isPasskeyFirstUse
+            )
+            if (initialScreenState == null) {
+                return null
+            }
+            return CreateCredentialUiState(
+                enabledProviders = enabledProviders,
+                disabledProviders = disabledProviders,
+                currentScreenState = initialScreenState,
+                requestDisplayInfo = requestDisplayInfo,
+                sortedCreateOptionsPairs = createOptionsPairs.sortedWith(
+                    compareByDescending { it.first.lastUsedTimeMillis }
+                ),
+                hasDefaultProvider = defaultProvider != null,
+                activeEntry = toActiveEntry(
+                    /*defaultProvider=*/defaultProvider,
+                    /*createOptionSize=*/createOptionsPairs.size,
+                    /*lastSeenProviderWithNonEmptyCreateOptions=*/
+                    lastSeenProviderWithNonEmptyCreateOptions,
+                    /*remoteEntry=*/remoteEntry
+                ),
+            )
         }
-        if (enabledProvider.createOptions.isNotEmpty()) {
-          lastSeenProviderWithNonEmptyCreateOptions = enabledProvider
-          enabledProvider.createOptions.forEach {
-            createOptionsPairs.add(Pair(it, enabledProvider))
-          }
-        }
-        if (enabledProvider.remoteEntry != null) {
-          remoteEntry = enabledProvider.remoteEntry!!
-        }
-      }
-      return CreateCredentialUiState(
-              enabledProviders = enabledProviders,
-              disabledProviders = disabledProviders,
-              toCreateScreenState(
-                      /*createOptionSize=*/createOptionsPairs.size,
-          /*isOnPasskeyIntroStateAlready=*/isOnPasskeyIntroStateAlready,
-          /*requestDisplayInfo=*/requestDisplayInfo,
-          /*defaultProvider=*/defaultProvider, /*remoteEntry=*/remoteEntry,
-          /*isPasskeyFirstUse=*/isPasskeyFirstUse),
-        requestDisplayInfo,
-        createOptionsPairs.sortedWith(compareByDescending{ it.first.lastUsedTimeMillis }),
-        defaultProvider != null,
-        toActiveEntry(
-          /*defaultProvider=*/defaultProvider,
-          /*createOptionSize=*/createOptionsPairs.size,
-                      /*lastSeenProviderWithNonEmptyCreateOptions=*/
-                      lastSeenProviderWithNonEmptyCreateOptions,
-                      /*remoteEntry=*/remoteEntry),
-      )
-    }
 
-    private fun toCreateScreenState(
+        private fun toCreateScreenState(
             createOptionSize: Int,
             isOnPasskeyIntroStateAlready: Boolean,
             requestDisplayInfo: RequestDisplayInfo,
             defaultProvider: EnabledProviderInfo?,
             remoteEntry: RemoteInfo?,
             isPasskeyFirstUse: Boolean,
-    ): CreateScreenState {
-      return if (
-              isPasskeyFirstUse && requestDisplayInfo
-                      .type == TYPE_PUBLIC_KEY_CREDENTIAL && !isOnPasskeyIntroStateAlready) {
-        CreateScreenState.PASSKEY_INTRO
-      } else if (
-              (defaultProvider == null || defaultProvider.createOptions.isEmpty()
-                      ) && createOptionSize > 1) {
-        CreateScreenState.PROVIDER_SELECTION
-      } else if (
-              ((defaultProvider == null || defaultProvider.createOptions.isEmpty()
-                      ) && createOptionSize == 1) || (
-                      defaultProvider != null && defaultProvider.createOptions.isNotEmpty())) {
-        CreateScreenState.CREATION_OPTION_SELECTION
-      } else if (createOptionSize == 0 && remoteEntry != null) {
-        CreateScreenState.EXTERNAL_ONLY_SELECTION
-      } else {
-        // TODO: properly handle error and gracefully finish itself
-        throw java.lang.IllegalStateException("Empty provider list.")
-      }
-    }
+        ): CreateScreenState? {
+            return if (isPasskeyFirstUse && requestDisplayInfo.type ==
+                TYPE_PUBLIC_KEY_CREDENTIAL && !isOnPasskeyIntroStateAlready) {
+                CreateScreenState.PASSKEY_INTRO
+            } else if ((defaultProvider == null || defaultProvider.createOptions.isEmpty()) &&
+                createOptionSize > 1) {
+                CreateScreenState.PROVIDER_SELECTION
+            } else if (((defaultProvider == null || defaultProvider.createOptions.isEmpty()) &&
+                    createOptionSize == 1) || (defaultProvider != null &&
+                    defaultProvider.createOptions.isNotEmpty())) {
+                CreateScreenState.CREATION_OPTION_SELECTION
+            } else if (createOptionSize == 0 && remoteEntry != null) {
+                CreateScreenState.EXTERNAL_ONLY_SELECTION
+            } else {
+                Log.d(
+                    Constants.LOG_TAG,
+                    "Unexpected failure: the screen state failed to instantiate" +
+                        " because the provider list is empty."
+                )
+                null
+            }
+        }
 
-    private fun toActiveEntry(
+        private fun toActiveEntry(
             defaultProvider: EnabledProviderInfo?,
             createOptionSize: Int,
             lastSeenProviderWithNonEmptyCreateOptions: EnabledProviderInfo?,
             remoteEntry: RemoteInfo?,
-    ): ActiveEntry? {
-      return if (
-              defaultProvider != null && defaultProvider.createOptions.isEmpty() &&
-              remoteEntry != null) {
-        ActiveEntry(defaultProvider, remoteEntry)
-      } else if (
-              defaultProvider != null && defaultProvider.createOptions.isNotEmpty()
-      ) {
-        ActiveEntry(defaultProvider, defaultProvider.createOptions.first())
-      } else if (createOptionSize == 1) {
-        ActiveEntry(lastSeenProviderWithNonEmptyCreateOptions!!,
-                lastSeenProviderWithNonEmptyCreateOptions.createOptions.first())
-      } else null
-    }
+        ): ActiveEntry? {
+            return if (
+                defaultProvider != null && defaultProvider.createOptions.isEmpty() &&
+                remoteEntry != null
+            ) {
+                ActiveEntry(defaultProvider, remoteEntry)
+            } else if (
+                defaultProvider != null && defaultProvider.createOptions.isNotEmpty()
+            ) {
+                ActiveEntry(defaultProvider, defaultProvider.createOptions.first())
+            } else if (createOptionSize == 1) {
+                ActiveEntry(
+                    lastSeenProviderWithNonEmptyCreateOptions!!,
+                    lastSeenProviderWithNonEmptyCreateOptions.createOptions.first()
+                )
+            } else null
+        }
 
-    private fun toCreationOptionInfoList(
+        private fun toCreationOptionInfoList(
             providerId: String,
             creationEntries: List<Entry>,
             context: Context,
-    ): List<CreateOptionInfo> {
-      return creationEntries.map {
-        // TODO: handle NPE gracefully
-        val createEntry = CreateEntry.fromSlice(it.slice)!!
+        ): List<CreateOptionInfo> {
+            return creationEntries.map {
+                // TODO: handle NPE gracefully
+                val createEntry = CreateEntry.fromSlice(it.slice)!!
 
-        return@map CreateOptionInfo(
-                // TODO: remove fallbacks
-                providerId = providerId,
-                entryKey = it.key,
-                entrySubkey = it.subkey,
-                pendingIntent = createEntry.pendingIntent,
-                fillInIntent = it.frameworkExtrasIntent,
-                userProviderDisplayName = createEntry.accountName.toString(),
-                profileIcon = createEntry.icon?.loadDrawable(context),
-                passwordCount = CredentialCountInformation.getPasswordCount(
-                        createEntry.credentialCountInformationList) ?: 0,
-                passkeyCount = CredentialCountInformation.getPasskeyCount(
-                        createEntry.credentialCountInformationList) ?: 0,
-                totalCredentialCount = CredentialCountInformation.getTotalCount(
-                        createEntry.credentialCountInformationList) ?: 0,
-                lastUsedTimeMillis = createEntry.lastUsedTimeMillis ?: 0,
-                footerDescription = createEntry.footerDescription?.toString()
-        )
-      }
-    }
+                return@map CreateOptionInfo(
+                    // TODO: remove fallbacks
+                    providerId = providerId,
+                    entryKey = it.key,
+                    entrySubkey = it.subkey,
+                    pendingIntent = createEntry.pendingIntent,
+                    fillInIntent = it.frameworkExtrasIntent,
+                    userProviderDisplayName = createEntry.accountName.toString(),
+                    profileIcon = createEntry.icon?.loadDrawable(context),
+                    passwordCount = CredentialCountInformation.getPasswordCount(
+                        createEntry.credentialCountInformationList
+                    ) ?: 0,
+                    passkeyCount = CredentialCountInformation.getPasskeyCount(
+                        createEntry.credentialCountInformationList
+                    ) ?: 0,
+                    totalCredentialCount = CredentialCountInformation.getTotalCount(
+                        createEntry.credentialCountInformationList
+                    ) ?: 0,
+                    lastUsedTimeMillis = createEntry.lastUsedTimeMillis ?: 0,
+                    footerDescription = createEntry.footerDescription?.toString()
+                )
+            }
+        }
 
-    private fun toRemoteInfo(
+        private fun toRemoteInfo(
             providerId: String,
             remoteEntry: Entry?,
-    ): RemoteInfo? {
-      // TODO: should also call fromSlice after getting the official jetpack code.
-      return if (remoteEntry != null) {
-        RemoteInfo(
-                providerId = providerId,
-                entryKey = remoteEntry.key,
-                entrySubkey = remoteEntry.subkey,
-                pendingIntent = remoteEntry.pendingIntent,
-                fillInIntent = remoteEntry.frameworkExtrasIntent,
-        )
-      } else null
+        ): RemoteInfo? {
+            // TODO: should also call fromSlice after getting the official jetpack code.
+            return if (remoteEntry != null) {
+                RemoteInfo(
+                    providerId = providerId,
+                    entryKey = remoteEntry.key,
+                    entrySubkey = remoteEntry.subkey,
+                    pendingIntent = remoteEntry.pendingIntent,
+                    fillInIntent = remoteEntry.frameworkExtrasIntent,
+                )
+            } else null
+        }
     }
-  }
 }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/Constants.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/Constants.kt
new file mode 100644
index 0000000..37e21a8
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/Constants.kt
@@ -0,0 +1,23 @@
+/*
+ * 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
+
+class Constants {
+    companion object Constants {
+        const val LOG_TAG = "CredentialSelector"
+    }
+}
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt
index d3cf241..01318b1 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt
@@ -25,6 +25,7 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
 import androidx.lifecycle.ViewModel
+import com.android.credentialmanager.common.Constants
 import com.android.credentialmanager.CreateFlowUtils
 import com.android.credentialmanager.CredentialManagerRepo
 import com.android.credentialmanager.UserConfigRepo
@@ -32,35 +33,16 @@
 import com.android.credentialmanager.common.ProviderActivityResult
 import com.android.credentialmanager.common.ProviderActivityState
 
-data class CreateCredentialUiState(
-    val enabledProviders: List<EnabledProviderInfo>,
-    val disabledProviders: List<DisabledProviderInfo>? = null,
-    val currentScreenState: CreateScreenState,
-    val requestDisplayInfo: RequestDisplayInfo,
-    val sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
-    // Should not change with the real time update of default provider, only determine whether
-    // we're showing provider selection page at the beginning
-    val hasDefaultProvider: Boolean,
-    val activeEntry: ActiveEntry? = null,
-    val selectedEntry: EntryInfo? = null,
-    val providerActivityState: ProviderActivityState =
-        ProviderActivityState.NOT_APPLICABLE,
-    val isFromProviderSelection: Boolean? = null,
-    val dialogState: DialogState = DialogState.ACTIVE,
-)
 
 class CreateCredentialViewModel(
     private val credManRepo: CredentialManagerRepo,
+    private val providerEnableListUiState: List<EnabledProviderInfo>,
+    private val providerDisableListUiState: List<DisabledProviderInfo>,
+    private val requestDisplayInfoUiState: RequestDisplayInfo,
     userConfigRepo: UserConfigRepo = UserConfigRepo.getInstance(),
 ) : ViewModel() {
-    val providerEnableListUiState = credManRepo.getCreateProviderEnableListInitialUiState()
-
-    val providerDisableListUiState = credManRepo.getCreateProviderDisableListInitialUiState()
-
-    val requestDisplayInfoUiState = credManRepo.getCreateRequestDisplayInfoInitialUiState()
 
     val defaultProviderId = userConfigRepo.getDefaultProviderId()
-
     val isPasskeyFirstUse = userConfigRepo.getIsPasskeyFirstUse()
 
     var uiState by mutableStateOf(
@@ -70,13 +52,18 @@
             defaultProviderId,
             requestDisplayInfoUiState,
             false,
-            isPasskeyFirstUse))
+            isPasskeyFirstUse)!!)
         private set
 
     fun onConfirmIntro() {
-        uiState = CreateFlowUtils.toCreateCredentialUiState(
+        val newUiState = CreateFlowUtils.toCreateCredentialUiState(
             providerEnableListUiState, providerDisableListUiState, defaultProviderId,
             requestDisplayInfoUiState, true, isPasskeyFirstUse)
+        if (newUiState == null) {
+            onInternalError()
+            return
+        }
+        uiState = newUiState
         UserConfigRepo.getInstance().setIsPasskeyFirstUse(false)
     }
 
@@ -143,6 +130,14 @@
         uiState = uiState.copy(dialogState = DialogState.CANCELED_FOR_SETTINGS)
     }
 
+    // When the view model runs into unexpected illegal state, reports the error back and close
+    // the activity gracefully.
+    private fun onInternalError() {
+        Log.w(Constants.LOG_TAG, "UI closed due to illegal internal state")
+        credManRepo.onParsingFailureCancel()
+        uiState = uiState.copy(dialogState = DialogState.COMPLETE)
+    }
+
     fun onCancel() {
         credManRepo.onUserCancel()
         uiState = uiState.copy(dialogState = DialogState.COMPLETE)
@@ -171,11 +166,11 @@
     fun onDefaultChanged(providerId: String?) {
         if (providerId != null) {
             Log.d(
-                "Account Selector", "Default provider changed to: " +
+                Constants.LOG_TAG, "Default provider changed to: " +
                 " {provider=$providerId")
             UserConfigRepo.getInstance().setDefaultProvider(providerId)
         } else {
-            Log.w("Account Selector", "Null provider is being changed")
+            Log.w(Constants.LOG_TAG, "Null provider is being changed")
         }
     }
 
@@ -184,7 +179,7 @@
         val entryKey = selectedEntry.entryKey
         val entrySubkey = selectedEntry.entrySubkey
         Log.d(
-            "Account Selector", "Option selected for entry: " +
+            Constants.LOG_TAG, "Option selected for entry: " +
             " {provider=$providerId, key=$entryKey, subkey=$entrySubkey")
         if (selectedEntry.pendingIntent != null) {
             uiState = uiState.copy(
@@ -211,7 +206,8 @@
                 .setFillInIntent(entry.fillInIntent).build()
             launcher.launch(intentSenderRequest)
         } else {
-            Log.w("Account Selector", "No provider UI to launch")
+            Log.d(Constants.LOG_TAG, "Unexpected: no provider UI to launch")
+            onInternalError()
         }
     }
 
@@ -220,9 +216,9 @@
         if (selectedEntry != null) {
             onEntrySelected(selectedEntry)
         } else {
-            Log.w("Account Selector",
-                "Illegal state: confirm is pressed but activeEntry isn't set.")
-            uiState = uiState.copy(dialogState = DialogState.COMPLETE)
+            Log.d(Constants.LOG_TAG,
+                "Unexpected: confirm is pressed but no active entry exists.")
+            onInternalError()
         }
     }
 
@@ -232,7 +228,7 @@
         val resultData = providerActivityResult.data
         if (resultCode == Activity.RESULT_CANCELED) {
             // Re-display the CredMan UI if the user canceled from the provider UI.
-            Log.d("Account Selector", "The provider activity was cancelled," +
+            Log.d(Constants.LOG_TAG, "The provider activity was cancelled," +
                 " re-displaying our UI.")
             uiState = uiState.copy(
                 selectedEntry = null,
@@ -241,18 +237,44 @@
         } else {
             if (entry != null) {
                 val providerId = entry.providerId
-                Log.d("Account Selector", "Got provider activity result: {provider=" +
+                Log.d(Constants.LOG_TAG, "Got provider activity result: {provider=" +
                     "$providerId, key=${entry.entryKey}, subkey=${entry.entrySubkey}, " +
                     "resultCode=$resultCode, resultData=$resultData}"
                 )
                 credManRepo.onOptionSelected(
                     providerId, entry.entryKey, entry.entrySubkey, resultCode, resultData,
                 )
+                uiState = uiState.copy(dialogState = DialogState.COMPLETE)
             } else {
-                Log.w("Account Selector",
+                Log.d(Constants.LOG_TAG,
                     "Illegal state: received a provider result but found no matching entry.")
+                onInternalError()
             }
-            uiState = uiState.copy(dialogState = DialogState.COMPLETE)
+        }
+    }
+
+    companion object Factory {
+        // Validates the input and returns null if the input is invalid.
+        fun newInstance(
+            credManRepo: CredentialManagerRepo,
+            providerEnableListUiState: List<EnabledProviderInfo>,
+            providerDisableListUiState: List<DisabledProviderInfo>,
+            requestDisplayInfoUiState: RequestDisplayInfo?,
+        ): CreateCredentialViewModel? {
+            if (providerEnableListUiState.isEmpty() || requestDisplayInfoUiState == null) {
+                return null
+            }
+            return try {
+                val result = CreateCredentialViewModel(
+                    credManRepo = credManRepo,
+                    providerEnableListUiState = providerEnableListUiState,
+                    providerDisableListUiState = providerDisableListUiState,
+                    requestDisplayInfoUiState = requestDisplayInfoUiState
+                )
+                result
+            } catch (e: Exception) {
+                null
+            }
         }
     }
 }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
index 957488f..12a5085 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
@@ -19,6 +19,25 @@
 import android.app.PendingIntent
 import android.content.Intent
 import android.graphics.drawable.Drawable
+import com.android.credentialmanager.common.DialogState
+import com.android.credentialmanager.common.ProviderActivityState
+
+data class CreateCredentialUiState(
+  val enabledProviders: List<EnabledProviderInfo>,
+  val disabledProviders: List<DisabledProviderInfo>? = null,
+  val currentScreenState: CreateScreenState,
+  val requestDisplayInfo: RequestDisplayInfo,
+  val sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
+  // Should not change with the real time update of default provider, only determine whether
+  // we're showing provider selection page at the beginning
+  val hasDefaultProvider: Boolean,
+  val activeEntry: ActiveEntry? = null,
+  val selectedEntry: EntryInfo? = null,
+  val providerActivityState: ProviderActivityState =
+    ProviderActivityState.NOT_APPLICABLE,
+  val isFromProviderSelection: Boolean? = null,
+  val dialogState: DialogState = DialogState.ACTIVE,
+)
 
 open class ProviderInfo(
   val icon: Drawable,
@@ -28,17 +47,17 @@
 
 class EnabledProviderInfo(
   icon: Drawable,
-  name: String,
+  id: String,
   displayName: String,
   var createOptions: List<CreateOptionInfo>,
   var remoteEntry: RemoteInfo?,
-) : ProviderInfo(icon, name, displayName)
+) : ProviderInfo(icon, id, displayName)
 
 class DisabledProviderInfo(
   icon: Drawable,
-  name: String,
+  id: String,
   displayName: String,
-) : ProviderInfo(icon, name, displayName)
+) : ProviderInfo(icon, id, displayName)
 
 open class EntryInfo (
   val providerId: String,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
index 065a2de..7d2f0da 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
@@ -26,6 +26,7 @@
 import androidx.compose.runtime.setValue
 import androidx.lifecycle.ViewModel
 import com.android.credentialmanager.CredentialManagerRepo
+import com.android.credentialmanager.common.Constants
 import com.android.credentialmanager.common.DialogState
 import com.android.credentialmanager.common.ProviderActivityResult
 import com.android.credentialmanager.common.ProviderActivityState
@@ -45,13 +46,16 @@
     val dialogState: DialogState = DialogState.ACTIVE,
 )
 
-class GetCredentialViewModel(private val credManRepo: CredentialManagerRepo) : ViewModel() {
+class GetCredentialViewModel(
+    private val credManRepo: CredentialManagerRepo,
+    initialUiState: GetCredentialUiState,
+) : ViewModel() {
 
-    var uiState by mutableStateOf(credManRepo.getCredentialInitialUiState())
+    var uiState by mutableStateOf(initialUiState)
         private set
 
     fun onEntrySelected(entry: EntryInfo) {
-        Log.d("Account Selector", "credential selected: {provider=${entry.providerId}" +
+        Log.d(Constants.LOG_TAG, "credential selected: {provider=${entry.providerId}" +
             ", key=${entry.entryKey}, subkey=${entry.entrySubkey}}")
         if (entry.pendingIntent != null) {
             uiState = uiState.copy(
@@ -69,9 +73,9 @@
         if (activeEntry != null) {
             onEntrySelected(activeEntry)
         } else {
-            Log.w("Account Selector",
+            Log.d(Constants.LOG_TAG,
                 "Illegal state: confirm is pressed but activeEntry isn't set.")
-            uiState = uiState.copy(dialogState = DialogState.COMPLETE)
+            onInternalError()
         }
     }
 
@@ -80,23 +84,32 @@
     ) {
         val entry = uiState.selectedEntry
         if (entry != null && entry.pendingIntent != null) {
-            Log.d("credentials", "Launching provider activity")
+            Log.d(Constants.LOG_TAG, "Launching provider activity")
             uiState = uiState.copy(providerActivityState = ProviderActivityState.PENDING)
             val intentSenderRequest = IntentSenderRequest.Builder(entry.pendingIntent)
                 .setFillInIntent(entry.fillInIntent).build()
             launcher.launch(intentSenderRequest)
         } else {
-            Log.w("Account Selector", "No provider UI to launch")
+            Log.d(Constants.LOG_TAG, "No provider UI to launch")
+            onInternalError()
         }
     }
 
+    // When the view model runs into unexpected illegal state, reports the error back and close
+    // the activity gracefully.
+    private fun onInternalError() {
+        Log.w(Constants.LOG_TAG, "UI closed due to illegal internal state")
+        credManRepo.onParsingFailureCancel()
+        uiState = uiState.copy(dialogState = DialogState.COMPLETE)
+    }
+
     fun onProviderActivityResult(providerActivityResult: ProviderActivityResult) {
         val entry = uiState.selectedEntry
         val resultCode = providerActivityResult.resultCode
         val resultData = providerActivityResult.data
         if (resultCode == Activity.RESULT_CANCELED) {
             // Re-display the CredMan UI if the user canceled from the provider UI.
-            Log.d("Account Selector", "The provider activity was cancelled," +
+            Log.d(Constants.LOG_TAG, "The provider activity was cancelled," +
                 " re-displaying our UI.")
             uiState = uiState.copy(
                 selectedEntry = null,
@@ -104,7 +117,8 @@
             )
         } else {
             if (entry != null) {
-                Log.d("Account Selector", "Got provider activity result: {provider=" +
+                Log.d(
+                    Constants.LOG_TAG, "Got provider activity result: {provider=" +
                     "${entry.providerId}, key=${entry.entryKey}, subkey=${entry.entrySubkey}" +
                     ", resultCode=$resultCode, resultData=$resultData}"
                 )
@@ -112,23 +126,24 @@
                     entry.providerId, entry.entryKey, entry.entrySubkey,
                     resultCode, resultData,
                 )
+                uiState = uiState.copy(dialogState = DialogState.COMPLETE)
             } else {
-                Log.w("Account Selector",
+                Log.w(Constants.LOG_TAG,
                     "Illegal state: received a provider result but found no matching entry.")
+                onInternalError()
             }
-            uiState = uiState.copy(dialogState = DialogState.COMPLETE)
         }
     }
 
     fun onMoreOptionSelected() {
-        Log.d("Account Selector", "More Option selected")
+        Log.d(Constants.LOG_TAG, "More Option selected")
         uiState = uiState.copy(
             currentScreenState = GetScreenState.ALL_SIGN_IN_OPTIONS
         )
     }
 
     fun onMoreOptionOnSnackBarSelected(isNoAccount: Boolean) {
-        Log.d("Account Selector", "More Option on snackBar selected")
+        Log.d(Constants.LOG_TAG, "More Option on snackBar selected")
         uiState = uiState.copy(
             currentScreenState = GetScreenState.ALL_SIGN_IN_OPTIONS,
             isNoAccount = isNoAccount,
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
index 4e96dda..cfc38df 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
@@ -33,8 +33,8 @@
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.LocalContentColor
-import androidx.compose.material3.LocalMinimumTouchTargetEnforcement
 import androidx.compose.material3.contentColorFor
+import androidx.compose.material3.minimumInteractiveComponentSize
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.DisposableEffect
@@ -65,21 +65,17 @@
 import androidx.compose.ui.graphics.drawscope.scale
 import androidx.compose.ui.layout.boundsInRoot
 import androidx.compose.ui.layout.findRootCoordinates
-import androidx.compose.ui.layout.layout
 import androidx.compose.ui.layout.onGloballyPositioned
 import androidx.compose.ui.platform.ComposeView
 import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.platform.LocalViewConfiguration
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.dp
 import androidx.lifecycle.ViewTreeLifecycleOwner
 import androidx.lifecycle.ViewTreeViewModelStoreOwner
-import com.android.compose.runtime.movableContentOf
 import com.android.systemui.animation.Expandable
 import com.android.systemui.animation.LaunchAnimator
 import kotlin.math.max
 import kotlin.math.min
-import kotlin.math.roundToInt
 
 /**
  * Create an expandable shape that can launch into an Activity or a Dialog.
@@ -220,21 +216,8 @@
     // If this expandable is expanded when it's being directly clicked on, let's ensure that it has
     // the minimum interactive size followed by all M3 components (48.dp).
     val minInteractiveSizeModifier =
-        if (onClick != null && LocalMinimumTouchTargetEnforcement.current) {
-            // TODO(b/242040009): Replace this by Modifier.minimumInteractiveComponentSize() once
-            // http://aosp/2305511 is available.
-            val minTouchSize = LocalViewConfiguration.current.minimumTouchTargetSize
-            Modifier.layout { measurable, constraints ->
-                // Copied from androidx.compose.material3.InteractiveComponentSize.kt
-                val placeable = measurable.measure(constraints)
-                val width = maxOf(placeable.width, minTouchSize.width.roundToPx())
-                val height = maxOf(placeable.height, minTouchSize.height.roundToPx())
-                layout(width, height) {
-                    val centerX = ((width - placeable.width) / 2f).roundToInt()
-                    val centerY = ((height - placeable.height) / 2f).roundToInt()
-                    placeable.place(centerX, centerY)
-                }
-            }
+        if (onClick != null) {
+            Modifier.minimumInteractiveComponentSize()
         } else {
             Modifier
         }
diff --git a/packages/SystemUI/docs/device-entry/quickaffordance.md b/packages/SystemUI/docs/device-entry/quickaffordance.md
index ccb35fa..79d5718 100644
--- a/packages/SystemUI/docs/device-entry/quickaffordance.md
+++ b/packages/SystemUI/docs/device-entry/quickaffordance.md
@@ -52,6 +52,10 @@
 * Unselect an already-selected quick affordance from a slot
 * Unselect all already-selected quick affordances from a slot
 
+## Testing
+* Add a unit test for your implementation of `KeyguardQuickAffordanceConfig`
+* Manually verify that your implementation works in multi-user environments from both the main user and a secondary user
+
 ## Debugging
 To see the current state of the system, you can run `dumpsys`:
 
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
index db88b59..314c736 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
@@ -171,7 +171,7 @@
             a1 = TonalSpec(HueSource(), ChromaConstant(36.0)),
             a2 = TonalSpec(HueSource(), ChromaConstant(16.0)),
             a3 = TonalSpec(HueAdd(60.0), ChromaConstant(24.0)),
-            n1 = TonalSpec(HueSource(), ChromaConstant(6.0)),
+            n1 = TonalSpec(HueSource(), ChromaConstant(4.0)),
             n2 = TonalSpec(HueSource(), ChromaConstant(8.0))
     )),
     VIBRANT(CoreSpec(
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index bc6e5ec..e0cc8f4 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -50,16 +50,24 @@
     String TAG = "BcSmartspaceDataPlugin";
 
     /** Register a listener to get Smartspace data. */
-    void registerListener(SmartspaceTargetListener listener);
+    default void registerListener(SmartspaceTargetListener listener) {
+        throw new UnsupportedOperationException("Not implemented by " + getClass());
+    }
 
     /** Unregister a listener. */
-    void unregisterListener(SmartspaceTargetListener listener);
+    default void unregisterListener(SmartspaceTargetListener listener) {
+        throw new UnsupportedOperationException("Not implemented by " + getClass());
+    }
 
     /** Register a SmartspaceEventNotifier. */
-    default void registerSmartspaceEventNotifier(SmartspaceEventNotifier notifier) {}
+    default void registerSmartspaceEventNotifier(SmartspaceEventNotifier notifier) {
+        throw new UnsupportedOperationException("Not implemented by " + getClass());
+    }
 
     /** Push a SmartspaceTargetEvent to the SmartspaceEventNotifier. */
-    default void notifySmartspaceEvent(SmartspaceTargetEvent event) {}
+    default void notifySmartspaceEvent(SmartspaceTargetEvent event) {
+        throw new UnsupportedOperationException("Not implemented by " + getClass());
+    }
 
     /** Allows for notifying the SmartspaceSession of SmartspaceTargetEvents. */
     interface SmartspaceEventNotifier {
@@ -72,16 +80,20 @@
      * will be responsible for correctly setting the LayoutParams
      */
     default SmartspaceView getView(ViewGroup parent) {
-        return null;
+        throw new UnsupportedOperationException("Not implemented by " + getClass());
     }
 
     /**
      * As the smartspace view becomes available, allow listeners to receive an event.
      */
-    default void addOnAttachStateChangeListener(View.OnAttachStateChangeListener listener) { }
+    default void addOnAttachStateChangeListener(View.OnAttachStateChangeListener listener) {
+        throw new UnsupportedOperationException("Not implemented by " + getClass());
+    }
 
     /** Updates Smartspace data and propagates it to any listeners. */
-    void onTargetsAvailable(List<SmartspaceTarget> targets);
+    default void onTargetsAvailable(List<SmartspaceTarget> targets) {
+        throw new UnsupportedOperationException("Not implemented by " + getClass());
+    }
 
     /** Provides Smartspace data to registered listeners. */
     interface SmartspaceTargetListener {
@@ -96,7 +108,9 @@
         /**
          * Sets {@link BcSmartspaceConfigPlugin}.
          */
-        void registerConfigProvider(BcSmartspaceConfigPlugin configProvider);
+        default void registerConfigProvider(BcSmartspaceConfigPlugin configProvider) {
+            throw new UnsupportedOperationException("Not implemented by " + getClass());
+        }
 
         /**
          * Primary color for unprotected text
@@ -138,28 +152,38 @@
         /**
          * Set or clear Do Not Disturb information.
          */
-        void setDnd(@Nullable Drawable image, @Nullable String description);
+        default void setDnd(@Nullable Drawable image, @Nullable String description) {
+            throw new UnsupportedOperationException("Not implemented by " + getClass());
+        }
 
         /**
          * Set or clear next alarm information
          */
-        void setNextAlarm(@Nullable Drawable image, @Nullable String description);
+        default void setNextAlarm(@Nullable Drawable image, @Nullable String description) {
+            throw new UnsupportedOperationException("Not implemented by " + getClass());
+        }
 
         /**
          * Set or clear device media playing
          */
-        void setMediaTarget(@Nullable SmartspaceTarget target);
+        default void setMediaTarget(@Nullable SmartspaceTarget target) {
+            throw new UnsupportedOperationException("Not implemented by " + getClass());
+        }
 
         /**
          * Get the index of the currently selected page.
          */
-        int getSelectedPage();
+        default int getSelectedPage() {
+            throw new UnsupportedOperationException("Not implemented by " + getClass());
+        }
 
         /**
          * Return the top padding value from the currently visible card, or 0 if there is no current
          * card.
          */
-        int getCurrentCardTopPadding();
+        default int getCurrentCardTopPadding() {
+            throw new UnsupportedOperationException("Not implemented by " + getClass());
+        }
     }
 
     /** Interface for launching Intents, which can differ on the lockscreen */
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
index 2cac9c7..90851e2 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
@@ -45,7 +45,7 @@
           android:id="@+id/user_switcher_header"
           android:textDirection="locale"
           android:layout_width="@dimen/bouncer_user_switcher_width"
-          android:layout_height="wrap_content" />
+          android:layout_height="match_parent" />
     </com.android.keyguard.KeyguardUserSwitcherAnchor>
 
 </LinearLayout>
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
index a1068c6..6c8db91 100644
--- a/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
@@ -25,9 +25,6 @@
     <!-- Margin around the various security views -->
     <dimen name="keyguard_security_view_top_margin">12dp</dimen>
 
-    <!-- Padding for the lock icon on the keyguard -->
-    <dimen name="lock_icon_padding">16dp</dimen>
-
     <!-- Overload default clock widget parameters -->
     <dimen name="widget_big_font_size">100dp</dimen>
     <dimen name="widget_label_font_size">18sp</dimen>
diff --git a/packages/SystemUI/res/layout/clipboard_overlay_legacy.xml b/packages/SystemUI/res/layout/clipboard_overlay_legacy.xml
deleted file mode 100644
index 1a1fc75..0000000
--- a/packages/SystemUI/res/layout/clipboard_overlay_legacy.xml
+++ /dev/null
@@ -1,160 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<com.android.systemui.screenshot.DraggableConstraintLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/clipboard_ui"
-    android:theme="@style/FloatingOverlay"
-    android:alpha="0"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:contentDescription="@string/clipboard_overlay_window_name">
-    <ImageView
-        android:id="@+id/actions_container_background"
-        android:visibility="gone"
-        android:layout_height="0dp"
-        android:layout_width="0dp"
-        android:elevation="4dp"
-        android:background="@drawable/action_chip_container_background"
-        android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
-        app:layout_constraintBottom_toBottomOf="@+id/actions_container"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="@+id/actions_container"
-        app:layout_constraintEnd_toEndOf="@+id/actions_container"/>
-    <HorizontalScrollView
-        android:id="@+id/actions_container"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal"
-        android:paddingEnd="@dimen/overlay_action_container_padding_right"
-        android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
-        android:elevation="4dp"
-        android:scrollbars="none"
-        android:layout_marginBottom="4dp"
-        app:layout_constraintHorizontal_bias="0"
-        app:layout_constraintWidth_percent="1.0"
-        app:layout_constraintWidth_max="wrap"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toEndOf="@+id/preview_border"
-        app:layout_constraintEnd_toEndOf="parent">
-        <LinearLayout
-            android:id="@+id/actions"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:animateLayoutChanges="true">
-            <include layout="@layout/overlay_action_chip"
-                     android:id="@+id/share_chip"/>
-            <include layout="@layout/overlay_action_chip"
-                     android:id="@+id/remote_copy_chip"/>
-            <include layout="@layout/overlay_action_chip"
-                     android:id="@+id/edit_chip"/>
-        </LinearLayout>
-    </HorizontalScrollView>
-    <View
-        android:id="@+id/preview_border"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_marginStart="@dimen/overlay_offset_x"
-        android:layout_marginBottom="12dp"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintBottom_toBottomOf="parent"
-        android:elevation="7dp"
-        app:layout_constraintEnd_toEndOf="@id/clipboard_preview_end"
-        app:layout_constraintTop_toTopOf="@id/clipboard_preview_top"
-        android:background="@drawable/overlay_border"/>
-    <androidx.constraintlayout.widget.Barrier
-        android:id="@+id/clipboard_preview_end"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        app:barrierMargin="@dimen/overlay_border_width"
-        app:barrierDirection="end"
-        app:constraint_referenced_ids="clipboard_preview"/>
-    <androidx.constraintlayout.widget.Barrier
-        android:id="@+id/clipboard_preview_top"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        app:barrierDirection="top"
-        app:barrierMargin="@dimen/overlay_border_width_neg"
-        app:constraint_referenced_ids="clipboard_preview"/>
-    <FrameLayout
-        android:id="@+id/clipboard_preview"
-        android:elevation="7dp"
-        android:background="@drawable/overlay_preview_background"
-        android:clipChildren="true"
-        android:clipToOutline="true"
-        android:clipToPadding="true"
-        android:layout_width="@dimen/clipboard_preview_size"
-        android:layout_margin="@dimen/overlay_border_width"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        app:layout_constraintBottom_toBottomOf="@id/preview_border"
-        app:layout_constraintStart_toStartOf="@id/preview_border"
-        app:layout_constraintEnd_toEndOf="@id/preview_border"
-        app:layout_constraintTop_toTopOf="@id/preview_border">
-        <TextView android:id="@+id/text_preview"
-                  android:textFontWeight="500"
-                  android:padding="8dp"
-                  android:gravity="center|start"
-                  android:ellipsize="end"
-                  android:autoSizeTextType="uniform"
-                  android:autoSizeMinTextSize="@dimen/clipboard_overlay_min_font"
-                  android:autoSizeMaxTextSize="@dimen/clipboard_overlay_max_font"
-                  android:textColor="?attr/overlayButtonTextColor"
-                  android:textColorLink="?attr/overlayButtonTextColor"
-                  android:background="?androidprv:attr/colorAccentSecondary"
-                  android:layout_width="@dimen/clipboard_preview_size"
-                  android:layout_height="@dimen/clipboard_preview_size"/>
-        <ImageView
-            android:id="@+id/image_preview"
-            android:scaleType="fitCenter"
-            android:adjustViewBounds="true"
-            android:contentDescription="@string/clipboard_image_preview"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"/>
-        <TextView
-            android:id="@+id/hidden_preview"
-            android:visibility="gone"
-            android:textFontWeight="500"
-            android:padding="8dp"
-            android:gravity="center"
-            android:textSize="14sp"
-            android:textColor="?attr/overlayButtonTextColor"
-            android:background="?androidprv:attr/colorAccentSecondary"
-            android:layout_width="@dimen/clipboard_preview_size"
-            android:layout_height="@dimen/clipboard_preview_size"/>
-    </FrameLayout>
-    <FrameLayout
-        android:id="@+id/dismiss_button"
-        android:layout_width="@dimen/overlay_dismiss_button_tappable_size"
-        android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
-        android:elevation="10dp"
-        android:visibility="gone"
-        android:alpha="0"
-        app:layout_constraintStart_toEndOf="@id/clipboard_preview"
-        app:layout_constraintEnd_toEndOf="@id/clipboard_preview"
-        app:layout_constraintTop_toTopOf="@id/clipboard_preview"
-        app:layout_constraintBottom_toTopOf="@id/clipboard_preview"
-        android:contentDescription="@string/clipboard_dismiss_description">
-        <ImageView
-            android:id="@+id/dismiss_image"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_margin="@dimen/overlay_dismiss_button_margin"
-            android:src="@drawable/overlay_cancel"/>
-    </FrameLayout>
-</com.android.systemui.screenshot.DraggableConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 3c860a9..a11ffcd 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -141,7 +141,7 @@
             android:id="@+id/lock_icon_bg"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:background="@drawable/fingerprint_bg"
+            android:src="@drawable/fingerprint_bg"
             android:visibility="invisible"/>
 
         <ImageView
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 5fd2fab..9f07a20 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -92,6 +92,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.settingslib.Utils;
+import com.android.settingslib.drawable.CircleFramedDrawable;
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
@@ -999,8 +1000,10 @@
         private Drawable findUserIcon(int userId) {
             Bitmap userIcon = UserManager.get(mView.getContext()).getUserIcon(userId);
             if (userIcon != null) {
-                return new BitmapDrawable(userIcon);
+                return CircleFramedDrawable.getInstance(mView.getContext(),
+                        userIcon);
             }
+
             return UserIcons.getDefaultUserIcon(mResources, userId, false);
         }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 9eb7e2cd..afa9ef6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -929,7 +929,7 @@
         @Override
         public void run() {
             mLogger.logRetryAfterFpHwUnavailable(mHardwareFingerprintUnavailableRetryCount);
-            if (mFpm.isHardwareDetected()) {
+            if (!mFingerprintSensorProperties.isEmpty()) {
                 updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
             } else if (mHardwareFingerprintUnavailableRetryCount < HAL_ERROR_RETRY_MAX) {
                 mHardwareFingerprintUnavailableRetryCount++;
@@ -1938,6 +1938,11 @@
             }
         }
         mGoingToSleep = true;
+        // Resetting assistant visibility state as the device is going to sleep now.
+        // TaskStackChangeListener gets triggered a little late when we transition to AoD,
+        // which results in face auth running once on AoD.
+        mAssistantVisible = false;
+        mLogger.d("Started going to sleep, mGoingToSleep=true, mAssistantVisible=false");
         updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_UPDATED_GOING_TO_SLEEP);
     }
 
@@ -2341,14 +2346,13 @@
     }
 
     private void updateFaceEnrolled(int userId) {
-        mIsFaceEnrolled = whitelistIpcs(
-                () -> mFaceManager != null && mFaceManager.isHardwareDetected()
-                        && mBiometricEnabledForUser.get(userId))
+        mIsFaceEnrolled = mFaceManager != null && !mFaceSensorProperties.isEmpty()
+                && mBiometricEnabledForUser.get(userId)
                 && mAuthController.isFaceAuthEnrolled(userId);
     }
 
     public boolean isFaceSupported() {
-        return mFaceManager != null && mFaceManager.isHardwareDetected();
+        return mFaceManager != null && !mFaceSensorProperties.isEmpty();
     }
 
     /**
@@ -2967,7 +2971,8 @@
     @VisibleForTesting
     boolean isUnlockWithFingerprintPossible(int userId) {
         // TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once.
-        mIsUnlockWithFingerprintPossible.put(userId, mFpm != null && mFpm.isHardwareDetected()
+        mIsUnlockWithFingerprintPossible.put(userId, mFpm != null
+                && !mFingerprintSensorProperties.isEmpty()
                 && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId));
         return mIsUnlockWithFingerprintPossible.get(userId);
     }
@@ -3332,7 +3337,8 @@
     /**
      * Handle {@link #MSG_KEYGUARD_RESET}
      */
-    private void handleKeyguardReset() {
+    @VisibleForTesting
+    protected void handleKeyguardReset() {
         mLogger.d("handleKeyguardReset");
         updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
                 FACE_AUTH_UPDATED_KEYGUARD_RESET);
@@ -3887,7 +3893,7 @@
         for (int subId : mServiceStates.keySet()) {
             pw.println("    " + subId + "=" + mServiceStates.get(subId));
         }
-        if (mFpm != null && mFpm.isHardwareDetected()) {
+        if (mFpm != null && !mFingerprintSensorProperties.isEmpty()) {
             final int userId = mUserTracker.getUserId();
             final int strongAuthFlags = mStrongAuthTracker.getStrongAuthForUser(userId);
             BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(userId);
@@ -3936,7 +3942,7 @@
                     mFingerprintListenBuffer.toList()
             ).printTableData(pw);
         }
-        if (mFaceManager != null && mFaceManager.isHardwareDetected()) {
+        if (mFaceManager != null && !mFaceSensorProperties.isEmpty()) {
             final int userId = mUserTracker.getUserId();
             final int strongAuthFlags = mStrongAuthTracker.getStrongAuthForUser(userId);
             BiometricAuthenticated face = mUserFaceAuthenticated.get(userId);
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
index 34a5ef7..abad0be 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
@@ -88,7 +88,9 @@
                     Utils.getColorAttrDefaultColor(getContext(), android.R.attr.textColorPrimary),
                     Color.WHITE,
                     mDozeAmount);
-            mBgView.setBackground(getContext().getDrawable(R.drawable.fingerprint_bg));
+            int backgroundColor = Utils.getColorAttrDefaultColor(getContext(),
+                    com.android.internal.R.attr.colorSurface);
+            mBgView.setImageTintList(ColorStateList.valueOf(backgroundColor));
             mBgView.setAlpha(1f - mDozeAmount);
             mBgView.setVisibility(View.VISIBLE);
         } else {
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 1bf63e59..413a3ca 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -431,6 +431,7 @@
         pw.println(" mStatusBarState: " + StatusBarState.toString(mStatusBarState));
         pw.println(" mInterpolatedDarkAmount: " + mInterpolatedDarkAmount);
         pw.println(" mSensorTouchLocation: " + mSensorTouchLocation);
+        pw.println(" mDefaultPaddingPx: " + mDefaultPaddingPx);
 
         if (mView != null) {
             mView.dump(pw, args);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index 4b57d45..04a2689 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -55,11 +55,11 @@
     private val fadeDuration = 83L
     private val retractDuration = 400L
     private var alphaInDuration: Long = 0
-    private var unlockedRippleInProgress: Boolean = false
     private val dwellShader = DwellRippleShader()
     private val dwellPaint = Paint()
     private val rippleShader = RippleShader()
     private val ripplePaint = Paint()
+    private var unlockedRippleAnimator: AnimatorSet? = null
     private var fadeDwellAnimator: Animator? = null
     private var retractDwellAnimator: Animator? = null
     private var dwellPulseOutAnimator: Animator? = null
@@ -205,7 +205,7 @@
      * Plays a ripple animation that grows to the dwellRadius with distortion.
      */
     fun startDwellRipple(isDozing: Boolean) {
-        if (unlockedRippleInProgress || dwellPulseOutAnimator?.isRunning == true) {
+        if (unlockedRippleAnimator?.isRunning == true || dwellPulseOutAnimator?.isRunning == true) {
             return
         }
 
@@ -262,9 +262,7 @@
      * Ripple that bursts outwards from the position of the sensor to the edges of the screen
      */
     fun startUnlockedRipple(onAnimationEnd: Runnable?) {
-        if (unlockedRippleInProgress) {
-            return // Ignore if ripple effect is already playing
-        }
+        unlockedRippleAnimator?.cancel()
 
         val rippleAnimator = ValueAnimator.ofFloat(0f, 1f).apply {
             interpolator = Interpolators.LINEAR_OUT_SLOW_IN
@@ -289,14 +287,13 @@
             }
         }
 
-        val animatorSet = AnimatorSet().apply {
+        unlockedRippleAnimator = AnimatorSet().apply {
             playTogether(
                 rippleAnimator,
                 alphaInAnimator
             )
             addListener(object : AnimatorListenerAdapter() {
                 override fun onAnimationStart(animation: Animator?) {
-                    unlockedRippleInProgress = true
                     rippleShader.rippleFill = false
                     drawRipple = true
                     visibility = VISIBLE
@@ -304,13 +301,13 @@
 
                 override fun onAnimationEnd(animation: Animator?) {
                     onAnimationEnd?.run()
-                    unlockedRippleInProgress = false
                     drawRipple = false
                     visibility = GONE
+                    unlockedRippleAnimator = null
                 }
             })
         }
-        animatorSet.start()
+        unlockedRippleAnimator?.start()
     }
 
     fun resetRippleAlpha() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index 6f594d5..c799e91 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -54,12 +54,18 @@
 import com.android.systemui.Dumpable
 import com.android.systemui.R
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.recents.OverviewProxyService
 import com.android.systemui.util.concurrency.DelayableExecutor
 import java.io.PrintWriter
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
 
 private const val TAG = "SideFpsController"
 
@@ -79,6 +85,9 @@
     displayManager: DisplayManager,
     @Main private val mainExecutor: DelayableExecutor,
     @Main private val handler: Handler,
+    private val alternateBouncerInteractor: AlternateBouncerInteractor,
+    @Application private val scope: CoroutineScope,
+    private val featureFlags: FeatureFlags,
     dumpManager: DumpManager
 ) : Dumpable {
     val requests: HashSet<SideFpsUiRequestSource> = HashSet()
@@ -168,9 +177,26 @@
             }
         )
         overviewProxyService.addCallback(overviewProxyListener)
+        listenForAlternateBouncerVisibility()
+
         dumpManager.registerDumpable(this)
     }
 
+    private fun listenForAlternateBouncerVisibility() {
+        alternateBouncerInteractor.setAlternateBouncerUIAvailable(true)
+        if (featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER)) {
+            scope.launch {
+                alternateBouncerInteractor.isVisible.collect { isVisible: Boolean ->
+                    if (isVisible) {
+                        show(SideFpsUiRequestSource.ALTERNATE_BOUNCER)
+                    } else {
+                        hide(SideFpsUiRequestSource.ALTERNATE_BOUNCER)
+                    }
+                }
+            }
+        }
+    }
+
     /** Shows the side fps overlay if not already shown. */
     fun show(request: SideFpsUiRequestSource) {
         requests.add(request)
@@ -423,4 +449,5 @@
     AUTO_SHOW,
     /** Pin, pattern or password bouncer */
     PRIMARY_BOUNCER,
+    ALTERNATE_BOUNCER
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index b4b3fae..6680787 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -262,7 +262,9 @@
             }
             REASON_AUTH_KEYGUARD -> {
                 UdfpsKeyguardViewController(
-                    view.addUdfpsView(R.layout.udfps_keyguard_view),
+                    view.addUdfpsView(R.layout.udfps_keyguard_view) {
+                        updateSensorLocation(sensorBounds)
+                    },
                     statusBarStateController,
                     shadeExpansionStateManager,
                     statusBarKeyguardViewManager,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
index 4017665..c82e6e1 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
@@ -68,10 +68,7 @@
         mEnrollHelper = enrollHelper;
         mView.setEnrollHelper(mEnrollHelper);
         mView.setProgressBarRadius(mEnrollProgressBarRadius);
-
-        if (featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
-            mView.mUseExpandedOverlay = true;
-        }
+        mView.mUseExpandedOverlay = featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index 339b8ca..ee9081c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
+import android.graphics.Rect;
 import android.graphics.RectF;
 import android.util.AttributeSet;
 import android.util.MathUtils;
@@ -34,6 +35,7 @@
 import android.widget.ImageView;
 
 import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
 
@@ -65,6 +67,7 @@
     private AnimatorSet mBackgroundInAnimator = new AnimatorSet();
     private int mAlpha; // 0-255
     private float mScaleFactor = 1;
+    private Rect mSensorBounds = new Rect();
 
     // AOD anti-burn-in offsets
     private final int mMaxBurnInOffsetX;
@@ -76,8 +79,6 @@
     private int mAnimationType = ANIMATION_NONE;
     private boolean mFullyInflated;
 
-    private LayoutParams mParams;
-
     public UdfpsKeyguardView(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
         mFingerprintDrawable = new UdfpsFpDrawable(context);
@@ -88,10 +89,7 @@
             .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
     }
 
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
+    public void startIconAsyncInflate() {
         // inflate Lottie views on a background thread in case it takes a while to inflate
         AsyncLayoutInflater inflater = new AsyncLayoutInflater(mContext);
         inflater.inflate(R.layout.udfps_keyguard_view_internal, this,
@@ -242,20 +240,8 @@
         updateAlpha();
     }
 
-    @Override
-    void onSensorRectUpdated(RectF bounds) {
-        super.onSensorRectUpdated(bounds);
-
-        if (mUseExpandedOverlay) {
-            mParams = new LayoutParams((int) bounds.width(), (int) bounds.height());
-            RectF converted = getBoundsRelativeToView(bounds);
-            mParams.setMargins(
-                    (int) converted.left,
-                    (int) converted.top,
-                    (int) converted.right,
-                    (int) converted.bottom
-            );
-        }
+    void updateSensorLocation(@NonNull Rect sensorBounds) {
+        mSensorBounds.set(sensorBounds);
     }
 
     /**
@@ -313,7 +299,17 @@
             updateAlpha();
 
             if (mUseExpandedOverlay) {
-                parent.addView(view, mParams);
+                final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+                lp.width = mSensorBounds.width();
+                lp.height = mSensorBounds.height();
+                RectF relativeToView = getBoundsRelativeToView(new RectF(mSensorBounds));
+                lp.setMargins(
+                        (int) relativeToView.left,
+                        (int) relativeToView.top,
+                        (int) relativeToView.right,
+                        (int) relativeToView.bottom
+                );
+                parent.addView(view, lp);
             } else {
                 parent.addView(view);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
index d072ec7..9bccafb 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
@@ -310,6 +310,7 @@
         lockScreenShadeTransitionController.udfpsKeyguardViewController = this
         activityLaunchAnimator.addListener(activityLaunchAnimatorListener)
         view.mUseExpandedOverlay = useExpandedOverlay
+        view.startIconAsyncInflate()
     }
 
     override fun onViewDetached() {
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
index 805a20a..1c26841 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
@@ -18,7 +18,6 @@
 
 import static android.content.ClipDescription.CLASSIFICATION_COMPLETE;
 
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_ENABLED;
 import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ENTERED;
 import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_UPDATED;
 import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_TOAST_SHOWN;
@@ -29,7 +28,6 @@
 import android.content.ClipboardManager;
 import android.content.Context;
 import android.os.SystemProperties;
-import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.util.Log;
 
@@ -37,9 +35,6 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.CoreStartable;
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
-import com.android.systemui.util.DeviceConfigProxy;
 
 import javax.inject.Inject;
 import javax.inject.Provider;
@@ -59,42 +54,28 @@
             "com.android.systemui.SUPPRESS_CLIPBOARD_OVERLAY";
 
     private final Context mContext;
-    private final DeviceConfigProxy mDeviceConfig;
     private final Provider<ClipboardOverlayController> mOverlayProvider;
-    private final ClipboardOverlayControllerLegacyFactory mOverlayFactory;
     private final ClipboardToast mClipboardToast;
     private final ClipboardManager mClipboardManager;
     private final UiEventLogger mUiEventLogger;
-    private final FeatureFlags mFeatureFlags;
-    private boolean mUsingNewOverlay;
     private ClipboardOverlay mClipboardOverlay;
 
     @Inject
-    public ClipboardListener(Context context, DeviceConfigProxy deviceConfigProxy,
+    public ClipboardListener(Context context,
             Provider<ClipboardOverlayController> clipboardOverlayControllerProvider,
-            ClipboardOverlayControllerLegacyFactory overlayFactory,
             ClipboardToast clipboardToast,
             ClipboardManager clipboardManager,
-            UiEventLogger uiEventLogger,
-            FeatureFlags featureFlags) {
+            UiEventLogger uiEventLogger) {
         mContext = context;
-        mDeviceConfig = deviceConfigProxy;
         mOverlayProvider = clipboardOverlayControllerProvider;
-        mOverlayFactory = overlayFactory;
         mClipboardToast = clipboardToast;
         mClipboardManager = clipboardManager;
         mUiEventLogger = uiEventLogger;
-        mFeatureFlags = featureFlags;
-
-        mUsingNewOverlay = mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR);
     }
 
     @Override
     public void start() {
-        if (mDeviceConfig.getBoolean(
-                DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED, true)) {
-            mClipboardManager.addPrimaryClipChangedListener(this);
-        }
+        mClipboardManager.addPrimaryClipChangedListener(this);
     }
 
     @Override
@@ -120,14 +101,8 @@
             return;
         }
 
-        boolean enabled = mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR);
-        if (mClipboardOverlay == null || enabled != mUsingNewOverlay) {
-            mUsingNewOverlay = enabled;
-            if (enabled) {
-                mClipboardOverlay = mOverlayProvider.get();
-            } else {
-                mClipboardOverlay = mOverlayFactory.create(mContext);
-            }
+        if (mClipboardOverlay == null) {
+            mClipboardOverlay = mOverlayProvider.get();
             mUiEventLogger.log(CLIPBOARD_OVERLAY_ENTERED, 0, clipSource);
         } else {
             mUiEventLogger.log(CLIPBOARD_OVERLAY_UPDATED, 0, clipSource);
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacy.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacy.java
deleted file mode 100644
index 3a040829..0000000
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacy.java
+++ /dev/null
@@ -1,963 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.clipboardoverlay;
-
-import static android.content.Intent.ACTION_CLOSE_SYSTEM_DIALOGS;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
-
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_SHOW_ACTIONS;
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_SHOW_EDIT_BUTTON;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ACTION_TAPPED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_DISMISSED_OTHER;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_DISMISS_TAPPED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_EDIT_TAPPED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHARE_TAPPED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TAP_OUTSIDE;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TIMED_OUT;
-
-import static java.util.Objects.requireNonNull;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.annotation.MainThread;
-import android.app.ICompatCameraControlCallback;
-import android.app.RemoteAction;
-import android.content.BroadcastReceiver;
-import android.content.ClipData;
-import android.content.ClipDescription;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Insets;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.graphics.drawable.Icon;
-import android.hardware.display.DisplayManager;
-import android.hardware.input.InputManager;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Looper;
-import android.provider.DeviceConfig;
-import android.text.TextUtils;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.MathUtils;
-import android.util.Size;
-import android.util.TypedValue;
-import android.view.Display;
-import android.view.DisplayCutout;
-import android.view.Gravity;
-import android.view.InputEvent;
-import android.view.InputEventReceiver;
-import android.view.InputMonitor;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewRootImpl;
-import android.view.ViewTreeObserver;
-import android.view.WindowInsets;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.LinearInterpolator;
-import android.view.animation.PathInterpolator;
-import android.view.textclassifier.TextClassification;
-import android.view.textclassifier.TextClassificationManager;
-import android.view.textclassifier.TextClassifier;
-import android.view.textclassifier.TextLinks;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
-
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.policy.PhoneWindow;
-import com.android.systemui.R;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.broadcast.BroadcastSender;
-import com.android.systemui.screenshot.DraggableConstraintLayout;
-import com.android.systemui.screenshot.FloatingWindowUtil;
-import com.android.systemui.screenshot.OverlayActionChip;
-import com.android.systemui.screenshot.TimeoutHandler;
-
-import java.io.IOException;
-import java.util.ArrayList;
-
-/**
- * Controls state and UI for the overlay that appears when something is added to the clipboard
- */
-public class ClipboardOverlayControllerLegacy implements ClipboardListener.ClipboardOverlay {
-    private static final String TAG = "ClipboardOverlayCtrlr";
-    private static final String REMOTE_COPY_ACTION = "android.intent.action.REMOTE_COPY";
-
-    /** Constants for screenshot/copy deconflicting */
-    public static final String SCREENSHOT_ACTION = "com.android.systemui.SCREENSHOT";
-    public static final String SELF_PERMISSION = "com.android.systemui.permission.SELF";
-    public static final String COPY_OVERLAY_ACTION = "com.android.systemui.COPY";
-
-    private static final String EXTRA_EDIT_SOURCE_CLIPBOARD = "edit_source_clipboard";
-
-    private static final int CLIPBOARD_DEFAULT_TIMEOUT_MILLIS = 6000;
-    private static final int SWIPE_PADDING_DP = 12; // extra padding around views to allow swipe
-    private static final int FONT_SEARCH_STEP_PX = 4;
-
-    private final Context mContext;
-    private final ClipboardLogger mClipboardLogger;
-    private final BroadcastDispatcher mBroadcastDispatcher;
-    private final DisplayManager mDisplayManager;
-    private final DisplayMetrics mDisplayMetrics;
-    private final WindowManager mWindowManager;
-    private final WindowManager.LayoutParams mWindowLayoutParams;
-    private final PhoneWindow mWindow;
-    private final TimeoutHandler mTimeoutHandler;
-    private final AccessibilityManager mAccessibilityManager;
-    private final TextClassifier mTextClassifier;
-
-    private final DraggableConstraintLayout mView;
-    private final View mClipboardPreview;
-    private final ImageView mImagePreview;
-    private final TextView mTextPreview;
-    private final TextView mHiddenPreview;
-    private final View mPreviewBorder;
-    private final OverlayActionChip mEditChip;
-    private final OverlayActionChip mShareChip;
-    private final OverlayActionChip mRemoteCopyChip;
-    private final View mActionContainerBackground;
-    private final View mDismissButton;
-    private final LinearLayout mActionContainer;
-    private final ArrayList<OverlayActionChip> mActionChips = new ArrayList<>();
-
-    private Runnable mOnSessionCompleteListener;
-
-    private InputMonitor mInputMonitor;
-    private InputEventReceiver mInputEventReceiver;
-
-    private BroadcastReceiver mCloseDialogsReceiver;
-    private BroadcastReceiver mScreenshotReceiver;
-
-    private boolean mBlockAttach = false;
-    private Animator mExitAnimator;
-    private Animator mEnterAnimator;
-    private final int mOrientation;
-    private boolean mKeyboardVisible;
-
-
-    public ClipboardOverlayControllerLegacy(Context context,
-            BroadcastDispatcher broadcastDispatcher,
-            BroadcastSender broadcastSender,
-            TimeoutHandler timeoutHandler, UiEventLogger uiEventLogger) {
-        mBroadcastDispatcher = broadcastDispatcher;
-        mDisplayManager = requireNonNull(context.getSystemService(DisplayManager.class));
-        final Context displayContext = context.createDisplayContext(getDefaultDisplay());
-        mContext = displayContext.createWindowContext(TYPE_SCREENSHOT, null);
-
-        mClipboardLogger = new ClipboardLogger(uiEventLogger);
-
-        mAccessibilityManager = AccessibilityManager.getInstance(mContext);
-        mTextClassifier = requireNonNull(context.getSystemService(TextClassificationManager.class))
-                .getTextClassifier();
-
-        mWindowManager = mContext.getSystemService(WindowManager.class);
-
-        mDisplayMetrics = new DisplayMetrics();
-        mContext.getDisplay().getRealMetrics(mDisplayMetrics);
-
-        mTimeoutHandler = timeoutHandler;
-        mTimeoutHandler.setDefaultTimeoutMillis(CLIPBOARD_DEFAULT_TIMEOUT_MILLIS);
-
-        // Setup the window that we are going to use
-        mWindowLayoutParams = FloatingWindowUtil.getFloatingWindowParams();
-        mWindowLayoutParams.setTitle("ClipboardOverlay");
-
-        mWindow = FloatingWindowUtil.getFloatingWindow(mContext);
-        mWindow.setWindowManager(mWindowManager, null, null);
-
-        setWindowFocusable(false);
-
-        mView = (DraggableConstraintLayout)
-                LayoutInflater.from(mContext).inflate(R.layout.clipboard_overlay_legacy, null);
-        mActionContainerBackground =
-                requireNonNull(mView.findViewById(R.id.actions_container_background));
-        mActionContainer = requireNonNull(mView.findViewById(R.id.actions));
-        mClipboardPreview = requireNonNull(mView.findViewById(R.id.clipboard_preview));
-        mImagePreview = requireNonNull(mView.findViewById(R.id.image_preview));
-        mTextPreview = requireNonNull(mView.findViewById(R.id.text_preview));
-        mHiddenPreview = requireNonNull(mView.findViewById(R.id.hidden_preview));
-        mPreviewBorder = requireNonNull(mView.findViewById(R.id.preview_border));
-        mEditChip = requireNonNull(mView.findViewById(R.id.edit_chip));
-        mShareChip = requireNonNull(mView.findViewById(R.id.share_chip));
-        mRemoteCopyChip = requireNonNull(mView.findViewById(R.id.remote_copy_chip));
-        mEditChip.setAlpha(1);
-        mShareChip.setAlpha(1);
-        mRemoteCopyChip.setAlpha(1);
-        mDismissButton = requireNonNull(mView.findViewById(R.id.dismiss_button));
-
-        mShareChip.setContentDescription(mContext.getString(com.android.internal.R.string.share));
-        mView.setCallbacks(new DraggableConstraintLayout.SwipeDismissCallbacks() {
-            @Override
-            public void onInteraction() {
-                mTimeoutHandler.resetTimeout();
-            }
-
-            @Override
-            public void onSwipeDismissInitiated(Animator animator) {
-                mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_SWIPE_DISMISSED);
-                mExitAnimator = animator;
-            }
-
-            @Override
-            public void onDismissComplete() {
-                hideImmediate();
-            }
-        });
-
-        mTextPreview.getViewTreeObserver().addOnPreDrawListener(() -> {
-            int availableHeight = mTextPreview.getHeight()
-                    - (mTextPreview.getPaddingTop() + mTextPreview.getPaddingBottom());
-            mTextPreview.setMaxLines(availableHeight / mTextPreview.getLineHeight());
-            return true;
-        });
-
-        mDismissButton.setOnClickListener(view -> {
-            mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_DISMISS_TAPPED);
-            animateOut();
-        });
-
-        mEditChip.setIcon(Icon.createWithResource(mContext, R.drawable.ic_screenshot_edit), true);
-        mRemoteCopyChip.setIcon(
-                Icon.createWithResource(mContext, R.drawable.ic_baseline_devices_24), true);
-        mShareChip.setIcon(Icon.createWithResource(mContext, R.drawable.ic_screenshot_share), true);
-        mOrientation = mContext.getResources().getConfiguration().orientation;
-
-        attachWindow();
-        withWindowAttached(() -> {
-            mWindow.setContentView(mView);
-            WindowInsets insets = mWindowManager.getCurrentWindowMetrics().getWindowInsets();
-            mKeyboardVisible = insets.isVisible(WindowInsets.Type.ime());
-            updateInsets(insets);
-            mWindow.peekDecorView().getViewTreeObserver().addOnGlobalLayoutListener(
-                    new ViewTreeObserver.OnGlobalLayoutListener() {
-                        @Override
-                        public void onGlobalLayout() {
-                            WindowInsets insets =
-                                    mWindowManager.getCurrentWindowMetrics().getWindowInsets();
-                            boolean keyboardVisible = insets.isVisible(WindowInsets.Type.ime());
-                            if (keyboardVisible != mKeyboardVisible) {
-                                mKeyboardVisible = keyboardVisible;
-                                updateInsets(insets);
-                            }
-                        }
-                    });
-            mWindow.peekDecorView().getViewRootImpl().setActivityConfigCallback(
-                    new ViewRootImpl.ActivityConfigCallback() {
-                        @Override
-                        public void onConfigurationChanged(Configuration overrideConfig,
-                                int newDisplayId) {
-                            if (mContext.getResources().getConfiguration().orientation
-                                    != mOrientation) {
-                                mClipboardLogger.logSessionComplete(
-                                        CLIPBOARD_OVERLAY_DISMISSED_OTHER);
-                                hideImmediate();
-                            }
-                        }
-
-                        @Override
-                        public void requestCompatCameraControl(
-                                boolean showControl, boolean transformationApplied,
-                                ICompatCameraControlCallback callback) {
-                            Log.w(TAG, "unexpected requestCompatCameraControl call");
-                        }
-                    });
-        });
-
-        mTimeoutHandler.setOnTimeoutRunnable(() -> {
-            mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_TIMED_OUT);
-            animateOut();
-        });
-
-        mCloseDialogsReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
-                    mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
-                    animateOut();
-                }
-            }
-        };
-
-        mBroadcastDispatcher.registerReceiver(mCloseDialogsReceiver,
-                new IntentFilter(ACTION_CLOSE_SYSTEM_DIALOGS));
-        mScreenshotReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (SCREENSHOT_ACTION.equals(intent.getAction())) {
-                    mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
-                    animateOut();
-                }
-            }
-        };
-
-        mBroadcastDispatcher.registerReceiver(mScreenshotReceiver,
-                new IntentFilter(SCREENSHOT_ACTION), null, null, Context.RECEIVER_EXPORTED,
-                SELF_PERMISSION);
-        monitorOutsideTouches();
-
-        Intent copyIntent = new Intent(COPY_OVERLAY_ACTION);
-        // Set package name so the system knows it's safe
-        copyIntent.setPackage(mContext.getPackageName());
-        broadcastSender.sendBroadcast(copyIntent, SELF_PERMISSION);
-    }
-
-    @Override // ClipboardListener.ClipboardOverlay
-    public void setClipData(ClipData clipData, String clipSource) {
-        if (mExitAnimator != null && mExitAnimator.isRunning()) {
-            mExitAnimator.cancel();
-        }
-        reset();
-        String accessibilityAnnouncement;
-
-        boolean isSensitive = clipData != null && clipData.getDescription().getExtras() != null
-                && clipData.getDescription().getExtras()
-                .getBoolean(ClipDescription.EXTRA_IS_SENSITIVE);
-        if (clipData == null || clipData.getItemCount() == 0) {
-            showTextPreview(
-                    mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
-                    mTextPreview);
-            accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
-        } else if (!TextUtils.isEmpty(clipData.getItemAt(0).getText())) {
-            ClipData.Item item = clipData.getItemAt(0);
-            if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
-                    CLIPBOARD_OVERLAY_SHOW_ACTIONS, false)) {
-                if (item.getTextLinks() != null) {
-                    AsyncTask.execute(() -> classifyText(clipData.getItemAt(0), clipSource));
-                }
-            }
-            if (isSensitive) {
-                showEditableText(
-                        mContext.getResources().getString(R.string.clipboard_asterisks), true);
-            } else {
-                showEditableText(item.getText(), false);
-            }
-            showShareChip(clipData);
-            accessibilityAnnouncement = mContext.getString(R.string.clipboard_text_copied);
-        } else if (clipData.getItemAt(0).getUri() != null) {
-            if (tryShowEditableImage(clipData.getItemAt(0).getUri(), isSensitive)) {
-                showShareChip(clipData);
-                accessibilityAnnouncement = mContext.getString(R.string.clipboard_image_copied);
-            } else {
-                accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
-            }
-        } else {
-            showTextPreview(
-                    mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
-                    mTextPreview);
-            accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
-        }
-        Intent remoteCopyIntent = IntentCreator.getRemoteCopyIntent(clipData, mContext);
-        // Only show remote copy if it's available.
-        PackageManager packageManager = mContext.getPackageManager();
-        if (packageManager.resolveActivity(
-                remoteCopyIntent, PackageManager.ResolveInfoFlags.of(0)) != null) {
-            mRemoteCopyChip.setContentDescription(
-                    mContext.getString(R.string.clipboard_send_nearby_description));
-            mRemoteCopyChip.setVisibility(View.VISIBLE);
-            mRemoteCopyChip.setOnClickListener((v) -> {
-                mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED);
-                mContext.startActivity(remoteCopyIntent);
-                animateOut();
-            });
-            mActionContainerBackground.setVisibility(View.VISIBLE);
-        } else {
-            mRemoteCopyChip.setVisibility(View.GONE);
-        }
-        withWindowAttached(() -> {
-            if (mEnterAnimator == null || !mEnterAnimator.isRunning()) {
-                mView.post(this::animateIn);
-            }
-            mView.announceForAccessibility(accessibilityAnnouncement);
-        });
-        mTimeoutHandler.resetTimeout();
-    }
-
-    @Override // ClipboardListener.ClipboardOverlay
-    public void setOnSessionCompleteListener(Runnable runnable) {
-        mOnSessionCompleteListener = runnable;
-    }
-
-    private void classifyText(ClipData.Item item, String source) {
-        ArrayList<RemoteAction> actions = new ArrayList<>();
-        for (TextLinks.TextLink link : item.getTextLinks().getLinks()) {
-            TextClassification classification = mTextClassifier.classifyText(
-                    item.getText(), link.getStart(), link.getEnd(), null);
-            actions.addAll(classification.getActions());
-        }
-        mView.post(() -> {
-            resetActionChips();
-            if (actions.size() > 0) {
-                mActionContainerBackground.setVisibility(View.VISIBLE);
-                for (RemoteAction action : actions) {
-                    Intent targetIntent = action.getActionIntent().getIntent();
-                    ComponentName component = targetIntent.getComponent();
-                    if (component != null && !TextUtils.equals(source,
-                            component.getPackageName())) {
-                        OverlayActionChip chip = constructActionChip(action);
-                        mActionContainer.addView(chip);
-                        mActionChips.add(chip);
-                        break; // only show at most one action chip
-                    }
-                }
-            }
-        });
-    }
-
-    private void showShareChip(ClipData clip) {
-        mShareChip.setVisibility(View.VISIBLE);
-        mActionContainerBackground.setVisibility(View.VISIBLE);
-        mShareChip.setOnClickListener((v) -> shareContent(clip));
-    }
-
-    private OverlayActionChip constructActionChip(RemoteAction action) {
-        OverlayActionChip chip = (OverlayActionChip) LayoutInflater.from(mContext).inflate(
-                R.layout.overlay_action_chip, mActionContainer, false);
-        chip.setText(action.getTitle());
-        chip.setContentDescription(action.getTitle());
-        chip.setIcon(action.getIcon(), false);
-        chip.setPendingIntent(action.getActionIntent(), () -> {
-            mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_ACTION_TAPPED);
-            animateOut();
-        });
-        chip.setAlpha(1);
-        return chip;
-    }
-
-    private void monitorOutsideTouches() {
-        InputManager inputManager = mContext.getSystemService(InputManager.class);
-        mInputMonitor = inputManager.monitorGestureInput("clipboard overlay", 0);
-        mInputEventReceiver = new InputEventReceiver(mInputMonitor.getInputChannel(),
-                Looper.getMainLooper()) {
-            @Override
-            public void onInputEvent(InputEvent event) {
-                if (event instanceof MotionEvent) {
-                    MotionEvent motionEvent = (MotionEvent) event;
-                    if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
-                        Region touchRegion = new Region();
-
-                        final Rect tmpRect = new Rect();
-                        mPreviewBorder.getBoundsOnScreen(tmpRect);
-                        tmpRect.inset(
-                                (int) FloatingWindowUtil.dpToPx(mDisplayMetrics, -SWIPE_PADDING_DP),
-                                (int) FloatingWindowUtil.dpToPx(mDisplayMetrics,
-                                        -SWIPE_PADDING_DP));
-                        touchRegion.op(tmpRect, Region.Op.UNION);
-                        mActionContainerBackground.getBoundsOnScreen(tmpRect);
-                        tmpRect.inset(
-                                (int) FloatingWindowUtil.dpToPx(mDisplayMetrics, -SWIPE_PADDING_DP),
-                                (int) FloatingWindowUtil.dpToPx(mDisplayMetrics,
-                                        -SWIPE_PADDING_DP));
-                        touchRegion.op(tmpRect, Region.Op.UNION);
-                        mDismissButton.getBoundsOnScreen(tmpRect);
-                        touchRegion.op(tmpRect, Region.Op.UNION);
-                        if (!touchRegion.contains(
-                                (int) motionEvent.getRawX(), (int) motionEvent.getRawY())) {
-                            mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_TAP_OUTSIDE);
-                            animateOut();
-                        }
-                    }
-                }
-                finishInputEvent(event, true /* handled */);
-            }
-        };
-    }
-
-    private void editImage(Uri uri) {
-        mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_EDIT_TAPPED);
-        mContext.startActivity(IntentCreator.getImageEditIntent(uri, mContext));
-        animateOut();
-    }
-
-    private void editText() {
-        mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_EDIT_TAPPED);
-        mContext.startActivity(IntentCreator.getTextEditorIntent(mContext));
-        animateOut();
-    }
-
-    private void shareContent(ClipData clip) {
-        mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_SHARE_TAPPED);
-        mContext.startActivity(IntentCreator.getShareIntent(clip, mContext));
-        animateOut();
-    }
-
-    private void showSinglePreview(View v) {
-        mTextPreview.setVisibility(View.GONE);
-        mImagePreview.setVisibility(View.GONE);
-        mHiddenPreview.setVisibility(View.GONE);
-        v.setVisibility(View.VISIBLE);
-    }
-
-    private void showTextPreview(CharSequence text, TextView textView) {
-        showSinglePreview(textView);
-        final CharSequence truncatedText = text.subSequence(0, Math.min(500, text.length()));
-        textView.setText(truncatedText);
-        updateTextSize(truncatedText, textView);
-
-        textView.addOnLayoutChangeListener(
-                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
-                    if (right - left != oldRight - oldLeft) {
-                        updateTextSize(truncatedText, textView);
-                    }
-                });
-        mEditChip.setVisibility(View.GONE);
-    }
-
-    private void updateTextSize(CharSequence text, TextView textView) {
-        Paint paint = new Paint(textView.getPaint());
-        Resources res = textView.getResources();
-        float minFontSize = res.getDimensionPixelSize(R.dimen.clipboard_overlay_min_font);
-        float maxFontSize = res.getDimensionPixelSize(R.dimen.clipboard_overlay_max_font);
-        if (isOneWord(text) && fitsInView(text, textView, paint, minFontSize)) {
-            // If the text is a single word and would fit within the TextView at the min font size,
-            // find the biggest font size that will fit.
-            float fontSizePx = minFontSize;
-            while (fontSizePx + FONT_SEARCH_STEP_PX < maxFontSize
-                    && fitsInView(text, textView, paint, fontSizePx + FONT_SEARCH_STEP_PX)) {
-                fontSizePx += FONT_SEARCH_STEP_PX;
-            }
-            // Need to turn off autosizing, otherwise setTextSize is a no-op.
-            textView.setAutoSizeTextTypeWithDefaults(TextView.AUTO_SIZE_TEXT_TYPE_NONE);
-            // It's possible to hit the max font size and not fill the width, so centering
-            // horizontally looks better in this case.
-            textView.setGravity(Gravity.CENTER);
-            textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, (int) fontSizePx);
-        } else {
-            // Otherwise just stick with autosize.
-            textView.setAutoSizeTextTypeUniformWithConfiguration((int) minFontSize,
-                    (int) maxFontSize, FONT_SEARCH_STEP_PX, TypedValue.COMPLEX_UNIT_PX);
-            textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
-        }
-    }
-
-    private static boolean fitsInView(CharSequence text, TextView textView, Paint paint,
-            float fontSizePx) {
-        paint.setTextSize(fontSizePx);
-        float size = paint.measureText(text.toString());
-        float availableWidth = textView.getWidth() - textView.getPaddingLeft()
-                - textView.getPaddingRight();
-        return size < availableWidth;
-    }
-
-    private static boolean isOneWord(CharSequence text) {
-        return text.toString().split("\\s+", 2).length == 1;
-    }
-
-    private void showEditableText(CharSequence text, boolean hidden) {
-        TextView textView = hidden ? mHiddenPreview : mTextPreview;
-        showTextPreview(text, textView);
-        View.OnClickListener listener = v -> editText();
-        setAccessibilityActionToEdit(textView);
-        if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
-                CLIPBOARD_OVERLAY_SHOW_EDIT_BUTTON, false)) {
-            mEditChip.setVisibility(View.VISIBLE);
-            mActionContainerBackground.setVisibility(View.VISIBLE);
-            mEditChip.setContentDescription(
-                    mContext.getString(R.string.clipboard_edit_text_description));
-            mEditChip.setOnClickListener(listener);
-        }
-        textView.setOnClickListener(listener);
-    }
-
-    private boolean tryShowEditableImage(Uri uri, boolean isSensitive) {
-        View.OnClickListener listener = v -> editImage(uri);
-        ContentResolver resolver = mContext.getContentResolver();
-        String mimeType = resolver.getType(uri);
-        boolean isEditableImage = mimeType != null && mimeType.startsWith("image");
-        if (isSensitive) {
-            mHiddenPreview.setText(mContext.getString(R.string.clipboard_text_hidden));
-            showSinglePreview(mHiddenPreview);
-            if (isEditableImage) {
-                mHiddenPreview.setOnClickListener(listener);
-                setAccessibilityActionToEdit(mHiddenPreview);
-            }
-        } else if (isEditableImage) { // if the MIMEtype is image, try to load
-            try {
-                int size = mContext.getResources().getDimensionPixelSize(R.dimen.overlay_x_scale);
-                // The width of the view is capped, height maintains aspect ratio, so allow it to be
-                // taller if needed.
-                Bitmap thumbnail = resolver.loadThumbnail(uri, new Size(size, size * 4), null);
-                showSinglePreview(mImagePreview);
-                mImagePreview.setImageBitmap(thumbnail);
-                mImagePreview.setOnClickListener(listener);
-                setAccessibilityActionToEdit(mImagePreview);
-            } catch (IOException e) {
-                Log.e(TAG, "Thumbnail loading failed", e);
-                showTextPreview(
-                        mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
-                        mTextPreview);
-                isEditableImage = false;
-            }
-        } else {
-            showTextPreview(
-                    mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
-                    mTextPreview);
-        }
-        if (isEditableImage && DeviceConfig.getBoolean(
-                DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_SHOW_EDIT_BUTTON, false)) {
-            mEditChip.setVisibility(View.VISIBLE);
-            mActionContainerBackground.setVisibility(View.VISIBLE);
-            mEditChip.setOnClickListener(listener);
-            mEditChip.setContentDescription(
-                    mContext.getString(R.string.clipboard_edit_image_description));
-        }
-        return isEditableImage;
-    }
-
-    private void setAccessibilityActionToEdit(View view) {
-        ViewCompat.replaceAccessibilityAction(view,
-                AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
-                mContext.getString(R.string.clipboard_edit), null);
-    }
-
-    private void animateIn() {
-        if (mAccessibilityManager.isEnabled()) {
-            mDismissButton.setVisibility(View.VISIBLE);
-        }
-        mEnterAnimator = getEnterAnimation();
-        mEnterAnimator.start();
-    }
-
-    private void animateOut() {
-        if (mExitAnimator != null && mExitAnimator.isRunning()) {
-            return;
-        }
-        Animator anim = getExitAnimation();
-        anim.addListener(new AnimatorListenerAdapter() {
-            private boolean mCancelled;
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                super.onAnimationCancel(animation);
-                mCancelled = true;
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                super.onAnimationEnd(animation);
-                if (!mCancelled) {
-                    hideImmediate();
-                }
-            }
-        });
-        mExitAnimator = anim;
-        anim.start();
-    }
-
-    private Animator getEnterAnimation() {
-        TimeInterpolator linearInterpolator = new LinearInterpolator();
-        TimeInterpolator scaleInterpolator = new PathInterpolator(0, 0, 0, 1f);
-        AnimatorSet enterAnim = new AnimatorSet();
-
-        ValueAnimator rootAnim = ValueAnimator.ofFloat(0, 1);
-        rootAnim.setInterpolator(linearInterpolator);
-        rootAnim.setDuration(66);
-        rootAnim.addUpdateListener(animation -> {
-            mView.setAlpha(animation.getAnimatedFraction());
-        });
-
-        ValueAnimator scaleAnim = ValueAnimator.ofFloat(0, 1);
-        scaleAnim.setInterpolator(scaleInterpolator);
-        scaleAnim.setDuration(333);
-        scaleAnim.addUpdateListener(animation -> {
-            float previewScale = MathUtils.lerp(.9f, 1f, animation.getAnimatedFraction());
-            mClipboardPreview.setScaleX(previewScale);
-            mClipboardPreview.setScaleY(previewScale);
-            mPreviewBorder.setScaleX(previewScale);
-            mPreviewBorder.setScaleY(previewScale);
-
-            float pivotX = mClipboardPreview.getWidth() / 2f + mClipboardPreview.getX();
-            mActionContainerBackground.setPivotX(pivotX - mActionContainerBackground.getX());
-            mActionContainer.setPivotX(pivotX - ((View) mActionContainer.getParent()).getX());
-            float actionsScaleX = MathUtils.lerp(.7f, 1f, animation.getAnimatedFraction());
-            float actionsScaleY = MathUtils.lerp(.9f, 1f, animation.getAnimatedFraction());
-            mActionContainer.setScaleX(actionsScaleX);
-            mActionContainer.setScaleY(actionsScaleY);
-            mActionContainerBackground.setScaleX(actionsScaleX);
-            mActionContainerBackground.setScaleY(actionsScaleY);
-        });
-
-        ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
-        alphaAnim.setInterpolator(linearInterpolator);
-        alphaAnim.setDuration(283);
-        alphaAnim.addUpdateListener(animation -> {
-            float alpha = animation.getAnimatedFraction();
-            mClipboardPreview.setAlpha(alpha);
-            mPreviewBorder.setAlpha(alpha);
-            mDismissButton.setAlpha(alpha);
-            mActionContainer.setAlpha(alpha);
-        });
-
-        mActionContainer.setAlpha(0);
-        mPreviewBorder.setAlpha(0);
-        mClipboardPreview.setAlpha(0);
-        enterAnim.play(rootAnim).with(scaleAnim);
-        enterAnim.play(alphaAnim).after(50).after(rootAnim);
-
-        enterAnim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                super.onAnimationEnd(animation);
-                mView.setAlpha(1);
-                mTimeoutHandler.resetTimeout();
-            }
-        });
-        return enterAnim;
-    }
-
-    private Animator getExitAnimation() {
-        TimeInterpolator linearInterpolator = new LinearInterpolator();
-        TimeInterpolator scaleInterpolator = new PathInterpolator(.3f, 0, 1f, 1f);
-        AnimatorSet exitAnim = new AnimatorSet();
-
-        ValueAnimator rootAnim = ValueAnimator.ofFloat(0, 1);
-        rootAnim.setInterpolator(linearInterpolator);
-        rootAnim.setDuration(100);
-        rootAnim.addUpdateListener(anim -> mView.setAlpha(1 - anim.getAnimatedFraction()));
-
-        ValueAnimator scaleAnim = ValueAnimator.ofFloat(0, 1);
-        scaleAnim.setInterpolator(scaleInterpolator);
-        scaleAnim.setDuration(250);
-        scaleAnim.addUpdateListener(animation -> {
-            float previewScale = MathUtils.lerp(1f, .9f, animation.getAnimatedFraction());
-            mClipboardPreview.setScaleX(previewScale);
-            mClipboardPreview.setScaleY(previewScale);
-            mPreviewBorder.setScaleX(previewScale);
-            mPreviewBorder.setScaleY(previewScale);
-
-            float pivotX = mClipboardPreview.getWidth() / 2f + mClipboardPreview.getX();
-            mActionContainerBackground.setPivotX(pivotX - mActionContainerBackground.getX());
-            mActionContainer.setPivotX(pivotX - ((View) mActionContainer.getParent()).getX());
-            float actionScaleX = MathUtils.lerp(1f, .8f, animation.getAnimatedFraction());
-            float actionScaleY = MathUtils.lerp(1f, .9f, animation.getAnimatedFraction());
-            mActionContainer.setScaleX(actionScaleX);
-            mActionContainer.setScaleY(actionScaleY);
-            mActionContainerBackground.setScaleX(actionScaleX);
-            mActionContainerBackground.setScaleY(actionScaleY);
-        });
-
-        ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
-        alphaAnim.setInterpolator(linearInterpolator);
-        alphaAnim.setDuration(166);
-        alphaAnim.addUpdateListener(animation -> {
-            float alpha = 1 - animation.getAnimatedFraction();
-            mClipboardPreview.setAlpha(alpha);
-            mPreviewBorder.setAlpha(alpha);
-            mDismissButton.setAlpha(alpha);
-            mActionContainer.setAlpha(alpha);
-        });
-
-        exitAnim.play(alphaAnim).with(scaleAnim);
-        exitAnim.play(rootAnim).after(150).after(alphaAnim);
-        return exitAnim;
-    }
-
-    private void hideImmediate() {
-        // Note this may be called multiple times if multiple dismissal events happen at the same
-        // time.
-        mTimeoutHandler.cancelTimeout();
-        final View decorView = mWindow.peekDecorView();
-        if (decorView != null && decorView.isAttachedToWindow()) {
-            mWindowManager.removeViewImmediate(decorView);
-        }
-        if (mCloseDialogsReceiver != null) {
-            mBroadcastDispatcher.unregisterReceiver(mCloseDialogsReceiver);
-            mCloseDialogsReceiver = null;
-        }
-        if (mScreenshotReceiver != null) {
-            mBroadcastDispatcher.unregisterReceiver(mScreenshotReceiver);
-            mScreenshotReceiver = null;
-        }
-        if (mInputEventReceiver != null) {
-            mInputEventReceiver.dispose();
-            mInputEventReceiver = null;
-        }
-        if (mInputMonitor != null) {
-            mInputMonitor.dispose();
-            mInputMonitor = null;
-        }
-        if (mOnSessionCompleteListener != null) {
-            mOnSessionCompleteListener.run();
-        }
-    }
-
-    private void resetActionChips() {
-        for (OverlayActionChip chip : mActionChips) {
-            mActionContainer.removeView(chip);
-        }
-        mActionChips.clear();
-    }
-
-    private void reset() {
-        mView.setTranslationX(0);
-        mView.setAlpha(0);
-        mActionContainerBackground.setVisibility(View.GONE);
-        mShareChip.setVisibility(View.GONE);
-        mEditChip.setVisibility(View.GONE);
-        mRemoteCopyChip.setVisibility(View.GONE);
-        resetActionChips();
-        mTimeoutHandler.cancelTimeout();
-        mClipboardLogger.reset();
-    }
-
-    @MainThread
-    private void attachWindow() {
-        View decorView = mWindow.getDecorView();
-        if (decorView.isAttachedToWindow() || mBlockAttach) {
-            return;
-        }
-        mBlockAttach = true;
-        mWindowManager.addView(decorView, mWindowLayoutParams);
-        decorView.requestApplyInsets();
-        mView.requestApplyInsets();
-        decorView.getViewTreeObserver().addOnWindowAttachListener(
-                new ViewTreeObserver.OnWindowAttachListener() {
-                    @Override
-                    public void onWindowAttached() {
-                        mBlockAttach = false;
-                    }
-
-                    @Override
-                    public void onWindowDetached() {
-                    }
-                }
-        );
-    }
-
-    private void withWindowAttached(Runnable action) {
-        View decorView = mWindow.getDecorView();
-        if (decorView.isAttachedToWindow()) {
-            action.run();
-        } else {
-            decorView.getViewTreeObserver().addOnWindowAttachListener(
-                    new ViewTreeObserver.OnWindowAttachListener() {
-                        @Override
-                        public void onWindowAttached() {
-                            mBlockAttach = false;
-                            decorView.getViewTreeObserver().removeOnWindowAttachListener(this);
-                            action.run();
-                        }
-
-                        @Override
-                        public void onWindowDetached() {
-                        }
-                    });
-        }
-    }
-
-    private void updateInsets(WindowInsets insets) {
-        int orientation = mContext.getResources().getConfiguration().orientation;
-        FrameLayout.LayoutParams p = (FrameLayout.LayoutParams) mView.getLayoutParams();
-        if (p == null) {
-            return;
-        }
-        DisplayCutout cutout = insets.getDisplayCutout();
-        Insets navBarInsets = insets.getInsets(WindowInsets.Type.navigationBars());
-        Insets imeInsets = insets.getInsets(WindowInsets.Type.ime());
-        if (cutout == null) {
-            p.setMargins(0, 0, 0, Math.max(imeInsets.bottom, navBarInsets.bottom));
-        } else {
-            Insets waterfall = cutout.getWaterfallInsets();
-            if (orientation == ORIENTATION_PORTRAIT) {
-                p.setMargins(
-                        waterfall.left,
-                        Math.max(cutout.getSafeInsetTop(), waterfall.top),
-                        waterfall.right,
-                        Math.max(imeInsets.bottom,
-                                Math.max(cutout.getSafeInsetBottom(),
-                                        Math.max(navBarInsets.bottom, waterfall.bottom))));
-            } else {
-                p.setMargins(
-                        waterfall.left,
-                        waterfall.top,
-                        waterfall.right,
-                        Math.max(imeInsets.bottom,
-                                Math.max(navBarInsets.bottom, waterfall.bottom)));
-            }
-        }
-        mView.setLayoutParams(p);
-        mView.requestLayout();
-    }
-
-    private Display getDefaultDisplay() {
-        return mDisplayManager.getDisplay(DEFAULT_DISPLAY);
-    }
-
-    /**
-     * Updates the window focusability.  If the window is already showing, then it updates the
-     * window immediately, otherwise the layout params will be applied when the window is next
-     * shown.
-     */
-    private void setWindowFocusable(boolean focusable) {
-        int flags = mWindowLayoutParams.flags;
-        if (focusable) {
-            mWindowLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        } else {
-            mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        }
-        if (mWindowLayoutParams.flags == flags) {
-            return;
-        }
-        final View decorView = mWindow.peekDecorView();
-        if (decorView != null && decorView.isAttachedToWindow()) {
-            mWindowManager.updateViewLayout(decorView, mWindowLayoutParams);
-        }
-    }
-
-    static class ClipboardLogger {
-        private final UiEventLogger mUiEventLogger;
-        private boolean mGuarded = false;
-
-        ClipboardLogger(UiEventLogger uiEventLogger) {
-            mUiEventLogger = uiEventLogger;
-        }
-
-        void logSessionComplete(@NonNull UiEventLogger.UiEventEnum event) {
-            if (!mGuarded) {
-                mGuarded = true;
-                mUiEventLogger.log(event);
-            }
-        }
-
-        void reset() {
-            mGuarded = false;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacyFactory.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacyFactory.java
deleted file mode 100644
index 0d989a7..0000000
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacyFactory.java
+++ /dev/null
@@ -1,54 +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.systemui.clipboardoverlay;
-
-import android.content.Context;
-
-import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.broadcast.BroadcastSender;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.screenshot.TimeoutHandler;
-
-import javax.inject.Inject;
-
-/**
- * A factory that churns out ClipboardOverlayControllerLegacys on demand.
- */
-@SysUISingleton
-public class ClipboardOverlayControllerLegacyFactory {
-
-    private final UiEventLogger mUiEventLogger;
-    private final BroadcastDispatcher mBroadcastDispatcher;
-    private final BroadcastSender mBroadcastSender;
-
-    @Inject
-    public ClipboardOverlayControllerLegacyFactory(BroadcastDispatcher broadcastDispatcher,
-            BroadcastSender broadcastSender, UiEventLogger uiEventLogger) {
-        this.mBroadcastDispatcher = broadcastDispatcher;
-        this.mBroadcastSender = broadcastSender;
-        this.mUiEventLogger = uiEventLogger;
-    }
-
-    /**
-     * One new ClipboardOverlayControllerLegacy, coming right up!
-     */
-    public ClipboardOverlayControllerLegacy create(Context context) {
-        return new ClipboardOverlayControllerLegacy(context, mBroadcastDispatcher, mBroadcastSender,
-                new TimeoutHandler(context), mUiEventLogger);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
index 54587b2..3808e73 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
@@ -189,9 +189,9 @@
                     authorizedPanelsRepository.addAuthorizedPanels(
                             setOf(serviceInfo.componentName.packageName)
                     )
-                    animateExitAndFinish()
                     val selected = SelectedItem.PanelItem(appName, componentName)
                     controlsController.setPreferredSelection(selected)
+                    animateExitAndFinish()
                     openControlsOrigin()
                 }
                 dialog = null
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 966dbf1..9e71bef 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -25,6 +25,7 @@
 import android.content.ComponentName
 import android.content.Context
 import android.content.Intent
+import android.content.pm.PackageManager
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.LayerDrawable
 import android.service.controls.Control
@@ -38,6 +39,7 @@
 import android.view.animation.DecelerateInterpolator
 import android.widget.AdapterView
 import android.widget.ArrayAdapter
+import android.widget.BaseAdapter
 import android.widget.FrameLayout
 import android.widget.ImageView
 import android.widget.LinearLayout
@@ -90,6 +92,7 @@
 class ControlsUiControllerImpl @Inject constructor (
         val controlsController: Lazy<ControlsController>,
         val context: Context,
+        private val packageManager: PackageManager,
         @Main val uiExecutor: DelayableExecutor,
         @Background val bgExecutor: DelayableExecutor,
         val controlsListingController: Lazy<ControlsListingController>,
@@ -113,6 +116,11 @@
         private const val PREF_IS_PANEL = "controls_is_panel"
 
         private const val FADE_IN_MILLIS = 200L
+
+        private const val OPEN_APP_ID = 0L
+        private const val ADD_CONTROLS_ID = 1L
+        private const val ADD_APP_ID = 2L
+        private const val EDIT_CONTROLS_ID = 3L
     }
 
     private var selectedItem: SelectedItem = SelectedItem.EMPTY_SELECTION
@@ -140,6 +148,9 @@
         it.getTitle()
     }
 
+    private var openAppIntent: Intent? = null
+    private var overflowMenuAdapter: BaseAdapter? = null
+
     private val onSeedingComplete = Consumer<Boolean> {
         accepted ->
             if (accepted) {
@@ -216,6 +227,8 @@
         this.parent = parent
         this.onDismiss = onDismiss
         this.activityContext = activityContext
+        this.openAppIntent = null
+        this.overflowMenuAdapter = null
         hidden = false
         retainCache = false
 
@@ -306,6 +319,12 @@
         startTargetedActivity(si, ControlsEditingActivity::class.java)
     }
 
+    private fun startDefaultActivity() {
+        openAppIntent?.let {
+            startActivity(it, animateExtra = false)
+        }
+    }
+
     private fun startTargetedActivity(si: StructureInfo, klazz: Class<*>) {
         val i = Intent(activityContext, klazz)
         putIntentExtras(i, si)
@@ -329,9 +348,11 @@
         startActivity(i)
     }
 
-    private fun startActivity(intent: Intent) {
+    private fun startActivity(intent: Intent, animateExtra: Boolean = true) {
         // Force animations when transitioning from a dialog to an activity
-        intent.putExtra(ControlsUiController.EXTRA_ANIMATE, true)
+        if (animateExtra) {
+            intent.putExtra(ControlsUiController.EXTRA_ANIMATE, true)
+        }
 
         if (keyguardStateController.isShowing()) {
             activityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */)
@@ -383,8 +404,31 @@
             Log.w(ControlsUiController.TAG, "Not TaskViewFactory to display panel $selectionItem")
         }
 
+        bgExecutor.execute {
+            val intent = Intent(Intent.ACTION_MAIN)
+                    .addCategory(Intent.CATEGORY_LAUNCHER)
+                    .setPackage(selectionItem.componentName.packageName)
+                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
+                            Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
+            val intents = packageManager
+                    .queryIntentActivities(intent, PackageManager.ResolveInfoFlags.of(0L))
+            intents.firstOrNull { it.activityInfo.exported }?.let { resolved ->
+                intent.setPackage(null)
+                intent.setComponent(resolved.activityInfo.componentName)
+                openAppIntent = intent
+                parent.post {
+                    // This will call show on the PopupWindow in the same thread, so make sure this
+                    // happens in the view thread.
+                    overflowMenuAdapter?.notifyDataSetChanged()
+                }
+            }
+        }
         createDropDown(panelsAndStructures, selectionItem)
-        createMenu()
+
+        val currentApps = panelsAndStructures.map { it.componentName }.toSet()
+        val allApps = controlsListingController.get()
+                .getCurrentServices().map { it.componentName }.toSet()
+        createMenu(extraApps = (allApps - currentApps).isNotEmpty())
     }
 
     private fun createPanelView(componentName: ComponentName) {
@@ -423,28 +467,41 @@
         }
     }
 
-    private fun createMenu() {
+    private fun createMenu(extraApps: Boolean) {
         val isPanel = selectedItem is SelectedItem.PanelItem
         val selectedStructure = (selectedItem as? SelectedItem.StructureItem)?.structure
                 ?: EMPTY_STRUCTURE
         val newFlows = featureFlags.isEnabled(Flags.CONTROLS_MANAGEMENT_NEW_FLOWS)
-        val addControlsId = if (newFlows || isPanel) {
-            R.string.controls_menu_add_another_app
-        } else {
-            R.string.controls_menu_add
+
+        val items = buildList {
+            add(OverflowMenuAdapter.MenuItem(
+                    context.getText(R.string.controls_open_app),
+                    OPEN_APP_ID
+            ))
+            if (newFlows || isPanel) {
+                if (extraApps) {
+                    add(OverflowMenuAdapter.MenuItem(
+                            context.getText(R.string.controls_menu_add_another_app),
+                            ADD_APP_ID
+                    ))
+                }
+            } else {
+                add(OverflowMenuAdapter.MenuItem(
+                        context.getText(R.string.controls_menu_add),
+                        ADD_CONTROLS_ID
+                ))
+            }
+            if (!isPanel) {
+                add(OverflowMenuAdapter.MenuItem(
+                        context.getText(R.string.controls_menu_edit),
+                        EDIT_CONTROLS_ID
+                ))
+            }
         }
 
-        val items = if (isPanel) {
-            arrayOf(
-                    context.resources.getString(addControlsId),
-            )
-        } else {
-            arrayOf(
-                    context.resources.getString(addControlsId),
-                    context.resources.getString(R.string.controls_menu_edit)
-            )
+        val adapter = OverflowMenuAdapter(context, R.layout.controls_more_item, items) { position ->
+                getItemId(position) != OPEN_APP_ID || openAppIntent != null
         }
-        var adapter = ArrayAdapter<String>(context, R.layout.controls_more_item, items)
 
         val anchor = parent.requireViewById<ImageView>(R.id.controls_more)
         anchor.setOnClickListener(object : View.OnClickListener {
@@ -462,25 +519,21 @@
                             pos: Int,
                             id: Long
                         ) {
-                            when (pos) {
-                                // 0: Add Control
-                                0 -> {
-                                    if (isPanel || newFlows) {
-                                        startProviderSelectorActivity()
-                                    } else {
-                                        startFavoritingActivity(selectedStructure)
-                                    }
-                                }
-                                // 1: Edit controls
-                                1 -> startEditingActivity(selectedStructure)
+                            when (id) {
+                                OPEN_APP_ID -> startDefaultActivity()
+                                ADD_APP_ID -> startProviderSelectorActivity()
+                                ADD_CONTROLS_ID -> startFavoritingActivity(selectedStructure)
+                                EDIT_CONTROLS_ID -> startEditingActivity(selectedStructure)
                             }
                             dismiss()
                         }
                     })
                     show()
+                    listView?.post { listView?.requestAccessibilityFocus() }
                 }
             }
         })
+        overflowMenuAdapter = adapter
     }
 
     private fun createDropDown(items: List<SelectionItem>, selected: SelectionItem) {
@@ -542,6 +595,7 @@
                         }
                     })
                     show()
+                    listView?.post { listView?.requestAccessibilityFocus() }
                 }
             }
         })
@@ -631,7 +685,7 @@
                 .putString(PREF_COMPONENT, selectedItem.componentName.flattenToString())
                 .putString(PREF_STRUCTURE_OR_APP_NAME, selectedItem.name.toString())
                 .putBoolean(PREF_IS_PANEL, selectedItem is SelectedItem.PanelItem)
-                .commit()
+                .apply()
     }
 
     private fun maybeUpdateSelectedItem(item: SelectionItem): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/OverflowMenuAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/OverflowMenuAdapter.kt
new file mode 100644
index 0000000..6b84e36
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/OverflowMenuAdapter.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.controls.ui
+
+import android.content.Context
+import android.widget.ArrayAdapter
+import androidx.annotation.LayoutRes
+
+open class OverflowMenuAdapter(
+    context: Context,
+    @LayoutRes layoutId: Int,
+    itemsWithIds: List<MenuItem>,
+    private val isEnabledInternal: OverflowMenuAdapter.(Int) -> Boolean
+) : ArrayAdapter<CharSequence>(context, layoutId, itemsWithIds.map(MenuItem::text)) {
+
+    private val ids = itemsWithIds.map(MenuItem::id)
+
+    override fun getItemId(position: Int): Long {
+        return ids[position]
+    }
+
+    override fun isEnabled(position: Int): Boolean {
+        return isEnabledInternal(position)
+    }
+
+    data class MenuItem(val text: CharSequence, val id: Long)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index c882f8a..c3bd5d9 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -182,6 +182,18 @@
             }
     }
 
+    /**
+     * Ends the dream content and dream overlay animations, if they're currently running.
+     * @see [AnimatorSet.end]
+     */
+    fun endAnimations() {
+        mAnimator =
+            mAnimator?.let {
+                it.end()
+                null
+            }
+    }
+
     private fun blurAnimator(
         view: View,
         fromBlurRadius: Float,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 539d2ca..50cfb6a 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -142,6 +142,23 @@
                 }
             };
 
+    /**
+     * If true, overlay entry animations should be skipped once.
+     *
+     * This is turned on when exiting low light and should be turned off once the entry animations
+     * are skipped once.
+     */
+    private boolean mSkipEntryAnimations;
+
+    private final DreamOverlayStateController.Callback
+            mDreamOverlayStateCallback =
+            new DreamOverlayStateController.Callback() {
+                @Override
+                public void onExitLowLight() {
+                    mSkipEntryAnimations = true;
+                }
+            };
+
     @Inject
     public DreamOverlayContainerViewController(
             DreamOverlayContainerView containerView,
@@ -187,6 +204,7 @@
 
     @Override
     protected void onInit() {
+        mStateController.addCallback(mDreamOverlayStateCallback);
         mStatusBarViewController.init();
         mComplicationHostViewController.init();
         mDreamOverlayAnimationsController.init(mView);
@@ -202,6 +220,13 @@
         // Start dream entry animations. Skip animations for low light clock.
         if (!mStateController.isLowLightActive()) {
             mDreamOverlayAnimationsController.startEntryAnimations();
+
+            if (mSkipEntryAnimations) {
+                // If we're transitioning from the low light dream back to the user dream, skip the
+                // overlay animations and show immediately.
+                mDreamOverlayAnimationsController.endAnimations();
+                mSkipEntryAnimations = false;
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
index ccfdd096..2c7ecb1 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
@@ -83,6 +83,12 @@
          */
         default void onAvailableComplicationTypesChanged() {
         }
+
+        /**
+         * Called when the low light dream is exiting and transitioning back to the user dream.
+         */
+        default void onExitLowLight() {
+        }
     }
 
     private final Executor mExecutor;
@@ -278,6 +284,10 @@
      * @param active {@code true} if low light mode is active, {@code false} otherwise.
      */
     public void setLowLightActive(boolean active) {
+        if (isLowLightActive() && !active) {
+            // Notify that we're exiting low light only on the transition from active to not active.
+            mCallbacks.forEach(Callback::onExitLowLight);
+        }
         modifyState(active ? OP_SET_STATE : OP_CLEAR_STATE, STATE_LOW_LIGHT_ACTIVE);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 95dd2d0..a6977e1 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -199,8 +199,7 @@
 
     /** A different path for unocclusion transitions back to keyguard */
     // TODO(b/262859270): Tracking Bug
-    @JvmField
-    val UNOCCLUSION_TRANSITION = unreleasedFlag(223, "unocclusion_transition", teamfood = true)
+    @JvmField val UNOCCLUSION_TRANSITION = releasedFlag(223, "unocclusion_transition")
 
     // flag for controlling auto pin confirmation and material u shapes in bouncer
     @JvmField
@@ -452,6 +451,12 @@
     val ENABLE_PIP_SIZE_LARGE_SCREEN =
         sysPropBooleanFlag(1114, "persist.wm.debug.enable_pip_size_large_screen", default = false)
 
+    // TODO(b/265998256): Tracking bug
+    @Keep
+    @JvmField
+    val ENABLE_PIP_APP_ICON_OVERLAY =
+        sysPropBooleanFlag(1115, "persist.wm.debug.enable_pip_app_icon_overlay", default = false)
+
     // 1200 - predictive back
     @Keep
     @JvmField
@@ -529,7 +534,6 @@
         releasedFlag(1600, "a11y_floating_menu_fling_spring_animations")
 
     // 1700 - clipboard
-    @JvmField val CLIPBOARD_OVERLAY_REFACTOR = releasedFlag(1700, "clipboard_overlay_refactor")
     @JvmField val CLIPBOARD_REMOTE_BEHAVIOR = releasedFlag(1701, "clipboard_remote_behavior")
 
     // 1800 - shade container
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
index 482138e..680c504 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
@@ -31,10 +31,12 @@
 import android.util.Log
 import com.android.systemui.SystemUIAppComponentFactoryBase
 import com.android.systemui.SystemUIAppComponentFactoryBase.ContextAvailableCallback
+import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
 import com.android.systemui.keyguard.ui.preview.KeyguardRemotePreviewManager
 import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.runBlocking
 
 class CustomizationProvider :
@@ -42,6 +44,7 @@
 
     @Inject lateinit var interactor: KeyguardQuickAffordanceInteractor
     @Inject lateinit var previewManager: KeyguardRemotePreviewManager
+    @Inject @Main lateinit var mainDispatcher: CoroutineDispatcher
 
     private lateinit var contextAvailableCallback: ContextAvailableCallback
 
@@ -138,12 +141,14 @@
         selectionArgs: Array<out String>?,
         sortOrder: String?,
     ): Cursor? {
-        return when (uriMatcher.match(uri)) {
-            MATCH_CODE_ALL_AFFORDANCES -> runBlocking { queryAffordances() }
-            MATCH_CODE_ALL_SLOTS -> querySlots()
-            MATCH_CODE_ALL_SELECTIONS -> runBlocking { querySelections() }
-            MATCH_CODE_ALL_FLAGS -> queryFlags()
-            else -> null
+        return runBlocking(mainDispatcher) {
+            when (uriMatcher.match(uri)) {
+                MATCH_CODE_ALL_AFFORDANCES -> queryAffordances()
+                MATCH_CODE_ALL_SLOTS -> querySlots()
+                MATCH_CODE_ALL_SELECTIONS -> querySelections()
+                MATCH_CODE_ALL_FLAGS -> queryFlags()
+                else -> null
+            }
         }
     }
 
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 f6e6d6b..5a9f775 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
@@ -19,6 +19,7 @@
 
 import android.app.StatusBarManager
 import android.content.Context
+import android.content.pm.PackageManager
 import com.android.systemui.R
 import com.android.systemui.animation.Expandable
 import com.android.systemui.camera.CameraGestureHelper
@@ -26,7 +27,6 @@
 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.statusbar.StatusBarState
 import dagger.Lazy
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
@@ -37,6 +37,7 @@
 @Inject
 constructor(
     @Application private val context: Context,
+    private val packageManager: PackageManager,
     private val cameraGestureHelper: Lazy<CameraGestureHelper>,
 ) : KeyguardQuickAffordanceConfig {
 
@@ -79,6 +80,6 @@
     }
 
     private fun isLaunchable(): Boolean {
-        return cameraGestureHelper.get().canCameraGestureBeLaunched(StatusBarState.KEYGUARD)
+        return packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
index 08edbc6..b3a9cf5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
@@ -22,14 +22,18 @@
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.stateIn
 
 /** Encapsulates state about device entry fingerprint auth mechanism. */
 interface DeviceEntryFingerprintAuthRepository {
     /** Whether the device entry fingerprint auth is locked out. */
-    val isLockedOut: Flow<Boolean>
+    val isLockedOut: StateFlow<Boolean>
 }
 
 /**
@@ -44,29 +48,34 @@
 @Inject
 constructor(
     val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+    @Application scope: CoroutineScope,
 ) : DeviceEntryFingerprintAuthRepository {
 
-    override val isLockedOut: Flow<Boolean> = conflatedCallbackFlow {
-        val sendLockoutUpdate =
-            fun() {
-                trySendWithFailureLogging(
-                    keyguardUpdateMonitor.isFingerprintLockedOut,
-                    TAG,
-                    "onLockedOutStateChanged"
-                )
-            }
-        val callback =
-            object : KeyguardUpdateMonitorCallback() {
-                override fun onLockedOutStateChanged(biometricSourceType: BiometricSourceType?) {
-                    if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
-                        sendLockoutUpdate()
+    override val isLockedOut: StateFlow<Boolean> =
+        conflatedCallbackFlow {
+                val sendLockoutUpdate =
+                    fun() {
+                        trySendWithFailureLogging(
+                            keyguardUpdateMonitor.isFingerprintLockedOut,
+                            TAG,
+                            "onLockedOutStateChanged"
+                        )
                     }
-                }
+                val callback =
+                    object : KeyguardUpdateMonitorCallback() {
+                        override fun onLockedOutStateChanged(
+                            biometricSourceType: BiometricSourceType?
+                        ) {
+                            if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
+                                sendLockoutUpdate()
+                            }
+                        }
+                    }
+                keyguardUpdateMonitor.registerCallback(callback)
+                sendLockoutUpdate()
+                awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
             }
-        keyguardUpdateMonitor.registerCallback(callback)
-        sendLockoutUpdate()
-        awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
-    }
+            .stateIn(scope, started = SharingStarted.Eagerly, initialValue = false)
 
     companion object {
         const val TAG = "DeviceEntryFingerprintAuthRepositoryImpl"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
index 4639597..cc99eb7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
@@ -32,4 +32,9 @@
     fun lightRevealScrimRepository(impl: LightRevealScrimRepositoryImpl): LightRevealScrimRepository
 
     @Binds fun biometricRepository(impl: BiometricRepositoryImpl): BiometricRepository
+
+    @Binds
+    fun deviceEntryFingerprintAuthRepository(
+        impl: DeviceEntryFingerprintAuthRepositoryImpl
+    ): DeviceEntryFingerprintAuthRepository
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
index 28c0b28..6020ef8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
@@ -21,6 +21,7 @@
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.BiometricRepository
+import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
 import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.LegacyAlternateBouncer
 import com.android.systemui.util.time.SystemClock
@@ -34,6 +35,7 @@
 constructor(
     private val bouncerRepository: KeyguardBouncerRepository,
     private val biometricRepository: BiometricRepository,
+    private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
     private val systemClock: SystemClock,
     private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
     featureFlags: FeatureFlags,
@@ -99,7 +101,8 @@
             bouncerRepository.isAlternateBouncerUIAvailable.value &&
                 biometricRepository.isFingerprintEnrolled.value &&
                 biometricRepository.isStrongBiometricAllowed.value &&
-                biometricRepository.isFingerprintEnabledByDevicePolicy.value
+                biometricRepository.isFingerprintEnabledByDevicePolicy.value &&
+                !deviceEntryFingerprintAuthRepository.isLockedOut.value
         } else {
             legacyAlternateBouncer != null &&
                 keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(true)
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 08d1857..6bfe1a0 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -17,10 +17,12 @@
 package com.android.systemui.notetask
 
 import android.app.KeyguardManager
+import android.content.ActivityNotFoundException
 import android.content.ComponentName
 import android.content.Context
 import android.content.pm.PackageManager
 import android.os.UserManager
+import android.util.Log
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
 import com.android.systemui.util.kotlin.getOrNull
@@ -57,7 +59,7 @@
      * If the keyguard is locked, notes will open as a full screen experience. A locked device has
      * no contextual information which let us use the whole screen space available.
      *
-     * If no in multi-window or the keyguard is unlocked, notes will open as a bubble OR it will be
+     * If not in multi-window or the keyguard is unlocked, notes will open as a bubble OR it will be
      * collapsed if the notes bubble is already opened.
      *
      * That will let users open other apps in full screen, and take contextual notes.
@@ -68,16 +70,23 @@
         val bubbles = optionalBubbles.getOrNull() ?: return
         val keyguardManager = optionalKeyguardManager.getOrNull() ?: return
         val userManager = optionalUserManager.getOrNull() ?: return
-        val intent = intentResolver.resolveIntent() ?: return
 
         // TODO(b/249954038): We should handle direct boot (isUserUnlocked). For now, we do nothing.
         if (!userManager.isUserUnlocked) return
 
-        if (isInMultiWindowMode || keyguardManager.isKeyguardLocked) {
-            context.startActivity(intent)
-        } else {
-            // TODO(b/254606432): Should include Intent.EXTRA_FLOATING_WINDOW_MODE parameter.
-            bubbles.showOrHideAppBubble(intent)
+        val intent = intentResolver.resolveIntent() ?: return
+
+        // TODO(b/266686199): We should handle when app not available. For now, we log.
+        try {
+            if (isInMultiWindowMode || keyguardManager.isKeyguardLocked) {
+                context.startActivity(intent)
+            } else {
+                bubbles.showOrHideAppBubble(intent)
+            }
+        } catch (e: ActivityNotFoundException) {
+            val message =
+                "Activity not found for action: ${NoteTaskIntentResolver.ACTION_CREATE_NOTE}."
+            Log.e(TAG, message, e)
         }
     }
 
@@ -106,6 +115,8 @@
     }
 
     companion object {
+        private val TAG = NoteTaskController::class.simpleName.orEmpty()
+
         // TODO(b/254604589): Use final KeyEvent.KEYCODE_* instead.
         const val NOTE_TASK_KEY_EVENT = 311
     }
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt
index 4b10d69..11dc1d7 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt
@@ -16,70 +16,39 @@
 
 package com.android.systemui.notetask
 
-import android.content.ComponentName
+import android.app.role.RoleManager
+import android.content.Context
 import android.content.Intent
-import android.content.pm.ActivityInfo
-import android.content.pm.PackageManager
-import android.content.pm.PackageManager.ResolveInfoFlags
-import com.android.systemui.notetask.NoteTaskIntentResolver.Companion.ACTION_CREATE_NOTE
 import javax.inject.Inject
 
-/**
- * Class responsible to query all apps and find one that can handle the [ACTION_CREATE_NOTE]. If
- * found, an [Intent] ready for be launched will be returned. Otherwise, returns null.
- *
- * TODO(b/248274123): should be revisited once the notes role is implemented.
- */
 internal class NoteTaskIntentResolver
 @Inject
 constructor(
-    private val packageManager: PackageManager,
+    private val context: Context,
+    private val roleManager: RoleManager,
 ) {
 
     fun resolveIntent(): Intent? {
-        val intent = Intent(ACTION_CREATE_NOTE)
-        val flags = ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong())
-        val infoList = packageManager.queryIntentActivities(intent, flags)
+        val packageName = roleManager.getRoleHoldersAsUser(ROLE_NOTES, context.user).firstOrNull()
 
-        for (info in infoList) {
-            val packageName = info.activityInfo.applicationInfo.packageName ?: continue
-            val activityName = resolveActivityNameForNotesAction(packageName) ?: continue
+        if (packageName.isNullOrEmpty()) return null
 
-            return Intent(ACTION_CREATE_NOTE)
-                .setPackage(packageName)
-                .setComponent(ComponentName(packageName, activityName))
-                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-        }
-
-        return null
-    }
-
-    private fun resolveActivityNameForNotesAction(packageName: String): String? {
-        val intent = Intent(ACTION_CREATE_NOTE).setPackage(packageName)
-        val flags = ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong())
-        val resolveInfo = packageManager.resolveActivity(intent, flags)
-
-        val activityInfo = resolveInfo?.activityInfo ?: return null
-        if (activityInfo.name.isNullOrBlank()) return null
-        if (!activityInfo.exported) return null
-        if (!activityInfo.enabled) return null
-        if (!activityInfo.showWhenLocked) return null
-        if (!activityInfo.turnScreenOn) return null
-
-        return activityInfo.name
+        return Intent(ACTION_CREATE_NOTE)
+            .setPackage(packageName)
+            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+            // EXTRA_USE_STYLUS_MODE does not mean a stylus is in-use, but a stylus entrypoint was
+            // used to start it.
+            .putExtra(INTENT_EXTRA_USE_STYLUS_MODE, true)
     }
 
     companion object {
-        // TODO(b/254606432): Use Intent.ACTION_CREATE_NOTE instead.
+        // TODO(b/265912743): Use Intent.ACTION_CREATE_NOTE instead.
         const val ACTION_CREATE_NOTE = "android.intent.action.CREATE_NOTE"
 
         // TODO(b/265912743): Use RoleManager.NOTES_ROLE instead.
-        const val NOTE_ROLE = "android.app.role.NOTES"
+        const val ROLE_NOTES = "android.app.role.NOTES"
+
+        // TODO(b/265912743): Use Intent.INTENT_EXTRA_USE_STYLUS_MODE instead.
+        const val INTENT_EXTRA_USE_STYLUS_MODE = "android.intent.extra.USE_STYLUS_MODE"
     }
 }
-
-private val ActivityInfo.showWhenLocked: Boolean
-    get() = flags and ActivityInfo.FLAG_SHOW_WHEN_LOCKED != 0
-
-private val ActivityInfo.turnScreenOn: Boolean
-    get() = flags and ActivityInfo.FLAG_TURN_SCREEN_ON != 0
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
index 22ce121..ec6a16a 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
@@ -51,7 +51,7 @@
             featureFlags: FeatureFlags,
             roleManager: RoleManager,
         ): Boolean {
-            val isRoleAvailable = roleManager.isRoleAvailable(NoteTaskIntentResolver.NOTE_ROLE)
+            val isRoleAvailable = roleManager.isRoleAvailable(NoteTaskIntentResolver.ROLE_NOTES)
             val isFeatureEnabled = featureFlags.isEnabled(Flags.NOTE_TASKS)
             return isRoleAvailable && isFeatureEnabled
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
index d1cf46c..464b6e7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
@@ -636,7 +636,8 @@
                 isRunning: Boolean
         ) {
             synchronized(lock) {
-                val userPackageKey = UserPackage(summary.sourceUserId, summary.sourcePackageName)
+                val userPackageKey = UserPackage(
+                        UserHandle.getUserId(summary.callingUid), summary.callingPackageName)
                 if (isRunning) {
                     runningTaskIdentifiers
                             .getOrPut(userPackageKey) { StartTimeAndIdentifiers(systemClock) }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 0f52133..1c4e319 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -43,6 +43,7 @@
 import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
 import static com.android.systemui.plugins.log.LogLevel.ERROR;
 
+import android.app.AlarmManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -99,6 +100,7 @@
 import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.AlarmTimeout;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.wakelock.SettableWakeLock;
 import com.android.systemui.util.wakelock.WakeLock;
@@ -128,10 +130,8 @@
     private static final String TAG = "KeyguardIndication";
     private static final boolean DEBUG_CHARGING_SPEED = false;
 
-    private static final int MSG_HIDE_TRANSIENT = 1;
-    private static final int MSG_SHOW_ACTION_TO_UNLOCK = 2;
-    private static final int MSG_HIDE_BIOMETRIC_MESSAGE = 3;
-    private static final int MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON = 4;
+    private static final int MSG_SHOW_ACTION_TO_UNLOCK = 1;
+    private static final int MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON = 2;
     private static final long TRANSIENT_BIOMETRIC_ERROR_TIMEOUT = 1300;
     public static final long DEFAULT_HIDE_DELAY_MS =
             3500 + KeyguardIndicationTextView.Y_IN_DURATION;
@@ -213,6 +213,11 @@
     };
     private boolean mFaceLockedOutThisAuthSession;
 
+    // Use AlarmTimeouts to guarantee that the events are handled even if scheduled and
+    // triggered while the device is asleep
+    private final AlarmTimeout mHideTransientMessageHandler;
+    private final AlarmTimeout mHideBiometricMessageHandler;
+
     /**
      * Creates a new KeyguardIndicationController and registers callbacks.
      */
@@ -239,7 +244,9 @@
             AccessibilityManager accessibilityManager,
             FaceHelpMessageDeferral faceHelpMessageDeferral,
             KeyguardLogger keyguardLogger,
-            AlternateBouncerInteractor alternateBouncerInteractor) {
+            AlternateBouncerInteractor alternateBouncerInteractor,
+            AlarmManager alarmManager
+    ) {
         mContext = context;
         mBroadcastDispatcher = broadcastDispatcher;
         mDevicePolicyManager = devicePolicyManager;
@@ -274,17 +281,26 @@
         mHandler = new Handler(mainLooper) {
             @Override
             public void handleMessage(Message msg) {
-                if (msg.what == MSG_HIDE_TRANSIENT) {
-                    hideTransientIndication();
-                } else if (msg.what == MSG_SHOW_ACTION_TO_UNLOCK) {
+                if (msg.what == MSG_SHOW_ACTION_TO_UNLOCK) {
                     showActionToUnlock();
-                } else if (msg.what == MSG_HIDE_BIOMETRIC_MESSAGE) {
-                    hideBiometricMessage();
                 } else if (msg.what == MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON) {
                     mBiometricErrorMessageToShowOnScreenOn = null;
                 }
             }
         };
+
+        mHideTransientMessageHandler = new AlarmTimeout(
+                alarmManager,
+                this::hideTransientIndication,
+                TAG,
+                mHandler
+        );
+        mHideBiometricMessageHandler = new AlarmTimeout(
+                alarmManager,
+                this::hideBiometricMessage,
+                TAG,
+                mHandler
+        );
     }
 
     /** Call this after construction to finish setting up the instance. */
@@ -336,6 +352,8 @@
      */
     public void destroy() {
         mHandler.removeCallbacksAndMessages(null);
+        mHideBiometricMessageHandler.cancel();
+        mHideTransientMessageHandler.cancel();
         mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
     }
 
@@ -691,7 +709,7 @@
         if (visible) {
             // If this is called after an error message was already shown, we should not clear it.
             // Otherwise the error message won't be shown
-            if (!mHandler.hasMessages(MSG_HIDE_TRANSIENT)) {
+            if (!mHideTransientMessageHandler.isScheduled()) {
                 hideTransientIndication();
             }
             updateDeviceEntryIndication(false);
@@ -739,16 +757,14 @@
      * Hides transient indication in {@param delayMs}.
      */
     public void hideTransientIndicationDelayed(long delayMs) {
-        mHandler.sendMessageDelayed(
-                mHandler.obtainMessage(MSG_HIDE_TRANSIENT), delayMs);
+        mHideTransientMessageHandler.schedule(delayMs, AlarmTimeout.MODE_RESCHEDULE_IF_SCHEDULED);
     }
 
     /**
      * Hides biometric indication in {@param delayMs}.
      */
     public void hideBiometricMessageDelayed(long delayMs) {
-        mHandler.sendMessageDelayed(
-                mHandler.obtainMessage(MSG_HIDE_BIOMETRIC_MESSAGE), delayMs);
+        mHideBiometricMessageHandler.schedule(delayMs, AlarmTimeout.MODE_RESCHEDULE_IF_SCHEDULED);
     }
 
     /**
@@ -763,7 +779,6 @@
      */
     private void showTransientIndication(CharSequence transientIndication) {
         mTransientIndication = transientIndication;
-        mHandler.removeMessages(MSG_HIDE_TRANSIENT);
         hideTransientIndicationDelayed(DEFAULT_HIDE_DELAY_MS);
 
         updateTransient();
@@ -789,7 +804,6 @@
         mBiometricMessageFollowUp = biometricMessageFollowUp;
 
         mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK);
-        mHandler.removeMessages(MSG_HIDE_BIOMETRIC_MESSAGE);
         hideBiometricMessageDelayed(
                 mBiometricMessageFollowUp != null
                         ? IMPORTANT_MSG_MIN_DURATION * 2
@@ -803,7 +817,7 @@
         if (mBiometricMessage != null || mBiometricMessageFollowUp != null) {
             mBiometricMessage = null;
             mBiometricMessageFollowUp = null;
-            mHandler.removeMessages(MSG_HIDE_BIOMETRIC_MESSAGE);
+            mHideBiometricMessageHandler.cancel();
             updateBiometricMessage();
         }
     }
@@ -814,7 +828,7 @@
     public void hideTransientIndication() {
         if (mTransientIndication != null) {
             mTransientIndication = null;
-            mHandler.removeMessages(MSG_HIDE_TRANSIENT);
+            mHideTransientMessageHandler.cancel();
             updateTransient();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index 1d7dfe1..0814ea5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -122,6 +122,10 @@
     public LoaderResult loadBitmap(int currentUserId, UserHandle selectedUser) {
         // May be called on any thread - only use thread safe operations.
 
+        if (mWallpaperManager.isLockscreenLiveWallpaperEnabled()) {
+            return LoaderResult.success(null);
+        }
+
         if (!mWallpaperManager.isWallpaperSupported()) {
             // When wallpaper is not supported, show the system wallpaper
             return LoaderResult.success(null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 24ad55d..11863627 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -501,7 +501,7 @@
         @VisibleForTesting
         protected StatusIconDisplayable addWifiIcon(int index, String slot, WifiIconState state) {
             if (mStatusBarPipelineFlags.useNewWifiIcon()) {
-                throw new IllegalStateException("Attempting to add a mobile icon while the new "
+                throw new IllegalStateException("Attempting to add a wifi icon while the new "
                         + "icons are enabled is not supported");
             }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index c85e559..c2ca7c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -279,7 +279,6 @@
     private boolean mLastScreenOffAnimationPlaying;
     private float mQsExpansion;
     final Set<KeyguardViewManagerCallback> mCallbacks = new HashSet<>();
-    private boolean mIsModernBouncerEnabled;
     private boolean mIsModernAlternateBouncerEnabled;
     private boolean mIsUnoccludeTransitionFlagEnabled;
     private boolean mIsBackAnimationEnabled;
@@ -358,7 +357,6 @@
         mPrimaryBouncerView = primaryBouncerView;
         mFoldAodAnimationController = sysUIUnfoldComponent
                 .map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null);
-        mIsModernBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_BOUNCER);
         mIsModernAlternateBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER);
         mAlternateBouncerInteractor = alternateBouncerInteractor;
         mIsUnoccludeTransitionFlagEnabled = featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
index d3ff357..491f3a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
@@ -97,15 +97,20 @@
         )
     }
 
-    fun logOnCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
+    fun logOnCapabilitiesChanged(
+        network: Network,
+        networkCapabilities: NetworkCapabilities,
+        isDefaultNetworkCallback: Boolean,
+    ) {
         buffer.log(
             SB_LOGGING_TAG,
             LogLevel.INFO,
             {
+                bool1 = isDefaultNetworkCallback
                 int1 = network.getNetId()
                 str1 = networkCapabilities.toString()
             },
-            { "onCapabilitiesChanged: net=$int1 capabilities=$str1" }
+            { "onCapabilitiesChanged[default=$bool1]: net=$int1 capabilities=$str1" }
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
index d26499c..8669047 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
@@ -114,13 +114,17 @@
                             network: Network,
                             networkCapabilities: NetworkCapabilities
                         ) {
+                            logger.logOnCapabilitiesChanged(
+                                network,
+                                networkCapabilities,
+                                isDefaultNetworkCallback = true,
+                            )
+
                             // This method will always be called immediately after the network
                             // becomes the default, in addition to any time the capabilities change
                             // while the network is the default.
-                            // If this network contains valid wifi info, then wifi is the default
-                            // network.
-                            val wifiInfo = networkCapabilitiesToWifiInfo(networkCapabilities)
-                            trySend(wifiInfo != null)
+                            // If this network is a wifi network, then wifi is the default network.
+                            trySend(isWifiNetwork(networkCapabilities))
                         }
 
                         override fun onLost(network: Network) {
@@ -152,7 +156,11 @@
                             network: Network,
                             networkCapabilities: NetworkCapabilities
                         ) {
-                            logger.logOnCapabilitiesChanged(network, networkCapabilities)
+                            logger.logOnCapabilitiesChanged(
+                                network,
+                                networkCapabilities,
+                                isDefaultNetworkCallback = false,
+                            )
 
                             wifiNetworkChangeEvents.tryEmit(Unit)
 
@@ -253,16 +261,30 @@
             networkCapabilities: NetworkCapabilities
         ): WifiInfo? {
             return when {
-                networkCapabilities.hasTransport(TRANSPORT_WIFI) ->
-                    networkCapabilities.transportInfo as WifiInfo?
                 networkCapabilities.hasTransport(TRANSPORT_CELLULAR) ->
                     // Sometimes, cellular networks can act as wifi networks (known as VCN --
                     // virtual carrier network). So, see if this cellular network has wifi info.
                     Utils.tryGetWifiInfoForVcn(networkCapabilities)
+                networkCapabilities.hasTransport(TRANSPORT_WIFI) ->
+                    if (networkCapabilities.transportInfo is WifiInfo) {
+                        networkCapabilities.transportInfo as WifiInfo
+                    } else {
+                        null
+                    }
                 else -> null
             }
         }
 
+        /** True if these capabilities represent a wifi network. */
+        private fun isWifiNetwork(networkCapabilities: NetworkCapabilities): Boolean {
+            return when {
+                networkCapabilities.hasTransport(TRANSPORT_WIFI) -> true
+                networkCapabilities.hasTransport(TRANSPORT_CELLULAR) ->
+                    Utils.tryGetWifiInfoForVcn(networkCapabilities) != null
+                else -> false
+            }
+        }
+
         private fun createWifiNetworkModel(
             wifiInfo: WifiInfo,
             network: Network,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
index 9946b4b..5dcafb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.policy;
 
 import android.annotation.WorkerThread;
-import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraCharacteristics;
@@ -255,7 +254,6 @@
                 setTorchMode(enabled);
                 mSecureSettings.putInt(Settings.Secure.FLASHLIGHT_AVAILABLE, 1);
                 mSecureSettings.putInt(Secure.FLASHLIGHT_ENABLED, enabled ? 1 : 0);
-                mBroadcastSender.sendBroadcast(new Intent(ACTION_FLASHLIGHT_CHANGED));
             }
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index eaef959..4d95a22 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -695,7 +695,6 @@
         setKeyguardBouncerVisibility(true);
 
         verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
-        verify(mFaceManager).isHardwareDetected();
         verify(mFaceManager, never()).hasEnrolledTemplates(anyInt());
     }
 
@@ -854,6 +853,32 @@
     }
 
     @Test
+    public void faceUnlockDoesNotRunWhenDeviceIsGoingToSleepWithAssistantVisible() {
+        mKeyguardUpdateMonitor.setKeyguardShowing(true, true);
+        mKeyguardUpdateMonitor.setAssistantVisible(true);
+
+        verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
+        mTestableLooper.processAllMessages();
+        clearInvocations(mFaceManager);
+
+        // Device going to sleep while assistant is visible
+        mKeyguardUpdateMonitor.handleStartedGoingToSleep(0);
+        mKeyguardUpdateMonitor.handleFinishedGoingToSleep(0);
+        mTestableLooper.moveTimeForward(DEFAULT_CANCEL_SIGNAL_TIMEOUT);
+        mTestableLooper.processAllMessages();
+
+        mKeyguardUpdateMonitor.handleKeyguardReset();
+
+        assertThat(mKeyguardUpdateMonitor.isFaceDetectionRunning()).isFalse();
+        verify(mFaceManager, never()).authenticate(any(),
+                any(),
+                any(),
+                any(),
+                anyInt(),
+                anyBoolean());
+    }
+
+    @Test
     public void testIgnoresAuth_whenTrustAgentOnKeyguard_withoutBypass() {
         mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
         mTestableLooper.processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
index b92c5d0..fd931b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -51,14 +51,24 @@
 import android.view.WindowMetrics
 import androidx.test.filters.SmallTest
 import com.airbnb.lottie.LottieAnimationView
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.ViewMediatorCallback
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.SysuiTestableContext
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags.MODERN_ALTERNATE_BOUNCER
+import com.android.systemui.keyguard.data.repository.FakeBiometricRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.recents.OverviewProxyService
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.TestCoroutineScope
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -101,6 +111,9 @@
     @Captor lateinit var overlayCaptor: ArgumentCaptor<View>
     @Captor lateinit var overlayViewParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams>
 
+    private lateinit var keyguardBouncerRepository: KeyguardBouncerRepository
+    private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+    private val featureFlags = FakeFeatureFlags()
     private val executor = FakeExecutor(FakeSystemClock())
     private lateinit var overlayController: ISidefpsController
     private lateinit var sideFpsController: SideFpsController
@@ -121,6 +134,24 @@
 
     @Before
     fun setup() {
+        featureFlags.set(MODERN_ALTERNATE_BOUNCER, true)
+        keyguardBouncerRepository =
+            KeyguardBouncerRepository(
+                mock(ViewMediatorCallback::class.java),
+                FakeSystemClock(),
+                TestCoroutineScope(),
+                mock(TableLogBuffer::class.java),
+            )
+        alternateBouncerInteractor =
+            AlternateBouncerInteractor(
+                keyguardBouncerRepository,
+                FakeBiometricRepository(),
+                FakeDeviceEntryFingerprintAuthRepository(),
+                FakeSystemClock(),
+                mock(KeyguardUpdateMonitor::class.java),
+                featureFlags,
+            )
+
         context.addMockSystemService(DisplayManager::class.java, displayManager)
         context.addMockSystemService(WindowManager::class.java, windowManager)
 
@@ -217,7 +248,10 @@
                 displayManager,
                 executor,
                 handler,
-                dumpManager
+                alternateBouncerInteractor,
+                TestCoroutineScope(),
+                featureFlags,
+                dumpManager,
             )
 
         overlayController =
@@ -507,6 +541,26 @@
 
     private fun verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible: Boolean) {
         sideFpsController.overlayOffsets = sensorLocation
+    }
+
+    fun alternateBouncerVisibility_showAndHideSideFpsUI() = testWithDisplay {
+        // WHEN alternate bouncer is visible
+        keyguardBouncerRepository.setAlternateVisible(true)
+        executor.runAllReady()
+
+        // THEN side fps shows UI
+        verify(windowManager).addView(any(), any())
+        verify(windowManager, never()).removeView(any())
+
+        // WHEN alternate bouncer is no longer visible
+        keyguardBouncerRepository.setAlternateVisible(false)
+        executor.runAllReady()
+
+        // THEN side fps UI is hidden
+        verify(windowManager).removeView(any())
+    }
+
+    private fun hidesWithTaskbar(visible: Boolean) {
         overlayController.show(SENSOR_ID, REASON_UNKNOWN)
         executor.runAllReady()
 
@@ -515,7 +569,7 @@
 
         verify(windowManager).addView(any(), any())
         verify(windowManager, never()).removeView(any())
-        verify(sideFpsView).visibility = if (sfpsViewVisible) View.VISIBLE else View.GONE
+        verify(sideFpsView).visibility = if (visible) View.VISIBLE else View.GONE
     }
 
     /**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index b9a952a..36ed6d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -105,6 +105,7 @@
     @Mock private lateinit var udfpsController: UdfpsController
     @Mock private lateinit var udfpsView: UdfpsView
     @Mock private lateinit var udfpsEnrollView: UdfpsEnrollView
+    @Mock private lateinit var udfpsKeyguardView: UdfpsKeyguardView
     @Mock private lateinit var activityLaunchAnimator: ActivityLaunchAnimator
     @Mock private lateinit var featureFlags: FeatureFlags
     @Mock private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
@@ -125,7 +126,7 @@
         whenever(inflater.inflate(R.layout.udfps_bp_view, null))
             .thenReturn(mock(UdfpsBpView::class.java))
         whenever(inflater.inflate(R.layout.udfps_keyguard_view, null))
-            .thenReturn(mock(UdfpsKeyguardView::class.java))
+            .thenReturn(udfpsKeyguardView)
         whenever(inflater.inflate(R.layout.udfps_fpm_empty_view, null))
             .thenReturn(mock(UdfpsFpmEmptyView::class.java))
         whenever(udfpsEnrollView.context).thenReturn(context)
@@ -152,7 +153,10 @@
     fun showUdfpsOverlay_bp() = withReason(REASON_AUTH_BP) { showUdfpsOverlay() }
 
     @Test
-    fun showUdfpsOverlay_keyguard() = withReason(REASON_AUTH_KEYGUARD) { showUdfpsOverlay() }
+    fun showUdfpsOverlay_keyguard() = withReason(REASON_AUTH_KEYGUARD) {
+        showUdfpsOverlay()
+        verify(udfpsKeyguardView).updateSensorLocation(eq(overlayParams.sensorBounds))
+    }
 
     @Test
     fun showUdfpsOverlay_settings() = withReason(REASON_AUTH_SETTINGS) { showUdfpsOverlay() }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
index 9060922..81a6bc2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.keyguard.DismissCallbackRegistry
 import com.android.systemui.keyguard.data.BouncerView
 import com.android.systemui.keyguard.data.repository.BiometricRepository
+import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
 import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
 import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor
@@ -91,6 +92,7 @@
             AlternateBouncerInteractor(
                 keyguardBouncerRepository,
                 mock(BiometricRepository::class.java),
+                mock(DeviceEntryFingerprintAuthRepository::class.java),
                 mock(SystemClock::class.java),
                 mock(KeyguardUpdateMonitor::class.java),
                 mock(FeatureFlags::class.java)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
index bdd496e..71c335e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.clipboardoverlay;
 
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_ENABLED;
-
 import static com.google.android.setupcompat.util.WizardManagerHelper.SETTINGS_SECURE_USER_SETUP_COMPLETE;
 
 import static org.junit.Assert.assertEquals;
@@ -33,7 +31,6 @@
 import android.content.ClipDescription;
 import android.content.ClipboardManager;
 import android.os.PersistableBundle;
-import android.provider.DeviceConfig;
 import android.provider.Settings;
 
 import androidx.test.filters.SmallTest;
@@ -41,9 +38,6 @@
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
-import com.android.systemui.util.DeviceConfigProxyFake;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -63,18 +57,11 @@
     @Mock
     private ClipboardManager mClipboardManager;
     @Mock
-    private ClipboardOverlayControllerLegacyFactory mClipboardOverlayControllerLegacyFactory;
-    @Mock
-    private ClipboardOverlayControllerLegacy mOverlayControllerLegacy;
-    @Mock
     private ClipboardOverlayController mOverlayController;
     @Mock
     private ClipboardToast mClipboardToast;
     @Mock
     private UiEventLogger mUiEventLogger;
-    @Mock
-    private FeatureFlags mFeatureFlags;
-    private DeviceConfigProxyFake mDeviceConfigProxy;
 
     private ClipData mSampleClipData;
     private String mSampleSource = "Example source";
@@ -97,8 +84,6 @@
         mOverlayControllerProvider = () -> mOverlayController;
 
         MockitoAnnotations.initMocks(this);
-        when(mClipboardOverlayControllerLegacyFactory.create(any()))
-                .thenReturn(mOverlayControllerLegacy);
         when(mClipboardManager.hasPrimaryClip()).thenReturn(true);
         Settings.Secure.putInt(
                 mContext.getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 1);
@@ -108,26 +93,13 @@
         when(mClipboardManager.getPrimaryClip()).thenReturn(mSampleClipData);
         when(mClipboardManager.getPrimaryClipSource()).thenReturn(mSampleSource);
 
-        mDeviceConfigProxy = new DeviceConfigProxyFake();
-
-        mClipboardListener = new ClipboardListener(getContext(), mDeviceConfigProxy,
-                mOverlayControllerProvider, mClipboardOverlayControllerLegacyFactory,
-                mClipboardToast, mClipboardManager, mUiEventLogger, mFeatureFlags);
+        mClipboardListener = new ClipboardListener(getContext(), mOverlayControllerProvider,
+                mClipboardToast, mClipboardManager, mUiEventLogger);
     }
 
-    @Test
-    public void test_disabled() {
-        mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED,
-                "false", false);
-        mClipboardListener.start();
-        verifyZeroInteractions(mClipboardManager);
-        verifyZeroInteractions(mUiEventLogger);
-    }
 
     @Test
-    public void test_enabled() {
-        mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED,
-                "true", false);
+    public void test_initialization() {
         mClipboardListener.start();
         verify(mClipboardManager).addPrimaryClipChangedListener(any());
         verifyZeroInteractions(mUiEventLogger);
@@ -135,45 +107,6 @@
 
     @Test
     public void test_consecutiveCopies() {
-        when(mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR)).thenReturn(false);
-
-        mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED,
-                "true", false);
-        mClipboardListener.start();
-        mClipboardListener.onPrimaryClipChanged();
-
-        verify(mClipboardOverlayControllerLegacyFactory).create(any());
-
-        verify(mOverlayControllerLegacy).setClipData(
-                mClipDataCaptor.capture(), mStringCaptor.capture());
-
-        assertEquals(mSampleClipData, mClipDataCaptor.getValue());
-        assertEquals(mSampleSource, mStringCaptor.getValue());
-
-        verify(mOverlayControllerLegacy).setOnSessionCompleteListener(mRunnableCaptor.capture());
-
-        // Should clear the overlay controller
-        mRunnableCaptor.getValue().run();
-
-        mClipboardListener.onPrimaryClipChanged();
-
-        verify(mClipboardOverlayControllerLegacyFactory, times(2)).create(any());
-
-        // Not calling the runnable here, just change the clip again and verify that the overlay is
-        // NOT recreated.
-
-        mClipboardListener.onPrimaryClipChanged();
-
-        verify(mClipboardOverlayControllerLegacyFactory, times(2)).create(any());
-        verifyZeroInteractions(mOverlayControllerProvider);
-    }
-
-    @Test
-    public void test_consecutiveCopies_new() {
-        when(mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR)).thenReturn(true);
-
-        mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED,
-                "true", false);
         mClipboardListener.start();
         mClipboardListener.onPrimaryClipChanged();
 
@@ -200,7 +133,6 @@
         mClipboardListener.onPrimaryClipChanged();
 
         verify(mOverlayControllerProvider, times(2)).get();
-        verifyZeroInteractions(mClipboardOverlayControllerLegacyFactory);
     }
 
     @Test
@@ -231,23 +163,6 @@
 
     @Test
     public void test_logging_enterAndReenter() {
-        when(mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR)).thenReturn(false);
-
-        mClipboardListener.start();
-
-        mClipboardListener.onPrimaryClipChanged();
-        mClipboardListener.onPrimaryClipChanged();
-
-        verify(mUiEventLogger, times(1)).log(
-                ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ENTERED, 0, mSampleSource);
-        verify(mUiEventLogger, times(1)).log(
-                ClipboardOverlayEvent.CLIPBOARD_OVERLAY_UPDATED, 0, mSampleSource);
-    }
-
-    @Test
-    public void test_logging_enterAndReenter_new() {
-        when(mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR)).thenReturn(true);
-
         mClipboardListener.start();
 
         mClipboardListener.onPrimaryClipChanged();
@@ -271,6 +186,5 @@
                 ClipboardOverlayEvent.CLIPBOARD_TOAST_SHOWN, 0, mSampleSource);
         verify(mClipboardToast, times(1)).showCopiedToast();
         verifyZeroInteractions(mOverlayControllerProvider);
-        verifyZeroInteractions(mClipboardOverlayControllerLegacyFactory);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
index ed40c90..85f9961 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
@@ -20,6 +20,7 @@
 import android.content.ComponentName
 import android.content.Context
 import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
 import android.content.pm.ServiceInfo
 import android.os.UserHandle
 import android.service.controls.ControlsProviderService
@@ -95,6 +96,7 @@
     @Mock lateinit var dumpManager: DumpManager
     @Mock lateinit var authorizedPanelsRepository: AuthorizedPanelsRepository
     @Mock lateinit var featureFlags: FeatureFlags
+    @Mock lateinit var packageManager: PackageManager
     val sharedPreferences = FakeSharedPreferences()
     lateinit var controlsSettingsRepository: FakeControlsSettingsRepository
 
@@ -124,6 +126,7 @@
             ControlsUiControllerImpl(
                 Lazy { controlsController },
                 context,
+                packageManager,
                 uiExecutor,
                 bgExecutor,
                 Lazy { controlsListingController },
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt
new file mode 100644
index 0000000..dbaf94f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.controls.ui
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class OverflowMenuAdapterTest : SysuiTestCase() {
+
+    @Test
+    fun testGetItemId() {
+        val ids = listOf(27L, 73L)
+        val labels = listOf("first", "second")
+        val adapter =
+            OverflowMenuAdapter(
+                context,
+                layoutId = 0,
+                labels.zip(ids).map { OverflowMenuAdapter.MenuItem(it.first, it.second) }
+            ) { true }
+
+        ids.forEachIndexed { index, id -> assertThat(adapter.getItemId(index)).isEqualTo(id) }
+    }
+
+    @Test
+    fun testCheckEnabled() {
+        val ids = listOf(27L, 73L)
+        val labels = listOf("first", "second")
+        val adapter =
+            OverflowMenuAdapter(
+                context,
+                layoutId = 0,
+                labels.zip(ids).map { OverflowMenuAdapter.MenuItem(it.first, it.second) }
+            ) { position -> position == 0 }
+
+        assertThat(adapter.isEnabled(0)).isTrue()
+        assertThat(adapter.isEnabled(1)).isFalse()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index ebc408e..6b095ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -214,6 +214,27 @@
     }
 
     @Test
+    public void testSkipEntryAnimationsWhenExitingLowLight() {
+        ArgumentCaptor<DreamOverlayStateController.Callback> callbackCaptor =
+                ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
+        when(mStateController.isLowLightActive()).thenReturn(false);
+
+        // Call onInit so that the callback is added.
+        mController.onInit();
+        verify(mStateController).addCallback(callbackCaptor.capture());
+
+        // Send the signal that low light is exiting
+        callbackCaptor.getValue().onExitLowLight();
+
+        // View is attached to trigger animations.
+        mController.onViewAttached();
+
+        // Entry animations should be started then immediately ended to skip to the end.
+        verify(mAnimationsController).startEntryAnimations();
+        verify(mAnimationsController).endAnimations();
+    }
+
+    @Test
     public void testCancelDreamEntryAnimationsOnDetached() {
         mController.onViewAttached();
         mController.onViewDetached();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
index ee989d1..b7d0f29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
@@ -251,6 +251,30 @@
     }
 
     @Test
+    public void testNotifyLowLightExit() {
+        final DreamOverlayStateController stateController =
+                new DreamOverlayStateController(mExecutor, true);
+
+        stateController.addCallback(mCallback);
+        mExecutor.runAllReady();
+        assertThat(stateController.isLowLightActive()).isFalse();
+
+        // Turn low light on then off to trigger the exiting callback.
+        stateController.setLowLightActive(true);
+        stateController.setLowLightActive(false);
+
+        // Callback was only called once, when
+        mExecutor.runAllReady();
+        verify(mCallback, times(1)).onExitLowLight();
+        assertThat(stateController.isLowLightActive()).isFalse();
+
+        // Set with false again, which should not cause the callback to trigger again.
+        stateController.setLowLightActive(false);
+        mExecutor.runAllReady();
+        verify(mCallback, times(1)).onExitLowLight();
+    }
+
+    @Test
     public void testNotifyEntryAnimationsFinishedChanged() {
         final DreamOverlayStateController stateController =
                 new DreamOverlayStateController(mExecutor, true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index c0af0cb..fb54d6d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -62,6 +62,7 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
@@ -184,6 +185,7 @@
                 mainDispatcher = testDispatcher,
                 backgroundHandler = backgroundHandler,
             )
+        underTest.mainDispatcher = UnconfinedTestDispatcher()
 
         underTest.attachInfoForTesting(
             context,
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 8da4eae..58cdec4 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
@@ -19,6 +19,7 @@
 
 import android.app.StatusBarManager
 import android.content.Context
+import android.content.pm.PackageManager
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.camera.CameraGestureHelper
@@ -32,7 +33,6 @@
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 import org.mockito.Mock
-import org.mockito.Mockito.anyInt
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
@@ -43,16 +43,19 @@
 
     @Mock private lateinit var cameraGestureHelper: CameraGestureHelper
     @Mock private lateinit var context: Context
+    @Mock private lateinit var packageManager: PackageManager
 
     private lateinit var underTest: CameraQuickAffordanceConfig
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
+        setLaunchable(true)
 
         underTest =
             CameraQuickAffordanceConfig(
                 context,
+                packageManager,
             ) {
                 cameraGestureHelper
             }
@@ -86,6 +89,7 @@
     }
 
     private fun setLaunchable(isLaunchable: Boolean) {
-        whenever(cameraGestureHelper.canCameraGestureBeLaunched(anyInt())).thenReturn(isLaunchable)
+        whenever(packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY))
+            .thenReturn(isLaunchable)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
index c4ae2db..9203f05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
@@ -55,7 +55,11 @@
         MockitoAnnotations.initMocks(this)
         testScope = TestScope()
 
-        underTest = DeviceEntryFingerprintAuthRepositoryImpl(keyguardUpdateMonitor)
+        underTest =
+            DeviceEntryFingerprintAuthRepositoryImpl(
+                keyguardUpdateMonitor,
+                testScope.backgroundScope,
+            )
     }
 
     @After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
index 1da7241..68fff26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeBiometricRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
 import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.util.time.FakeSystemClock
@@ -46,6 +47,8 @@
     private lateinit var underTest: AlternateBouncerInteractor
     private lateinit var bouncerRepository: KeyguardBouncerRepository
     private lateinit var biometricRepository: FakeBiometricRepository
+    private lateinit var deviceEntryFingerprintAuthRepository:
+        FakeDeviceEntryFingerprintAuthRepository
     @Mock private lateinit var systemClock: SystemClock
     @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
     @Mock private lateinit var bouncerLogger: TableLogBuffer
@@ -62,11 +65,13 @@
                 bouncerLogger,
             )
         biometricRepository = FakeBiometricRepository()
+        deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
         featureFlags = FakeFeatureFlags().apply { this.set(Flags.MODERN_ALTERNATE_BOUNCER, true) }
         underTest =
             AlternateBouncerInteractor(
                 bouncerRepository,
                 biometricRepository,
+                deviceEntryFingerprintAuthRepository,
                 systemClock,
                 keyguardUpdateMonitor,
                 featureFlags,
@@ -112,6 +117,14 @@
     }
 
     @Test
+    fun canShowAlternateBouncerForFingerprint_fingerprintLockedOut() {
+        givenCanShowAlternateBouncer()
+        deviceEntryFingerprintAuthRepository.setLockedOut(true)
+
+        assertFalse(underTest.canShowAlternateBouncerForFingerprint())
+    }
+
+    @Test
     fun show_whenCanShow() {
         givenCanShowAlternateBouncer()
 
@@ -148,6 +161,7 @@
         biometricRepository.setFingerprintEnrolled(true)
         biometricRepository.setStrongBiometricAllowed(true)
         biometricRepository.setFingerprintEnabledByDevicePolicy(true)
+        deviceEntryFingerprintAuthRepository.setLockedOut(false)
     }
 
     private fun givenCannotShowAlternateBouncer() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskIntentResolverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskIntentResolverTest.kt
index bbe60f4..18be92b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskIntentResolverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskIntentResolverTest.kt
@@ -16,17 +16,14 @@
 
 package com.android.systemui.notetask
 
-import android.content.ComponentName
+import android.app.role.RoleManager
 import android.content.Intent
-import android.content.pm.ActivityInfo
-import android.content.pm.ApplicationInfo
 import android.content.pm.PackageManager
-import android.content.pm.PackageManager.ResolveInfoFlags
-import android.content.pm.ResolveInfo
 import android.test.suitebuilder.annotation.SmallTest
 import androidx.test.runner.AndroidJUnit4
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.notetask.NoteTaskIntentResolver.Companion.ACTION_CREATE_NOTE
+import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
@@ -47,172 +44,39 @@
 internal class NoteTaskIntentResolverTest : SysuiTestCase() {
 
     @Mock lateinit var packageManager: PackageManager
+    @Mock lateinit var roleManager: RoleManager
 
-    private lateinit var resolver: NoteTaskIntentResolver
+    private lateinit var underTest: NoteTaskIntentResolver
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-        resolver = NoteTaskIntentResolver(packageManager)
-    }
-
-    private fun createResolveInfo(
-        activityInfo: ActivityInfo? = createActivityInfo(),
-    ): ResolveInfo {
-        return ResolveInfo().apply { this.activityInfo = activityInfo }
-    }
-
-    private fun createActivityInfo(
-        packageName: String = "PackageName",
-        name: String? = "ActivityName",
-        exported: Boolean = true,
-        enabled: Boolean = true,
-        showWhenLocked: Boolean = true,
-        turnScreenOn: Boolean = true,
-    ): ActivityInfo {
-        return ActivityInfo().apply {
-            this.name = name
-            this.exported = exported
-            this.enabled = enabled
-            if (showWhenLocked) {
-                flags = flags or ActivityInfo.FLAG_SHOW_WHEN_LOCKED
-            }
-            if (turnScreenOn) {
-                flags = flags or ActivityInfo.FLAG_TURN_SCREEN_ON
-            }
-            this.applicationInfo = ApplicationInfo().apply { this.packageName = packageName }
-        }
-    }
-
-    private fun givenQueryIntentActivities(block: () -> List<ResolveInfo>) {
-        whenever(packageManager.queryIntentActivities(any(), any<ResolveInfoFlags>()))
-            .thenReturn(block())
-    }
-
-    private fun givenResolveActivity(block: () -> ResolveInfo?) {
-        whenever(packageManager.resolveActivity(any(), any<ResolveInfoFlags>())).thenReturn(block())
+        underTest = NoteTaskIntentResolver(context, roleManager)
     }
 
     @Test
-    fun resolveIntent_shouldReturnNotesIntent() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity { createResolveInfo(activityInfo = createActivityInfo()) }
+    fun resolveIntent_shouldReturnIntentInStylusMode() {
+        val packageName = "com.android.note.app"
+        whenever(roleManager.getRoleHoldersAsUser(NoteTaskIntentResolver.ROLE_NOTES, context.user))
+            .then { listOf(packageName) }
 
-        val actual = resolver.resolveIntent()
+        val actual = underTest.resolveIntent()
 
-        val expected =
-            Intent(ACTION_CREATE_NOTE)
-                .setPackage("PackageName")
-                .setComponent(ComponentName("PackageName", "ActivityName"))
-                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-        // Compares the string representation of both intents, as they are different instances.
-        assertThat(actual.toString()).isEqualTo(expected.toString())
+        requireNotNull(actual) { "Intent must not be null" }
+        assertThat(actual.action).isEqualTo(ACTION_CREATE_NOTE)
+        assertThat(actual.`package`).isEqualTo(packageName)
+        val expectedExtra = actual.getExtra(NoteTaskIntentResolver.INTENT_EXTRA_USE_STYLUS_MODE)
+        assertThat(expectedExtra).isEqualTo(true)
+        val expectedFlag = actual.flags and Intent.FLAG_ACTIVITY_NEW_TASK
+        assertThat(expectedFlag).isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK)
     }
 
     @Test
-    fun resolveIntent_activityInfoEnabledIsFalse_shouldReturnNull() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity {
-            createResolveInfo(activityInfo = createActivityInfo(enabled = false))
-        }
+    fun resolveIntent_noRoleHolderIsSet_shouldReturnNull() {
+        whenever(roleManager.getRoleHoldersAsUser(eq(NoteTaskIntentResolver.ROLE_NOTES), any()))
+            .then { listOf<String>() }
 
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_activityInfoExportedIsFalse_shouldReturnNull() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity {
-            createResolveInfo(activityInfo = createActivityInfo(exported = false))
-        }
-
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_activityInfoShowWhenLockedIsFalse_shouldReturnNull() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity {
-            createResolveInfo(activityInfo = createActivityInfo(showWhenLocked = false))
-        }
-
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_activityInfoTurnScreenOnIsFalse_shouldReturnNull() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity {
-            createResolveInfo(activityInfo = createActivityInfo(turnScreenOn = false))
-        }
-
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_activityInfoNameIsBlank_shouldReturnNull() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity { createResolveInfo(activityInfo = createActivityInfo(name = "")) }
-
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_activityInfoNameIsNull_shouldReturnNull() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity { createResolveInfo(activityInfo = createActivityInfo(name = null)) }
-
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_activityInfoIsNull_shouldReturnNull() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity { createResolveInfo(activityInfo = null) }
-
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_resolveActivityIsNull_shouldReturnNull() {
-        givenQueryIntentActivities { listOf(createResolveInfo()) }
-        givenResolveActivity { null }
-
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_packageNameIsBlank_shouldReturnNull() {
-        givenQueryIntentActivities {
-            listOf(createResolveInfo(createActivityInfo(packageName = "")))
-        }
-
-        val actual = resolver.resolveIntent()
-
-        assertThat(actual).isNull()
-    }
-
-    @Test
-    fun resolveIntent_activityNotFoundForAction_shouldReturnNull() {
-        givenQueryIntentActivities { emptyList() }
-
-        val actual = resolver.resolveIntent()
+        val actual = underTest.resolveIntent()
 
         assertThat(actual).isNull()
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java
index bbd62c7..6f54f62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java
@@ -147,16 +147,25 @@
         setUserProfiles(0);
         setShowUserVisibleJobs(true);
 
-        UserVisibleJobSummary j1 = new UserVisibleJobSummary(0, 0, "pkg1", null, 0);
-        UserVisibleJobSummary j2 = new UserVisibleJobSummary(1, 0, "pkg2", null, 1);
+        UserVisibleJobSummary j1 = new UserVisibleJobSummary(0, "pkg1", 0, "pkg1", null, 0);
+        UserVisibleJobSummary j2 = new UserVisibleJobSummary(1, "pkg2", 0, "pkg2", null, 1);
+        // pkg2 is performing work on behalf of pkg3. Since pkg2 will show the notification
+        // It should be the one shown in TaskManager.
+        UserVisibleJobSummary j3 = new UserVisibleJobSummary(1, "pkg2", 0, "pkg3", null, 3);
         Assert.assertEquals(0, mFmc.getNumRunningPackages());
         mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j1, true);
         Assert.assertEquals(1, mFmc.getNumRunningPackages());
         mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j2, true);
         Assert.assertEquals(2, mFmc.getNumRunningPackages());
+        // Job3 starts running. The source package (pkg3) shouldn't matter. Since pkg2 is
+        // already running, the running package count shouldn't increase.
+        mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j3, true);
+        Assert.assertEquals(2, mFmc.getNumRunningPackages());
         mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j1, false);
         Assert.assertEquals(1, mFmc.getNumRunningPackages());
         mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j2, false);
+        Assert.assertEquals(1, mFmc.getNumRunningPackages());
+        mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j3, false);
         Assert.assertEquals(0, mFmc.getNumRunningPackages());
     }
 
@@ -167,8 +176,8 @@
 
         Binder b1 = new Binder();
         Binder b2 = new Binder();
-        UserVisibleJobSummary j1 = new UserVisibleJobSummary(0, 0, "pkg1", null, 0);
-        UserVisibleJobSummary j3 = new UserVisibleJobSummary(1, 0, "pkg3", null, 1);
+        UserVisibleJobSummary j1 = new UserVisibleJobSummary(0, "pkg1", 0, "pkg1", null, 0);
+        UserVisibleJobSummary j3 = new UserVisibleJobSummary(1, "pkg3", 0, "pkg3", null, 1);
         Assert.assertEquals(0, mFmc.getNumRunningPackages());
         mIForegroundServiceObserver.onForegroundStateChanged(b1, "pkg1", 0, true);
         Assert.assertEquals(1, mFmc.getNumRunningPackages());
@@ -359,8 +368,8 @@
         // pkg1 has only job
         // pkg2 has both job and fgs
         // pkg3 has only fgs
-        UserVisibleJobSummary j1 = new UserVisibleJobSummary(0, 0, "pkg1", null, 0);
-        UserVisibleJobSummary j2 = new UserVisibleJobSummary(1, 0, "pkg2", null, 1);
+        UserVisibleJobSummary j1 = new UserVisibleJobSummary(0, "pkg1", 0, "pkg1", null, 0);
+        UserVisibleJobSummary j2 = new UserVisibleJobSummary(1, "pkg2", 0, "pkg2", null, 1);
         Binder b2 = new Binder();
         Binder b3 = new Binder();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 817d6a2..0806a62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -58,6 +58,7 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import android.app.AlarmManager;
 import android.app.Instrumentation;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyResourcesManager;
@@ -184,6 +185,8 @@
     private ScreenLifecycle mScreenLifecycle;
     @Mock
     private AuthController mAuthController;
+    @Mock
+    private AlarmManager mAlarmManager;
     @Captor
     private ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener;
     @Captor
@@ -286,7 +289,9 @@
                 mAuthController, mLockPatternUtils, mScreenLifecycle,
                 mKeyguardBypassController, mAccessibilityManager,
                 mFaceHelpMessageDeferral, mock(KeyguardLogger.class),
-                mAlternateBouncerInteractor);
+                mAlternateBouncerInteractor,
+                mAlarmManager
+        );
         mController.init();
         mController.setIndicationArea(mIndicationArea);
         verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
index b32058f..3dccbbf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
@@ -45,7 +45,7 @@
 
     @Test
     fun testLogNetworkCapsChange_bufferHasInfo() {
-        logger.logOnCapabilitiesChanged(NET_1, NET_1_CAPS)
+        logger.logOnCapabilitiesChanged(NET_1, NET_1_CAPS, isDefaultNetworkCallback = true)
 
         val stringWriter = StringWriter()
         buffer.dump(PrintWriter(stringWriter), tailLength = 0)
@@ -54,6 +54,7 @@
         val expectedNetId = NET_1_ID.toString()
         val expectedCaps = NET_1_CAPS.toString()
 
+        assertThat(actualString).contains("true")
         assertThat(actualString).contains(expectedNetId)
         assertThat(actualString).contains(expectedCaps)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
index 87ce8fa..7099f1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
@@ -21,7 +21,10 @@
 import android.net.NetworkCapabilities
 import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
 import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.net.NetworkCapabilities.TRANSPORT_VPN
 import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import android.net.TransportInfo
+import android.net.VpnTransportInfo
 import android.net.vcn.VcnTransportInfo
 import android.net.wifi.WifiInfo
 import android.net.wifi.WifiManager
@@ -243,6 +246,54 @@
         job.cancel()
     }
 
+    /** Regression test for b/266628069. */
+    @Test
+    fun isWifiDefault_transportInfoIsNotWifi_andNoWifiTransport_false() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.isWifiDefault.launchIn(this)
+
+            val transportInfo = VpnTransportInfo(
+                /* type= */ 0,
+                /* sessionId= */ "sessionId",
+            )
+            val networkCapabilities = mock<NetworkCapabilities>().also {
+                whenever(it.hasTransport(TRANSPORT_VPN)).thenReturn(true)
+                whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false)
+                whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false)
+                whenever(it.transportInfo).thenReturn(transportInfo)
+            }
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, networkCapabilities)
+
+            assertThat(underTest.isWifiDefault.value).isFalse()
+
+            job.cancel()
+        }
+
+    /** Regression test for b/266628069. */
+    @Test
+    fun isWifiDefault_transportInfoIsNotWifi_butHasWifiTransport_true() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.isWifiDefault.launchIn(this)
+
+            val transportInfo = VpnTransportInfo(
+                /* type= */ 0,
+                /* sessionId= */ "sessionId",
+            )
+            val networkCapabilities = mock<NetworkCapabilities>().also {
+                whenever(it.hasTransport(TRANSPORT_VPN)).thenReturn(true)
+                whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+                whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false)
+                whenever(it.transportInfo).thenReturn(transportInfo)
+            }
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, networkCapabilities)
+
+            assertThat(underTest.isWifiDefault.value).isTrue()
+
+            job.cancel()
+        }
+
     @Test
     fun isWifiDefault_cellularVcnNetwork_isTrue() = runBlocking(IMMEDIATE) {
         val job = underTest.isWifiDefault.launchIn(this)
@@ -260,6 +311,24 @@
     }
 
     @Test
+    fun wifiNetwork_cellularAndWifiTransports_usesCellular_isTrue() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.isWifiDefault.launchIn(this)
+
+            val capabilities = mock<NetworkCapabilities>().apply {
+                whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+                whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+                whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO))
+            }
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
+
+            assertThat(underTest.isWifiDefault.value).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
     fun isWifiDefault_cellularNotVcnNetwork_isFalse() = runBlocking(IMMEDIATE) {
         val job = underTest.isWifiDefault.launchIn(this)
 
@@ -467,6 +536,28 @@
         job.cancel()
     }
 
+    /** Regression test for b/266628069. */
+    @Test
+    fun wifiNetwork_transportInfoIsNotWifi_flowHasNoNetwork() =
+        runBlocking(IMMEDIATE) {
+            var latest: WifiNetworkModel? = null
+            val job = underTest
+                .wifiNetwork
+                .onEach { latest = it }
+                .launchIn(this)
+
+            val transportInfo = VpnTransportInfo(
+                /* type= */ 0,
+                /* sessionId= */ "sessionId",
+            )
+            getNetworkCallback()
+                .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(transportInfo))
+
+            assertThat(latest is WifiNetworkModel.Inactive).isTrue()
+
+            job.cancel()
+        }
+
     @Test
     fun wifiNetwork_cellularVcnNetworkAdded_flowHasNetwork() = runBlocking(IMMEDIATE) {
         var latest: WifiNetworkModel? = null
@@ -535,6 +626,31 @@
     }
 
     @Test
+    fun wifiNetwork_cellularAndWifiTransports_usesCellular() =
+        runBlocking(IMMEDIATE) {
+            var latest: WifiNetworkModel? = null
+            val job = underTest
+                .wifiNetwork
+                .onEach { latest = it }
+                .launchIn(this)
+
+            val capabilities = mock<NetworkCapabilities>().apply {
+                whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+                whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+                whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO))
+            }
+
+            getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
+
+            assertThat(latest is WifiNetworkModel.Active).isTrue()
+            val latestActive = latest as WifiNetworkModel.Active
+            assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
+            assertThat(latestActive.ssid).isEqualTo(SSID)
+
+            job.cancel()
+        }
+
+    @Test
     fun wifiNetwork_newPrimaryWifiNetwork_flowHasNewNetwork() = runBlocking(IMMEDIATE) {
         var latest: WifiNetworkModel? = null
         val job = underTest
@@ -870,12 +986,12 @@
     }
 
     private fun createWifiNetworkCapabilities(
-        wifiInfo: WifiInfo,
+        transportInfo: TransportInfo,
         isValidated: Boolean = true,
     ): NetworkCapabilities {
         return mock<NetworkCapabilities>().also {
             whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
-            whenever(it.transportInfo).thenReturn(wifiInfo)
+            whenever(it.transportInfo).thenReturn(transportInfo)
             whenever(it.hasCapability(NET_CAPABILITY_VALIDATED)).thenReturn(isValidated)
         }
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
new file mode 100644
index 0000000..5641832
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.data.repository
+
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeDeviceEntryFingerprintAuthRepository : DeviceEntryFingerprintAuthRepository {
+    private val _isLockedOut = MutableStateFlow<Boolean>(false)
+    override val isLockedOut: StateFlow<Boolean> = _isLockedOut.asStateFlow()
+
+    fun setLockedOut(lockedOut: Boolean) {
+        _isLockedOut.value = lockedOut
+    }
+}
diff --git a/proto/src/OWNERS b/proto/src/OWNERS
index ccff624..4d898b41 100644
--- a/proto/src/OWNERS
+++ b/proto/src/OWNERS
@@ -3,3 +3,4 @@
 per-file camera.proto = file:/services/core/java/com/android/server/camera/OWNERS
 per-file system_messages.proto = file:/core/res/OWNERS
 per-file altitude.proto = file:/location/OWNERS
+per-file am_capabilities.proto = rpaquay@google.com, sanglardf@google.com
diff --git a/proto/src/am_capabilities.proto b/proto/src/am_capabilities.proto
new file mode 100644
index 0000000..d97bf81
--- /dev/null
+++ b/proto/src/am_capabilities.proto
@@ -0,0 +1,12 @@
+syntax = "proto3";
+
+package com.android.server.am;
+option java_multiple_files = true;
+
+message Capability {
+  string name = 1;
+}
+
+message Capabilities {
+  repeated Capability values = 1;
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 9b0560c..e824205 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -258,7 +258,7 @@
     private final MagnificationController mMagnificationController;
     private final MagnificationProcessor mMagnificationProcessor;
 
-    private final MainHandler mMainHandler;
+    private final Handler mMainHandler;
 
     // Lazily initialized - access through getSystemActionPerformer()
     private SystemActionPerformer mSystemActionPerformer;
@@ -412,6 +412,7 @@
     @VisibleForTesting
     AccessibilityManagerService(
             Context context,
+            Handler handler,
             PackageManager packageManager,
             AccessibilitySecurityPolicy securityPolicy,
             SystemActionPerformer systemActionPerformer,
@@ -425,7 +426,7 @@
         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
         mTraceManager = AccessibilityTraceManager.getInstance(
                 mWindowManagerService.getAccessibilityController(), this, mLock);
-        mMainHandler = new MainHandler(mContext.getMainLooper());
+        mMainHandler = handler;
         mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
         mPackageManager = packageManager;
         mSecurityPolicy = securityPolicy;
@@ -4123,7 +4124,7 @@
         private final ArrayList<Display> mDisplaysList = new ArrayList<>();
         private int mSystemUiUid = 0;
 
-        AccessibilityDisplayListener(Context context, MainHandler handler) {
+        AccessibilityDisplayListener(Context context, Handler handler) {
             mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
             mDisplayManager.registerDisplayListener(this, handler);
             initializeDisplayList();
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 7db27ac..b68adab 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -199,8 +199,10 @@
                 intent.putExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY, true);
 
                 PendingIntent p = PendingIntent.getActivityAsUser(this, /* requestCode= */ 0,
-                        intent, PendingIntent.FLAG_MUTABLE, /* options= */ null,
-                        UserHandle.CURRENT);
+                        intent,
+                        PendingIntent.FLAG_MUTABLE
+                                | PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT,
+                        /* options= */ null, UserHandle.CURRENT);
                 if (sDebug) {
                     Slog.d(TAG, "startActivity add save UI restored with intent=" + intent);
                 }
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncCallback.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncCallback.java
index 56e777f..7c339d2 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncCallback.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncCallback.java
@@ -22,4 +22,6 @@
     abstract void processCallControlAction(int crossDeviceCallId, int callControlAction);
 
     abstract void requestCrossDeviceSync(int userId);
+
+    abstract void updateStatus(int userId, boolean shouldSyncCallMetadata);
 }
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java
index 97e70a4..ae4766a 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java
@@ -39,6 +39,8 @@
 
     @VisibleForTesting
     final Map<Call, CrossDeviceCall> mCurrentCalls = new HashMap<>();
+    @VisibleForTesting
+    boolean mShouldSync;
     final Call.Callback mTelecomCallback = new Call.Callback() {
         @Override
         public void onDetailsChanged(Call call, Call.Details details) {
@@ -92,12 +94,29 @@
         @Override
         void requestCrossDeviceSync(int userId) {
         }
+
+        @Override
+        void updateStatus(int userId, boolean shouldSyncCallMetadata) {
+            if (userId == getUserId()) {
+                mShouldSync = shouldSyncCallMetadata;
+                if (shouldSyncCallMetadata) {
+                    initializeCalls();
+                } else {
+                    mCurrentCalls.clear();
+                }
+            }
+        }
     };
 
     @Override
     public void onCreate() {
         super.onCreate();
-        if (CompanionDeviceConfig.isEnabled(CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) {
+        initializeCalls();
+    }
+
+    private void initializeCalls() {
+        if (CompanionDeviceConfig.isEnabled(CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)
+                && mShouldSync) {
             mCurrentCalls.putAll(getCalls().stream().collect(Collectors.toMap(call -> call,
                     call -> new CrossDeviceCall(getPackageManager(), call, getCallAudioState()))));
         }
@@ -119,7 +138,8 @@
 
     @Override
     public void onCallAdded(Call call) {
-        if (CompanionDeviceConfig.isEnabled(CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) {
+        if (CompanionDeviceConfig.isEnabled(CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)
+                && mShouldSync) {
             mCurrentCalls.put(call,
                     new CrossDeviceCall(getPackageManager(), call, getCallAudioState()));
         }
@@ -127,21 +147,24 @@
 
     @Override
     public void onCallRemoved(Call call) {
-        if (CompanionDeviceConfig.isEnabled(CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) {
+        if (CompanionDeviceConfig.isEnabled(CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)
+                && mShouldSync) {
             mCurrentCalls.remove(call);
         }
     }
 
     @Override
     public void onMuteStateChanged(boolean isMuted) {
-        if (CompanionDeviceConfig.isEnabled(CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) {
+        if (CompanionDeviceConfig.isEnabled(CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)
+                && mShouldSync) {
             mCurrentCalls.values().forEach(call -> call.updateMuted(isMuted));
         }
     }
 
     @Override
     public void onSilenceRinger() {
-        if (CompanionDeviceConfig.isEnabled(CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) {
+        if (CompanionDeviceConfig.isEnabled(CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)
+                && mShouldSync) {
             mCurrentCalls.values().forEach(call -> call.updateSilencedIfRinging());
         }
     }
diff --git a/services/companion/java/com/android/server/companion/virtual/InputController.java b/services/companion/java/com/android/server/companion/virtual/InputController.java
index d5cc58f..df5e37c 100644
--- a/services/companion/java/com/android/server/companion/virtual/InputController.java
+++ b/services/companion/java/com/android/server/companion/virtual/InputController.java
@@ -46,6 +46,7 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.nio.charset.StandardCharsets;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Objects;
@@ -79,6 +80,14 @@
     @interface PhysType {
     }
 
+    /**
+     * The maximum length of a device name (in bytes in UTF-8 encoding).
+     *
+     * This limitation comes directly from uinput.
+     * See also UINPUT_MAX_NAME_SIZE in linux/uinput.h
+     */
+    private static final int DEVICE_NAME_MAX_LENGTH = 80;
+
     final Object mLock;
 
     /* Token -> file descriptor associations. */
@@ -312,6 +321,34 @@
         }
     }
 
+    /**
+     * Validates a device name by checking length and whether a device with the same name
+     * already exists. Throws exceptions if the validation fails.
+     * @param deviceName The name of the device to be validated
+     * @throws DeviceCreationException if {@code deviceName} is not valid.
+     */
+    private void validateDeviceName(String deviceName) throws DeviceCreationException {
+        // Comparison is greater or equal because the device name must fit into a const char*
+        // including the \0-terminator. Therefore the actual number of bytes that can be used
+        // for device name is DEVICE_NAME_MAX_LENGTH - 1
+        if (deviceName.getBytes(StandardCharsets.UTF_8).length >= DEVICE_NAME_MAX_LENGTH) {
+            throw new DeviceCreationException(
+                    "Input device name exceeds maximum length of " + DEVICE_NAME_MAX_LENGTH
+                            + "bytes: " + deviceName);
+        }
+
+        synchronized (mLock) {
+            InputDeviceDescriptor[] values = mInputDeviceDescriptors.values().toArray(
+                    new InputDeviceDescriptor[0]);
+            for (InputDeviceDescriptor value : values) {
+                if (value.mName.equals(deviceName)) {
+                    throw new DeviceCreationException(
+                            "Input device name already in use: " + deviceName);
+                }
+            }
+        }
+    }
+
     private static String createPhys(@PhysType String type) {
         return String.format("virtual%s:%d", type, sNextPhysId.getAndIncrement());
     }
@@ -451,10 +488,10 @@
 
     @VisibleForTesting
     void addDeviceForTesting(IBinder deviceToken, int fd, int type, int displayId, String phys,
-            int inputDeviceId) {
+            String deviceName, int inputDeviceId) {
         synchronized (mLock) {
             mInputDeviceDescriptors.put(deviceToken, new InputDeviceDescriptor(fd, () -> {
-            }, type, displayId, phys, inputDeviceId));
+            }, type, displayId, phys, deviceName, inputDeviceId));
         }
     }
 
@@ -565,6 +602,9 @@
         private final @Type int mType;
         private final int mDisplayId;
         private final String mPhys;
+        // The name given to this device by the client. Enforced to be unique within
+        // InputController.
+        private final String mName;
         // The input device id that was associated to the device by the InputReader on device
         // creation.
         private final int mInputDeviceId;
@@ -572,12 +612,13 @@
         private final long mCreationOrderNumber;
 
         InputDeviceDescriptor(int fd, IBinder.DeathRecipient deathRecipient, @Type int type,
-                int displayId, String phys, int inputDeviceId) {
+                int displayId, String phys, String name, int inputDeviceId) {
             mFd = fd;
             mDeathRecipient = deathRecipient;
             mType = type;
             mDisplayId = displayId;
             mPhys = phys;
+            mName = name;
             mInputDeviceId = inputDeviceId;
             mCreationOrderNumber = sNextCreationOrderNumber.getAndIncrement();
         }
@@ -733,6 +774,7 @@
                     "Virtual device creation should happen on an auxiliary thread (e.g. binder "
                             + "thread) and not from the handler's thread.");
         }
+        validateDeviceName(deviceName);
 
         final int fd;
         final BinderDeathRecipient binderDeathRecipient;
@@ -769,7 +811,7 @@
         synchronized (mLock) {
             mInputDeviceDescriptors.put(deviceToken,
                     new InputDeviceDescriptor(fd, binderDeathRecipient, type, displayId, phys,
-                            inputDeviceId));
+                            deviceName, inputDeviceId));
         }
     }
 
diff --git a/services/core/java/android/os/BatteryStatsInternal.java b/services/core/java/android/os/BatteryStatsInternal.java
index b70cbe3..9c2de65 100644
--- a/services/core/java/android/os/BatteryStatsInternal.java
+++ b/services/core/java/android/os/BatteryStatsInternal.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.net.Network;
 
 import com.android.internal.os.BinderCallsStats;
 import com.android.server.power.stats.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes;
@@ -82,6 +83,15 @@
     public abstract void noteJobsDeferred(int uid, int numDeferred, long sinceLast);
 
     /**
+     * Informs battery stats of a data packet that woke up the CPU.
+     *
+     * @param network The network over which the packet arrived.
+     * @param elapsedMillis The time of the packet's arrival in elapsed timebase.
+     * @param uid The uid that received the packet.
+     */
+    public abstract void noteCpuWakingNetworkPacket(Network network, long elapsedMillis, int uid);
+
+    /**
      * Informs battery stats of binder stats for the given work source UID.
      */
     public abstract void noteBinderCallStats(int workSourceUid, long incrementalBinderCallCount,
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index ecc303f..c17a2ec 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -41,6 +41,7 @@
 import android.content.pm.ModuleInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.Signature;
@@ -82,6 +83,8 @@
 import com.android.internal.os.IBinaryTransparencyService;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.pm.ApexManager;
+import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.PackageState;
 
 import libcore.util.HexEncoding;
 
@@ -121,7 +124,9 @@
     static final long RECORD_MEASUREMENTS_COOLDOWN_MS = 24 * 60 * 60 * 1000;
 
     @VisibleForTesting
-    static final String BUNDLE_PACKAGE_INFO = "package-info";
+    static final String BUNDLE_PACKAGE_NAME = "package-name";
+    @VisibleForTesting
+    static final String BUNDLE_PACKAGE_IS_APEX = "package-is-apex";
     @VisibleForTesting
     static final String BUNDLE_CONTENT_DIGEST_ALGORITHM = "content-digest-algo";
     @VisibleForTesting
@@ -150,6 +155,7 @@
     private String mVbmetaDigest;
     // the system time (in ms) the last measurement was taken
     private long mMeasurementsLastRecordedMs;
+    private PackageManagerInternal mPackageManagerInternal;
     private BiometricLogger mBiometricLogger;
 
     /**
@@ -172,7 +178,18 @@
             List<Bundle> results = new ArrayList<>();
 
             for (PackageInfo packageInfo : getCurrentInstalledApexs()) {
-                Bundle apexMeasurement = measurePackage(packageInfo);
+                PackageState packageState = mPackageManagerInternal.getPackageStateInternal(
+                        packageInfo.packageName);
+                if (packageState == null) {
+                    Slog.w(TAG, "Package state is unavailable, ignoring the package "
+                            + packageInfo.packageName);
+                    continue;
+                }
+                Bundle apexMeasurement = measurePackage(packageState);
+                if (apexMeasurement == null) {
+                    Slog.w(TAG, "Skipping the missing APEX in " + packageState.getPath());
+                    continue;
+                }
                 results.add(apexMeasurement);
             }
 
@@ -205,26 +222,30 @@
 
         /**
          * Perform basic measurement (i.e. content digest) on a given package.
-         * @param packageInfo The package to be measured.
+         * @param packageState The package to be measured.
          * @return a {@link android.os.Bundle} that packs the measurement result with the following
-         *         keys: {@link #BUNDLE_PACKAGE_INFO},
+         *         keys: {@link #BUNDLE_PACKAGE_NAME},
+         *               {@link #BUNDLE_PACKAGE_IS_APEX}
          *               {@link #BUNDLE_CONTENT_DIGEST_ALGORITHM}
          *               {@link #BUNDLE_CONTENT_DIGEST}
          */
-        private @NonNull Bundle measurePackage(PackageInfo packageInfo) {
+        private @Nullable Bundle measurePackage(PackageState packageState) {
             Bundle result = new Bundle();
 
             // compute content digest
             if (DEBUG) {
-                Slog.d(TAG, "Computing content digest for " + packageInfo.packageName + " at "
-                        + packageInfo.applicationInfo.sourceDir);
+                Slog.d(TAG, "Computing content digest for " + packageState.getPackageName() + " at "
+                        + packageState.getPath());
             }
-            Map<Integer, byte[]> contentDigests = computeApkContentDigest(
-                    packageInfo.applicationInfo.sourceDir);
-            result.putParcelable(BUNDLE_PACKAGE_INFO, packageInfo);
+            AndroidPackage pkg = packageState.getAndroidPackage();
+            if (pkg == null) {
+                Slog.w(TAG, "Skipping the missing APK in " + packageState.getPath());
+                return null;
+            }
+            Map<Integer, byte[]> contentDigests = computeApkContentDigest(pkg.getBaseApkPath());
+            result.putString(BUNDLE_PACKAGE_NAME, pkg.getPackageName());
             if (contentDigests == null) {
-                Slog.d(TAG, "Failed to compute content digest for "
-                        + packageInfo.applicationInfo.sourceDir);
+                Slog.d(TAG, "Failed to compute content digest for " + pkg.getBaseApkPath());
                 result.putInt(BUNDLE_CONTENT_DIGEST_ALGORITHM, 0);
                 result.putByteArray(BUNDLE_CONTENT_DIGEST, null);
                 return result;
@@ -248,6 +269,7 @@
                 result.putInt(BUNDLE_CONTENT_DIGEST_ALGORITHM, 0);
                 result.putByteArray(BUNDLE_CONTENT_DIGEST, null);
             }
+            result.putBoolean(BUNDLE_PACKAGE_IS_APEX, packageState.isApex());
 
             return result;
         }
@@ -278,26 +300,15 @@
                     + " and is now updated to: " + currentTimeMs);
             mMeasurementsLastRecordedMs = currentTimeMs;
 
-            PackageManager pm = mContext.getPackageManager();
             Set<String> packagesMeasured = new HashSet<>();
 
             // measure all APEXs first
             if (DEBUG) {
                 Slog.d(TAG, "Measuring APEXs...");
             }
-            for (PackageInfo packageInfo : getCurrentInstalledApexs()) {
-                packagesMeasured.add(packageInfo.packageName);
-
-                Bundle apexMeasurement = measurePackage(packageInfo);
-
-                var apexInfo = new IBinaryTransparencyService.ApexInfo();
-                apexInfo.packageName = packageInfo.packageName;
-                apexInfo.longVersion = packageInfo.getLongVersionCode();
-                apexInfo.digest = apexMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST);
-                apexInfo.digestAlgorithm =
-                        apexMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM);
-                apexInfo.signerDigests =
-                        computePackageSignerSha256Digests(packageInfo.signingInfo);
+            List<IBinaryTransparencyService.ApexInfo> allApexInfo = collectAllApexInfo();
+            for (IBinaryTransparencyService.ApexInfo apexInfo : allApexInfo) {
+                packagesMeasured.add(apexInfo.packageName);
 
                 recordApexInfo(apexInfo);
             }
@@ -307,48 +318,11 @@
             }
 
             // proceed with all preloaded apps
-            for (PackageInfo packageInfo : pm.getInstalledPackages(
-                    PackageManager.PackageInfoFlags.of(PackageManager.MATCH_FACTORY_ONLY
-                            | PackageManager.GET_SIGNING_CERTIFICATES))) {
-                if (packagesMeasured.contains(packageInfo.packageName)) {
-                    continue;
-                }
-                packagesMeasured.add(packageInfo.packageName);
-
-                int mbaStatus = MBA_STATUS_PRELOADED;
-                if (packageInfo.signingInfo == null) {
-                    Slog.d(TAG, "Preload " + packageInfo.packageName  + " at "
-                            + packageInfo.applicationInfo.sourceDir + " has likely been updated.");
-                    mbaStatus = MBA_STATUS_UPDATED_PRELOAD;
-
-                    PackageInfo origPackageInfo = packageInfo;
-                    try {
-                        packageInfo = pm.getPackageInfo(packageInfo.packageName,
-                                PackageManager.PackageInfoFlags.of(PackageManager.MATCH_ALL
-                                        | PackageManager.GET_SIGNING_CERTIFICATES));
-                    } catch (PackageManager.NameNotFoundException e) {
-                        Slog.e(TAG, "Failed to obtain an updated PackageInfo of "
-                                + origPackageInfo.packageName, e);
-                        packageInfo = origPackageInfo;
-                        mbaStatus = MBA_STATUS_ERROR;
-                    }
-                }
-
-                if (mbaStatus == MBA_STATUS_UPDATED_PRELOAD) {
-                    Bundle packageMeasurement = measurePackage(packageInfo);
-
-                    var appInfo = new IBinaryTransparencyService.AppInfo();
-                    appInfo.packageName = packageInfo.packageName;
-                    appInfo.longVersion = packageInfo.getLongVersionCode();
-                    appInfo.digest = packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST);
-                    appInfo.digestAlgorithm =
-                            packageMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM);
-                    appInfo.signerDigests =
-                            computePackageSignerSha256Digests(packageInfo.signingInfo);
-                    appInfo.mbaStatus = mbaStatus;
-
-                    writeAppInfoToLog(appInfo);
-                }
+            List<IBinaryTransparencyService.AppInfo> allUpdatedPreloadInfo =
+                    collectAllUpdatedPreloadInfo(packagesMeasured);
+            for (IBinaryTransparencyService.AppInfo appInfo : allUpdatedPreloadInfo) {
+                packagesMeasured.add(appInfo.packageName);
+                writeAppInfoToLog(appInfo);
             }
             if (DEBUG) {
                 Slog.d(TAG, "Measured " + packagesMeasured.size()
@@ -357,43 +331,10 @@
 
             if (CompatChanges.isChangeEnabled(LOG_MBA_INFO)) {
                 // lastly measure all newly installed MBAs
-                for (PackageInfo packageInfo : getNewlyInstalledMbas()) {
-                    if (packagesMeasured.contains(packageInfo.packageName)) {
-                        continue;
-                    }
-                    packagesMeasured.add(packageInfo.packageName);
-
-                    Bundle packageMeasurement = measurePackage(packageInfo);
-
-                    if (DEBUG) {
-                        Slog.d(TAG,
-                                "Extracting InstallSourceInfo for " + packageInfo.packageName);
-                    }
-                    var appInfo = new IBinaryTransparencyService.AppInfo();
-                    appInfo.packageName = packageInfo.packageName;
-                    appInfo.longVersion = packageInfo.getLongVersionCode();
-                    appInfo.digest = packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST);
-                    appInfo.digestAlgorithm =
-                            packageMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM);
-                    appInfo.signerDigests =
-                            computePackageSignerSha256Digests(packageInfo.signingInfo);
-                    appInfo.mbaStatus = MBA_STATUS_NEW_INSTALL;
-
-                    // extract package's InstallSourceInfo
-                    InstallSourceInfo installSourceInfo = getInstallSourceInfo(
-                            packageInfo.packageName);
-                    if (installSourceInfo != null) {
-                        appInfo.initiator = installSourceInfo.getInitiatingPackageName();
-                        SigningInfo initiatorSignerInfo =
-                                installSourceInfo.getInitiatingPackageSigningInfo();
-                        if (initiatorSignerInfo != null) {
-                            appInfo.initiatorSignerDigests =
-                                    computePackageSignerSha256Digests(initiatorSignerInfo);
-                        }
-                        appInfo.installer = installSourceInfo.getInstallingPackageName();
-                        appInfo.originator = installSourceInfo.getOriginatingPackageName();
-                    }
-
+                List<IBinaryTransparencyService.AppInfo> allMbaInfo =
+                        collectAllMbaInfo(packagesMeasured);
+                for (IBinaryTransparencyService.AppInfo appInfo : allUpdatedPreloadInfo) {
+                    packagesMeasured.add(appInfo.packageName);
                     writeAppInfoToLog(appInfo);
                 }
             }
@@ -404,6 +345,129 @@
             }
         }
 
+        private List<IBinaryTransparencyService.ApexInfo> collectAllApexInfo() {
+            var results = new ArrayList<IBinaryTransparencyService.ApexInfo>();
+            for (PackageInfo packageInfo : getCurrentInstalledApexs()) {
+                PackageState packageState = mPackageManagerInternal.getPackageStateInternal(
+                        packageInfo.packageName);
+                if (packageState == null) {
+                    Slog.w(TAG, "Package state is unavailable, ignoring the APEX "
+                            + packageInfo.packageName);
+                    continue;
+                }
+
+                Bundle apexMeasurement = measurePackage(packageState);
+                if (apexMeasurement == null) {
+                    Slog.w(TAG, "Skipping the missing APEX in " + packageState.getPath());
+                    continue;
+                }
+
+                var apexInfo = new IBinaryTransparencyService.ApexInfo();
+                apexInfo.packageName = packageState.getPackageName();
+                apexInfo.longVersion = packageState.getVersionCode();
+                apexInfo.digest = apexMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST);
+                apexInfo.digestAlgorithm =
+                        apexMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM);
+                apexInfo.signerDigests =
+                        computePackageSignerSha256Digests(packageState.getSigningInfo());
+
+                results.add(apexInfo);
+            }
+            return results;
+        }
+
+        private List<IBinaryTransparencyService.AppInfo> collectAllUpdatedPreloadInfo(
+                Set<String> packagesToSkip) {
+            final var results = new ArrayList<IBinaryTransparencyService.AppInfo>();
+
+            PackageManager pm = mContext.getPackageManager();
+            mPackageManagerInternal.forEachPackageState((packageState) -> {
+                if (!packageState.isUpdatedSystemApp()) {
+                    return;
+                }
+                if (packagesToSkip.contains(packageState.getPackageName())) {
+                    return;
+                }
+
+                Slog.d(TAG, "Preload " + packageState.getPackageName() + " at "
+                        + packageState.getPath() + " has likely been updated.");
+
+                Bundle packageMeasurement = measurePackage(packageState);
+                if (packageMeasurement == null) {
+                    Slog.w(TAG, "Skipping the missing APK in " + packageState.getPath());
+                    return;
+                }
+
+                var appInfo = new IBinaryTransparencyService.AppInfo();
+                appInfo.packageName = packageState.getPackageName();
+                appInfo.longVersion = packageState.getVersionCode();
+                appInfo.digest = packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST);
+                appInfo.digestAlgorithm =
+                        packageMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM);
+                appInfo.signerDigests =
+                        computePackageSignerSha256Digests(packageState.getSigningInfo());
+                appInfo.mbaStatus = MBA_STATUS_UPDATED_PRELOAD;
+
+                results.add(appInfo);
+            });
+            return results;
+        }
+
+        private List<IBinaryTransparencyService.AppInfo> collectAllMbaInfo(
+                Set<String> packagesToSkip) {
+            var results = new ArrayList<IBinaryTransparencyService.AppInfo>();
+            for (PackageInfo packageInfo : getNewlyInstalledMbas()) {
+                if (packagesToSkip.contains(packageInfo.packageName)) {
+                    continue;
+                }
+                PackageState packageState = mPackageManagerInternal.getPackageStateInternal(
+                        packageInfo.packageName);
+                if (packageState == null) {
+                    Slog.w(TAG, "Package state is unavailable, ignoring the package "
+                            + packageInfo.packageName);
+                    continue;
+                }
+
+                Bundle packageMeasurement = measurePackage(packageState);
+                if (packageMeasurement == null) {
+                    Slog.w(TAG, "Skipping the missing APK in " + packageState.getPath());
+                    continue;
+                }
+                if (DEBUG) {
+                    Slog.d(TAG,
+                            "Extracting InstallSourceInfo for " + packageState.getPackageName());
+                }
+                var appInfo = new IBinaryTransparencyService.AppInfo();
+                appInfo.packageName = packageState.getPackageName();
+                appInfo.longVersion = packageState.getVersionCode();
+                appInfo.digest = packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST);
+                appInfo.digestAlgorithm =
+                    packageMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM);
+                appInfo.signerDigests =
+                        computePackageSignerSha256Digests(packageState.getSigningInfo());
+                appInfo.mbaStatus = MBA_STATUS_NEW_INSTALL;
+
+                // Install source isn't currently available in PackageState (there's a TODO).
+                // Extract manually with another call.
+                InstallSourceInfo installSourceInfo = getInstallSourceInfo(
+                        packageState.getPackageName());
+                if (installSourceInfo != null) {
+                    appInfo.initiator = installSourceInfo.getInitiatingPackageName();
+                    SigningInfo initiatorSignerInfo =
+                            installSourceInfo.getInitiatingPackageSigningInfo();
+                    if (initiatorSignerInfo != null) {
+                        appInfo.initiatorSignerDigests =
+                                computePackageSignerSha256Digests(initiatorSignerInfo);
+                    }
+                    appInfo.installer = installSourceInfo.getInstallingPackageName();
+                    appInfo.originator = installSourceInfo.getOriginatingPackageName();
+                }
+
+                results.add(appInfo);
+            }
+            return results;
+        }
+
         private void recordApexInfo(IBinaryTransparencyService.ApexInfo apexInfo) {
             FrameworkStatsLog.write(FrameworkStatsLog.APEX_INFO_GATHERED,
                     apexInfo.packageName,
@@ -1101,6 +1165,7 @@
         mServiceImpl = new BinaryTransparencyServiceImpl();
         mVbmetaDigest = VBMETA_DIGEST_UNINITIALIZED;
         mMeasurementsLastRecordedMs = 0;
+        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
         mBiometricLogger = biometricLogger;
     }
 
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 73bb8d7..f0b168d 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1272,7 +1272,8 @@
                 : (wasStartRequested || !r.getConnections().isEmpty()
                 ? SERVICE_REQUEST_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_HOT
                 : SERVICE_REQUEST_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM),
-                getShortProcessNameForStats(callingUid, callingProcessName));
+                getShortProcessNameForStats(callingUid, callingProcessName),
+                getShortServiceNameForStats(r));
 
         if (r.startRequested && addToStarting) {
             boolean first = smap.mStartingBackground.size() == 0;
@@ -1311,6 +1312,11 @@
         return processName;
     }
 
+    private @Nullable String getShortServiceNameForStats(@NonNull ServiceRecord r) {
+        final ComponentName cn = r.getComponentName();
+        return cn != null ? cn.getShortClassName() : null;
+    }
+
     private void stopServiceLocked(ServiceRecord service, boolean enqueueOomAdj) {
         try {
             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "stopServiceLocked()");
@@ -3488,7 +3494,8 @@
                     : (wasStartRequested || hadConnections
                     ? SERVICE_REQUEST_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_HOT
                     : SERVICE_REQUEST_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM),
-                    getShortProcessNameForStats(callingUid, callerApp.processName));
+                    getShortProcessNameForStats(callingUid, callerApp.processName),
+                    getShortServiceNameForStats(s));
 
             if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bind " + s + " with " + b
                     + ": received=" + b.intent.received
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 0a73eaa..1e97285 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -114,6 +114,8 @@
 import com.android.internal.compat.CompatibilityChangeConfig;
 import com.android.internal.util.MemInfoReader;
 import com.android.server.am.LowMemDetector.MemFactor;
+import com.android.server.am.nano.Capabilities;
+import com.android.server.am.nano.Capability;
 import com.android.server.compat.PlatformCompat;
 import com.android.server.utils.Slogf;
 
@@ -197,6 +199,9 @@
 
     final boolean mDumping;
 
+    private static final String[] CAPABILITIES = {"start.suspend"};
+
+
     ActivityManagerShellCommand(ActivityManagerService service, boolean dumping) {
         mInterface = service;
         mTaskInterface = service.mActivityTaskManager;
@@ -378,6 +383,8 @@
                     return runListDisplaysForStartingUsers(pw);
                 case "set-foreground-service-delegate":
                     return runSetForegroundServiceDelegate(pw);
+                case "capabilities":
+                    return runCapabilities(pw);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -387,6 +394,46 @@
         return -1;
     }
 
+    int runCapabilities(PrintWriter pw) throws RemoteException {
+        final PrintWriter err = getErrPrintWriter();
+        boolean outputAsProtobuf = false;
+
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            if (opt.equals("--protobuf")) {
+                outputAsProtobuf = true;
+            } else {
+                err.println("Error: Unknown option: " + opt);
+                return -1;
+            }
+        }
+
+        if (outputAsProtobuf) {
+            Capabilities capabilities = new Capabilities();
+            capabilities.values =  new Capability[CAPABILITIES.length];
+            for (int i = 0; i < CAPABILITIES.length; i++) {
+                Capability cap = new Capability();
+                cap.name = CAPABILITIES[i];
+                capabilities.values[i] = cap;
+            }
+
+            try {
+                getRawOutputStream().write(Capabilities.toByteArray(capabilities));
+            } catch (IOException e) {
+                pw.println("Error while serializing capabilities protobuffer");
+            }
+
+        } else {
+            // Unfortunately we don't have protobuf text format capabilities here.
+            // Fallback to line separated list instead for text parser.
+            pw.println("Format: 1");
+            for (String capability : CAPABILITIES) {
+                pw.println(capability);
+            }
+        }
+        return 0;
+    }
+
     private Intent makeIntent(int defUser) throws URISyntaxException {
         mStartFlags = 0;
         mWaitOption = false;
@@ -3830,9 +3877,11 @@
             pw.println("      Print this help text.");
             pw.println("  start-activity [-D] [-N] [-W] [-P <FILE>] [--start-profiler <FILE>]");
             pw.println("          [--sampling INTERVAL] [--streaming] [-R COUNT] [-S]");
-            pw.println("          [--track-allocation] [--user <USER_ID> | current] <INTENT>");
+            pw.println("          [--track-allocation] [--user <USER_ID> | current] [--suspend]");
+            pw.println("          <INTENT>");
             pw.println("      Start an Activity.  Options are:");
             pw.println("      -D: enable debugging");
+            pw.println("      --suspend: debugged app suspend threads at startup (only with -D)");
             pw.println("      -N: enable native debugging");
             pw.println("      -W: wait for launch to complete");
             pw.println("      --start-profiler <FILE>: start profiler and send results to <FILE>");
@@ -4133,6 +4182,9 @@
             pw.println("         Start ignoring delivery group policy set for a broadcast action");
             pw.println("  clear-ignore-delivery-group-policy <ACTION>");
             pw.println("         Stop ignoring delivery group policy set for a broadcast action");
+            pw.println("  capabilities [--protobuf]");
+            pw.println("         Output am supported features (text format). Options are:");
+            pw.println("         --protobuf: format output using protobuffer");
             Intent.printIntentArgsHelp(pw, "");
         }
     }
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 0327d16..f09622f 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -457,6 +457,11 @@
         }
 
         @Override
+        public void noteCpuWakingNetworkPacket(Network network, long elapsedMillis, int uid) {
+            Slog.d(TAG, "Wakeup due to incoming packet on network " + network + " to uid " + uid);
+        }
+
+        @Override
         public void noteBinderCallStats(int workSourceUid, long incrementatCallCount,
                 Collection<BinderCallsStats.CallStat> callStats) {
             synchronized (BatteryStatsService.this.mLock) {
@@ -2900,11 +2905,9 @@
             if (DBG) Slog.d(TAG, "begin dumpLocked from UID " + Binder.getCallingUid());
             awaitCompletion();
 
-            synchronized (mStats) {
-                mStats.dumpLocked(mContext, pw, flags, reqUid, historyStart);
-                if (writeData) {
-                    mStats.writeAsyncLocked();
-                }
+            mStats.dump(mContext, pw, flags, reqUid, historyStart);
+            if (writeData) {
+                mStats.writeAsyncLocked();
             }
             pw.println();
             mCpuWakeupStats.dump(new IndentingPrintWriter(pw, "  "), SystemClock.elapsedRealtime());
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 21bd7bc..b001f3d 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -58,6 +58,7 @@
 import com.android.server.utils.EventLogger;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -453,6 +454,48 @@
         return device;
     }
 
+    private static final int[] VALID_COMMUNICATION_DEVICE_TYPES = {
+            AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
+            AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
+            AudioDeviceInfo.TYPE_WIRED_HEADSET,
+            AudioDeviceInfo.TYPE_USB_HEADSET,
+            AudioDeviceInfo.TYPE_BUILTIN_EARPIECE,
+            AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
+            AudioDeviceInfo.TYPE_HEARING_AID,
+            AudioDeviceInfo.TYPE_BLE_HEADSET,
+            AudioDeviceInfo.TYPE_USB_DEVICE,
+            AudioDeviceInfo.TYPE_BLE_SPEAKER,
+            AudioDeviceInfo.TYPE_LINE_ANALOG,
+            AudioDeviceInfo.TYPE_HDMI,
+            AudioDeviceInfo.TYPE_AUX_LINE
+    };
+
+    /*package */ static boolean isValidCommunicationDevice(AudioDeviceInfo device) {
+        for (int type : VALID_COMMUNICATION_DEVICE_TYPES) {
+            if (device.getType() == type) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /* package */ static List<AudioDeviceInfo> getAvailableCommunicationDevices() {
+        ArrayList<AudioDeviceInfo> commDevices = new ArrayList<>();
+        AudioDeviceInfo[] allDevices =
+                AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
+        for (AudioDeviceInfo device : allDevices) {
+            if (isValidCommunicationDevice(device)) {
+                commDevices.add(device);
+            }
+        }
+        return commDevices;
+    }
+
+    private @Nullable AudioDeviceInfo getCommunicationDeviceOfType(int type) {
+        return getAvailableCommunicationDevices().stream().filter(d -> d.getType() == type)
+                .findFirst().orElse(null);
+    }
+
     /**
      * Returns the device currently requested for communication use case.
      * @return AudioDeviceInfo the requested device for communication.
@@ -460,7 +503,29 @@
     /* package */ AudioDeviceInfo getCommunicationDevice() {
         synchronized (mDeviceStateLock) {
             updateActiveCommunicationDevice();
-            return mActiveCommunicationDevice;
+            AudioDeviceInfo device = mActiveCommunicationDevice;
+            // make sure we return a valid communication device (i.e. a device that is allowed by
+            // setCommunicationDevice()) for consistency.
+            if (device != null) {
+                // a digital dock is used instead of the speaker in speakerphone mode and should
+                // be reflected as such
+                if (device.getType() == AudioDeviceInfo.TYPE_DOCK) {
+                    device = getCommunicationDeviceOfType(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
+                }
+            }
+            // Try to default to earpiece when current communication device is not valid. This can
+            // happen for instance if no call is active. If no earpiece device is available take the
+            // first valid communication device
+            if (device == null || !AudioDeviceBroker.isValidCommunicationDevice(device)) {
+                device = getCommunicationDeviceOfType(AudioDeviceInfo.TYPE_BUILTIN_EARPIECE);
+                if (device == null) {
+                    List<AudioDeviceInfo> commDevices = getAvailableCommunicationDevices();
+                    if (!commDevices.isEmpty()) {
+                        device = commDevices.get(0);
+                    }
+                }
+            }
+            return device;
         }
     }
 
@@ -942,8 +1007,8 @@
 
     @GuardedBy("mDeviceStateLock")
     private void dispatchCommunicationDevice() {
-        int portId = (mActiveCommunicationDevice == null) ? 0
-                : mActiveCommunicationDevice.getId();
+        AudioDeviceInfo device = getCommunicationDevice();
+        int portId = device != null ? device.getId() : 0;
         if (portId == mCurCommunicationPortId) {
             return;
         }
@@ -960,6 +1025,7 @@
         mCommDevDispatchers.finishBroadcast();
     }
 
+
     //---------------------------------------------------------------------
     // Communication with (to) AudioService
     //TODO check whether the AudioService methods are candidates to move here
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4eb6c7f..b4992d7 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -6067,49 +6067,16 @@
         restoreDeviceVolumeBehavior();
     }
 
-    private static final int[] VALID_COMMUNICATION_DEVICE_TYPES = {
-        AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
-        AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
-        AudioDeviceInfo.TYPE_WIRED_HEADSET,
-        AudioDeviceInfo.TYPE_USB_HEADSET,
-        AudioDeviceInfo.TYPE_BUILTIN_EARPIECE,
-        AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
-        AudioDeviceInfo.TYPE_HEARING_AID,
-        AudioDeviceInfo.TYPE_BLE_HEADSET,
-        AudioDeviceInfo.TYPE_USB_DEVICE,
-        AudioDeviceInfo.TYPE_BLE_SPEAKER,
-        AudioDeviceInfo.TYPE_LINE_ANALOG,
-        AudioDeviceInfo.TYPE_HDMI,
-        AudioDeviceInfo.TYPE_AUX_LINE
-    };
-
-    private boolean isValidCommunicationDevice(AudioDeviceInfo device) {
-        if (!device.isSink()) {
-            return false;
-        }
-        for (int type : VALID_COMMUNICATION_DEVICE_TYPES) {
-            if (device.getType() == type) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     /** @see AudioManager#getAvailableCommunicationDevices(int) */
     public int[] getAvailableCommunicationDeviceIds() {
-        ArrayList<Integer> deviceIds = new ArrayList<>();
-        AudioDeviceInfo[] devices = AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
-        for (AudioDeviceInfo device : devices) {
-            if (isValidCommunicationDevice(device)) {
-                deviceIds.add(device.getId());
-            }
-        }
-        return deviceIds.stream().mapToInt(Integer::intValue).toArray();
+        List<AudioDeviceInfo> commDevices = AudioDeviceBroker.getAvailableCommunicationDevices();
+        return commDevices.stream().mapToInt(AudioDeviceInfo::getId).toArray();
     }
-        /**
-         * @see AudioManager#setCommunicationDevice(int)
-         * @see AudioManager#clearCommunicationDevice()
-         */
+
+    /**
+     * @see AudioManager#setCommunicationDevice(int)
+     * @see AudioManager#clearCommunicationDevice()
+     */
     public boolean setCommunicationDevice(IBinder cb, int portId) {
         final int uid = Binder.getCallingUid();
         final int pid = Binder.getCallingPid();
@@ -6118,9 +6085,10 @@
         if (portId != 0) {
             device = AudioManager.getDeviceForPortId(portId, AudioManager.GET_DEVICES_OUTPUTS);
             if (device == null) {
-                throw new IllegalArgumentException("invalid portID " + portId);
+                Log.w(TAG, "setCommunicationDevice: invalid portID " + portId);
+                return false;
             }
-            if (!isValidCommunicationDevice(device)) {
+            if (!AudioDeviceBroker.isValidCommunicationDevice(device)) {
                 if (!device.isSink()) {
                     throw new IllegalArgumentException("device must have sink role");
                 } else {
@@ -6168,17 +6136,15 @@
 
     /** @see AudioManager#getCommunicationDevice() */
     public int getCommunicationDevice() {
-        AudioDeviceInfo device = null;
+        int deviceId = 0;
         final long ident = Binder.clearCallingIdentity();
         try {
-            device = mDeviceBroker.getCommunicationDevice();
+            AudioDeviceInfo device = mDeviceBroker.getCommunicationDevice();
+            deviceId = device != null ? device.getId() : 0;
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
-        if (device == null) {
-            return 0;
-        }
-        return device.getId();
+        return deviceId;
     }
 
     /** @see AudioManager#addOnCommunicationDeviceChangedListener(
@@ -8083,6 +8049,7 @@
             volumeChangedOptions.setDeliveryGroupPolicy(DELIVERY_GROUP_POLICY_MOST_RECENT);
             volumeChangedOptions.setDeliveryGroupMatchingKey(
                     AudioManager.VOLUME_CHANGED_ACTION, String.valueOf(mStreamType));
+            volumeChangedOptions.setDeferUntilActive(true);
             mVolumeChangedOptions = volumeChangedOptions.toBundle();
 
             mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
@@ -8091,6 +8058,7 @@
             streamDevicesChangedOptions.setDeliveryGroupPolicy(DELIVERY_GROUP_POLICY_MOST_RECENT);
             streamDevicesChangedOptions.setDeliveryGroupMatchingKey(
                     AudioManager.STREAM_DEVICES_CHANGED_ACTION, String.valueOf(mStreamType));
+            streamDevicesChangedOptions.setDeferUntilActive(true);
             mStreamDevicesChangedOptions = streamDevicesChangedOptions.toBundle();
         }
 
@@ -11409,12 +11377,12 @@
         }
 
         try {
-            if (!projectionService.isValidMediaProjection(projection)) {
+            if (!projectionService.isCurrentProjection(projection)) {
                 Log.w(TAG, "App passed invalid MediaProjection token");
                 return false;
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "Can't call .isValidMediaProjection() on IMediaProjectionManager"
+            Log.e(TAG, "Can't call .isCurrentProjection() on IMediaProjectionManager"
                     + projectionService.asBinder(), e);
             return false;
         }
diff --git a/services/core/java/com/android/server/display/DisplayBrightnessState.java b/services/core/java/com/android/server/display/DisplayBrightnessState.java
index 87cbbfe..e27182f 100644
--- a/services/core/java/com/android/server/display/DisplayBrightnessState.java
+++ b/services/core/java/com/android/server/display/DisplayBrightnessState.java
@@ -28,11 +28,13 @@
     private final float mBrightness;
     private final float mSdrBrightness;
     private final BrightnessReason mBrightnessReason;
+    private final String mDisplayBrightnessStrategyName;
 
     private DisplayBrightnessState(Builder builder) {
         this.mBrightness = builder.getBrightness();
         this.mSdrBrightness = builder.getSdrBrightness();
         this.mBrightnessReason = builder.getBrightnessReason();
+        this.mDisplayBrightnessStrategyName = builder.getDisplayBrightnessStrategyName();
     }
 
     /**
@@ -56,6 +58,14 @@
         return mBrightnessReason;
     }
 
+    /**
+     * Gets the {@link com.android.server.display.brightness.strategy.DisplayBrightnessStrategy}
+     * name
+     */
+    public String getDisplayBrightnessStrategyName() {
+        return mDisplayBrightnessStrategyName;
+    }
+
     @Override
     public String toString() {
         StringBuilder stringBuilder = new StringBuilder("DisplayBrightnessState:");
@@ -93,6 +103,10 @@
         if (!mBrightnessReason.equals(displayBrightnessState.getBrightnessReason())) {
             return false;
         }
+        if (!mDisplayBrightnessStrategyName.equals(
+                displayBrightnessState.getDisplayBrightnessStrategyName())) {
+            return false;
+        }
         return true;
     }
 
@@ -108,6 +122,7 @@
         private float mBrightness;
         private float mSdrBrightness;
         private BrightnessReason mBrightnessReason = new BrightnessReason();
+        private String mDisplayBrightnessStrategyName;
 
         /**
          * Gets the brightness
@@ -164,6 +179,27 @@
         }
 
         /**
+         * Gets the {@link com.android.server.display.brightness.strategy.DisplayBrightnessStrategy}
+         * name
+         */
+        public String getDisplayBrightnessStrategyName() {
+            return mDisplayBrightnessStrategyName;
+        }
+
+        /**
+         * Sets the
+         * {@link com.android.server.display.brightness.strategy.DisplayBrightnessStrategy}'s name
+         *
+         * @param displayBrightnessStrategyName The name of the
+         * {@link com.android.server.display.brightness.strategy.DisplayBrightnessStrategy} being
+         *                                      used.
+         */
+        public Builder setDisplayBrightnessStrategyName(String displayBrightnessStrategyName) {
+            this.mDisplayBrightnessStrategyName = displayBrightnessStrategyName;
+            return this;
+        }
+
+        /**
          * This is used to construct an immutable DisplayBrightnessState object from its builder
          */
         public DisplayBrightnessState build() {
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 535129c..e048a0f 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -17,12 +17,14 @@
 package com.android.server.display;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
+import android.hardware.input.HostUsiVersion;
 import android.os.Environment;
 import android.os.PowerManager;
 import android.text.TextUtils;
@@ -57,6 +59,7 @@
 import com.android.server.display.config.ThermalStatus;
 import com.android.server.display.config.ThermalThrottling;
 import com.android.server.display.config.ThresholdPoint;
+import com.android.server.display.config.UsiVersion;
 import com.android.server.display.config.XmlParser;
 
 import org.xmlpull.v1.XmlPullParserException;
@@ -390,6 +393,12 @@
  *         <item>80</item>
  *         <item>1500</item>
  *     </screenOffBrightnessSensorValueToLux>
+ *     // The version of the Universal Stylus Initiative (USI) protocol supported by this display.
+ *     // This should be omitted if the display does not support USI styluses.
+ *     <usiVersion>
+ *         <majorVersion>2</majorVersion>
+ *         <minorVersion>0</minorVersion>
+ *     </usiVersion>
  *    </displayConfiguration>
  *  }
  *  </pre>
@@ -626,6 +635,9 @@
     // The concurrent displays mode might need a stricter throttling policy
     private BrightnessThrottlingData mConcurrentDisplaysBrightnessThrottlingData;
 
+    @Nullable
+    private HostUsiVersion mHostUsiVersion;
+
     @VisibleForTesting
     DisplayDeviceConfig(Context context) {
         mContext = context;
@@ -1370,6 +1382,15 @@
         return mScreenOffBrightnessSensorValueToLux;
     }
 
+    /**
+     * @return The USI version supported by this display, or null if USI is not supported.
+     * @see HostUsiVersion
+     */
+    @Nullable
+    public HostUsiVersion getHostUsiVersion() {
+        return mHostUsiVersion;
+    }
+
     @Override
     public String toString() {
         return "DisplayDeviceConfig{"
@@ -1474,6 +1495,8 @@
                 + "\n"
                 + ", mScreenOffBrightnessSensorValueToLux=" + Arrays.toString(
                 mScreenOffBrightnessSensorValueToLux)
+                + "\n"
+                + ", mUsiVersion= " + mHostUsiVersion
                 + "}";
     }
 
@@ -1535,6 +1558,7 @@
                 loadAutoBrightnessConfigValues(config);
                 loadRefreshRateSetting(config);
                 loadScreenOffBrightnessSensorValueToLuxFromDdc(config);
+                loadUsiVersion(config);
             } else {
                 Slog.w(TAG, "DisplayDeviceConfig file is null");
             }
@@ -2689,6 +2713,15 @@
         }
     }
 
+    private void loadUsiVersion(DisplayConfiguration config) {
+        final UsiVersion usiVersion = config.getUsiVersion();
+        mHostUsiVersion = usiVersion != null
+                ? new HostUsiVersion(
+                        usiVersion.getMajorVersion().intValue(),
+                        usiVersion.getMinorVersion().intValue())
+                : null;
+    }
+
     /**
      * Uniquely identifies a Sensor, with the combination of Type and Name.
      */
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index f2110fe..42e0978 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -86,6 +86,7 @@
 import android.hardware.display.VirtualDisplayConfig;
 import android.hardware.display.WifiDisplayStatus;
 import android.hardware.graphics.common.DisplayDecorationSupport;
+import android.hardware.input.HostUsiVersion;
 import android.media.projection.IMediaProjection;
 import android.media.projection.IMediaProjectionManager;
 import android.net.Uri;
@@ -1327,8 +1328,9 @@
 
         if (projection != null) {
             try {
-                if (!getProjectionService().isValidMediaProjection(projection)) {
-                    throw new SecurityException("Invalid media projection");
+                if (!getProjectionService().isCurrentProjection(projection)) {
+                    throw new SecurityException("Cannot create VirtualDisplay with "
+                            + "non-current MediaProjection");
                 }
                 flags = projection.applyVirtualDisplayFlags(flags);
             } catch (RemoteException e) {
@@ -4151,6 +4153,19 @@
 
             return SurfaceControl.getDisplayNativePrimaries(displayToken);
         }
+
+        @Override
+        public HostUsiVersion getHostUsiVersion(int displayId) {
+            synchronized (mSyncRoot) {
+                final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
+                if (display == null) {
+                    return null;
+                }
+
+                return display.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig()
+                        .getHostUsiVersion();
+            }
+        }
     }
 
     class DesiredDisplayModeSpecsObserver
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index dbd2ab0..fc2a4e5 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -2885,6 +2885,9 @@
     }
 
     private void noteScreenState(int screenState) {
+        // Log screen state change with display id
+        FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_STATE_CHANGED_V2,
+                screenState, mDisplayStatsId);
         if (mBatteryStats != null) {
             try {
                 // TODO(multi-display): make this multi-display
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 103a1da..a744415 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -1548,6 +1548,8 @@
                 ? mCdsi.getReduceBrightColorsStrength() : -1);
         mTempBrightnessEvent.setPowerFactor(mPowerRequest.screenLowPowerBrightnessFactor);
         mTempBrightnessEvent.setWasShortTermModelActive(hadUserBrightnessPoint);
+        mTempBrightnessEvent.setDisplayBrightnessStrategyName(displayBrightnessState
+                .getDisplayBrightnessStrategyName());
         // Temporary is what we use during slider interactions. We avoid logging those so that
         // we don't spam logcat when the slider is being used.
         boolean tempToTempTransition =
@@ -2390,6 +2392,9 @@
     }
 
     private void noteScreenState(int screenState) {
+        // Log screen state change with display id
+        FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_STATE_CHANGED_V2,
+                screenState, mDisplayStatsId);
         if (mBatteryStats != null) {
             try {
                 // TODO(multi-display): make this multi-display
diff --git a/services/core/java/com/android/server/display/brightness/BrightnessEvent.java b/services/core/java/com/android/server/display/brightness/BrightnessEvent.java
index f19852b..8b09571 100644
--- a/services/core/java/com/android/server/display/brightness/BrightnessEvent.java
+++ b/services/core/java/com/android/server/display/brightness/BrightnessEvent.java
@@ -53,6 +53,7 @@
     private int mFlags;
     private int mAdjustmentFlags;
     private boolean mAutomaticBrightnessEnabled;
+    private String mDisplayBrightnessStrategyName;
 
     public BrightnessEvent(BrightnessEvent that) {
         copyFrom(that);
@@ -92,6 +93,7 @@
         mAdjustmentFlags = that.getAdjustmentFlags();
         // Auto-brightness setting
         mAutomaticBrightnessEnabled = that.isAutomaticBrightnessEnabled();
+        mDisplayBrightnessStrategyName = that.getDisplayBrightnessStrategyName();
     }
 
     /**
@@ -120,6 +122,7 @@
         mAdjustmentFlags = 0;
         // Auto-brightness setting
         mAutomaticBrightnessEnabled = true;
+        mDisplayBrightnessStrategyName = "";
     }
 
     /**
@@ -157,7 +160,8 @@
                 && mWasShortTermModelActive == that.mWasShortTermModelActive
                 && mFlags == that.mFlags
                 && mAdjustmentFlags == that.mAdjustmentFlags
-                && mAutomaticBrightnessEnabled == that.mAutomaticBrightnessEnabled;
+                && mAutomaticBrightnessEnabled == that.mAutomaticBrightnessEnabled
+                && mDisplayBrightnessStrategyName.equals(that.mDisplayBrightnessStrategyName);
     }
 
     /**
@@ -185,7 +189,8 @@
                 + ", wasShortTermModelActive=" + mWasShortTermModelActive
                 + ", flags=" + flagsToString()
                 + ", reason=" + mReason.toString(mAdjustmentFlags)
-                + ", autoBrightness=" + mAutomaticBrightnessEnabled;
+                + ", autoBrightness=" + mAutomaticBrightnessEnabled
+                + ", strategy=" + mDisplayBrightnessStrategyName;
     }
 
     @Override
@@ -355,6 +360,14 @@
         return mAutomaticBrightnessEnabled;
     }
 
+    public void setDisplayBrightnessStrategyName(String displayBrightnessStrategyName) {
+        mDisplayBrightnessStrategyName = displayBrightnessStrategyName;
+    }
+
+    public String getDisplayBrightnessStrategyName() {
+        return mDisplayBrightnessStrategyName;
+    }
+
     public void setAutomaticBrightnessEnabled(boolean mAutomaticBrightnessEnabled) {
         this.mAutomaticBrightnessEnabled = mAutomaticBrightnessEnabled;
     }
diff --git a/services/core/java/com/android/server/display/brightness/BrightnessUtils.java b/services/core/java/com/android/server/display/brightness/BrightnessUtils.java
index d5aeba1..169cc4a 100644
--- a/services/core/java/com/android/server/display/brightness/BrightnessUtils.java
+++ b/services/core/java/com/android/server/display/brightness/BrightnessUtils.java
@@ -45,13 +45,15 @@
      * A utility to construct the DisplayBrightnessState
      */
     public static DisplayBrightnessState constructDisplayBrightnessState(
-            int brightnessChangeReason, float brightness, float sdrBrightness) {
+            int brightnessChangeReason, float brightness, float sdrBrightness,
+            String displayBrightnessStrategyName) {
         BrightnessReason brightnessReason = new BrightnessReason();
         brightnessReason.setReason(brightnessChangeReason);
         return new DisplayBrightnessState.Builder()
                 .setBrightness(brightness)
                 .setSdrBrightness(sdrBrightness)
                 .setBrightnessReason(brightnessReason)
+                .setDisplayBrightnessStrategyName(displayBrightnessStrategyName)
                 .build();
     }
 }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java
index 0cf234b..dd400d9 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java
@@ -40,7 +40,7 @@
         DisplayBrightnessState displayBrightnessState =
                 BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_BOOST,
                         PowerManager.BRIGHTNESS_MAX,
-                        PowerManager.BRIGHTNESS_MAX);
+                        PowerManager.BRIGHTNESS_MAX, getName());
         return displayBrightnessState;
     }
 
diff --git a/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java
index 98075f9..8299586 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java
@@ -33,7 +33,8 @@
         // Todo(b/241308599): Introduce a validator class and add validations before setting
         // the brightness
         return BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_DOZE,
-                displayPowerRequest.dozeScreenBrightness, displayPowerRequest.dozeScreenBrightness);
+                displayPowerRequest.dozeScreenBrightness, displayPowerRequest.dozeScreenBrightness,
+                getName());
     }
 
     @Override
diff --git a/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java
index fe684a4..090ec13 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java
@@ -48,7 +48,7 @@
         // Todo(b/241308599): Introduce a validator class and add validations before setting
         // the brightness
         return BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_FOLLOWER,
-                mBrightnessToFollow, mBrightnessToFollow);
+                mBrightnessToFollow, mBrightnessToFollow, getName());
     }
 
     @Override
diff --git a/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java
index 612bbe9..bc24196 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java
@@ -31,7 +31,8 @@
     public DisplayBrightnessState updateBrightness(
             DisplayManagerInternal.DisplayPowerRequest displayPowerRequest) {
         return BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_UNKNOWN,
-                PowerManager.BRIGHTNESS_INVALID_FLOAT, PowerManager.BRIGHTNESS_INVALID_FLOAT);
+                PowerManager.BRIGHTNESS_INVALID_FLOAT, PowerManager.BRIGHTNESS_INVALID_FLOAT,
+                getName());
     }
 
     @Override
diff --git a/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
index 6d3830a..13327cb 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
@@ -33,7 +33,7 @@
         // the brightness
         return BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_OVERRIDE,
                 displayPowerRequest.screenBrightnessOverride,
-                displayPowerRequest.screenBrightnessOverride);
+                displayPowerRequest.screenBrightnessOverride, getName());
     }
 
     @Override
diff --git a/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java
index ee5e066..3d411d3 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java
@@ -34,7 +34,7 @@
         // the brightness
         return BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_SCREEN_OFF,
                 PowerManager.BRIGHTNESS_OFF_FLOAT,
-                PowerManager.BRIGHTNESS_OFF_FLOAT);
+                PowerManager.BRIGHTNESS_OFF_FLOAT, getName());
     }
 
     @Override
diff --git a/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
index d97415d..35f7dd0 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
@@ -48,7 +48,7 @@
         DisplayBrightnessState displayBrightnessState =
                 BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_TEMPORARY,
                         mTemporaryScreenBrightness,
-                        mTemporaryScreenBrightness);
+                        mTemporaryScreenBrightness, getName());
         return displayBrightnessState;
     }
 
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index e5357f6..f870c0a 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -46,6 +46,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.UUID;
 
 /**
@@ -152,10 +153,20 @@
                     + ", isPreviewMode=" + isPreviewMode + ", canDoze=" + canDoze
                     + ", userId=" + userId + ", reason='" + reason + "'");
 
-            if (mCurrentDream != null) {
-                mPreviousDreams.add(mCurrentDream);
-            }
+            final DreamRecord oldDream = mCurrentDream;
             mCurrentDream = new DreamRecord(token, name, isPreviewMode, canDoze, userId, wakeLock);
+            if (oldDream != null) {
+                if (!oldDream.mWakingGently) {
+                    // We will stop these previous dreams once the new dream is started.
+                    mPreviousDreams.add(oldDream);
+                } else if (Objects.equals(oldDream.mName, mCurrentDream.mName)) {
+                    // We are attempting to start a dream that is currently waking up gently.
+                    // Let's silently stop the old instance here to clear the dream state.
+                    // This should happen after the new mCurrentDream is set to avoid announcing
+                    // a "dream stopped" state.
+                    stopDreamInstance(/* immediately */ true, "restarting same dream", oldDream);
+                }
+            }
 
             mCurrentDream.mDreamStartTime = SystemClock.elapsedRealtime();
             MetricsLogger.visible(mContext,
@@ -281,7 +292,10 @@
                         new int[] {ACTIVITY_TYPE_DREAM});
 
                 mListener.onDreamStopped(dream.mToken);
+            } else if (dream.mCanDoze && !mCurrentDream.mCanDoze) {
+                mListener.stopDozing(dream.mToken);
             }
+
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_POWER);
         }
@@ -327,6 +341,7 @@
      */
     public interface Listener {
         void onDreamStopped(Binder token);
+        void stopDozing(Binder token);
     }
 
     private final class DreamRecord implements DeathRecipient, ServiceConnection {
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index a4d2d03..d9cdba7 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -499,7 +499,12 @@
         }
 
         synchronized (mLock) {
-            if (mCurrentDream != null && mCurrentDream.token == token && mCurrentDream.isDozing) {
+            if (mCurrentDream == null) {
+                return;
+            }
+
+            final boolean sameDream = mCurrentDream.token == token;
+            if ((sameDream && mCurrentDream.isDozing) || (!sameDream && !mCurrentDream.isDozing)) {
                 mCurrentDream.isDozing = false;
                 mDozeWakeLock.release();
                 mPowerManagerInternal.setDozeOverrideFromDreamManager(
@@ -768,6 +773,11 @@
                 }
             }
         }
+
+        @Override
+        public void stopDozing(Binder token) {
+            stopDozingInternal(token);
+        }
     };
 
     private final ContentObserver mDozeEnabledObserver = new ContentObserver(null) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 376e6f8..9087354 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -727,7 +727,7 @@
     void sendCommand(final HdmiCecMessage cecMessage,
             final HdmiControlService.SendMessageCallback callback) {
         assertRunOnServiceThread();
-        addCecMessageToHistory(false /* isReceived */, cecMessage);
+        List<String> sendResults = new ArrayList<>();
         runOnIoThread(new Runnable() {
             @Override
             public void run() {
@@ -738,6 +738,12 @@
                 do {
                     errorCode = mNativeWrapperImpl.nativeSendCecCommand(
                         cecMessage.getSource(), cecMessage.getDestination(), body);
+                    switch (errorCode) {
+                        case SendMessageResult.SUCCESS: sendResults.add("ACK"); break;
+                        case SendMessageResult.FAIL: sendResults.add("FAIL"); break;
+                        case SendMessageResult.NACK: sendResults.add("NACK"); break;
+                        case SendMessageResult.BUSY: sendResults.add("BUSY"); break;
+                    }
                     if (errorCode == SendMessageResult.SUCCESS) {
                         break;
                     }
@@ -763,6 +769,8 @@
                 });
             }
         });
+
+        addCecMessageToHistory(false /* isReceived */, cecMessage, sendResults);
     }
 
     /**
@@ -785,7 +793,7 @@
         }
 
         HdmiLogger.debug("[R]:" + command);
-        addCecMessageToHistory(true /* isReceived */, command);
+        addCecMessageToHistory(true /* isReceived */, command, null);
 
         mHdmiCecAtomWriter.messageReported(command,
                 incomingMessageDirection(srcAddress, dstAddress), getCallingUid());
@@ -836,9 +844,10 @@
     }
 
     @ServiceThreadOnly
-    private void addCecMessageToHistory(boolean isReceived, HdmiCecMessage message) {
+    private void addCecMessageToHistory(boolean isReceived, HdmiCecMessage message,
+            List<String> sendResults) {
         assertRunOnServiceThread();
-        addEventToHistory(new MessageHistoryRecord(isReceived, message));
+        addEventToHistory(new MessageHistoryRecord(isReceived, message, sendResults));
     }
 
     private void addEventToHistory(Dumpable event) {
@@ -1128,8 +1137,7 @@
         @Override
         public void nativeSetHpdSignalType(int signal, int portId) {
             try {
-                // TODO(b/266178786) add portId to the HAL method
-                mHdmiConnection.setHpdSignal((byte) signal);
+                mHdmiConnection.setHpdSignal((byte) signal, portId);
             } catch (ServiceSpecificException sse) {
                 HdmiLogger.error(
                         "Could not set HPD signal type for portId " + portId + " to " + signal
@@ -1144,8 +1152,7 @@
         @Override
         public int nativeGetHpdSignalType(int portId) {
             try {
-                // TODO(b/266178786) add portId to the HAL method
-                return mHdmiConnection.getHpdSignal();
+                return mHdmiConnection.getHpdSignal(portId);
             } catch (RemoteException e) {
                 HdmiLogger.error(
                         "Could not get HPD signal type for portId " + portId + ". Exception: ", e);
@@ -1720,11 +1727,13 @@
     private static final class MessageHistoryRecord extends Dumpable {
         private final boolean mIsReceived; // true if received message and false if sent message
         private final HdmiCecMessage mMessage;
+        private final List<String> mSendResults;
 
-        MessageHistoryRecord(boolean isReceived, HdmiCecMessage message) {
+        MessageHistoryRecord(boolean isReceived, HdmiCecMessage message, List<String> sendResults) {
             super();
             mIsReceived = isReceived;
             mMessage = message;
+            mSendResults = sendResults;
         }
 
         @Override
@@ -1733,7 +1742,16 @@
             pw.print(" time=");
             pw.print(sdf.format(new Date(mTime)));
             pw.print(" message=");
-            pw.println(mMessage);
+            pw.print(mMessage);
+
+            StringBuilder results = new StringBuilder();
+            if (!mIsReceived && mSendResults != null) {
+                results.append(" (");
+                results.append(String.join(", ", mSendResults));
+                results.append(")");
+            }
+
+            pw.println(results);
         }
     }
 
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index be4373a..8c13297 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -38,7 +38,9 @@
 import android.hardware.SensorPrivacyManager.Sensors;
 import android.hardware.SensorPrivacyManagerInternal;
 import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.DisplayViewport;
+import android.hardware.input.HostUsiVersion;
 import android.hardware.input.IInputDeviceBatteryListener;
 import android.hardware.input.IInputDeviceBatteryState;
 import android.hardware.input.IInputDevicesChangedListener;
@@ -168,6 +170,7 @@
 
     private final Context mContext;
     private final InputManagerHandler mHandler;
+    private DisplayManagerInternal mDisplayManagerInternal;
 
     // Context cache used for loading pointer resources.
     private Context mPointerIconDisplayContext;
@@ -519,6 +522,8 @@
             Slog.d(TAG, "System ready.");
         }
 
+        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
+
         synchronized (mLidSwitchLock) {
             mSystemReady = true;
 
@@ -1450,7 +1455,8 @@
     }
 
     private void updateMaximumObscuringOpacityForTouchFromSettings() {
-        final float opacity = InputManager.getInstance().getMaximumObscuringOpacityForTouch();
+        InputManager im = Objects.requireNonNull(mContext.getSystemService(InputManager.class));
+        final float opacity = im.getMaximumObscuringOpacityForTouch();
         if (opacity < 0 || opacity > 1) {
             Log.e(TAG, "Invalid maximum obscuring opacity " + opacity
                     + ", it should be >= 0 and <= 1, rejecting update.");
@@ -2254,6 +2260,11 @@
     }
 
     @Override
+    public HostUsiVersion getHostUsiVersionFromDisplayConfig(int displayId) {
+        return mDisplayManagerInternal.getHostUsiVersion(displayId);
+    }
+
+    @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
         IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
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 e9ee750..25efe0c 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -64,7 +64,7 @@
  * The {@link MediaProjectionManagerService} manages the creation and lifetime of MediaProjections,
  * as well as the capabilities they grant. Any service using MediaProjection tokens as permission
  * grants <b>must</b> validate the token before use by calling {@link
- * IMediaProjectionService#isValidMediaProjection}.
+ * IMediaProjectionService#isCurrentProjection}.
  */
 public final class MediaProjectionManagerService extends SystemService
         implements Watchdog.Monitor {
@@ -228,7 +228,7 @@
         mCallbackDelegate.dispatchStop(projection);
     }
 
-    private boolean isValidMediaProjection(IBinder token) {
+    private boolean isCurrentProjection(IBinder token) {
         synchronized (mLock) {
             if (mProjectionToken != null) {
                 return mProjectionToken.equals(token);
@@ -313,8 +313,8 @@
         }
 
         @Override // Binder call
-        public boolean isValidMediaProjection(IMediaProjection projection) {
-            return MediaProjectionManagerService.this.isValidMediaProjection(
+        public boolean isCurrentProjection(IMediaProjection projection) {
+            return MediaProjectionManagerService.this.isCurrentProjection(
                     projection == null ? null : projection.asBinder());
         }
 
@@ -357,7 +357,7 @@
                 throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to notify "
                         + "on captured content resize");
             }
-            if (!isValidMediaProjection(mProjectionGrant)) {
+            if (!isCurrentProjection(mProjectionGrant)) {
                 return;
             }
             final long token = Binder.clearCallingIdentity();
@@ -377,7 +377,7 @@
                 throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to notify "
                         + "on captured content resize");
             }
-            if (!isValidMediaProjection(mProjectionGrant)) {
+            if (!isCurrentProjection(mProjectionGrant)) {
                 return;
             }
             final long token = Binder.clearCallingIdentity();
@@ -429,8 +429,9 @@
             final long origId = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
-                    if (!isValidMediaProjection(projection)) {
-                        throw new SecurityException("Invalid media projection");
+                    if (!isCurrentProjection(projection)) {
+                        throw new SecurityException("Unable to set ContentRecordingSession on "
+                                + "non-current MediaProjection");
                     }
                     if (!LocalServices.getService(
                             WindowManagerInternal.class).setContentRecordingSession(
@@ -536,7 +537,7 @@
                 throw new IllegalArgumentException("callback must not be null");
             }
             synchronized (mLock) {
-                if (isValidMediaProjection(asBinder())) {
+                if (isCurrentProjection(asBinder())) {
                     Slog.w(TAG, "UID " + Binder.getCallingUid()
                             + " attempted to start already started MediaProjection");
                     return;
@@ -603,7 +604,7 @@
         @Override // Binder call
         public void stop() {
             synchronized (mLock) {
-                if (!isValidMediaProjection(asBinder())) {
+                if (!isCurrentProjection(asBinder())) {
                     Slog.w(TAG, "Attempted to stop inactive MediaProjection "
                             + "(uid=" + Binder.getCallingUid() + ", "
                             + "pid=" + Binder.getCallingPid() + ")");
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index ff6420c..a610b5b 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -430,8 +430,9 @@
      * checks.
      */
     @Override
-    public void setInteractAcrossProfilesAppOp(String packageName, @Mode int newMode) {
-        setInteractAcrossProfilesAppOp(packageName, newMode, mInjector.getCallingUserId());
+    public void setInteractAcrossProfilesAppOp(
+            @UserIdInt int userId, String packageName, @Mode int newMode) {
+        setInteractAcrossProfilesAppOp(packageName, newMode, userId);
     }
 
     private void setInteractAcrossProfilesAppOp(
@@ -594,8 +595,12 @@
     }
 
     @Override
-    public boolean canConfigureInteractAcrossProfiles(String packageName) {
-        return canConfigureInteractAcrossProfiles(packageName, mInjector.getCallingUserId());
+    public boolean canConfigureInteractAcrossProfiles(int userId, String packageName) {
+        if (mInjector.getCallingUserId() != userId) {
+            mContext.checkCallingOrSelfPermission(INTERACT_ACROSS_USERS);
+        }
+
+        return canConfigureInteractAcrossProfiles(packageName, userId);
     }
 
     private boolean canConfigureInteractAcrossProfiles(String packageName, @UserIdInt int userId) {
@@ -613,9 +618,13 @@
     }
 
     @Override
-    public boolean canUserAttemptToConfigureInteractAcrossProfiles(String packageName) {
+    public boolean canUserAttemptToConfigureInteractAcrossProfiles(int userId, String packageName) {
+        if (mInjector.getCallingUserId() != userId) {
+            mContext.checkCallingOrSelfPermission(INTERACT_ACROSS_USERS);
+        }
+
         return canUserAttemptToConfigureInteractAcrossProfiles(
-                packageName, mInjector.getCallingUserId());
+                packageName, userId);
     }
 
     private boolean canUserAttemptToConfigureInteractAcrossProfiles(
@@ -676,28 +685,31 @@
     }
 
     @Override
-    public void resetInteractAcrossProfilesAppOps(List<String> packageNames) {
-        packageNames.forEach(this::resetInteractAcrossProfilesAppOp);
+    public void resetInteractAcrossProfilesAppOps(@UserIdInt int userId, List<String> packageNames) {
+        for (String packageName : packageNames) {
+            resetInteractAcrossProfilesAppOp(userId, packageName);
+        }
     }
 
-    private void resetInteractAcrossProfilesAppOp(String packageName) {
-        if (canConfigureInteractAcrossProfiles(packageName)) {
+    private void resetInteractAcrossProfilesAppOp(@UserIdInt int userId, String packageName) {
+        if (canConfigureInteractAcrossProfiles(packageName, userId)) {
             Slog.w(TAG, "Not resetting app-op for package " + packageName
                     + " since it is still configurable by users.");
             return;
         }
         final String op =
                 AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES);
-        setInteractAcrossProfilesAppOp(packageName, AppOpsManager.opToDefaultMode(op));
+        setInteractAcrossProfilesAppOp(userId, packageName, AppOpsManager.opToDefaultMode(op));
     }
 
     @Override
-    public void clearInteractAcrossProfilesAppOps() {
+    public void clearInteractAcrossProfilesAppOps(@UserIdInt int userId) {
         final int defaultMode =
                 AppOpsManager.opToDefaultMode(
                         AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES));
         findAllPackageNames()
-                .forEach(packageName -> setInteractAcrossProfilesAppOp(packageName, defaultMode));
+                .forEach(packageName -> setInteractAcrossProfilesAppOp(
+                        userId, packageName, defaultMode));
     }
 
     private List<String> findAllPackageNames() {
diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFilter.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFilter.java
index c58128a..9683469 100644
--- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFilter.java
+++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFilter.java
@@ -30,7 +30,7 @@
  * Representation of an immutable default cross-profile intent filter.
  */
 @Immutable
-final class DefaultCrossProfileIntentFilter {
+public final class DefaultCrossProfileIntentFilter {
 
     @IntDef({
             Direction.TO_PARENT,
diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
index ceaaefd..3799193 100644
--- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
+++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
@@ -321,6 +321,15 @@
     }
 
     /**
+     * Returns default telephony related intent filters for managed profile.
+     */
+    public static List<DefaultCrossProfileIntentFilter> getDefaultManagedProfileTelephonyFilters() {
+        return Arrays.asList(
+                DIAL_DATA,
+                SMS_MMS);
+    }
+
+    /**
      * Clone profile's DefaultCrossProfileIntentFilter
      */
 
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index c38b822..c5bcddc 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -17,6 +17,8 @@
 package com.android.server.pm;
 
 import static android.app.ActivityOptions.KEY_SPLASH_SCREEN_THEME;
+import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
+import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
 import static android.app.PendingIntent.FLAG_IMMUTABLE;
 import static android.app.PendingIntent.FLAG_MUTABLE;
 import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
@@ -1143,7 +1145,8 @@
             final int code;
             try {
                 code = mActivityTaskManagerInternal.startActivitiesAsPackage(publisherPackage,
-                        publishedFeatureId, userId, intents, startActivityOptions);
+                        publishedFeatureId, userId, intents,
+                        getActivityOptionsForLauncher(startActivityOptions));
                 if (ActivityManager.isStartResultSuccessful(code)) {
                     return true; // Success
                 } else {
@@ -1158,6 +1161,23 @@
             }
         }
 
+        private Bundle getActivityOptionsForLauncher(Bundle startActivityOptions) {
+            // starting a shortcut implies the user's consent, so grant the launchers/senders BAL
+            // privileges (unless the caller explicitly defined the behavior)
+            if (startActivityOptions == null) {
+                return ActivityOptions.makeBasic().setPendingIntentBackgroundActivityStartMode(
+                                MODE_BACKGROUND_ACTIVITY_START_ALLOWED).toBundle();
+            }
+            ActivityOptions activityOptions = ActivityOptions.fromBundle(startActivityOptions);
+            if (activityOptions.getPendingIntentBackgroundActivityStartMode()
+                    == MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED) {
+                // only override if the property was not explicitly set
+                return activityOptions.setPendingIntentBackgroundActivityStartMode(
+                        MODE_BACKGROUND_ACTIVITY_START_ALLOWED).toBundle();
+            }
+            return startActivityOptions;
+        }
+
         @Override
         public boolean isActivityEnabled(
                 String callingPackage, ComponentName component, UserHandle user)
@@ -1216,8 +1236,8 @@
             i.setSourceBounds(sourceBounds);
 
             mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage,
-                    callingFeatureId, i, /* resultTo= */ null, Intent.FLAG_ACTIVITY_NEW_TASK, opts,
-                    userId);
+                    callingFeatureId, i, /* resultTo= */ null, Intent.FLAG_ACTIVITY_NEW_TASK,
+                    getActivityOptionsForLauncher(opts), userId);
         }
 
         @Override
@@ -1264,7 +1284,8 @@
 
             mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage,
                     callingFeatureId, launchIntent, /* resultTo= */ null,
-                    Intent.FLAG_ACTIVITY_NEW_TASK, opts, user.getIdentifier());
+                    Intent.FLAG_ACTIVITY_NEW_TASK, getActivityOptionsForLauncher(opts),
+                    user.getIdentifier());
         }
 
         /**
@@ -1347,7 +1368,7 @@
             }
             mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage,
                     callingFeatureId, intent, /* resultTo= */ null, Intent.FLAG_ACTIVITY_NEW_TASK,
-                    opts, user.getIdentifier());
+                    getActivityOptionsForLauncher(opts), user.getIdentifier());
         }
 
         /** Checks if user is a profile of or same as listeningUser.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 94e96b0..620ee37 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -187,6 +187,7 @@
 import com.android.permission.persistence.RuntimePermissionsPersistence;
 import com.android.server.EventLogTags;
 import com.android.server.FgThread;
+import com.android.server.IntentResolver;
 import com.android.server.LocalManagerRegistry;
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
@@ -4745,6 +4746,44 @@
         }
 
         @Override
+        public boolean removeCrossProfileIntentFilter(IntentFilter intentFilter,
+                String ownerPackage,
+                int sourceUserId,
+                int targetUserId, int flags) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+            final int callingUid = Binder.getCallingUid();
+            enforceOwnerRights(snapshotComputer(), ownerPackage, callingUid);
+            mUserManager.enforceCrossProfileIntentFilterAccess(sourceUserId, targetUserId,
+                    callingUid, /* addCrossProfileIntentFilter */ false);
+            PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(),
+                    UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
+
+            boolean removedMatchingFilter = false;
+            synchronized (mLock) {
+                CrossProfileIntentResolver resolver =
+                        mSettings.editCrossProfileIntentResolverLPw(sourceUserId);
+
+                ArraySet<CrossProfileIntentFilter> set =
+                        new ArraySet<>(resolver.filterSet());
+                for (CrossProfileIntentFilter filter : set) {
+                    if (IntentResolver.filterEquals(filter.mFilter, intentFilter)
+                            && filter.getOwnerPackage().equals(ownerPackage)
+                            && filter.getTargetUserId() == targetUserId
+                            && filter.getFlags() == flags) {
+                        resolver.removeFilter(filter);
+                        removedMatchingFilter = true;
+                        break;
+                    }
+                }
+            }
+            if (removedMatchingFilter) {
+                scheduleWritePackageRestrictions(sourceUserId);
+            }
+            return removedMatchingFilter;
+        }
+
+        @Override
         public final void deleteApplicationCacheFiles(final String packageName,
                 final IPackageDataObserver observer) {
             final int userId = UserHandle.getCallingUserId();
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index c278550..89c5c9e 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -11299,7 +11299,7 @@
      */
     @Override
     public BatteryStatsHistoryIterator iterateBatteryStatsHistory() {
-        return mHistory.iterate();
+        return mHistory.copy().iterate();
     }
 
     @Override
@@ -14054,7 +14054,8 @@
                     && (oldStatus == BatteryManager.BATTERY_STATUS_FULL
                     || level >= 90
                     || (mDischargeCurrentLevel < 20 && level >= 80)
-                    || getHighDischargeAmountSinceCharge() >= 200)) {
+                    || getHighDischargeAmountSinceCharge() >= 200)
+                    && mHistory.isResetEnabled()) {
                 Slog.i(TAG, "Resetting battery stats: level=" + level + " status=" + oldStatus
                         + " dischargeLevel=" + mDischargeCurrentLevel
                         + " lowAmount=" + getLowDischargeAmountSinceCharge()
@@ -16604,7 +16605,7 @@
     }
 
     @GuardedBy("this")
-    public void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
+    public void dump(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
         if (DEBUG) {
             pw.println("mOnBatteryTimeBase:");
             mOnBatteryTimeBase.dump(pw, "  ");
@@ -16676,36 +16677,39 @@
             pr.println("*** Camera timer:");
             mCameraOnTimer.logState(pr, "  ");
         }
-        super.dumpLocked(context, pw, flags, reqUid, histStart);
+        super.dump(context, pw, flags, reqUid, histStart);
 
-        pw.print("Per process state tracking available: ");
-        pw.println(trackPerProcStateCpuTimes());
-        pw.print("Total cpu time reads: ");
-        pw.println(mNumSingleUidCpuTimeReads);
-        pw.print("Batching Duration (min): ");
-        pw.println((mClock.uptimeMillis() - mCpuTimeReadsTrackingStartTimeMs) / (60 * 1000));
-        pw.print("All UID cpu time reads since the later of device start or stats reset: ");
-        pw.println(mNumAllUidCpuTimeReads);
-        pw.print("UIDs removed since the later of device start or stats reset: ");
-        pw.println(mNumUidsRemoved);
+        synchronized (this) {
+            pw.print("Per process state tracking available: ");
+            pw.println(trackPerProcStateCpuTimes());
+            pw.print("Total cpu time reads: ");
+            pw.println(mNumSingleUidCpuTimeReads);
+            pw.print("Batching Duration (min): ");
+            pw.println((mClock.uptimeMillis() - mCpuTimeReadsTrackingStartTimeMs) / (60 * 1000));
+            pw.print("All UID cpu time reads since the later of device start or stats reset: ");
+            pw.println(mNumAllUidCpuTimeReads);
+            pw.print("UIDs removed since the later of device start or stats reset: ");
+            pw.println(mNumUidsRemoved);
 
-        pw.println("Currently mapped isolated uids:");
-        final int numIsolatedUids = mIsolatedUids.size();
-        for (int i = 0; i < numIsolatedUids; i++) {
-            final int isolatedUid = mIsolatedUids.keyAt(i);
-            final int ownerUid = mIsolatedUids.valueAt(i);
-            final int refCount = mIsolatedUidRefCounts.get(isolatedUid);
-            pw.println("  " + isolatedUid + "->" + ownerUid + " (ref count = " + refCount + ")");
+            pw.println("Currently mapped isolated uids:");
+            final int numIsolatedUids = mIsolatedUids.size();
+            for (int i = 0; i < numIsolatedUids; i++) {
+                final int isolatedUid = mIsolatedUids.keyAt(i);
+                final int ownerUid = mIsolatedUids.valueAt(i);
+                final int refCount = mIsolatedUidRefCounts.get(isolatedUid);
+                pw.println(
+                        "  " + isolatedUid + "->" + ownerUid + " (ref count = " + refCount + ")");
+            }
+
+            pw.println();
+            dumpConstantsLocked(pw);
+
+            pw.println();
+            dumpCpuPowerBracketsLocked(pw);
+
+            pw.println();
+            dumpEnergyConsumerStatsLocked(pw);
         }
-
-        pw.println();
-        dumpConstantsLocked(pw);
-
-        pw.println();
-        dumpCpuPowerBracketsLocked(pw);
-
-        pw.println();
-        dumpEnergyConsumerStatsLocked(pw);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperData.java b/services/core/java/com/android/server/wallpaper/WallpaperData.java
index 25ce280..625e7d9 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperData.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperData.java
@@ -56,6 +56,12 @@
     int mWhich;
 
     /**
+     * True if the system wallpaper was also used for lock screen before this wallpaper was set.
+     * This is needed to update state after setting the wallpaper.
+     */
+    boolean mSystemWasBoth;
+
+    /**
      * Callback once the set + crop is finished
      */
     IWallpaperManagerCallback setComplete;
@@ -139,6 +145,61 @@
                 (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_CROP : WALLPAPER_CROP);
     }
 
+    /**
+     * Copies the essential properties of a WallpaperData to a new instance, including the id and
+     * WallpaperConnection, usually in preparation for migrating a system+lock wallpaper to system-
+     * or lock-only. NB: the source object retains the pointer to the connection and it is the
+     * caller's responsibility to set this to null or otherwise be sure the connection is not shared
+     * between WallpaperData instances.
+     *
+     * @param source WallpaperData object to copy
+     */
+    WallpaperData(WallpaperData source) {
+        this.userId = source.userId;
+        this.wallpaperFile = source.wallpaperFile;
+        this.cropFile = source.cropFile;
+        this.wallpaperComponent = source.wallpaperComponent;
+        this.mWhich = source.mWhich;
+        this.wallpaperId = source.wallpaperId;
+        this.cropHint.set(source.cropHint);
+        this.allowBackup = source.allowBackup;
+        this.primaryColors = source.primaryColors;
+        this.mWallpaperDimAmount = source.mWallpaperDimAmount;
+        this.connection = source.connection;
+        this.connection.mWallpaper = this;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder out = new StringBuilder(defaultString(this));
+        out.append(", id: ");
+        out.append(wallpaperId);
+        out.append(", which: ");
+        out.append(mWhich);
+        out.append(", file mod: ");
+        out.append(wallpaperFile != null ? wallpaperFile.lastModified() : "null");
+        if (connection == null) {
+            out.append(", no connection");
+        } else {
+            out.append(", info: ");
+            out.append(connection.mInfo);
+            out.append(", engine(s):");
+            connection.forEachDisplayConnector(connector -> {
+                if (connector.mEngine != null) {
+                    out.append(" ");
+                    out.append(defaultString(connector.mEngine));
+                } else {
+                    out.append(" null");
+                }
+            });
+        }
+        return out.toString();
+    }
+
+    private static String defaultString(Object o) {
+        return o.getClass().getSimpleName() + "@" + Integer.toHexString(o.hashCode());
+    }
+
     // Called during initialization of a given user's wallpaper bookkeeping
     boolean cropExists() {
         return cropFile.exists();
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index bf09b67..262b964 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -194,7 +194,11 @@
     }
 
     private final Object mLock = new Object();
-    private final boolean mEnableSeparateLockScreenEngine;
+    /** True to enable a second engine for lock screen wallpaper when different from system wp. */
+    @VisibleForTesting
+    final boolean mEnableSeparateLockScreenEngine;
+    /** Tracks wallpaper being migrated from system+lock to lock when setting static wp. */
+    WallpaperDestinationChangeHandler mPendingMigrationViaStatic;
 
     /**
      * Minimum time between crashes of a wallpaper service for us to consider
@@ -241,11 +245,161 @@
             return (wallpaper != null) ? wallpaper : mWallpaper;
         }
 
-        @Override
-        public void onEvent(int event, String path) {
-            if (path == null) {
+        // Handles static wallpaper changes generated by WallpaperObserver events when
+        // mEnableSeparateLockScreenEngine is true.
+        private void updateWallpapers(int event, String path) {
+            // System and system+lock changes happen on the system wallpaper input file;
+            // lock-only changes happen on the dedicated lock wallpaper input file
+            final File changedFile = new File(mWallpaperDir, path);
+            final boolean sysWallpaperChanged = (mWallpaperFile.equals(changedFile));
+            final boolean lockWallpaperChanged = (mWallpaperLockFile.equals(changedFile));
+            final WallpaperData wallpaper = dataForEvent(sysWallpaperChanged, lockWallpaperChanged);
+
+            final boolean moved = (event == MOVED_TO);
+            final boolean written = (event == CLOSE_WRITE || moved);
+            final boolean isMigration = moved && lockWallpaperChanged;
+            final boolean isRestore = moved && !isMigration;
+            final boolean isAppliedToLock = (wallpaper.mWhich & FLAG_LOCK) != 0;
+            final boolean needsUpdate = wallpaper.wallpaperComponent == null
+                    || event != CLOSE_WRITE // includes the MOVED_TO case
+                    || wallpaper.imageWallpaperPending;
+
+            if (DEBUG) {
+                Slog.v(TAG, "Wallpaper file change: evt=" + event
+                        + " path=" + path
+                        + " sys=" + sysWallpaperChanged
+                        + " lock=" + lockWallpaperChanged
+                        + " imagePending=" + wallpaper.imageWallpaperPending
+                        + " mWhich=0x" + Integer.toHexString(wallpaper.mWhich)
+                        + " written=" + written
+                        + " isMigration=" + isMigration
+                        + " isRestore=" + isRestore
+                        + " isAppliedToLock=" + isAppliedToLock
+                        + " needsUpdate=" + needsUpdate);
+            }
+
+            if (isMigration) {
+                // When separate lock screen engine is supported, migration will be handled by
+                // WallpaperDestinationChangeHandler.
                 return;
             }
+            if (!(sysWallpaperChanged || lockWallpaperChanged)) {
+                return;
+            }
+
+            int notifyColorsWhich = 0;
+            synchronized (mLock) {
+                notifyCallbacksLocked(wallpaper);
+
+                if (!written || !needsUpdate) {
+                    return;
+                }
+
+                if (DEBUG) {
+                    Slog.v(TAG, "Setting new static wallpaper: which=" + wallpaper.mWhich);
+                }
+
+                WallpaperDestinationChangeHandler localSync = mPendingMigrationViaStatic;
+                mPendingMigrationViaStatic = null;
+                // The image source has finished writing the source image,
+                // so we now produce the crop rect (in the background), and
+                // only publish the new displayable (sub)image as a result
+                // of that work.
+                SELinux.restorecon(changedFile);
+                if (isRestore) {
+                    // This is a restore, so generate the crop using any just-restored new
+                    // crop guidelines, making sure to preserve our local dimension hints.
+                    // We also make sure to reapply the correct SELinux label.
+                    if (DEBUG) {
+                        Slog.v(TAG, "Wallpaper restore; reloading metadata");
+                    }
+                    loadSettingsLocked(wallpaper.userId, true);
+                }
+                if (DEBUG) {
+                    Slog.v(TAG, "Wallpaper written; generating crop");
+                }
+                mWallpaperCropper.generateCrop(wallpaper);
+                if (DEBUG) {
+                    Slog.v(TAG, "Crop done; invoking completion callback");
+                }
+                wallpaper.imageWallpaperPending = false;
+
+                if (sysWallpaperChanged) {
+                    if (DEBUG) {
+                        Slog.v(TAG, "Home screen wallpaper changed");
+                    }
+                    IRemoteCallback.Stub callback = new IRemoteCallback.Stub() {
+                        @Override
+                        public void sendResult(Bundle data) throws RemoteException {
+                            if (DEBUG) {
+                                Slog.d(TAG, "publish system wallpaper changed!");
+                            }
+                            if (localSync != null) {
+                                localSync.complete();
+                            }
+                            notifyWallpaperChanged(wallpaper);
+                        }
+                    };
+
+                    // If this was the system wallpaper, rebind...
+                    bindWallpaperComponentLocked(mImageWallpaper, true, false, wallpaper,
+                            callback);
+                    notifyColorsWhich |= FLAG_SYSTEM;
+                }
+
+                if (lockWallpaperChanged) {
+                    // This is lock-only, so (re)bind to the static engine.
+                    if (DEBUG) {
+                        Slog.v(TAG, "Lock screen wallpaper changed");
+                    }
+                    IRemoteCallback.Stub callback = new IRemoteCallback.Stub() {
+                        @Override
+                        public void sendResult(Bundle data) throws RemoteException {
+                            if (DEBUG) {
+                                Slog.d(TAG, "publish lock wallpaper changed!");
+                            }
+                            if (localSync != null) {
+                                localSync.complete();
+                            }
+                            notifyWallpaperChanged(wallpaper);
+                        }
+                    };
+
+                    bindWallpaperComponentLocked(mImageWallpaper, true /* force */,
+                            false /* fromUser */, wallpaper, callback);
+                    notifyColorsWhich |= FLAG_LOCK;
+                } else if (isAppliedToLock) {
+                    // This is system-plus-lock: we need to wipe the lock bookkeeping since
+                    // we're falling back to displaying the system wallpaper there.
+                    if (DEBUG) {
+                        Slog.v(TAG, "Lock screen wallpaper changed to same as home");
+                    }
+                    final WallpaperData lockedWallpaper = mLockWallpaperMap.get(
+                            mWallpaper.userId);
+                    if (lockedWallpaper != null) {
+                        detachWallpaperLocked(lockedWallpaper);
+                    }
+                    mLockWallpaperMap.remove(wallpaper.userId);
+                    notifyColorsWhich |= FLAG_LOCK;
+                }
+
+                saveSettingsLocked(wallpaper.userId);
+                // Notify the client immediately if only lockscreen wallpaper changed.
+                if (lockWallpaperChanged && !sysWallpaperChanged) {
+                    notifyWallpaperChanged(wallpaper);
+                }
+            }
+
+            // Outside of the lock since it will synchronize itself
+            if (notifyColorsWhich != 0) {
+                notifyWallpaperColorsChanged(wallpaper, notifyColorsWhich);
+            }
+        }
+
+        // Handles static wallpaper changes generated by WallpaperObserver events when
+        // mEnableSeparateLockScreenEngine is false.
+        // TODO(b/266818039) Remove this method
+        private void updateWallpapersLegacy(int event, String path) {
             final boolean moved = (event == MOVED_TO);
             final boolean written = (event == CLOSE_WRITE || moved);
             final File changedFile = new File(mWallpaperDir, path);
@@ -268,7 +422,6 @@
             }
 
             if (moved && lockWallpaperChanged) {
-                // TODO(b/253507223) Start lock screen WallpaperService
                 // We just migrated sys -> lock to preserve imagery for an impending
                 // new system-only wallpaper.  Tell keyguard about it and make sure it
                 // has the right SELinux label.
@@ -323,8 +476,6 @@
                                         false, wallpaper, callback);
                                 notifyColorsWhich |= FLAG_SYSTEM;
                             }
-                            // TODO(b/253507223) Start lock screen WallpaperService if only lock
-                            // screen wp changed
                             if (lockWallpaperChanged
                                     || (wallpaper.mWhich & FLAG_LOCK) != 0) {
                                 if (DEBUG) {
@@ -356,6 +507,19 @@
                 notifyWallpaperColorsChanged(wallpaper, notifyColorsWhich);
             }
         }
+
+        @Override
+        public void onEvent(int event, String path) {
+            if (path == null) {
+                return;
+            }
+
+            if (mEnableSeparateLockScreenEngine) {
+                updateWallpapers(event, path);
+            } else {
+                updateWallpapersLegacy(event, path);
+            }
+        }
     }
 
     private void notifyWallpaperChanged(WallpaperData wallpaper) {
@@ -382,6 +546,9 @@
     }
 
     void notifyWallpaperColorsChanged(@NonNull WallpaperData wallpaper, int which) {
+        if (DEBUG) {
+            Slog.i(TAG, "Notifying wallpaper colors changed");
+        }
         if (wallpaper.connection != null) {
             wallpaper.connection.forEachDisplayConnector(connector -> {
                 notifyWallpaperColorsChangedOnDisplay(wallpaper, which, connector.mDisplayId);
@@ -807,7 +974,7 @@
          * A map for each display.
          * Use {@link #getDisplayConnectorOrCreate(int displayId)} to ensure the display is usable.
          */
-        private SparseArray<DisplayConnector> mDisplayConnector = new SparseArray<>();
+        private final SparseArray<DisplayConnector> mDisplayConnector = new SparseArray<>();
 
         /** Time in milliseconds until we expect the wallpaper to reconnect (unless we're in the
          *  middle of an update). If exceeded, the wallpaper gets reset to the system default. */
@@ -1170,6 +1337,110 @@
         }
     }
 
+    /**
+     * Tracks wallpaper information during a wallpaper change and does bookkeeping afterwards to
+     * update Engine destination, wallpaper maps, and last wallpaper.
+     */
+    class WallpaperDestinationChangeHandler {
+        final WallpaperData mNewWallpaper;
+        final WallpaperData mOriginalSystem;
+
+        WallpaperDestinationChangeHandler(WallpaperData newWallpaper) {
+            this.mNewWallpaper = newWallpaper;
+            WallpaperData sysWp = mWallpaperMap.get(newWallpaper.userId);
+            mOriginalSystem = new WallpaperData(sysWp);
+        }
+
+        void complete() {
+            // Only changes from home+lock to just home or lock need attention
+            // If setting the wallpaper fails, this callback will be called
+            // when the wallpaper is detached, in which case wallpapers may have
+            // already changed. Make sure we're not overwriting a more recent wallpaper.
+            if (mNewWallpaper.mSystemWasBoth) {
+                if (DEBUG) {
+                    Slog.v(TAG, "Handling change from system+lock wallpaper");
+                }
+                if (mNewWallpaper.mWhich == FLAG_SYSTEM) {
+                    // New wp is system only, so old system+lock is now lock only
+                    final boolean originalIsStatic = mImageWallpaper.equals(
+                            mOriginalSystem.wallpaperComponent);
+                    if (originalIsStatic) {
+                        // Static wp: image file rename has already been tried via
+                        // migrateStaticSystemToLockWallpaperLocked() and added to the lock wp map
+                        // if successful.
+                        WallpaperData lockWp = mLockWallpaperMap.get(mNewWallpaper.userId);
+                        if (lockWp != null) {
+                            // Successful rename, set old system+lock to the pending lock wp
+                            if (DEBUG) {
+                                Slog.v(TAG, "static system+lock to system success");
+                            }
+                            lockWp.wallpaperComponent =
+                                    mOriginalSystem.wallpaperComponent;
+                            lockWp.connection = mOriginalSystem.connection;
+                            lockWp.connection.mWallpaper = lockWp;
+                            updateEngineFlags(mOriginalSystem, FLAG_LOCK);
+                            notifyWallpaperColorsChanged(lockWp, FLAG_LOCK);
+                        } else {
+                            // Failed rename, use current system wp for both
+                            if (DEBUG) {
+                                Slog.v(TAG, "static system+lock to system failure");
+                            }
+                            WallpaperData currentSystem = mWallpaperMap.get(mNewWallpaper.userId);
+                            currentSystem.mWhich = FLAG_SYSTEM | FLAG_LOCK;
+                            updateEngineFlags(currentSystem, FLAG_SYSTEM | FLAG_LOCK);
+                            mLockWallpaperMap.remove(mNewWallpaper.userId);
+                        }
+                    } else {
+                        // Live wp: just update old system+lock to lock only
+                        if (DEBUG) {
+                            Slog.v(TAG, "live system+lock to system success");
+                        }
+                        mOriginalSystem.mWhich = FLAG_LOCK;
+                        updateEngineFlags(mOriginalSystem, FLAG_LOCK);
+                        mLockWallpaperMap.put(mNewWallpaper.userId, mOriginalSystem);
+                        mLastLockWallpaper = mOriginalSystem;
+                        notifyWallpaperColorsChanged(mOriginalSystem, FLAG_LOCK);
+                    }
+                } else if (mNewWallpaper.mWhich == FLAG_LOCK) {
+                    // New wp is lock only, so old system+lock is now system only
+                    if (DEBUG) {
+                        Slog.v(TAG, "system+lock to lock");
+                    }
+                    WallpaperData currentSystem = mWallpaperMap.get(mNewWallpaper.userId);
+                    if (currentSystem.wallpaperId == mOriginalSystem.wallpaperId) {
+                        currentSystem.mWhich = FLAG_SYSTEM;
+                        updateEngineFlags(currentSystem, FLAG_SYSTEM);
+                    }
+                }
+            }
+
+            if (DEBUG) {
+                Slog.v(TAG, "--- wallpaper changed --");
+                Slog.v(TAG, "new sysWp: " + mWallpaperMap.get(mCurrentUserId));
+                Slog.v(TAG, "new lockWp: " + mLockWallpaperMap.get(mCurrentUserId));
+                Slog.v(TAG, "new lastWp: " + mLastWallpaper);
+                Slog.v(TAG, "new lastLockWp: " + mLastLockWallpaper);
+            }
+        }
+
+        private void updateEngineFlags(WallpaperData wallpaper, @SetWallpaperFlags int which) {
+            if (wallpaper.connection == null) {
+                return;
+            }
+            wallpaper.connection.forEachDisplayConnector(
+                    connector -> {
+                        try {
+                            if (connector.mEngine != null) {
+                                connector.mEngine.setWallpaperFlags(which);
+                            }
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "Failed to update wallpaper engine flags", e);
+                        }
+                    }
+            );
+        }
+    }
+
     class MyPackageMonitor extends PackageMonitor {
         @Override
         public void onPackageUpdateFinished(String packageName, int uid) {
@@ -1345,6 +1616,9 @@
 
         mEnableSeparateLockScreenEngine = mContext.getResources().getBoolean(
                 R.bool.config_independentLockscreenLiveWallpaper);
+        if (DEBUG) {
+            Slog.v(TAG, "Separate lock screen engine enabled: " + mEnableSeparateLockScreenEngine);
+        }
 
         LocalServices.addService(WallpaperManagerInternal.class, new LocalService());
     }
@@ -2467,23 +2741,33 @@
         synchronized (mLock) {
             if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which));
             WallpaperData wallpaper;
+            final WallpaperData originalSystemWallpaper = mWallpaperMap.get(userId);
+            final boolean systemIsStatic =
+                    originalSystemWallpaper != null && mImageWallpaper.equals(
+                            originalSystemWallpaper.wallpaperComponent);
+            final boolean systemIsBoth = mLockWallpaperMap.get(userId) == null;
 
             /* If we're setting system but not lock, and lock is currently sharing the system
              * wallpaper, we need to migrate that image over to being lock-only before
              * the caller here writes new bitmap data.
              */
-            if (which == FLAG_SYSTEM && mLockWallpaperMap.get(userId) == null) {
+            if (which == FLAG_SYSTEM && systemIsStatic && systemIsBoth) {
                 Slog.i(TAG, "Migrating current wallpaper to be lock-only before"
-                        + "updating system wallpaper");
-                migrateSystemToLockWallpaperLocked(userId);
+                        + " updating system wallpaper");
+                migrateStaticSystemToLockWallpaperLocked(userId);
             }
 
             wallpaper = getWallpaperSafeLocked(userId, which);
+            if (mPendingMigrationViaStatic != null) {
+                Slog.w(TAG, "Starting new static wp migration before previous migration finished");
+            }
+            mPendingMigrationViaStatic = new WallpaperDestinationChangeHandler(wallpaper);
             final long ident = Binder.clearCallingIdentity();
             try {
                 ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras);
                 if (pfd != null) {
                     wallpaper.imageWallpaperPending = true;
+                    wallpaper.mSystemWasBoth = systemIsBoth;
                     wallpaper.mWhich = which;
                     wallpaper.setComplete = completion;
                     wallpaper.fromForegroundApp = fromForegroundApp;
@@ -2498,7 +2782,7 @@
         }
     }
 
-    private void migrateSystemToLockWallpaperLocked(int userId) {
+    private void migrateStaticSystemToLockWallpaperLocked(int userId) {
         WallpaperData sysWP = mWallpaperMap.get(userId);
         if (sysWP == null) {
             if (DEBUG) {
@@ -2520,14 +2804,17 @@
         try {
             Os.rename(sysWP.wallpaperFile.getAbsolutePath(), lockWP.wallpaperFile.getAbsolutePath());
             Os.rename(sysWP.cropFile.getAbsolutePath(), lockWP.cropFile.getAbsolutePath());
+            mLockWallpaperMap.put(userId, lockWP);
+            if (mEnableSeparateLockScreenEngine) {
+                SELinux.restorecon(lockWP.wallpaperFile);
+                mLastLockWallpaper = lockWP;
+            }
         } catch (ErrnoException e) {
             Slog.e(TAG, "Can't migrate system wallpaper: " + e.getMessage());
             lockWP.wallpaperFile.delete();
             lockWP.cropFile.delete();
             return;
         }
-
-        mLockWallpaperMap.put(userId, lockWP);
     }
 
     ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper,
@@ -2582,11 +2869,116 @@
 
     @VisibleForTesting
     void setWallpaperComponent(ComponentName name, @SetWallpaperFlags int which, int userId) {
+        if (mEnableSeparateLockScreenEngine) {
+            setWallpaperComponentInternal(name, which, userId);
+        } else {
+            setWallpaperComponentInternalLegacy(name, which, userId);
+        }
+    }
+
+    private void setWallpaperComponentInternal(ComponentName name, @SetWallpaperFlags int which,
+            int userIdIn) {
+        if (DEBUG) {
+            Slog.v(TAG, "Setting new live wallpaper: which=" + which + ", component: " + name);
+        }
+        final int userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(),
+                userIdIn, false /* all */, true /* full */, "changing live wallpaper",
+                null /* pkg */);
+        checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
+
+        boolean shouldNotifyColors = false;
+        final WallpaperData newWallpaper;
+
+        synchronized (mLock) {
+            Slog.v(TAG, "setWallpaperComponent name=" + name);
+            final WallpaperData originalSystemWallpaper = mWallpaperMap.get(userId);
+            if (originalSystemWallpaper == null) {
+                throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
+            }
+            final boolean systemIsStatic = mImageWallpaper.equals(
+                    originalSystemWallpaper.wallpaperComponent);
+            final boolean systemIsBoth = mLockWallpaperMap.get(userId) == null;
+
+            if (which == FLAG_SYSTEM && systemIsBoth && systemIsStatic) {
+                // Migrate current static system+lock wp to lock only before proceeding.
+                Slog.i(TAG, "Migrating current wallpaper to be lock-only before"
+                        + "updating system wallpaper");
+                migrateStaticSystemToLockWallpaperLocked(userId);
+            }
+
+            newWallpaper = getWallpaperSafeLocked(userId, which);
+            final long ident = Binder.clearCallingIdentity();
+
+            try {
+                newWallpaper.imageWallpaperPending = false;
+                newWallpaper.mWhich = which;
+                newWallpaper.mSystemWasBoth = systemIsBoth;
+                final WallpaperDestinationChangeHandler
+                        liveSync = new WallpaperDestinationChangeHandler(
+                        newWallpaper);
+                boolean same = changingToSame(name, newWallpaper);
+                IRemoteCallback.Stub callback = new IRemoteCallback.Stub() {
+                    @Override
+                    public void sendResult(Bundle data) throws RemoteException {
+                        if (DEBUG) {
+                            Slog.d(TAG, "publish system wallpaper changed!");
+                        }
+                        liveSync.complete();
+                    }
+                };
+                boolean bindSuccess = bindWallpaperComponentLocked(name, /* force */
+                        false, /* fromUser */ true, newWallpaper, callback);
+                if (bindSuccess) {
+                    if (!same) {
+                        newWallpaper.primaryColors = null;
+                    } else {
+                        if (newWallpaper.connection != null) {
+                            newWallpaper.connection.forEachDisplayConnector(displayConnector -> {
+                                try {
+                                    if (displayConnector.mEngine != null) {
+                                        displayConnector.mEngine.dispatchWallpaperCommand(
+                                                COMMAND_REAPPLY, 0, 0, 0, null);
+                                    }
+                                } catch (RemoteException e) {
+                                    Slog.w(TAG, "Error sending apply message to wallpaper", e);
+                                }
+                            });
+                        }
+                    }
+                    newWallpaper.wallpaperId = makeWallpaperIdLocked();
+                    notifyCallbacksLocked(newWallpaper);
+                    shouldNotifyColors = true;
+
+                    if (which == (FLAG_SYSTEM | FLAG_LOCK)) {
+                        if (DEBUG) {
+                            Slog.v(TAG, "Lock screen wallpaper changed to same as home");
+                        }
+                        final WallpaperData lockedWallpaper = mLockWallpaperMap.get(
+                                newWallpaper.userId);
+                        if (lockedWallpaper != null) {
+                            detachWallpaperLocked(lockedWallpaper);
+                        }
+                        mLockWallpaperMap.remove(newWallpaper.userId);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        if (shouldNotifyColors) {
+            notifyWallpaperColorsChanged(newWallpaper, which);
+            notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
+        }
+    }
+
+    // TODO(b/266818039) Remove this method
+    private void setWallpaperComponentInternalLegacy(ComponentName name,
+            @SetWallpaperFlags int which, int userId) {
         userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
                 false /* all */, true /* full */, "changing live wallpaper", null /* pkg */);
         checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
 
-        // TODO(b/253507223) Use passed destination and properly start lock screen LWP
         int legacyWhich = FLAG_SYSTEM;
         boolean shouldNotifyColors = false;
         WallpaperData wallpaper;
@@ -2609,7 +3001,7 @@
                     // therefore it's a shared system+lock image that we need to migrate.
                     Slog.i(TAG, "Migrating current wallpaper to be lock-only before"
                             + "updating system wallpaper");
-                    migrateSystemToLockWallpaperLocked(userId);
+                    migrateStaticSystemToLockWallpaperLocked(userId);
                 }
             }
 
@@ -2689,8 +3081,6 @@
                 if (componentName == null) {
                     // Fall back to static image wallpaper
                     componentName = mImageWallpaper;
-                    //clearWallpaperComponentLocked();
-                    //return;
                     if (DEBUG_LIVE) Slog.v(TAG, "No default component; using image wallpaper");
                 }
             }
@@ -2713,11 +3103,13 @@
                 return false;
             }
 
+            // This will only get set for non-static wallpapers.
             WallpaperInfo wi = null;
 
             Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
             if (componentName != null && !componentName.equals(mImageWallpaper)) {
-                // Make sure the selected service is actually a wallpaper service.
+                // The requested component is not the static wallpaper service, so make sure it's
+                // actually a wallpaper service.
                 List<ResolveInfo> ris =
                         mIPackageManager.queryIntentServices(intent,
                                 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
@@ -2789,13 +3181,13 @@
             intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
                     com.android.internal.R.string.wallpaper_binding_label);
             intent.putExtra(Intent.EXTRA_CLIENT_INTENT, clientIntent);
-            if (!mContext.bindServiceAsUser(intent, newConn,
+            boolean bindSuccess = mContext.bindServiceAsUser(intent, newConn,
                     Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI
                             | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
                             | Context.BIND_INCLUDE_CAPABILITIES,
-                    new UserHandle(serviceUserId))) {
-                String msg = "Unable to bind service: "
-                        + componentName;
+                    new UserHandle(serviceUserId));
+            if (!bindSuccess) {
+                String msg = "Unable to bind service: " + componentName;
                 if (fromUser) {
                     throw new IllegalArgumentException(msg);
                 }
@@ -2834,15 +3226,15 @@
     // Updates tracking of the currently bound wallpapers. Assumes mEnableSeparateLockScreenEngine
     // is true.
     private void updateCurrentWallpapers(WallpaperData newWallpaper) {
-        if (newWallpaper.userId == mCurrentUserId && !newWallpaper.equals(mFallbackWallpaper)) {
-            if (newWallpaper.mWhich == (FLAG_SYSTEM | FLAG_LOCK)) {
-                mLastWallpaper = newWallpaper;
-                mLastLockWallpaper = null;
-            } else if (newWallpaper.mWhich == FLAG_SYSTEM) {
-                mLastWallpaper = newWallpaper;
-            } else if (newWallpaper.mWhich == FLAG_LOCK) {
-                mLastLockWallpaper = newWallpaper;
-            }
+        if (newWallpaper.userId != mCurrentUserId || newWallpaper.equals(mFallbackWallpaper)) {
+            return;
+        }
+        if (newWallpaper.mWhich == (FLAG_SYSTEM | FLAG_LOCK)) {
+            mLastWallpaper = newWallpaper;
+        } else if (newWallpaper.mWhich == FLAG_SYSTEM) {
+            mLastWallpaper = newWallpaper;
+        } else if (newWallpaper.mWhich == FLAG_LOCK) {
+            mLastLockWallpaper = newWallpaper;
         }
     }
 
@@ -2854,10 +3246,8 @@
         }
         boolean homeUpdated = (newWallpaper.mWhich & FLAG_SYSTEM) != 0;
         boolean lockUpdated = (newWallpaper.mWhich & FLAG_LOCK) != 0;
-        // This is the case where a home+lock wallpaper was changed to home-only, and the old
-        // home+lock became (static) or will become (live) lock-only.
-        boolean lockNeedsHomeWallpaper = mLastLockWallpaper == null && !lockUpdated;
-        if (mLastWallpaper != null && homeUpdated && !lockNeedsHomeWallpaper) {
+        boolean systemWillBecomeLock = newWallpaper.mSystemWasBoth && !lockUpdated;
+        if (mLastWallpaper != null && homeUpdated && !systemWillBecomeLock) {
             detachWallpaperLocked(mLastWallpaper);
         }
         if (mLastLockWallpaper != null && lockUpdated) {
@@ -2865,8 +3255,13 @@
         }
     }
 
+    // Frees up all rendering resources used by the given wallpaper so that the WallpaperData object
+    // can be reused: detaches Engine, unbinds WallpaperService, etc.
     private void detachWallpaperLocked(WallpaperData wallpaper) {
         if (wallpaper.connection != null) {
+            if (DEBUG) {
+                Slog.v(TAG, "Detaching wallpaper: " + wallpaper);
+            }
             if (wallpaper.connection.mReply != null) {
                 try {
                     wallpaper.connection.mReply.sendResult(null);
@@ -2882,7 +3277,11 @@
             } catch (RemoteException e) {
                 Slog.w(TAG, "Failed detaching wallpaper service ", e);
             }
-            mContext.unbindService(wallpaper.connection);
+            try {
+                mContext.unbindService(wallpaper.connection);
+            } catch (IllegalArgumentException e) {
+                Slog.w(TAG, "Attempted to unbind unregistered service");
+            }
             wallpaper.connection.forEachDisplayConnector(DisplayConnector::disconnectLocked);
             wallpaper.connection.mService = null;
             wallpaper.connection.mDisplayConnector.clear();
@@ -3192,6 +3591,9 @@
     }
 
     /**
+     * Determines and returns the current wallpaper for the given user and destination, creating
+     * a valid entry if it does not already exist and adding it to the appropriate wallpaper map.
+     *
      * Sometimes it is expected the wallpaper map may not have a user's data.  E.g. This could
      * happen during user switch.  The async user switch observer may not have received
      * the event yet.  We use this safe method when we don't care about this ordering and just
@@ -3215,10 +3617,10 @@
             // unified lock, so we bring up the saved state lazily now and recheck.
             loadSettingsLocked(userId, false);
             wallpaper = whichSet.get(userId);
-            // if it's still null here, this is a lock-only operation and there is not
-            // yet a lock-only wallpaper set for this user, so we need to establish
-            // it now.
             if (wallpaper == null) {
+                // if it's still null here, this is likely a lock-only operation and there is not
+                // currently a lock-only wallpaper set for this user, so we need to establish
+                // it now.
                 if (which == FLAG_LOCK) {
                     wallpaper = new WallpaperData(userId, FLAG_LOCK);
                     mLockWallpaperMap.put(userId, wallpaper);
@@ -3341,6 +3743,10 @@
         WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
         if (lockWallpaper != null) {
             ensureSaneWallpaperData(lockWallpaper);
+            lockWallpaper.mWhich = FLAG_LOCK;
+            wallpaper.mWhich = FLAG_SYSTEM;
+        } else {
+            wallpaper.mWhich = FLAG_SYSTEM | FLAG_LOCK;
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index d4895ed..316b12a 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -762,7 +762,8 @@
         synchronized (mGlobalLock) {
             final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
             return r != null
-                    ? r.getRequestedOrientation() : ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+                    ? r.getOverrideOrientation()
+                    : ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index fd3f32d..24fe518 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1172,8 +1172,10 @@
             pw.println(prefix + "mVoiceInteraction=true");
         }
         pw.print(prefix); pw.print("mOccludesParent="); pw.println(mOccludesParent);
-        pw.print(prefix); pw.print("mOrientation=");
-        pw.println(ActivityInfo.screenOrientationToString(mOrientation));
+        pw.print(prefix); pw.print("overrideOrientation=");
+        pw.println(ActivityInfo.screenOrientationToString(getOverrideOrientation()));
+        pw.print(prefix); pw.print("requestedOrientation=");
+        pw.println(ActivityInfo.screenOrientationToString(super.getOverrideOrientation()));
         pw.println(prefix + "mVisibleRequested=" + mVisibleRequested
                 + " mVisible=" + mVisible + " mClientVisible=" + isClientVisible()
                 + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
@@ -1506,6 +1508,13 @@
     }
 
     @Override
+    boolean canStartChangeTransition() {
+        final Task task = getTask();
+        // Skip change transition when the Task is drag resizing.
+        return task != null && !task.isDragResizing() && super.canStartChangeTransition();
+    }
+
+    @Override
     void onParentChanged(ConfigurationContainer rawNewParent, ConfigurationContainer rawOldParent) {
         final TaskFragment oldParent = (TaskFragment) rawOldParent;
         final TaskFragment newParent = (TaskFragment) rawNewParent;
@@ -1960,6 +1969,15 @@
                     new ComponentName(info.packageName, info.targetActivity);
         }
 
+        // Don't move below setActivityType since it triggers onConfigurationChange ->
+        // resolveOverrideConfiguration that requires having mLetterboxUiController initialised.
+        // Don't move below setOrientation(info.screenOrientation) since it triggers
+        // getOverrideOrientation that requires having mLetterboxUiController
+        // initialised.
+        mLetterboxUiController = new LetterboxUiController(mWmService, this);
+        mCameraCompatControlEnabled = mWmService.mContext.getResources()
+                .getBoolean(R.bool.config_isCameraCompatControlForStretchedIssuesEnabled);
+
         mTargetSdk = info.applicationInfo.targetSdkVersion;
         mShowForAllUsers = (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0;
         setOrientation(info.screenOrientation);
@@ -2080,12 +2098,6 @@
 
         launchMode = aInfo.launchMode;
 
-        // Don't move below setActivityType since it triggers onConfigurationChange ->
-        // resolveOverrideConfiguration that requires having mLetterboxUiController initialised.
-        mLetterboxUiController = new LetterboxUiController(mWmService, this);
-        mCameraCompatControlEnabled = mWmService.mContext.getResources()
-                .getBoolean(R.bool.config_isCameraCompatControlForStretchedIssuesEnabled);
-
         setActivityType(_componentSpecified, _launchedFromUid, _intent, options, sourceRecord);
 
         immersive = (aInfo.flags & FLAG_IMMERSIVE) != 0;
@@ -2499,7 +2511,8 @@
             if (topAttached != null) {
                 if (topAttached.isSnapshotCompatible(snapshot)
                         // This trampoline must be the same rotation.
-                        && mDisplayContent.getDisplayRotation().rotationForOrientation(mOrientation,
+                        && mDisplayContent.getDisplayRotation().rotationForOrientation(
+                                getOverrideOrientation(),
                                 mDisplayContent.getRotation()) == snapshot.getRotation()) {
                     return STARTING_WINDOW_TYPE_SNAPSHOT;
                 }
@@ -7759,13 +7772,13 @@
                 return mLetterboxUiController.getInheritedOrientation();
             }
         }
-        if (mOrientation == SCREEN_ORIENTATION_BEHIND && task != null) {
+        if (task != null && getOverrideOrientation() == SCREEN_ORIENTATION_BEHIND) {
             // We use Task here because we want to be consistent with what happens in
             // multi-window mode where other tasks orientations are ignored.
             final ActivityRecord belowCandidate = task.getActivity(
-                    a -> a.mOrientation != SCREEN_ORIENTATION_UNSET && !a.finishing
-                            && a.mOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND, this,
-                    false /* includeBoundary */, true /* traverseTopToBottom */);
+                    a -> a.canDefineOrientationForActivitiesAbove() /* callback */,
+                    this /* boundary */, false /* includeBoundary */,
+                    true /* traverseTopToBottom */);
             if (belowCandidate != null) {
                 return belowCandidate.getRequestedConfigurationOrientation(forDisplay);
             }
@@ -7773,6 +7786,19 @@
         return super.getRequestedConfigurationOrientation(forDisplay);
     }
 
+    /**
+     * Whether this activity can be used as an orientation source for activities above with
+     * {@link SCREEN_ORIENTATION_BEHIND}.
+     */
+    boolean canDefineOrientationForActivitiesAbove() {
+        if (finishing) {
+            return false;
+        }
+        final int overrideOrientation = getOverrideOrientation();
+        return overrideOrientation != SCREEN_ORIENTATION_UNSET
+                && overrideOrientation != SCREEN_ORIENTATION_BEHIND;
+    }
+
     @Override
     void onCancelFixedRotationTransform(int originalDisplayRotation) {
         if (this != mDisplayContent.getLastOrientationSource()) {
@@ -7799,7 +7825,7 @@
         }
     }
 
-    void setRequestedOrientation(int requestedOrientation) {
+    void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) {
         if (mLetterboxUiController.shouldIgnoreRequestedOrientation(requestedOrientation)) {
             return;
         }
@@ -7842,7 +7868,7 @@
     @VisibleForTesting
     boolean shouldIgnoreOrientationRequests() {
         if (!mAppActivityEmbeddingSplitsEnabled
-                || !ActivityInfo.isFixedOrientationPortrait(mOrientation)
+                || !ActivityInfo.isFixedOrientationPortrait(getOverrideOrientation())
                 || task.inMultiWindowMode()) {
             return false;
         }
@@ -7865,7 +7891,7 @@
             // Allow app to specify orientation regardless of its visibility state if the current
             // candidate want us to use orientation behind. I.e. the visible app on-top of this one
             // wants us to use the orientation of the app behind it.
-            return mOrientation;
+            return getOverrideOrientation();
         }
 
         // The {@link ActivityRecord} should only specify an orientation when it is not closing.
@@ -7873,15 +7899,31 @@
         // task being started in the wrong orientation during the transition.
         if (!getDisplayContent().mClosingApps.contains(this)
                 && (isVisibleRequested() || getDisplayContent().mOpeningApps.contains(this))) {
-            return mOrientation;
+            return getOverrideOrientation();
         }
 
         return SCREEN_ORIENTATION_UNSET;
     }
 
-    /** Returns the app's preferred orientation regardless of its currently visibility state. */
+    /**
+     * Returns the app's preferred orientation regardless of its current visibility state taking
+     * into account orientation per-app overrides applied by the device manufacturers.
+     */
+    @Override
+    protected int getOverrideOrientation() {
+        return mLetterboxUiController.overrideOrientationIfNeeded(super.getOverrideOrientation());
+    }
+
+    /**
+     * Returns the app's preferred orientation regardless of its currently visibility state. This
+     * is used to return a requested value to an app if they call {@link
+     * android.app.Activity#getRequestedOrientation} since {@link #getOverrideOrientation} value
+     * with override can confuse an app if it's different from what they requested with {@link
+     * android.app.Activity#setRequestedOrientation}.
+     */
+    @ActivityInfo.ScreenOrientation
     int getRequestedOrientation() {
-        return mOrientation;
+        return super.getOverrideOrientation();
     }
 
     /**
@@ -8444,8 +8486,8 @@
         // If orientation is respected when insets are applied, then stableBounds will be empty.
         boolean orientationRespectedWithInsets =
                 orientationRespectedWithInsets(parentBounds, stableBounds);
-        if (orientationRespectedWithInsets
-                && handlesOrientationChangeFromDescendant(mOrientation)) {
+        if (orientationRespectedWithInsets && handlesOrientationChangeFromDescendant(
+                getOverrideOrientation())) {
             // No need to letterbox because of fixed orientation. Display will handle
             // fixed-orientation requests and a display rotation is enough to respect requested
             // orientation with insets applied.
@@ -9083,7 +9125,8 @@
         }
 
         if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
-                && !ActivityInfo.isFixedOrientationPortrait(getRequestedOrientation())) {
+                && !ActivityInfo.isFixedOrientationPortrait(
+                        getOverrideOrientation())) {
             return info.getMinAspectRatio();
         }
 
diff --git a/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java b/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java
index 47e78f0..91c4a2f 100644
--- a/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java
+++ b/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java
@@ -43,9 +43,12 @@
     static final String DOC_LINK = "go/android-asm";
 
     private static final String NAMESPACE = NAMESPACE_WINDOW_MANAGER;
-    private static final String KEY_ASM_RESTRICTIONS_ENABLED = "asm_restrictions_enabled";
-    private static final String KEY_ASM_TOASTS_ENABLED = "asm_toasts_enabled";
-    private static final String KEY_ASM_EXEMPTED_PACKAGES = "asm_exempted_packages";
+    private static final String KEY_ASM_PREFIX = "ActivitySecurity__";
+    private static final String KEY_ASM_RESTRICTIONS_ENABLED = KEY_ASM_PREFIX
+            + "asm_restrictions_enabled";
+    private static final String KEY_ASM_TOASTS_ENABLED = KEY_ASM_PREFIX + "asm_toasts_enabled";
+    private static final String KEY_ASM_EXEMPTED_PACKAGES = KEY_ASM_PREFIX
+            + "asm_exempted_packages";
     private static final int VALUE_DISABLE = 0;
     private static final int VALUE_ENABLE_FOR_U = 1;
     private static final int VALUE_ENABLE_FOR_ALL = 2;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index d6d3dc7..50eb356 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1965,7 +1965,7 @@
                 /* action */
                 action,
                 /* version */
-                1,
+                2,
                 /* 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()
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 7aa734b..cd79f2e 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -86,7 +86,8 @@
     /** Apps that fulfill a certain role that can can always launch new tasks */
     static final int BAL_ALLOW_ALLOWLISTED_COMPONENT = 3;
 
-    /** Apps which currently have a visible window */
+    /** Apps which currently have a visible window or are bound by a service with a visible
+     * window */
     static final int BAL_ALLOW_VISIBLE_WINDOW = 4;
 
     /** Allowed due to the PendingIntent sender */
diff --git a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
index bdb06a97..63dc7d2 100644
--- a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
+++ b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
@@ -26,6 +26,7 @@
 import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_BAL_PERMISSION;
 import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_FOREGROUND;
 import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_GRACE_PERIOD;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_VISIBLE_WINDOW;
 import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK;
 
 import static java.util.Objects.requireNonNull;
@@ -152,7 +153,7 @@
                 Slog.d(TAG, "[Process(" + pid
                         + ")] Activity start allowed: process bound by foreground uid");
             }
-            return BAL_ALLOW_FOREGROUND;
+            return BAL_ALLOW_VISIBLE_WINDOW;
         }
         // Allow if the flag was explicitly set.
         if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) {
diff --git a/services/core/java/com/android/server/wm/DeviceStateController.java b/services/core/java/com/android/server/wm/DeviceStateController.java
index a6f8557..7d9a4ec 100644
--- a/services/core/java/com/android/server/wm/DeviceStateController.java
+++ b/services/core/java/com/android/server/wm/DeviceStateController.java
@@ -16,80 +16,107 @@
 
 package com.android.server.wm;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.devicestate.DeviceStateManager;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 
+import com.android.internal.R;
 import com.android.internal.util.ArrayUtils;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.function.Consumer;
 
 /**
- * Class that registers callbacks with the {@link DeviceStateManager} and
- * responds to fold state changes by forwarding such events to a delegate.
+ * Class that registers callbacks with the {@link DeviceStateManager} and responds to device
+ * changes.
  */
-final class DeviceStateController {
+final class DeviceStateController implements DeviceStateManager.DeviceStateCallback {
+
+    @NonNull
     private final DeviceStateManager mDeviceStateManager;
-    private final Context mContext;
+    @NonNull
+    private final int[] mOpenDeviceStates;
+    @NonNull
+    private final int[] mHalfFoldedDeviceStates;
+    @NonNull
+    private final int[] mFoldedDeviceStates;
+    @NonNull
+    private final int[] mRearDisplayDeviceStates;
+    @NonNull
+    private final int[] mReverseRotationAroundZAxisStates;
+    @NonNull
+    private final List<Consumer<DeviceState>> mDeviceStateCallbacks = new ArrayList<>();
 
-    private FoldStateListener mDeviceStateListener;
+    @Nullable
+    private DeviceState mLastDeviceState;
+    private int mCurrentState;
 
-    public enum FoldState {
-        UNKNOWN, OPEN, FOLDED, HALF_FOLDED
+    public enum DeviceState {
+        UNKNOWN, OPEN, FOLDED, HALF_FOLDED, REAR,
     }
 
-    DeviceStateController(Context context, Handler handler, Consumer<FoldState> delegate) {
-        mContext = context;
-        mDeviceStateManager = mContext.getSystemService(DeviceStateManager.class);
+    DeviceStateController(@NonNull Context context, @NonNull Handler handler) {
+        mDeviceStateManager = context.getSystemService(DeviceStateManager.class);
+
+        mOpenDeviceStates = context.getResources()
+                .getIntArray(R.array.config_openDeviceStates);
+        mHalfFoldedDeviceStates = context.getResources()
+                .getIntArray(R.array.config_halfFoldedDeviceStates);
+        mFoldedDeviceStates = context.getResources()
+                .getIntArray(R.array.config_foldedDeviceStates);
+        mRearDisplayDeviceStates = context.getResources()
+                .getIntArray(R.array.config_rearDisplayDeviceStates);
+        mReverseRotationAroundZAxisStates = context.getResources()
+                .getIntArray(R.array.config_deviceStatesToReverseDefaultDisplayRotationAroundZAxis);
+
         if (mDeviceStateManager != null) {
-            mDeviceStateListener = new FoldStateListener(mContext, delegate);
-            mDeviceStateManager
-                    .registerCallback(new HandlerExecutor(handler),
-                            mDeviceStateListener);
+            mDeviceStateManager.registerCallback(new HandlerExecutor(handler), this);
         }
     }
 
     void unregisterFromDeviceStateManager() {
-        if (mDeviceStateListener != null) {
-            mDeviceStateManager.unregisterCallback(mDeviceStateListener);
+        if (mDeviceStateManager != null) {
+            mDeviceStateManager.unregisterCallback(this);
         }
     }
 
+    void registerDeviceStateCallback(@NonNull Consumer<DeviceState> callback) {
+        mDeviceStateCallbacks.add(callback);
+    }
+
     /**
-     * A listener for half-fold device state events that dispatches state changes to a delegate.
+     * @return true if the rotation direction on the Z axis should be reversed.
      */
-    static final class FoldStateListener implements DeviceStateManager.DeviceStateCallback {
+    boolean shouldReverseRotationDirectionAroundZAxis() {
+        return ArrayUtils.contains(mReverseRotationAroundZAxisStates, mCurrentState);
+    }
 
-        private final int[] mHalfFoldedDeviceStates;
-        private final int[] mFoldedDeviceStates;
+    @Override
+    public void onStateChanged(int state) {
+        mCurrentState = state;
 
-        @Nullable
-        private FoldState mLastResult;
-        private final Consumer<FoldState> mDelegate;
-
-        FoldStateListener(Context context, Consumer<FoldState> delegate) {
-            mFoldedDeviceStates = context.getResources().getIntArray(
-                    com.android.internal.R.array.config_foldedDeviceStates);
-            mHalfFoldedDeviceStates = context.getResources().getIntArray(
-                    com.android.internal.R.array.config_halfFoldedDeviceStates);
-            mDelegate = delegate;
+        final DeviceState deviceState;
+        if (ArrayUtils.contains(mHalfFoldedDeviceStates, state)) {
+            deviceState = DeviceState.HALF_FOLDED;
+        } else if (ArrayUtils.contains(mFoldedDeviceStates, state)) {
+            deviceState = DeviceState.FOLDED;
+        } else if (ArrayUtils.contains(mRearDisplayDeviceStates, state)) {
+            deviceState = DeviceState.REAR;
+        } else if (ArrayUtils.contains(mOpenDeviceStates, state)) {
+            deviceState = DeviceState.OPEN;
+        } else {
+            deviceState = DeviceState.UNKNOWN;
         }
 
-        @Override
-        public void onStateChanged(int state) {
-            final boolean halfFolded = ArrayUtils.contains(mHalfFoldedDeviceStates, state);
-            FoldState result;
-            if (halfFolded) {
-                result = FoldState.HALF_FOLDED;
-            } else {
-                final boolean folded = ArrayUtils.contains(mFoldedDeviceStates, state);
-                result = folded ? FoldState.FOLDED : FoldState.OPEN;
-            }
-            if (mLastResult == null || !mLastResult.equals(result)) {
-                mLastResult = result;
-                mDelegate.accept(result);
+        if (mLastDeviceState == null || !mLastDeviceState.equals(deviceState)) {
+            mLastDeviceState = deviceState;
+
+            for (Consumer<DeviceState> callback : mDeviceStateCallbacks) {
+                callback.accept(mLastDeviceState);
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index a15453e..de63191 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -94,7 +94,7 @@
     DisplayArea(WindowManagerService wms, Type type, String name, int featureId) {
         super(wms);
         // TODO(display-area): move this up to ConfigurationContainer
-        mOrientation = SCREEN_ORIENTATION_UNSET;
+        setOverrideOrientation(SCREEN_ORIENTATION_UNSET);
         mType = type;
         mName = name;
         mFeatureId = featureId;
@@ -166,7 +166,8 @@
         // If this is set to ignore the orientation request, we don't propagate descendant
         // orientation request.
         final int orientation = requestingContainer != null
-                ? requestingContainer.mOrientation : SCREEN_ORIENTATION_UNSET;
+                ? requestingContainer.getOverrideOrientation()
+                : SCREEN_ORIENTATION_UNSET;
         return !getIgnoreOrientationRequest(orientation)
                 && super.onDescendantOrientationChanged(requestingContainer);
     }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 1794e2a..f183760 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -27,6 +27,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -1145,14 +1146,18 @@
                     mWmService.mAtmService.getRecentTasks().getInputListener());
         }
 
-        mDisplayPolicy = new DisplayPolicy(mWmService, this);
-        mDisplayRotation = new DisplayRotation(mWmService, this, mDisplayInfo.address);
+        mDeviceStateController = new DeviceStateController(mWmService.mContext, mWmService.mH);
 
-        mDeviceStateController = new DeviceStateController(mWmService.mContext, mWmService.mH,
-                newFoldState -> {
+        mDisplayPolicy = new DisplayPolicy(mWmService, this);
+        mDisplayRotation = new DisplayRotation(mWmService, this, mDisplayInfo.address,
+                mDeviceStateController);
+
+        final Consumer<DeviceStateController.DeviceState> deviceStateConsumer =
+                (@NonNull DeviceStateController.DeviceState newFoldState) -> {
                     mDisplaySwitchTransitionLauncher.foldStateChanged(newFoldState);
                     mDisplayRotation.foldStateChanged(newFoldState);
-                });
+                };
+        mDeviceStateController.registerDeviceStateCallback(deviceStateConsumer);
 
         mCloseToSquareMaxAspectRatio = mWmService.mContext.getResources().getFloat(
                 R.dimen.config_closeToSquareDisplayMaxAspectRatio);
@@ -1618,7 +1623,8 @@
         // If display rotation class tells us that it doesn't consider app requested orientation,
         // this display won't rotate just because of an app changes its requested orientation. Thus
         // it indicates that this display chooses not to handle this request.
-        final int orientation = requestingContainer != null ? requestingContainer.mOrientation
+        final int orientation = requestingContainer != null
+                ? requestingContainer.getOverrideOrientation()
                 : SCREEN_ORIENTATION_UNSET;
         final boolean handled = handlesOrientationChangeFromDescendant(orientation);
         if (config == null) {
@@ -1744,14 +1750,17 @@
         if (mTransitionController.useShellTransitionsRotation()) {
             return ROTATION_UNDEFINED;
         }
+        final int activityOrientation = r.getOverrideOrientation();
         if (!WindowManagerService.ENABLE_FIXED_ROTATION_TRANSFORM
-                || getIgnoreOrientationRequest(r.mOrientation)) {
+                || getIgnoreOrientationRequest(activityOrientation)) {
             return ROTATION_UNDEFINED;
         }
-        if (r.mOrientation == ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
+        if (activityOrientation == ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
+            // TODO(b/266280737): Use ActivityRecord#canDefineOrientationForActivitiesAbove
             final ActivityRecord nextCandidate = getActivity(
-                    a -> a.mOrientation != SCREEN_ORIENTATION_UNSET
-                            && a.mOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND,
+                    a -> a.getOverrideOrientation() != SCREEN_ORIENTATION_UNSET
+                            && a.getOverrideOrientation()
+                                    != ActivityInfo.SCREEN_ORIENTATION_BEHIND,
                     r, false /* includeBoundary */, true /* traverseTopToBottom */);
             if (nextCandidate != null) {
                 r = nextCandidate;
@@ -2774,6 +2783,15 @@
         final int orientation = super.getOrientation();
 
         if (!handlesOrientationChangeFromDescendant(orientation)) {
+            ActivityRecord topActivity = topRunningActivity(/* considerKeyguardState= */ true);
+            if (topActivity != null && topActivity.mLetterboxUiController
+                    .shouldUseDisplayLandscapeNaturalOrientation()) {
+                ProtoLog.v(WM_DEBUG_ORIENTATION,
+                        "Display id=%d is ignoring orientation request for %d, return %d"
+                        + " following a per-app override for %s",
+                        mDisplayId, orientation, SCREEN_ORIENTATION_LANDSCAPE, topActivity);
+                return SCREEN_ORIENTATION_LANDSCAPE;
+            }
             mLastOrientationSource = null;
             // Return SCREEN_ORIENTATION_UNSPECIFIED so that Display respect sensor rotation
             ProtoLog.v(WM_DEBUG_ORIENTATION,
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index e6d8b3d..6f7ff5c 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -41,6 +41,7 @@
 
 import android.annotation.AnimRes;
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.content.ContentResolver;
@@ -117,6 +118,8 @@
     private SettingsObserver mSettingsObserver;
     @Nullable
     private FoldController mFoldController;
+    @NonNull
+    private final DeviceStateController mDeviceStateController;
 
     @ScreenOrientation
     private int mCurrentAppOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
@@ -218,21 +221,24 @@
     private boolean mDemoRotationLock;
 
     DisplayRotation(WindowManagerService service, DisplayContent displayContent,
-            DisplayAddress displayAddress) {
+            DisplayAddress displayAddress, @NonNull DeviceStateController deviceStateController) {
         this(service, displayContent, displayAddress, displayContent.getDisplayPolicy(),
-                service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock());
+                service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock(),
+                deviceStateController);
     }
 
     @VisibleForTesting
     DisplayRotation(WindowManagerService service, DisplayContent displayContent,
             DisplayAddress displayAddress, DisplayPolicy displayPolicy,
-            DisplayWindowSettings displayWindowSettings, Context context, Object lock) {
+            DisplayWindowSettings displayWindowSettings, Context context, Object lock,
+            @NonNull DeviceStateController deviceStateController) {
         mService = service;
         mDisplayContent = displayContent;
         mDisplayPolicy = displayPolicy;
         mDisplayWindowSettings = displayWindowSettings;
         mContext = context;
         mLock = lock;
+        mDeviceStateController = deviceStateController;
         isDefaultDisplay = displayContent.isDefaultDisplay;
         mCompatPolicyForImmersiveApps = initImmersiveAppCompatPolicy(service, displayContent);
 
@@ -1137,6 +1143,15 @@
         int sensorRotation = mOrientationListener != null
                 ? mOrientationListener.getProposedRotation() // may be -1
                 : -1;
+        if (mDeviceStateController.shouldReverseRotationDirectionAroundZAxis()) {
+            // Flipping 270 and 90 has the same effect as changing the direction which rotation is
+            // applied.
+            if (sensorRotation == Surface.ROTATION_90) {
+                sensorRotation = Surface.ROTATION_270;
+            } else if (sensorRotation == Surface.ROTATION_270) {
+                sensorRotation = Surface.ROTATION_90;
+            }
+        }
         mLastSensorRotation = sensorRotation;
         if (sensorRotation < 0) {
             sensorRotation = lastRotation;
@@ -1573,7 +1588,7 @@
         proto.end(token);
     }
 
-    boolean isDeviceInPosture(DeviceStateController.FoldState state, boolean isTabletop) {
+    boolean isDeviceInPosture(DeviceStateController.DeviceState state, boolean isTabletop) {
         if (mFoldController == null) return false;
         return mFoldController.isDeviceInPosture(state, isTabletop);
     }
@@ -1585,10 +1600,10 @@
     /**
      * Called by the DeviceStateManager callback when the device state changes.
      */
-    void foldStateChanged(DeviceStateController.FoldState foldState) {
+    void foldStateChanged(DeviceStateController.DeviceState deviceState) {
         if (mFoldController != null) {
             synchronized (mLock) {
-                mFoldController.foldStateChanged(foldState);
+                mFoldController.foldStateChanged(deviceState);
             }
         }
     }
@@ -1596,8 +1611,8 @@
     private class FoldController {
         @Surface.Rotation
         private int mHalfFoldSavedRotation = -1; // No saved rotation
-        private DeviceStateController.FoldState mFoldState =
-                DeviceStateController.FoldState.UNKNOWN;
+        private DeviceStateController.DeviceState mDeviceState =
+                DeviceStateController.DeviceState.UNKNOWN;
         private boolean mInHalfFoldTransition = false;
         private final boolean mIsDisplayAlwaysSeparatingHinge;
         private final Set<Integer> mTabletopRotations;
@@ -1637,32 +1652,33 @@
                     R.bool.config_isDisplayHingeAlwaysSeparating);
         }
 
-        boolean isDeviceInPosture(DeviceStateController.FoldState state, boolean isTabletop) {
-            if (state != mFoldState) {
+        boolean isDeviceInPosture(DeviceStateController.DeviceState state, boolean isTabletop) {
+            if (state != mDeviceState) {
                 return false;
             }
-            if (mFoldState == DeviceStateController.FoldState.HALF_FOLDED) {
+            if (mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED) {
                 return !(isTabletop ^ mTabletopRotations.contains(mRotation));
             }
             return true;
         }
 
-        DeviceStateController.FoldState getFoldState() {
-            return mFoldState;
+        DeviceStateController.DeviceState getFoldState() {
+            return mDeviceState;
         }
 
         boolean isSeparatingHinge() {
-            return mFoldState == DeviceStateController.FoldState.HALF_FOLDED
-                    || (mFoldState == DeviceStateController.FoldState.OPEN
+            return mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED
+                    || (mDeviceState == DeviceStateController.DeviceState.OPEN
                         && mIsDisplayAlwaysSeparatingHinge);
         }
 
         boolean overrideFrozenRotation() {
-            return mFoldState == DeviceStateController.FoldState.HALF_FOLDED;
+            return mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED;
         }
 
         boolean shouldRevertOverriddenRotation() {
-            return mFoldState == DeviceStateController.FoldState.OPEN // When transitioning to open.
+            // When transitioning to open.
+            return mDeviceState == DeviceStateController.DeviceState.OPEN
                     && mInHalfFoldTransition
                     && mHalfFoldSavedRotation != -1 // Ignore if we've already reverted.
                     && mUserRotationMode
@@ -1676,30 +1692,30 @@
             return savedRotation;
         }
 
-        void foldStateChanged(DeviceStateController.FoldState newState) {
+        void foldStateChanged(DeviceStateController.DeviceState newState) {
             ProtoLog.v(WM_DEBUG_ORIENTATION,
                     "foldStateChanged: displayId %d, halfFoldStateChanged %s, "
                     + "saved rotation: %d, mUserRotation: %d, mLastSensorRotation: %d, "
                     + "mLastOrientation: %d, mRotation: %d",
                     mDisplayContent.getDisplayId(), newState.name(), mHalfFoldSavedRotation,
                     mUserRotation, mLastSensorRotation, mLastOrientation, mRotation);
-            if (mFoldState == DeviceStateController.FoldState.UNKNOWN) {
-                mFoldState = newState;
+            if (mDeviceState == DeviceStateController.DeviceState.UNKNOWN) {
+                mDeviceState = newState;
                 return;
             }
-            if (newState == DeviceStateController.FoldState.HALF_FOLDED
-                    && mFoldState != DeviceStateController.FoldState.HALF_FOLDED) {
+            if (newState == DeviceStateController.DeviceState.HALF_FOLDED
+                    && mDeviceState != DeviceStateController.DeviceState.HALF_FOLDED) {
                 // The device has transitioned to HALF_FOLDED state: save the current rotation and
                 // update the device rotation.
                 mHalfFoldSavedRotation = mRotation;
-                mFoldState = newState;
+                mDeviceState = newState;
                 // Now mFoldState is set to HALF_FOLDED, the overrideFrozenRotation function will
                 // return true, so rotation is unlocked.
                 mService.updateRotation(false /* alwaysSendConfiguration */,
                         false /* forceRelayout */);
             } else {
                 mInHalfFoldTransition = true;
-                mFoldState = newState;
+                mDeviceState = newState;
                 // Tell the device to update its orientation.
                 mService.updateRotation(false /* alwaysSendConfiguration */,
                         false /* forceRelayout */);
@@ -1822,7 +1838,7 @@
             final long mTimestamp = System.currentTimeMillis();
             final int mHalfFoldSavedRotation;
             final boolean mInHalfFoldTransition;
-            final DeviceStateController.FoldState mFoldState;
+            final DeviceStateController.DeviceState mDeviceState;
             @Nullable final String mDisplayRotationCompatPolicySummary;
 
             Record(DisplayRotation dr, int fromRotation, int toRotation) {
@@ -1843,8 +1859,9 @@
                 if (source != null) {
                     mLastOrientationSource = source.toString();
                     final WindowState w = source.asWindowState();
-                    mSourceOrientation =
-                            w != null ? w.mAttrs.screenOrientation : source.mOrientation;
+                    mSourceOrientation = w != null
+                            ? w.mAttrs.screenOrientation
+                            : source.getOverrideOrientation();
                 } else {
                     mLastOrientationSource = null;
                     mSourceOrientation = SCREEN_ORIENTATION_UNSET;
@@ -1852,11 +1869,11 @@
                 if (dr.mFoldController != null) {
                     mHalfFoldSavedRotation = dr.mFoldController.mHalfFoldSavedRotation;
                     mInHalfFoldTransition = dr.mFoldController.mInHalfFoldTransition;
-                    mFoldState = dr.mFoldController.mFoldState;
+                    mDeviceState = dr.mFoldController.mDeviceState;
                 } else {
                     mHalfFoldSavedRotation = NO_FOLD_CONTROLLER;
                     mInHalfFoldTransition = false;
-                    mFoldState = DeviceStateController.FoldState.UNKNOWN;
+                    mDeviceState = DeviceStateController.DeviceState.UNKNOWN;
                 }
                 mDisplayRotationCompatPolicySummary = dc.mDisplayRotationCompatPolicy == null
                         ? null
@@ -1882,7 +1899,7 @@
                     pw.println(prefix + " halfFoldSavedRotation="
                             + mHalfFoldSavedRotation
                             + " mInHalfFoldTransition=" + mInHalfFoldTransition
-                            + " mFoldState=" + mFoldState);
+                            + " mFoldState=" + mDeviceState);
                 }
                 if (mDisplayRotationCompatPolicySummary != null) {
                     pw.println(prefix + mDisplayRotationCompatPolicySummary);
diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
index c6037da..3ffb2fa 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
@@ -296,8 +296,8 @@
                 && activity.getRequestedConfigurationOrientation() != ORIENTATION_UNDEFINED
                 // "locked" and "nosensor" values are often used by camera apps that can't
                 // handle dynamic changes so we shouldn't force rotate them.
-                && activity.getRequestedOrientation() != SCREEN_ORIENTATION_NOSENSOR
-                && activity.getRequestedOrientation() != SCREEN_ORIENTATION_LOCKED
+                && activity.getOverrideOrientation() != SCREEN_ORIENTATION_NOSENSOR
+                && activity.getOverrideOrientation() != SCREEN_ORIENTATION_LOCKED
                 && mCameraIdPackageBiMap.containsPackageName(activity.packageName)
                 && activity.mLetterboxUiController.shouldForceRotateForCameraCompat();
     }
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 73d1ff9d..c5a50ca 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -17,11 +17,21 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION;
 import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
 import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
 import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
 import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE;
+import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR;
+import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT;
+import static android.content.pm.ActivityInfo.OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.ActivityInfo.isFixedOrientation;
+import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
 import static android.content.pm.ActivityInfo.screenOrientationToString;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -29,6 +39,8 @@
 import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION;
 import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH;
 import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE;
 import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
 
 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__BOTTOM;
@@ -62,6 +74,9 @@
 import static com.android.server.wm.LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
 import static com.android.server.wm.LetterboxConfiguration.letterboxBackgroundTypeToString;
 
+import static java.lang.Boolean.FALSE;
+import static java.lang.Boolean.TRUE;
+
 import android.annotation.Nullable;
 import android.app.ActivityManager.TaskDescription;
 import android.content.pm.ActivityInfo.ScreenOrientation;
@@ -111,6 +126,34 @@
      */
     private final float mExpandedTaskBarHeight;
 
+    // TODO(b/265576778): Cache other overrides as well.
+
+    // Corresponds to OVERRIDE_ANY_ORIENTATION
+    private final boolean mIsOverrideAnyOrientationEnabled;
+    // Corresponds to OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT
+    private final boolean mIsOverrideToPortraitOrientationEnabled;
+    // Corresponds to OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR
+    private final boolean mIsOverrideToNosensorOrientationEnabled;
+    // Corresponds to OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE
+    private final boolean mIsOverrideToReverseLandscapeOrientationEnabled;
+    // Corresponds to OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION
+    private final boolean mIsOverrideUseDisplayLandscapeNaturalOrientationEnabled;
+
+    // Corresponds to OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION
+    private final boolean mIsOverrideCameraCompatDisableForceRotationEnabled;
+    // Corresponds to OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH
+    private final boolean mIsOverrideCameraCompatDisableRefreshEnabled;
+    // Corresponds to OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE
+    private final boolean mIsOverrideCameraCompatEnableRefreshViaPauseEnabled;
+
+    // Corresponds to OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION
+    private final boolean mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled;
+
+    @Nullable
+    private final Boolean mBooleanPropertyAllowOrientationOverride;
+    @Nullable
+    private final Boolean mBooleanPropertyAllowDisplayOrientationOverride;
+
     /*
      * WindowContainerListener responsible to make translucent activities inherit
      * constraints from the first opaque activity beneath them. It's null for not
@@ -193,6 +236,35 @@
 
         mExpandedTaskBarHeight =
                 getResources().getDimensionPixelSize(R.dimen.taskbar_frame_height);
+
+        mBooleanPropertyAllowOrientationOverride =
+                readComponentProperty(packageManager, mActivityRecord.packageName,
+                        /* gatingCondition */ null,
+                        PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE);
+        mBooleanPropertyAllowDisplayOrientationOverride =
+                readComponentProperty(packageManager, mActivityRecord.packageName,
+                        /* gatingCondition */ null,
+                        PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE);
+
+        mIsOverrideAnyOrientationEnabled = isCompatChangeEnabled(OVERRIDE_ANY_ORIENTATION);
+        mIsOverrideToPortraitOrientationEnabled =
+                isCompatChangeEnabled(OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT);
+        mIsOverrideToReverseLandscapeOrientationEnabled =
+                isCompatChangeEnabled(OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE);
+        mIsOverrideToNosensorOrientationEnabled =
+                isCompatChangeEnabled(OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR);
+        mIsOverrideUseDisplayLandscapeNaturalOrientationEnabled =
+                isCompatChangeEnabled(OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION);
+
+        mIsOverrideCameraCompatDisableForceRotationEnabled =
+                isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION);
+        mIsOverrideCameraCompatDisableRefreshEnabled =
+                isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH);
+        mIsOverrideCameraCompatEnableRefreshViaPauseEnabled =
+                isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE);
+
+        mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled =
+                isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION);
     }
 
     /**
@@ -207,8 +279,8 @@
      */
     @Nullable
     private static Boolean readComponentProperty(PackageManager packageManager, String packageName,
-            BooleanSupplier gatingCondition, String propertyName) {
-        if (!gatingCondition.getAsBoolean()) {
+            @Nullable BooleanSupplier gatingCondition, String propertyName) {
+        if (gatingCondition != null && !gatingCondition.getAsBoolean()) {
             return null;
         }
         try {
@@ -262,7 +334,7 @@
         if (!shouldEnableWithOverrideAndProperty(
                 /* gatingCondition */ mLetterboxConfiguration
                         ::isPolicyForIgnoringRequestedOrientationEnabled,
-                OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION,
+                mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled,
                 mBooleanPropertyIgnoreRequestedOrientation)) {
             return false;
         }
@@ -308,6 +380,66 @@
     }
 
     /**
+     * Whether should fix display orientation to landscape natural orientation when a task is
+     * fullscreen and the display is ignoring orientation requests.
+     *
+     * <p>This treatment is enabled when the following conditions are met:
+     * <ul>
+     *     <li>Opt-out component property isn't enabled
+     *     <li>Opt-in per-app override is enabled
+     *     <li>Task is in fullscreen.
+     *     <li>{@link DisplayContent#getIgnoreOrientationRequest} is enabled
+     *     <li>Natural orientation of the display is landscape.
+     * </ul>
+     */
+    boolean shouldUseDisplayLandscapeNaturalOrientation() {
+        return shouldEnableWithOptInOverrideAndOptOutProperty(
+                /* gatingCondition */ () -> mActivityRecord.mDisplayContent != null
+                        && mActivityRecord.getTask() != null
+                        && mActivityRecord.mDisplayContent.getIgnoreOrientationRequest()
+                        && !mActivityRecord.getTask().inMultiWindowMode()
+                        && mActivityRecord.mDisplayContent.getNaturalOrientation()
+                                == ORIENTATION_LANDSCAPE,
+                mIsOverrideUseDisplayLandscapeNaturalOrientationEnabled,
+                mBooleanPropertyAllowDisplayOrientationOverride);
+    }
+
+    @ScreenOrientation
+    int overrideOrientationIfNeeded(@ScreenOrientation int candidate) {
+        if (FALSE.equals(mBooleanPropertyAllowOrientationOverride)) {
+            return candidate;
+        }
+
+        if (mIsOverrideToReverseLandscapeOrientationEnabled
+                && (isFixedOrientationLandscape(candidate) || mIsOverrideAnyOrientationEnabled)) {
+            Slog.w(TAG, "Requested orientation  " + screenOrientationToString(candidate) + " for "
+                    + mActivityRecord + " is overridden to "
+                    + screenOrientationToString(SCREEN_ORIENTATION_REVERSE_LANDSCAPE));
+            return SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+        }
+
+        if (!mIsOverrideAnyOrientationEnabled && isFixedOrientation(candidate)) {
+            return candidate;
+        }
+
+        if (mIsOverrideToPortraitOrientationEnabled) {
+            Slog.w(TAG, "Requested orientation  " + screenOrientationToString(candidate) + " for "
+                    + mActivityRecord + " is overridden to "
+                    + screenOrientationToString(SCREEN_ORIENTATION_PORTRAIT));
+            return SCREEN_ORIENTATION_PORTRAIT;
+        }
+
+        if (mIsOverrideToNosensorOrientationEnabled) {
+            Slog.w(TAG, "Requested orientation  " + screenOrientationToString(candidate) + " for "
+                    + mActivityRecord + " is overridden to "
+                    + screenOrientationToString(SCREEN_ORIENTATION_NOSENSOR));
+            return SCREEN_ORIENTATION_NOSENSOR;
+        }
+
+        return candidate;
+    }
+
+    /**
      * Whether activity is eligible for activity "refresh" after camera compat force rotation
      * treatment. See {@link DisplayRotationCompatPolicy} for context.
      *
@@ -322,7 +454,7 @@
         return shouldEnableWithOptOutOverrideAndProperty(
                 /* gatingCondition */ () -> mLetterboxConfiguration
                         .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true),
-                OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH,
+                mIsOverrideCameraCompatDisableRefreshEnabled,
                 mBooleanPropertyCameraCompatAllowRefresh);
     }
 
@@ -344,7 +476,7 @@
         return shouldEnableWithOverrideAndProperty(
                 /* gatingCondition */ () -> mLetterboxConfiguration
                         .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true),
-                OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE,
+                mIsOverrideCameraCompatEnableRefreshViaPauseEnabled,
                 mBooleanPropertyCameraCompatEnableRefreshViaPause);
     }
 
@@ -363,15 +495,19 @@
         return shouldEnableWithOptOutOverrideAndProperty(
                 /* gatingCondition */ () -> mLetterboxConfiguration
                         .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true),
-                OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION,
+                mIsOverrideCameraCompatDisableForceRotationEnabled,
                 mBooleanPropertyCameraCompatAllowForceRotation);
     }
 
+    private boolean isCompatChangeEnabled(long overrideChangeId) {
+        return mActivityRecord.info.isChangeEnabled(overrideChangeId);
+    }
+
     /**
      * Returns {@code true} when the following conditions are met:
      * <ul>
      *     <li>{@code gatingCondition} isn't {@code false}
-     *     <li>OEM didn't opt out with a {@code overrideChangeId} override
+     *     <li>OEM didn't opt out with a per-app override
      *     <li>App developers didn't opt out with a component {@code property}
      * </ul>
      *
@@ -379,12 +515,30 @@
      * disabled on per-app basis by OEMs or app developers.
      */
     private boolean shouldEnableWithOptOutOverrideAndProperty(BooleanSupplier gatingCondition,
-            long overrideChangeId, Boolean property) {
+            boolean isOverrideChangeEnabled, Boolean property) {
         if (!gatingCondition.getAsBoolean()) {
             return false;
         }
-        return !Boolean.FALSE.equals(property)
-                && !mActivityRecord.info.isChangeEnabled(overrideChangeId);
+        return !FALSE.equals(property) && !isOverrideChangeEnabled;
+    }
+
+    /**
+     * Returns {@code true} when the following conditions are met:
+     * <ul>
+     *     <li>{@code gatingCondition} isn't {@code false}
+     *     <li>OEM did opt in with a per-app override
+     *     <li>App developers didn't opt out with a component {@code property}
+     * </ul>
+     *
+     * <p>This is used for the treatments that are enabled based with the heuristic but can be
+     * disabled on per-app basis by OEMs or app developers.
+     */
+    private boolean shouldEnableWithOptInOverrideAndOptOutProperty(BooleanSupplier gatingCondition,
+            boolean isOverrideChangeEnabled, Boolean property) {
+        if (!gatingCondition.getAsBoolean()) {
+            return false;
+        }
+        return !FALSE.equals(property) && isOverrideChangeEnabled;
     }
 
     /**
@@ -393,21 +547,20 @@
      *     <li>{@code gatingCondition} isn't {@code false}
      *     <li>App developers didn't opt out with a component {@code property}
      *     <li>App developers opted in with a component {@code property} or an OEM opted in with a
-     *     component {@code property}
+     *     per-app override
      * </ul>
      *
      * <p>This is used for the treatments that are enabled only on per-app basis.
      */
     private boolean shouldEnableWithOverrideAndProperty(BooleanSupplier gatingCondition,
-            long overrideChangeId, Boolean property) {
+            boolean isOverrideChangeEnabled, Boolean property) {
         if (!gatingCondition.getAsBoolean()) {
             return false;
         }
-        if (Boolean.FALSE.equals(property)) {
+        if (FALSE.equals(property)) {
             return false;
         }
-        return Boolean.TRUE.equals(property)
-                || mActivityRecord.info.isChangeEnabled(overrideChangeId);
+        return TRUE.equals(property) || isOverrideChangeEnabled;
     }
 
     boolean hasWallpaperBackgroundForLetterbox() {
@@ -542,7 +695,7 @@
     // Note that we check the task rather than the parent as with ActivityEmbedding the parent might
     // be a TaskFragment, and its windowing mode is always MULTI_WINDOW, even if the task is
     // actually fullscreen.
-    private boolean isDisplayFullScreenAndInPosture(DeviceStateController.FoldState state,
+    private boolean isDisplayFullScreenAndInPosture(DeviceStateController.DeviceState state,
             boolean isTabletop) {
         Task task = mActivityRecord.getTask();
         return mActivityRecord.mDisplayContent != null
@@ -568,7 +721,7 @@
         // Don't check resolved configuration because it may not be updated yet during
         // configuration change.
         boolean bookMode = isDisplayFullScreenAndInPosture(
-                DeviceStateController.FoldState.HALF_FOLDED, false /* isTabletop */);
+                DeviceStateController.DeviceState.HALF_FOLDED, false /* isTabletop */);
         return isHorizontalReachabilityEnabled(parentConfiguration)
                 // Using the last global dynamic position to avoid "jumps" when moving
                 // between apps or activities.
@@ -580,7 +733,7 @@
         // Don't check resolved configuration because it may not be updated yet during
         // configuration change.
         boolean tabletopMode = isDisplayFullScreenAndInPosture(
-                DeviceStateController.FoldState.HALF_FOLDED, true /* isTabletop */);
+                DeviceStateController.DeviceState.HALF_FOLDED, true /* isTabletop */);
         return isVerticalReachabilityEnabled(parentConfiguration)
                 // Using the last global dynamic position to avoid "jumps" when moving
                 // between apps or activities.
@@ -1107,7 +1260,7 @@
             int letterboxPositionForHorizontalReachability = getLetterboxConfiguration()
                     .getLetterboxPositionForHorizontalReachability(
                             isDisplayFullScreenAndInPosture(
-                                    DeviceStateController.FoldState.HALF_FOLDED,
+                                    DeviceStateController.DeviceState.HALF_FOLDED,
                                     false /* isTabletop */));
             positionToLog = letterboxHorizontalReachabilityPositionToLetterboxPosition(
                     letterboxPositionForHorizontalReachability);
@@ -1115,7 +1268,7 @@
             int letterboxPositionForVerticalReachability = getLetterboxConfiguration()
                     .getLetterboxPositionForVerticalReachability(
                             isDisplayFullScreenAndInPosture(
-                                    DeviceStateController.FoldState.HALF_FOLDED,
+                                    DeviceStateController.DeviceState.HALF_FOLDED,
                                     true /* isTabletop */));
             positionToLog = letterboxVerticalReachabilityPositionToLetterboxPosition(
                     letterboxPositionForVerticalReachability);
@@ -1224,7 +1377,8 @@
         // To avoid wrong behaviour, we're not forcing orientation for activities with not
         // fixed orientation (e.g. permission dialogs).
         return hasInheritedLetterboxBehavior()
-                && mActivityRecord.mOrientation != SCREEN_ORIENTATION_UNSPECIFIED;
+                && mActivityRecord.getOverrideOrientation()
+                        != SCREEN_ORIENTATION_UNSPECIFIED;
     }
 
     float getInheritedMinAspectRatio() {
diff --git a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
index 30bdc34..2edb082 100644
--- a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
+++ b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
@@ -51,10 +51,10 @@
     /**
      *   Called by the DeviceStateManager callback when the state changes.
      */
-    void foldStateChanged(DeviceStateController.FoldState newFoldState) {
+    void foldStateChanged(DeviceStateController.DeviceState newDeviceState) {
         // Ignore transitions to/from half-folded.
-        if (newFoldState == DeviceStateController.FoldState.HALF_FOLDED) return;
-        mIsFolded = newFoldState == DeviceStateController.FoldState.FOLDED;
+        if (newDeviceState == DeviceStateController.DeviceState.HALF_FOLDED) return;
+        mIsFolded = newDeviceState == DeviceStateController.DeviceState.FOLDED;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index fd5c5eb..8ba54ff 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2086,8 +2086,10 @@
                     // When the Task is entering picture-in-picture, we should clear all override
                     // from the client organizer, so the PIP activity can get the correct config
                     // from the Task, and prevent conflict with the PipTaskOrganizer.
+                    // TaskFragmentOrganizer may have requested relative bounds, so reset the
+                    // relative bounds before update configuration.
+                    tf.setRelativeEmbeddedBounds(new Rect());
                     tf.updateRequestedOverrideConfiguration(EMPTY);
-                    tf.updateRelativeEmbeddedBounds();
                 }
             });
             rootTask.setWindowingMode(WINDOWING_MODE_PINNED);
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index 8a6ddf6..98ca9ae 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -143,7 +143,11 @@
                 .setLaunchTaskDisplayArea(options.getLaunchTaskDisplayArea())
                 .setLaunchDisplayId(options.getLaunchDisplayId())
                 .setCallerDisplayId(options.getCallerDisplayId())
-                .setLaunchRootTask(options.getLaunchRootTask());
+                .setLaunchRootTask(options.getLaunchRootTask())
+                .setPendingIntentBackgroundActivityStartMode(
+                        options.getPendingIntentBackgroundActivityStartMode())
+                .setIgnorePendingIntentCreatorForegroundState(
+                        options.getIgnorePendingIntentCreatorForegroundState());
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 1b59d8d..ee11f68 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -276,8 +276,6 @@
 
     private static final int DEFAULT_MIN_TASK_SIZE_DP = 220;
 
-    private float mShadowRadius = 0;
-
     /**
      * The modes to control how root task is moved to the front when calling {@link Task#reparent}.
      */
@@ -5020,70 +5018,76 @@
         ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Adding activity %s to task %s "
                         + "callers: %s", r, task, new RuntimeException("here").fillInStackTrace());
 
-        // The transition animation and starting window are not needed if {@code allowMoveToFront}
-        // is false, because the activity won't be visible.
-        if ((!isActivityTypeHomeOrRecents() || hasActivity()) && allowMoveToFront) {
-            final DisplayContent dc = mDisplayContent;
-            if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
-                    "Prepare open transition: starting " + r);
-            if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
-                dc.prepareAppTransition(TRANSIT_NONE);
-                mTaskSupervisor.mNoAnimActivities.add(r);
-                mTransitionController.setNoAnimation(r);
-            } else {
-                dc.prepareAppTransition(TRANSIT_OPEN);
-                mTaskSupervisor.mNoAnimActivities.remove(r);
-            }
-            if (newTask && !r.mLaunchTaskBehind) {
-                // If a new task is being launched, then mark the existing top activity as
-                // supporting picture-in-picture while pausing only if the starting activity
-                // would not be considered an overlay on top of the current activity
-                // (eg. not fullscreen, or the assistant)
-                enableEnterPipOnTaskSwitch(pipCandidate,
-                        null /* toFrontTask */, r, options);
-            }
-            boolean doShow = true;
-            if (newTask) {
-                // Even though this activity is starting fresh, we still need
-                // to reset it to make sure we apply affinities to move any
-                // existing activities from other tasks in to it.
-                // If the caller has requested that the target task be
-                // reset, then do so.
-                if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
-                    resetTaskIfNeeded(r, r);
-                    doShow = topRunningNonDelayedActivityLocked(null) == r;
-                }
-            } else if (options != null && options.getAnimationType()
-                    == ActivityOptions.ANIM_SCENE_TRANSITION) {
-                doShow = false;
-            }
-            if (options != null && options.getDisableStartingWindow()) {
-                doShow = false;
-            }
-            if (r.mLaunchTaskBehind) {
-                // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we
-                // tell WindowManager that r is visible even though it is at the back of the root
-                // task.
-                r.setVisibility(true);
-                ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
-                // Go ahead to execute app transition for this activity since the app transition
-                // will not be triggered through the resume channel.
-                mDisplayContent.executeAppTransition();
-            } else if (SHOW_APP_STARTING_PREVIEW && doShow) {
-                // Figure out if we are transitioning from another activity that is
-                // "has the same starting icon" as the next one.  This allows the
-                // window manager to keep the previous window it had previously
-                // created, if it still had one.
-                Task baseTask = r.getTask();
-                final ActivityRecord prev = baseTask.getActivity(
-                        a -> a.mStartingData != null && a.showToCurrentUser());
-                mWmService.mStartingSurfaceController.showStartingWindow(r, prev, newTask,
-                        isTaskSwitch, sourceRecord);
-            }
-        } else {
+        if (isActivityTypeHomeOrRecents() && getActivityBelow(r) == null) {
             // If this is the first activity, don't do any fancy animations,
             // because there is nothing for it to animate on top of.
             ActivityOptions.abort(options);
+            return;
+        }
+
+        if (!allowMoveToFront) {
+            // The transition animation and starting window are not needed if
+            // {@code allowMoveToFront} is false, because the activity won't be visible.
+            ActivityOptions.abort(options);
+            return;
+        }
+
+        final DisplayContent dc = mDisplayContent;
+        if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
+                "Prepare open transition: starting " + r);
+        if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
+            dc.prepareAppTransition(TRANSIT_NONE);
+            mTaskSupervisor.mNoAnimActivities.add(r);
+            mTransitionController.setNoAnimation(r);
+        } else {
+            dc.prepareAppTransition(TRANSIT_OPEN);
+            mTaskSupervisor.mNoAnimActivities.remove(r);
+        }
+        if (newTask && !r.mLaunchTaskBehind) {
+            // If a new task is being launched, then mark the existing top activity as
+            // supporting picture-in-picture while pausing only if the starting activity
+            // would not be considered an overlay on top of the current activity
+            // (eg. not fullscreen, or the assistant)
+            enableEnterPipOnTaskSwitch(pipCandidate,
+                    null /* toFrontTask */, r, options);
+        }
+        boolean doShow = true;
+        if (newTask) {
+            // Even though this activity is starting fresh, we still need
+            // to reset it to make sure we apply affinities to move any
+            // existing activities from other tasks in to it.
+            // If the caller has requested that the target task be
+            // reset, then do so.
+            if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
+                resetTaskIfNeeded(r, r);
+                doShow = topRunningNonDelayedActivityLocked(null) == r;
+            }
+        } else if (options != null && options.getAnimationType()
+                == ActivityOptions.ANIM_SCENE_TRANSITION) {
+            doShow = false;
+        }
+        if (options != null && options.getDisableStartingWindow()) {
+            doShow = false;
+        }
+        if (r.mLaunchTaskBehind) {
+            // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we
+            // tell WindowManager that r is visible even though it is at the back of the root
+            // task.
+            r.setVisibility(true);
+            ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+            // Go ahead to execute app transition for this activity since the app transition
+            // will not be triggered through the resume channel.
+            mDisplayContent.executeAppTransition();
+        } else if (SHOW_APP_STARTING_PREVIEW && doShow) {
+            // Figure out if we are transitioning from another activity that is
+            // "has the same starting icon" as the next one.  This allows the
+            // window manager to keep the previous window it had previously
+            // created, if it still had one.
+            Task baseTask = r.getTask();
+            final ActivityRecord prev = baseTask.getActivity(
+                    a -> a.mStartingData != null && a.showToCurrentUser());
+            mWmService.mStartingSurfaceController.showStartingWindow(r, prev, newTask,
+                    isTaskSwitch, sourceRecord);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index db17ae1..eb06b91 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -312,9 +312,8 @@
     private TaskFragmentAnimationParams mAnimationParams = TaskFragmentAnimationParams.DEFAULT;
 
     /**
-     * The bounds of the embedded TaskFragment relative to the parent Task.
+     * The organizer requested bounds of the embedded TaskFragment relative to the parent Task.
      * {@code null} if it is not {@link #mIsEmbedded}
-     * TODO(b/261785978) cleanup with legacy app transition
      */
     @Nullable
     private final Rect mRelativeEmbeddedBounds;
@@ -335,6 +334,7 @@
     final Point mLastSurfaceSize = new Point();
 
     private final Rect mTmpBounds = new Rect();
+    private final Rect mTmpAbsBounds = new Rect();
     private final Rect mTmpFullBounds = new Rect();
     /** For calculating screenWidthDp and screenWidthDp, i.e. the area without the system bars. */
     private final Rect mTmpStableBounds = new Rect();
@@ -1966,16 +1966,21 @@
     void resolveOverrideConfiguration(Configuration newParentConfig) {
         mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
         super.resolveOverrideConfiguration(newParentConfig);
+        final Configuration resolvedConfig = getResolvedOverrideConfiguration();
 
-        int windowingMode =
-                getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
+        if (mRelativeEmbeddedBounds != null && !mRelativeEmbeddedBounds.isEmpty()) {
+            // For embedded TaskFragment, make sure the bounds is set based on the relative bounds.
+            resolvedConfig.windowConfiguration.setBounds(translateRelativeBoundsToAbsoluteBounds(
+                    mRelativeEmbeddedBounds, newParentConfig.windowConfiguration.getBounds()));
+        }
+        int windowingMode = resolvedConfig.windowConfiguration.getWindowingMode();
         final int parentWindowingMode = newParentConfig.windowConfiguration.getWindowingMode();
 
         // Resolve override windowing mode to fullscreen for home task (even on freeform
         // display), or split-screen if in split-screen mode.
         if (getActivityType() == ACTIVITY_TYPE_HOME && windowingMode == WINDOWING_MODE_UNDEFINED) {
             windowingMode = WINDOWING_MODE_FULLSCREEN;
-            getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode);
+            resolvedConfig.windowConfiguration.setWindowingMode(windowingMode);
         }
 
         // Do not allow tasks not support multi window to be in a multi-window mode, unless it is in
@@ -1985,8 +1990,7 @@
                     windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : parentWindowingMode;
             if (WindowConfiguration.inMultiWindowMode(candidateWindowingMode)
                     && candidateWindowingMode != WINDOWING_MODE_PINNED) {
-                getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(
-                        WINDOWING_MODE_FULLSCREEN);
+                resolvedConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
             }
         }
 
@@ -1995,7 +1999,7 @@
             thisTask.resolveLeafTaskOnlyOverrideConfigs(newParentConfig,
                     mTmpBounds /* previousBounds */);
         }
-        computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
+        computeConfigResourceOverrides(resolvedConfig, newParentConfig);
     }
 
     boolean supportsMultiWindow() {
@@ -2422,17 +2426,55 @@
     }
 
     /**
-     * Updates the record of the relative bounds of this embedded TaskFragment. This should only be
-     * called when the embedded TaskFragment's override bounds are changed.
-     * Returns {@code true} if the bounds is changed.
+     * Translates the given relative bounds to screen space based on the given parent bounds.
+     * When the relative bounds is outside of the parent bounds, it will be adjusted to fit the Task
+     * bounds.
      */
-    void updateRelativeEmbeddedBounds() {
-        // We only record the override bounds, which means it will not be changed when it is filling
-        // Task, and resize with the parent.
-        getRequestedOverrideBounds(mTmpBounds);
-        getRelativePosition(mTmpPoint);
-        mTmpBounds.offsetTo(mTmpPoint.x, mTmpPoint.y);
-        mRelativeEmbeddedBounds.set(mTmpBounds);
+    Rect translateRelativeBoundsToAbsoluteBounds(@NonNull Rect relativeBounds,
+            @NonNull Rect parentBounds) {
+        if (relativeBounds.isEmpty()) {
+            mTmpAbsBounds.setEmpty();
+            return mTmpAbsBounds;
+        }
+        // Translate the relative bounds to absolute bounds.
+        mTmpAbsBounds.set(relativeBounds);
+        mTmpAbsBounds.offset(parentBounds.left, parentBounds.top);
+
+        if (!isAllowedToBeEmbeddedInTrustedMode() && !parentBounds.contains(mTmpAbsBounds)) {
+            // For untrusted embedding, we want to make sure the embedded bounds will never go
+            // outside of the Task bounds.
+            // We expect the organizer to update the bounds after receiving the Task bounds changed,
+            // so skip trusted embedding to avoid unnecessary configuration change before organizer
+            // requests a new bounds.
+            // When the requested TaskFragment bounds is outside of Task bounds, try use the
+            // intersection.
+            // This can happen when the Task resized before the TaskFragmentOrganizer request.
+            if (!mTmpAbsBounds.intersect(parentBounds)) {
+                // Use empty bounds to fill Task if there is no intersection.
+                mTmpAbsBounds.setEmpty();
+            }
+        }
+        return mTmpAbsBounds;
+    }
+
+    void recomputeConfiguration() {
+        onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
+    }
+
+    /**
+     * Sets the relative bounds in parent coordinate for this embedded TaskFragment.
+     * This will not override the requested bounds, and the actual bounds will be calculated in
+     * {@link #resolveOverrideConfiguration}, so that it makes sure to record and use the relative
+     * bounds that is set by the organizer until the organizer requests a new relative bounds.
+     */
+    void setRelativeEmbeddedBounds(@NonNull Rect relativeEmbeddedBounds) {
+        if (mRelativeEmbeddedBounds == null) {
+            throw new IllegalStateException("The TaskFragment is not embedded");
+        }
+        if (mRelativeEmbeddedBounds.equals(relativeEmbeddedBounds)) {
+            return;
+        }
+        mRelativeEmbeddedBounds.set(relativeEmbeddedBounds);
     }
 
     /**
@@ -2458,6 +2500,13 @@
         }
     }
 
+    @Override
+    boolean canStartChangeTransition() {
+        final Task task = getTask();
+        // Skip change transition when the Task is drag resizing.
+        return task != null && !task.isDragResizing() && super.canStartChangeTransition();
+    }
+
     /** Records the starting bounds of the closing organized TaskFragment. */
     void setClosingChangingStartBoundsIfNeeded() {
         if (isOrganizedTaskFragment() && mDisplayContent != null
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 63bb5c3..b06bdb1 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -73,6 +73,7 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ActivityInfo.ScreenOrientation;
 import android.content.res.Configuration;
 import android.graphics.Color;
 import android.graphics.Point;
@@ -178,8 +179,9 @@
     protected final WindowList<E> mChildren = new WindowList<E>();
 
     // The specified orientation for this window container.
-    @ActivityInfo.ScreenOrientation
-    protected int mOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+    // Shouldn't be accessed directly since subclasses can override getOverrideOrientation.
+    @ScreenOrientation
+    private int mOverrideOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
 
     /**
      * The window container which decides its orientation since the last time
@@ -1456,19 +1458,20 @@
 
     /**
      * Gets the configuration orientation by the requested screen orientation
-     * ({@link ActivityInfo.ScreenOrientation}) of this activity.
+     * ({@link ScreenOrientation}) of this activity.
      *
      * @return orientation in ({@link Configuration#ORIENTATION_LANDSCAPE},
      *         {@link Configuration#ORIENTATION_PORTRAIT},
      *         {@link Configuration#ORIENTATION_UNDEFINED}).
      */
+    @ScreenOrientation
     int getRequestedConfigurationOrientation() {
         return getRequestedConfigurationOrientation(false /* forDisplay */);
     }
 
     /**
      * Gets the configuration orientation by the requested screen orientation
-     * ({@link ActivityInfo.ScreenOrientation}) of this activity.
+     * ({@link ScreenOrientation}) of this activity.
      *
      * @param forDisplay whether it is the requested config orientation for display.
      *                   If {@code true}, we may reverse the requested orientation if the root is
@@ -1479,8 +1482,9 @@
      *         {@link Configuration#ORIENTATION_PORTRAIT},
      *         {@link Configuration#ORIENTATION_UNDEFINED}).
      */
+    @ScreenOrientation
     int getRequestedConfigurationOrientation(boolean forDisplay) {
-        int requestedOrientation = mOrientation;
+        int requestedOrientation = getOverrideOrientation();
         final RootDisplayArea root = getRootDisplayArea();
         if (forDisplay && root != null && root.isOrientationDifferentFromDisplay()) {
             // Reverse the requested orientation if the orientation of its root is different from
@@ -1490,7 +1494,7 @@
             // (portrait).
             // When an app below the DAG is requesting landscape, it should actually request the
             // display to be portrait, so that the DAG and the app will be in landscape.
-            requestedOrientation = reverseOrientation(mOrientation);
+            requestedOrientation = reverseOrientation(getOverrideOrientation());
         }
 
         if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
@@ -1515,7 +1519,7 @@
      *
      * @param orientation the specified orientation.
      */
-    void setOrientation(int orientation) {
+    void setOrientation(@ScreenOrientation int orientation) {
         setOrientation(orientation, null /* requestingContainer */);
     }
 
@@ -1523,17 +1527,17 @@
      * Sets the specified orientation of this container. It percolates this change upward along the
      * hierarchy to let each level of the hierarchy a chance to respond to it.
      *
-     * @param orientation the specified orientation. Needs to be one of {@link
-     *      android.content.pm.ActivityInfo.ScreenOrientation}.
+     * @param orientation the specified orientation. Needs to be one of {@link ScreenOrientation}.
      * @param requestingContainer the container which orientation request has changed. Mostly used
      *                            to ensure it gets correct configuration.
      */
-    void setOrientation(int orientation, @Nullable WindowContainer requestingContainer) {
-        if (mOrientation == orientation) {
+    void setOrientation(@ScreenOrientation int orientation,
+            @Nullable WindowContainer requestingContainer) {
+        if (getOverrideOrientation() == orientation) {
             return;
         }
 
-        mOrientation = orientation;
+        setOverrideOrientation(orientation);
         final WindowContainer parent = getParent();
         if (parent != null) {
             if (getConfiguration().orientation != getRequestedConfigurationOrientation()
@@ -1552,9 +1556,9 @@
         }
     }
 
-    @ActivityInfo.ScreenOrientation
+    @ScreenOrientation
     int getOrientation() {
-        return getOrientation(mOrientation);
+        return getOrientation(getOverrideOrientation());
     }
 
     /**
@@ -1568,7 +1572,8 @@
      *                  better match.
      * @return The orientation as specified by this branch or the window hierarchy.
      */
-    int getOrientation(int candidate) {
+    @ScreenOrientation
+    int getOrientation(@ScreenOrientation int candidate) {
         mLastOrientationSource = null;
         if (!providesOrientation()) {
             return SCREEN_ORIENTATION_UNSET;
@@ -1578,16 +1583,16 @@
         // specified; otherwise we prefer to use the orientation of its topmost child that has one
         // specified and fall back on this container's unset or unspecified value as a candidate
         // if none of the children have a better candidate for the orientation.
-        if (mOrientation != SCREEN_ORIENTATION_UNSET
-                && mOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
+        if (getOverrideOrientation() != SCREEN_ORIENTATION_UNSET
+                && getOverrideOrientation() != SCREEN_ORIENTATION_UNSPECIFIED) {
             mLastOrientationSource = this;
-            return mOrientation;
+            return getOverrideOrientation();
         }
 
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             final WindowContainer wc = mChildren.get(i);
 
-            // TODO: Maybe mOrientation should default to SCREEN_ORIENTATION_UNSET vs.
+            // TODO: Maybe mOverrideOrientation should default to SCREEN_ORIENTATION_UNSET vs.
             // SCREEN_ORIENTATION_UNSPECIFIED?
             final int orientation = wc.getOrientation(candidate == SCREEN_ORIENTATION_BEHIND
                     ? SCREEN_ORIENTATION_BEHIND : SCREEN_ORIENTATION_UNSET);
@@ -1619,6 +1624,20 @@
     }
 
     /**
+     * Returns orientation specified on this level of hierarchy without taking children into
+     * account, like {@link #getOrientation} does, allowing subclasses to override. See {@link
+     * ActivityRecord#getOverrideOrientation} for an example.
+     */
+    @ScreenOrientation
+    protected int getOverrideOrientation() {
+        return mOverrideOrientation;
+    }
+
+    protected void setOverrideOrientation(@ScreenOrientation int orientation) {
+        mOverrideOrientation = orientation;
+    }
+
+    /**
      * @return The deepest source which decides the orientation of this window container since the
      *         last time {@link #getOrientation(int) was called.
      */
@@ -2674,7 +2693,7 @@
 
         final long token = proto.start(fieldId);
         super.dumpDebug(proto, CONFIGURATION_CONTAINER, logLevel);
-        proto.write(ORIENTATION, mOrientation);
+        proto.write(ORIENTATION, mOverrideOrientation);
         proto.write(VISIBLE, isVisible);
         writeIdentifierToProto(proto, IDENTIFIER);
         if (mSurfaceAnimator.isAnimating()) {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 5c68b12..29d3462 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -31,6 +31,7 @@
 import static android.window.TaskFragmentOperation.OP_TYPE_SET_COMPANION_TASK_FRAGMENT;
 import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
 import static android.window.TaskFragmentOperation.OP_TYPE_UNKNOWN;
+import static android.window.WindowContainerTransaction.Change.CHANGE_RELATIVE_BOUNDS;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
@@ -627,8 +628,8 @@
         }
     }
 
-    private int applyChanges(WindowContainer<?> container,
-            WindowContainerTransaction.Change change, @Nullable IBinder errorCallbackToken) {
+    private int applyChanges(@NonNull WindowContainer<?> container,
+            @NonNull WindowContainerTransaction.Change change) {
         // The "client"-facing API should prevent bad changes; however, just in case, sanitize
         // masks here.
         final int configMask = change.getConfigSetMask() & CONTROLLABLE_CONFIGS;
@@ -636,9 +637,6 @@
         int effects = TRANSACT_EFFECTS_NONE;
         final int windowingMode = change.getWindowingMode();
         if (configMask != 0) {
-
-            adjustBoundsForMinDimensionsIfNeeded(container, change, errorCallbackToken);
-
             if (windowingMode > -1 && windowingMode != container.getWindowingMode()) {
                 // Special handling for when we are setting a windowingMode in the same transaction.
                 // Setting the windowingMode is going to call onConfigurationChanged so we don't
@@ -691,28 +689,8 @@
         return effects;
     }
 
-    private void adjustBoundsForMinDimensionsIfNeeded(WindowContainer<?> container,
-            WindowContainerTransaction.Change change, @Nullable IBinder errorCallbackToken) {
-        final TaskFragment taskFragment = container.asTaskFragment();
-        if (taskFragment == null || !taskFragment.isEmbedded()) {
-            return;
-        }
-        if ((change.getWindowSetMask() & WINDOW_CONFIG_BOUNDS) == 0) {
-            return;
-        }
-        final WindowConfiguration winConfig = change.getConfiguration().windowConfiguration;
-        final Rect bounds = winConfig.getBounds();
-        final Point minDimensions = taskFragment.calculateMinDimension();
-        if (bounds.width() < minDimensions.x || bounds.height() < minDimensions.y) {
-            sendMinimumDimensionViolation(taskFragment, minDimensions, errorCallbackToken,
-                    "setBounds:" + bounds);
-            // Sets the bounds to match parent bounds.
-            winConfig.setBounds(new Rect());
-        }
-    }
-
     private int applyTaskChanges(Task tr, WindowContainerTransaction.Change c) {
-        int effects = applyChanges(tr, c, null /* errorCallbackToken */);
+        int effects = applyChanges(tr, c);
         final SurfaceControl.Transaction t = c.getBoundsChangeTransaction();
 
         if ((c.getChangeMask() & WindowContainerTransaction.Change.CHANGE_HIDDEN) != 0) {
@@ -773,7 +751,7 @@
     private int applyDisplayAreaChanges(DisplayArea displayArea,
             WindowContainerTransaction.Change c) {
         final int[] effects = new int[1];
-        effects[0] = applyChanges(displayArea, c, null /* errorCallbackToken */);
+        effects[0] = applyChanges(displayArea, c);
 
         if ((c.getChangeMask()
                 & WindowContainerTransaction.Change.CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
@@ -807,8 +785,30 @@
         mTmpBounds0.set(taskFragment.getBounds());
         mTmpBounds1.set(taskFragment.getRelativeEmbeddedBounds());
         taskFragment.deferOrganizedTaskFragmentSurfaceUpdate();
-        final int effects = applyChanges(taskFragment, c, errorCallbackToken);
-        taskFragment.updateRelativeEmbeddedBounds();
+        final Rect relBounds = c.getRelativeBounds();
+        if (relBounds != null) {
+            // Make sure the TaskFragment bounds satisfied the min dimensions requirement.
+            adjustTaskFragmentBoundsForMinDimensionsIfNeeded(taskFragment, relBounds,
+                    errorCallbackToken);
+
+            // For embedded TaskFragment, the organizer set the bounds in parent coordinate to
+            // prevent flicker in case there is a racing condition between the parent bounds changed
+            // and the organizer request.
+            final Rect parentBounds = taskFragment.getParent().getBounds();
+            // Convert relative bounds to screen space.
+            final Rect absBounds = taskFragment.translateRelativeBoundsToAbsoluteBounds(relBounds,
+                    parentBounds);
+            c.getConfiguration().windowConfiguration.setBounds(absBounds);
+            taskFragment.setRelativeEmbeddedBounds(relBounds);
+        } else if ((c.getWindowSetMask() & WINDOW_CONFIG_BOUNDS) != 0) {
+            // TODO(b/265271880): remove after we drop support to setBounds for TaskFragment in next
+            // release.
+            adjustTaskFragmentBoundsForMinDimensionsIfNeeded(taskFragment, c.getConfiguration()
+                    .windowConfiguration.getBounds(), errorCallbackToken);
+            // Reset the relative embedded bounds if WCT#setBounds is used instead for CTS compat.
+            taskFragment.setRelativeEmbeddedBounds(new Rect());
+        }
+        final int effects = applyChanges(taskFragment, c);
         if (taskFragment.shouldStartChangeTransition(mTmpBounds0, mTmpBounds1)) {
             taskFragment.initializeChangeTransition(mTmpBounds0);
         }
@@ -816,6 +816,29 @@
         return effects;
     }
 
+    /**
+     * Adjusts the override absolute bounds on {@link TaskFragment} to make sure it satisfies the
+     * activity min dimensions.
+     */
+    private void adjustTaskFragmentBoundsForMinDimensionsIfNeeded(
+            @NonNull TaskFragment taskFragment, @NonNull Rect inOutBounds,
+            @Nullable IBinder errorCallbackToken) {
+        if (inOutBounds.isEmpty()) {
+            return;
+        }
+        final Point minDimensions = taskFragment.calculateMinDimension();
+        if (inOutBounds.width() < minDimensions.x || inOutBounds.height() < minDimensions.y) {
+            // Reset to match parent bounds.
+            inOutBounds.setEmpty();
+            // Notify organizer about the request failure.
+            final Throwable exception = new SecurityException("The task fragment's bounds:"
+                    + taskFragment.getBounds() + " does not satisfy minimum dimensions:"
+                    + minDimensions);
+            sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(),
+                    errorCallbackToken, taskFragment, OP_TYPE_UNKNOWN, exception);
+        }
+    }
+
     private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
             int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
             @NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,
@@ -1312,19 +1335,6 @@
         return true;
     }
 
-    /** A helper method to send minimum dimension violation error to the client. */
-    private void sendMinimumDimensionViolation(TaskFragment taskFragment, Point minDimensions,
-            IBinder errorCallbackToken, String reason) {
-        if (taskFragment == null || taskFragment.getTaskFragmentOrganizer() == null) {
-            return;
-        }
-        final Throwable exception = new SecurityException("The task fragment's bounds:"
-                + taskFragment.getBounds() + " does not satisfy minimum dimensions:"
-                + minDimensions + " " + reason);
-        sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(),
-                errorCallbackToken, taskFragment, OP_TYPE_UNKNOWN, exception);
-    }
-
     /**
      * Post and wait for the result of the activity start to prevent potential deadlock against
      * {@link WindowManagerGlobalLock}.
@@ -1579,10 +1589,10 @@
             return applyDisplayAreaChanges(wc.asDisplayArea(), c);
         } else if (wc.asTask() != null) {
             return applyTaskChanges(wc.asTask(), c);
-        } else if (wc.asTaskFragment() != null) {
+        } else if (wc.asTaskFragment() != null && wc.asTaskFragment().isEmbedded()) {
             return applyTaskFragmentChanges(wc.asTaskFragment(), c, errorCallbackToken);
         } else {
-            return applyChanges(wc, c, errorCallbackToken);
+            return applyChanges(wc, c);
         }
     }
 
@@ -1799,8 +1809,13 @@
             return;
         }
         final int changeMask = change.getChangeMask();
-        if (changeMask != 0) {
-            // None of the change should be requested from a TaskFragment organizer.
+        if (changeMask != 0 && changeMask != CHANGE_RELATIVE_BOUNDS) {
+            // None of the change should be requested from a TaskFragment organizer except
+            // setRelativeBounds.
+            // For setRelativeBounds, we don't need to check whether it is outside of the Task
+            // bounds, because it is possible that the Task is also resizing, for which we don't
+            // want to throw an exception. The bounds will be adjusted in
+            // TaskFragment#translateRelativeBoundsToAbsoluteBounds.
             String msg = "Permission Denial: " + func + " from pid="
                     + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
                     + " trying to apply changes of " + changeMask + " to TaskFragment"
@@ -1818,6 +1833,7 @@
             Slog.e(TAG, "Attempt to apply config change on task fragment that has no parent");
             return;
         }
+        // TODO(b/265271880): we can remove those and only support WCT#setRelativeBounds.
         final Configuration requestedConfig = change.getConfiguration();
         final Configuration parentConfig = wcParent.getConfiguration();
         if (parentConfig.screenWidthDp < requestedConfig.screenWidthDp
@@ -1932,9 +1948,17 @@
         }
         ownerTask.addChild(taskFragment, position);
         taskFragment.setWindowingMode(creationParams.getWindowingMode());
-        taskFragment.setBounds(creationParams.getInitialBounds());
-        // Record the initial relative embedded bounds.
-        taskFragment.updateRelativeEmbeddedBounds();
+        if (creationParams.areInitialRelativeBoundsSet()) {
+            // Set relative bounds instead of using setBounds. This will avoid unnecessary update in
+            // case the parent has resized since the last time parent info is sent to the organizer.
+            taskFragment.setRelativeEmbeddedBounds(creationParams.getInitialRelativeBounds());
+            // Recompute configuration as the bounds will be calculated based on relative bounds in
+            // TaskFragment#resolveOverrideConfiguration.
+            taskFragment.recomputeConfiguration();
+        } else {
+            // TODO(b/232476698): remove after remove creationParams.getInitialBounds().
+            taskFragment.setBounds(creationParams.getInitialBounds());
+        }
         mLaunchTaskFragments.put(creationParams.getFragmentToken(), taskFragment);
 
         if (transition != null) transition.collectExistenceChange(taskFragment);
diff --git a/services/core/jni/tvinput/JTvInputHal.cpp b/services/core/jni/tvinput/JTvInputHal.cpp
index 3453cbd..98e6b19 100644
--- a/services/core/jni/tvinput/JTvInputHal.cpp
+++ b/services/core/jni/tvinput/JTvInputHal.cpp
@@ -338,6 +338,12 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
+::ndk::ScopedAStatus JTvInputHal::TvInputCallback::notifyTvMessageEvent(
+        const AidlTvMessageEvent& event) {
+    // TODO: Implement this
+    return ::ndk::ScopedAStatus::ok();
+}
+
 JTvInputHal::ITvInputWrapper::ITvInputWrapper(std::shared_ptr<AidlITvInput>& aidlTvInput)
       : mIsHidl(false), mAidlTvInput(aidlTvInput) {}
 
diff --git a/services/core/jni/tvinput/JTvInputHal.h b/services/core/jni/tvinput/JTvInputHal.h
index 2697294..984407a 100644
--- a/services/core/jni/tvinput/JTvInputHal.h
+++ b/services/core/jni/tvinput/JTvInputHal.h
@@ -52,6 +52,7 @@
 using AidlNativeHandle = ::aidl::android::hardware::common::NativeHandle;
 using AidlTvInputDeviceInfo = ::aidl::android::hardware::tv::input::TvInputDeviceInfo;
 using AidlTvInputEvent = ::aidl::android::hardware::tv::input::TvInputEvent;
+using AidlTvMessageEvent = ::aidl::android::hardware::tv::input::TvMessageEvent;
 using AidlTvStreamConfig = ::aidl::android::hardware::tv::input::TvStreamConfig;
 
 extern gTvInputHalClassInfoType gTvInputHalClassInfo;
@@ -131,6 +132,7 @@
     public:
         explicit TvInputCallback(JTvInputHal* hal);
         ::ndk::ScopedAStatus notify(const AidlTvInputEvent& event) override;
+        ::ndk::ScopedAStatus notifyTvMessageEvent(const AidlTvMessageEvent& event) override;
         Return<void> notify(const HidlTvInputEvent& event) override;
 
     private:
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index a27eb7f..97dbe04 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -117,6 +117,11 @@
                 <xs:element type="integer-array" name="screenOffBrightnessSensorValueToLux">
                     <xs:annotation name="final"/>
                 </xs:element>
+                <!-- The version of the Universal Stylus Initiative
+                 (USI, https://universalstylus.org/) protocol supported by the display, if any. -->
+                <xs:element type="usiVersion" name="usiVersion">
+                    <xs:annotation name="final"/>
+                </xs:element>
             </xs:sequence>
         </xs:complexType>
     </xs:element>
@@ -502,4 +507,15 @@
             <xs:element name="item" type="xs:nonNegativeInteger" minOccurs="0" maxOccurs="unbounded"/>
         </xs:sequence>
     </xs:complexType>
+
+    <xs:complexType name="usiVersion">
+        <xs:element name="majorVersion" type="xs:nonNegativeInteger"
+                    minOccurs="1" maxOccurs="1">
+            <xs:annotation name="final"/>
+        </xs:element>
+        <xs:element name="minorVersion" type="xs:nonNegativeInteger"
+                    minOccurs="1" maxOccurs="1">
+            <xs:annotation name="final"/>
+        </xs:element>
+    </xs:complexType>
 </xs:schema>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index 6c66d0d..aba8a2c 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -101,6 +101,7 @@
     method public final com.android.server.display.config.SensorDetails getScreenOffBrightnessSensor();
     method public final com.android.server.display.config.IntegerArray getScreenOffBrightnessSensorValueToLux();
     method @NonNull public final com.android.server.display.config.ThermalThrottling getThermalThrottling();
+    method public final com.android.server.display.config.UsiVersion getUsiVersion();
     method public final void setAmbientBrightnessChangeThresholds(@NonNull com.android.server.display.config.Thresholds);
     method public final void setAmbientBrightnessChangeThresholdsIdle(com.android.server.display.config.Thresholds);
     method public final void setAmbientLightHorizonLong(java.math.BigInteger);
@@ -125,6 +126,7 @@
     method public final void setScreenOffBrightnessSensor(com.android.server.display.config.SensorDetails);
     method public final void setScreenOffBrightnessSensorValueToLux(com.android.server.display.config.IntegerArray);
     method public final void setThermalThrottling(@NonNull com.android.server.display.config.ThermalThrottling);
+    method public final void setUsiVersion(com.android.server.display.config.UsiVersion);
   }
 
   public class DisplayQuirks {
@@ -263,6 +265,14 @@
     method public final void setDarkeningThresholds(@NonNull com.android.server.display.config.BrightnessThresholds);
   }
 
+  public class UsiVersion {
+    ctor public UsiVersion();
+    method public final java.math.BigInteger getMajorVersion();
+    method public final java.math.BigInteger getMinorVersion();
+    method public final void setMajorVersion(java.math.BigInteger);
+    method public final void setMinorVersion(java.math.BigInteger);
+  }
+
   public class XmlParser {
     ctor public XmlParser();
     method public static com.android.server.display.config.DisplayConfiguration read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
diff --git a/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java b/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java
index 865cba8..fbdcc44 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java
@@ -30,6 +30,7 @@
 public class CredentialDescriptionRegistry {
 
     private static final int MAX_ALLOWED_CREDENTIAL_DESCRIPTIONS = 128;
+    private static final int MAX_ALLOWED_ENTRIES_PER_PROVIDER = 16;
     private static SparseArray<CredentialDescriptionRegistry> sCredentialDescriptionSessionPerUser;
 
     static {
@@ -50,9 +51,11 @@
     }
 
     private Map<String, Set<CredentialDescription>> mCredentialDescriptions;
+    private int mTotalDescriptionCount;
 
     private CredentialDescriptionRegistry() {
         this.mCredentialDescriptions = new HashMap<>();
+        this.mTotalDescriptionCount = 0;
     }
 
     /** Handle the given {@link RegisterCredentialDescriptionRequest} by creating
@@ -60,13 +63,20 @@
     public void executeRegisterRequest(RegisterCredentialDescriptionRequest request,
             String callingPackageName) {
 
-        if (!mCredentialDescriptions.containsKey(callingPackageName)
-                && mCredentialDescriptions.size() <= MAX_ALLOWED_CREDENTIAL_DESCRIPTIONS) {
+        if (!mCredentialDescriptions.containsKey(callingPackageName)) {
             mCredentialDescriptions.put(callingPackageName, new HashSet<>());
         }
 
-        mCredentialDescriptions.get(callingPackageName)
-                .addAll(request.getCredentialDescriptions());
+        if (mTotalDescriptionCount <= MAX_ALLOWED_CREDENTIAL_DESCRIPTIONS
+                && mCredentialDescriptions.get(callingPackageName).size()
+                <= MAX_ALLOWED_ENTRIES_PER_PROVIDER) {
+            Set<CredentialDescription> descriptions = request.getCredentialDescriptions();
+            int size = mCredentialDescriptions.get(callingPackageName).size();
+            mCredentialDescriptions.get(callingPackageName)
+                    .addAll(descriptions);
+            mTotalDescriptionCount += size - mCredentialDescriptions.get(callingPackageName).size();
+        }
+
     }
 
     /** Handle the given {@link UnregisterCredentialDescriptionRequest} by creating
@@ -76,8 +86,10 @@
             String callingPackageName) {
 
         if (mCredentialDescriptions.containsKey(callingPackageName)) {
+            int size = mCredentialDescriptions.get(callingPackageName).size();
             mCredentialDescriptions.get(callingPackageName)
                     .removeAll(request.getCredentialDescriptions());
+            mTotalDescriptionCount -= size - mCredentialDescriptions.get(callingPackageName).size();
         }
     }
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
index 304d148..4351bc1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
@@ -20,11 +20,12 @@
 import android.app.admin.DevicePolicyManager;
 import android.os.UserHandle;
 import android.util.IndentingPrintWriter;
-import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 
 import com.android.internal.annotations.GuardedBy;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+
 /**
  * Implementation of {@link DevicePolicyCache}, to which {@link DevicePolicyManagerService} pushes
  * policies.
@@ -51,20 +52,13 @@
     @GuardedBy("mLock")
     private final SparseIntArray mPermissionPolicy = new SparseIntArray();
 
-    /** Maps to {@code ActiveAdmin.mAdminCanGrantSensorsPermissions}.
-     *
-     * <p>For users affiliated with the device, they inherit the policy from {@code DO} so
-     * it will map to the {@code DO}'s policy. Otherwise it will map to the admin of the requesting
-     * user.
-     */
-    @GuardedBy("mLock")
-    private final SparseBooleanArray mCanGrantSensorsPermissions = new SparseBooleanArray();
+    /** Maps to {@code ActiveAdmin.mAdminCanGrantSensorsPermissions}. */
+    private final AtomicBoolean mCanGrantSensorsPermissions = new AtomicBoolean(false);
 
     public void onUserRemoved(int userHandle) {
         synchronized (mLock) {
             mPasswordQuality.delete(userHandle);
             mPermissionPolicy.delete(userHandle);
-            mCanGrantSensorsPermissions.delete(userHandle);
         }
     }
 
@@ -119,28 +113,25 @@
     }
 
     @Override
-    public boolean canAdminGrantSensorsPermissionsForUser(@UserIdInt int userId) {
-        synchronized (mLock) {
-            return mCanGrantSensorsPermissions.get(userId, false);
-        }
+    public boolean canAdminGrantSensorsPermissions() {
+        return mCanGrantSensorsPermissions.get();
     }
 
-    /** Sets ahmin control over permission grants for user. */
-    public void setAdminCanGrantSensorsPermissions(@UserIdInt int userId, boolean canGrant) {
-        synchronized (mLock) {
-            mCanGrantSensorsPermissions.put(userId, canGrant);
-        }
+    /** Sets admin control over permission grants. */
+    public void setAdminCanGrantSensorsPermissions(boolean canGrant) {
+        mCanGrantSensorsPermissions.set(canGrant);
     }
 
     /** Dump content */
     public void dump(IndentingPrintWriter pw) {
-        pw.println("Device policy cache:");
-        pw.increaseIndent();
-        pw.println("Screen capture disallowed user: " + mScreenCaptureDisallowedUser);
-        pw.println("Password quality: " + mPasswordQuality.toString());
-        pw.println("Permission policy: " + mPermissionPolicy.toString());
-        pw.println("Admin can grant sensors permission: "
-                + mCanGrantSensorsPermissions.toString());
-        pw.decreaseIndent();
+        synchronized (mLock) {
+            pw.println("Device policy cache:");
+            pw.increaseIndent();
+            pw.println("Screen capture disallowed user: " + mScreenCaptureDisallowedUser);
+            pw.println("Password quality: " + mPasswordQuality);
+            pw.println("Permission policy: " + mPermissionPolicy);
+            pw.println("Admin can grant sensors permission: " + mCanGrantSensorsPermissions.get());
+            pw.decreaseIndent();
+        }
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7d1b5ca..c9c9c55 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -396,6 +396,8 @@
 import com.android.server.devicepolicy.ActiveAdmin.TrustAgentInfo;
 import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.net.NetworkPolicyManagerInternal;
+import com.android.server.pm.DefaultCrossProfileIntentFilter;
+import com.android.server.pm.DefaultCrossProfileIntentFiltersUtils;
 import com.android.server.pm.RestrictionsSet;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.pm.UserManagerInternal.UserRestrictionsListener;
@@ -1625,8 +1627,9 @@
             return LocalServices.getService(LockSettingsInternal.class);
         }
 
-        CrossProfileApps getCrossProfileApps() {
-            return mContext.getSystemService(CrossProfileApps.class);
+        CrossProfileApps getCrossProfileApps(@UserIdInt int userId) {
+            return mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0)
+                    .getSystemService(CrossProfileApps.class);
         }
 
         boolean hasUserSetupCompleted(DevicePolicyData userData) {
@@ -2412,22 +2415,23 @@
             return;
         }
 
-        final UserHandle doUserHandle = UserHandle.of(doUserId);
-
-        // Based on  CDD : https://source.android.com/compatibility/12/android-12-cdd#95_multi-user_support,
-        // creation of clone profile is not allowed in case device owner is set.
-        // Enforcing this restriction on setting up of device owner.
-        if (!mUserManager.hasUserRestriction(
-                UserManager.DISALLOW_ADD_CLONE_PROFILE, doUserHandle)) {
-            mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE, true,
-                    doUserHandle);
-        }
-        // Creation of managed profile is restricted in case device owner is set, enforcing this
-        // restriction by setting user level restriction at time of device owner setup.
-        if (!mUserManager.hasUserRestriction(
-                UserManager.DISALLOW_ADD_MANAGED_PROFILE, doUserHandle)) {
-            mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true,
-                    doUserHandle);
+        for (UserInfo userInfo : mUserManager.getUsers()) {
+            UserHandle userHandle = userInfo.getUserHandle();
+            // Based on  CDD : https://source.android.com/compatibility/12/android-12-cdd#95_multi-user_support,
+            // creation of clone profile is not allowed in case device owner is set.
+            // Enforcing this restriction on setting up of device owner.
+            if (!mUserManager.hasUserRestriction(
+                    UserManager.DISALLOW_ADD_CLONE_PROFILE, userHandle)) {
+                mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE, true,
+                        userHandle);
+            }
+            // Creation of managed profile is restricted in case device owner is set, enforcing this
+            // restriction by setting user level restriction at time of device owner setup.
+            if (!mUserManager.hasUserRestriction(
+                    UserManager.DISALLOW_ADD_MANAGED_PROFILE, userHandle)) {
+                mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true,
+                        userHandle);
+            }
         }
     }
 
@@ -3132,8 +3136,9 @@
             unregisterOnSubscriptionsChangedListener();
             int policyType = getManagedSubscriptionsPolicy().getPolicyType();
             if (policyType == ManagedSubscriptionsPolicy.TYPE_ALL_PERSONAL_SUBSCRIPTIONS) {
+                final int parentUserId = getProfileParentId(copeProfileUserId);
                 // By default, assign all current and future subs to system user on COPE devices.
-                registerListenerToAssignSubscriptionsToUser(UserHandle.USER_SYSTEM);
+                registerListenerToAssignSubscriptionsToUser(parentUserId);
             } else if (policyType == ManagedSubscriptionsPolicy.TYPE_ALL_MANAGED_SUBSCRIPTIONS) {
                 // Add listener to assign all current and future subs to managed profile.
                 registerListenerToAssignSubscriptionsToUser(copeProfileUserId);
@@ -3764,21 +3769,56 @@
     }
 
     private void clearDeviceOwnerUserRestriction(UserHandle userHandle) {
-        // ManagedProvisioning/DPC sets DISALLOW_ADD_USER. Clear to recover to the original state
-        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER, userHandle)) {
-            mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false, userHandle);
-        }
-        // When a device owner is set, the system automatically restricts adding a managed profile.
-        // Remove this restriction when the device owner is cleared.
-        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, userHandle)) {
-            mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, false,
-                    userHandle);
-        }
-        // When a device owner is set, the system automatically restricts adding a clone profile.
-        // Remove this restriction when the device owner is cleared.
-        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE, userHandle)) {
-            mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE, false,
-                    userHandle);
+        if (isHeadlessFlagEnabled()) {
+            for (int userId : mUserManagerInternal.getUserIds()) {
+                UserHandle user = UserHandle.of(userId);
+                // ManagedProvisioning/DPC sets DISALLOW_ADD_USER. Clear to recover to the
+                // original state
+                if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER, user)) {
+                    mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER,
+                            false, user);
+                }
+                // When a device owner is set, the system automatically restricts adding a
+                // managed profile.
+                // Remove this restriction when the device owner is cleared.
+                if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE,
+                        user)) {
+                    mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE,
+                            false,
+                            user);
+                }
+                // When a device owner is set, the system automatically restricts adding a
+                // clone profile.
+                // Remove this restriction when the device owner is cleared.
+                if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE, user)) {
+                    mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE,
+                            false, user);
+                }
+            }
+        } else {
+            // ManagedProvisioning/DPC sets DISALLOW_ADD_USER. Clear to recover to the original state
+            if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER, userHandle)) {
+                mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false,
+                        userHandle);
+            }
+            // When a device owner is set, the system automatically restricts adding a
+            // managed profile.
+            // Remove this restriction when the device owner is cleared.
+            if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE,
+                    userHandle)) {
+                mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE,
+                        false,
+                        userHandle);
+            }
+            // When a device owner is set, the system automatically restricts adding a clone
+            // profile.
+            // Remove this restriction when the device owner is cleared.
+            if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE,
+                    userHandle)) {
+                mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE,
+                        false,
+                        userHandle);
+            }
         }
     }
 
@@ -7022,6 +7062,7 @@
 
         if (isWorkProfileTelephonyFlagEnabled()) {
             clearManagedSubscriptionsPolicy();
+            updateTelephonyCrossProfileIntentFilters(parentId, UserHandle.USER_NULL, false);
         }
         Slogf.i(LOG_TAG, "Cleaning up device-wide policies done.");
     }
@@ -7038,6 +7079,33 @@
         }
     }
 
+    private void updateTelephonyCrossProfileIntentFilters(int parentUserId, int profileUserId,
+            boolean enableWorkTelephony) {
+        try {
+            String packageName = mContext.getOpPackageName();
+            if (enableWorkTelephony) {
+                // Reset call/sms cross profile intent filters to be handled by managed profile.
+                for (DefaultCrossProfileIntentFilter filter :
+                        DefaultCrossProfileIntentFiltersUtils
+                                .getDefaultManagedProfileTelephonyFilters()) {
+                    IntentFilter intentFilter = filter.filter.getIntentFilter();
+                    if (!mIPackageManager.removeCrossProfileIntentFilter(intentFilter, packageName,
+                            profileUserId, parentUserId, filter.flags)) {
+                        Slogf.w(LOG_TAG,
+                                "Failed to remove cross-profile intent filter: " + intentFilter);
+                    }
+
+                    mIPackageManager.addCrossProfileIntentFilter(intentFilter, packageName,
+                            parentUserId, profileUserId, PackageManager.SKIP_CURRENT_PROFILE);
+                }
+            } else {
+                mIPackageManager.clearCrossProfileIntentFilters(parentUserId, packageName);
+            }
+        } catch (RemoteException re) {
+            Slogf.wtf(LOG_TAG, "Error updating telephony cross profile intent filters", re);
+        }
+    }
+
     /**
      * @param factoryReset null: legacy behaviour, false: attempt to remove user, true: attempt to
      *                     factory reset
@@ -8642,7 +8710,7 @@
             // hard-coded default value setting.
             if (isAdb(caller)) {
                 activeAdmin.mAdminCanGrantSensorsPermissions = true;
-                mPolicyCache.setAdminCanGrantSensorsPermissions(userId, true);
+                mPolicyCache.setAdminCanGrantSensorsPermissions(true);
                 saveSettingsLocked(userId);
             }
 
@@ -8654,14 +8722,31 @@
                 // profile, such that the admin on that managed profile has extended management
                 // capabilities that can affect the entire device (but not access private data
                 // on the primary profile).
-                mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true,
-                        UserHandle.of(userId));
-                // Restrict adding a clone profile when a device owner is set on the device.
-                // That is to prevent the co-existence of a clone profile and a device owner
-                // on the same device.
-                // CDD for reference : https://source.android.com/compatibility/12/android-12-cdd#95_multi-user_support
-                mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE, true,
-                        UserHandle.of(userId));
+                if (isHeadlessFlagEnabled()) {
+                    for (int u : mUserManagerInternal.getUserIds()) {
+                        mUserManager.setUserRestriction(
+                                UserManager.DISALLOW_ADD_MANAGED_PROFILE, true,
+                                UserHandle.of(u));
+                        // Restrict adding a clone profile when a device owner is set on the device.
+                        // That is to prevent the co-existence of a clone profile and a device owner
+                        // on the same device.
+                        // CDD for reference : https://source.android.com/compatibility/12/android-12-cdd#95_multi-user_support
+                        mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE,
+                                true,
+                                UserHandle.of(u));
+                    }
+                } else {
+                    mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE,
+                            true,
+                            UserHandle.of(userId));
+                    // Restrict adding a clone profile when a device owner is set on the device.
+                    // That is to prevent the co-existence of a clone profile and a device owner
+                    // on the same device.
+                    // CDD for reference : https://source.android.com/compatibility/12/android-12-cdd#95_multi-user_support
+                    mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE,
+                            true,
+                            UserHandle.of(userId));
+                }
                 // TODO Send to system too?
                 sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED, userId);
             });
@@ -9288,7 +9373,7 @@
     }
 
     @Override
-    public int getUserProvisioningState() {
+    public int getUserProvisioningState(int userHandle) {
         if (!mHasFeature) {
             return DevicePolicyManager.STATE_USER_UNMANAGED;
         }
@@ -9296,10 +9381,11 @@
         Preconditions.checkCallAuthorization(canManageUsers(caller)
                 || hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
 
-        return getUserProvisioningState(caller.getUserId());
-    }
+        if (userHandle != caller.getUserId()) {
+            Preconditions.checkCallAuthorization(canManageUsers(caller)
+                    || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS));
+        }
 
-    private int getUserProvisioningState(int userHandle) {
         return getUserData(userHandle).mUserProvisioningState;
     }
 
@@ -9310,7 +9396,6 @@
                     + userId);
             return;
         }
-
         Preconditions.checkCallAuthorization(
                 hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
 
@@ -14667,7 +14752,7 @@
                     AdminPermissionControlParams permissionParams =
                             new AdminPermissionControlParams(packageName, permission,
                                     grantState,
-                                    canAdminGrantSensorsPermissionsForUser(caller.getUserId()));
+                                    canAdminGrantSensorsPermissions());
                     mInjector.getPermissionControllerManager(caller.getUserHandle())
                             .setRuntimePermissionGrantStateByDeviceAdmin(
                                     caller.getPackageName(),
@@ -18645,7 +18730,7 @@
                         "Error creating profile, createProfileForUserEvenWhenDisallowed "
                                 + "returned null.");
             }
-            resetInteractAcrossProfilesAppOps();
+            resetInteractAcrossProfilesAppOps(caller.getUserId());
             logEventDuration(
                     DevicePolicyEnums.PLATFORM_PROVISIONING_CREATE_PROFILE_MS,
                     startTime,
@@ -18797,37 +18882,37 @@
         return caller.getPackageName().equals(devicePolicyManagementRoleHolderPackageName);
     }
 
-    private void resetInteractAcrossProfilesAppOps() {
-        mInjector.getCrossProfileApps().clearInteractAcrossProfilesAppOps();
-        pregrantDefaultInteractAcrossProfilesAppOps();
+    private void resetInteractAcrossProfilesAppOps(@UserIdInt int userId) {
+        mInjector.getCrossProfileApps(userId).clearInteractAcrossProfilesAppOps();
+        pregrantDefaultInteractAcrossProfilesAppOps(userId);
     }
 
-    private void pregrantDefaultInteractAcrossProfilesAppOps() {
+    private void pregrantDefaultInteractAcrossProfilesAppOps(@UserIdInt int userId) {
         final String op =
                 AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES);
-        for (String packageName : getConfigurableDefaultCrossProfilePackages()) {
-            if (appOpIsChangedFromDefault(op, packageName)) {
+        for (String packageName : getConfigurableDefaultCrossProfilePackages(userId)) {
+            if (!appOpIsDefaultOrAllowed(userId, op, packageName)) {
                 continue;
             }
-            mInjector.getCrossProfileApps().setInteractAcrossProfilesAppOp(
+            mInjector.getCrossProfileApps(userId).setInteractAcrossProfilesAppOp(
                     packageName, MODE_ALLOWED);
         }
     }
 
-    private Set<String> getConfigurableDefaultCrossProfilePackages() {
+    private Set<String> getConfigurableDefaultCrossProfilePackages(@UserIdInt int userId) {
         List<String> defaultPackages = getDefaultCrossProfilePackages();
         return defaultPackages.stream().filter(
-                mInjector.getCrossProfileApps()::canConfigureInteractAcrossProfiles).collect(
+                mInjector.getCrossProfileApps(userId)::canConfigureInteractAcrossProfiles).collect(
                 Collectors.toSet());
     }
 
-    private boolean appOpIsChangedFromDefault(String op, String packageName) {
+    private boolean appOpIsDefaultOrAllowed(@UserIdInt int userId, String op, String packageName) {
         try {
-            final int uid = mContext.getPackageManager().getPackageUid(
-                    packageName, /* flags= */ 0);
-            return mInjector.getAppOpsManager().unsafeCheckOpNoThrow(
-                    op, uid, packageName)
-                    != AppOpsManager.MODE_DEFAULT;
+            final int uid = mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0).
+                    getPackageManager().getPackageUid(packageName, /* flags= */ 0);
+            int mode = mInjector.getAppOpsManager().unsafeCheckOpNoThrow(
+                    op, uid, packageName);
+            return mode == MODE_ALLOWED || mode == MODE_DEFAULT;
         } catch (NameNotFoundException e) {
             return false;
         }
@@ -19263,7 +19348,7 @@
                     "May only be set on a the user of a device owner.");
 
             owner.mAdminCanGrantSensorsPermissions = canGrant;
-            mPolicyCache.setAdminCanGrantSensorsPermissions(userId, canGrant);
+            mPolicyCache.setAdminCanGrantSensorsPermissions(canGrant);
             saveSettingsLocked(userId);
         }
     }
@@ -19278,6 +19363,7 @@
             mInjector.settingsGlobalPutStringForUser(
                     Settings.Global.DEVICE_DEMO_MODE, Integer.toString(/* value= */ 1), userId);
         }
+
         setUserProvisioningState(STATE_USER_SETUP_FINALIZED, userId);
     }
 
@@ -19293,7 +19379,7 @@
                 owner = getDeviceOrProfileOwnerAdminLocked(userId);
             }
             boolean canGrant = owner != null ? owner.mAdminCanGrantSensorsPermissions : false;
-            mPolicyCache.setAdminCanGrantSensorsPermissions(userId, canGrant);
+            mPolicyCache.setAdminCanGrantSensorsPermissions(canGrant);
         }
     }
 
@@ -19338,12 +19424,12 @@
     }
 
     @Override
-    public boolean canAdminGrantSensorsPermissionsForUser(int userId) {
+    public boolean canAdminGrantSensorsPermissions() {
         if (!mHasFeature) {
             return false;
         }
 
-        return mPolicyCache.canAdminGrantSensorsPermissionsForUser(userId);
+        return mPolicyCache.canAdminGrantSensorsPermissions();
     }
 
     @Override
@@ -20285,6 +20371,7 @@
             try {
                 int parentUserId = getProfileParentId(caller.getUserId());
                 installOemDefaultDialerAndMessagesApp(parentUserId, caller.getUserId());
+                updateTelephonyCrossProfileIntentFilters(parentUserId, caller.getUserId(), true);
             } finally {
                 mInjector.binderRestoreCallingIdentity(id);
             }
diff --git a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
index 730cac9..0962b0d 100644
--- a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
@@ -146,6 +146,7 @@
             addPermissions(packageState, changedPermissionNames)
             trimPermissions(packageState.packageName, changedPermissionNames)
             trimPermissionStates(packageState.appId)
+            revokePermissionsOnPackageUpdate(packageState.appId)
         }
         changedPermissionNames.forEachIndexed { _, permissionName ->
             evaluatePermissionStateForAllPackages(permissionName, null)
@@ -175,10 +176,10 @@
         adoptPermissions(packageState, changedPermissionNames)
         addPermissionGroups(packageState)
         addPermissions(packageState, changedPermissionNames)
-        // TODO: revokeStoragePermissionsIfScopeExpandedInternal()
         // TODO: revokeSystemAlertWindowIfUpgradedPast23()
         trimPermissions(packageState.packageName, changedPermissionNames)
         trimPermissionStates(packageState.appId)
+        revokePermissionsOnPackageUpdate(packageState.appId)
         changedPermissionNames.forEachIndexed { _, permissionName ->
             evaluatePermissionStateForAllPackages(permissionName, null)
         }
@@ -602,6 +603,40 @@
         }
     }
 
+    private fun MutateStateScope.revokePermissionsOnPackageUpdate(appId: Int) {
+        // If the app is updated, and has scoped storage permissions, then it is possible that the
+        // app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
+        newState.userStates.forEachIndexed { _, userId, userState ->
+            userState.uidPermissionFlags[appId]?.forEachReversedIndexed {
+                _, permissionName, oldFlags ->
+                if (permissionName !in STORAGE_AND_MEDIA_PERMISSIONS || oldFlags == 0) {
+                    return@forEachReversedIndexed
+                }
+                val oldTargetSdkVersion = getAppIdTargetSdkVersion(appId, permissionName, oldState)
+                val newTargetSdkVersion = getAppIdTargetSdkVersion(appId, permissionName, newState)
+                val isTargetSdkVersionDowngraded = oldTargetSdkVersion >= Build.VERSION_CODES.Q &&
+                    newTargetSdkVersion < Build.VERSION_CODES.Q
+                val isTargetSdkVersionUpgraded = oldTargetSdkVersion < Build.VERSION_CODES.Q &&
+                    newTargetSdkVersion >= Build.VERSION_CODES.Q
+                val oldIsRequestLegacyExternalStorage = anyPackageInAppId(appId, oldState) {
+                    it.androidPackage!!.isRequestLegacyExternalStorage
+                }
+                val newIsRequestLegacyExternalStorage = anyPackageInAppId(appId, newState) {
+                    it.androidPackage!!.isRequestLegacyExternalStorage
+                }
+                val isNewlyRequestingLegacyExternalStorage = !isTargetSdkVersionUpgraded &&
+                    !oldIsRequestLegacyExternalStorage && newIsRequestLegacyExternalStorage
+                if ((isNewlyRequestingLegacyExternalStorage || isTargetSdkVersionDowngraded) &&
+                    oldFlags.hasBits(PermissionFlags.RUNTIME_GRANTED)) {
+                    val newFlags = oldFlags andInv (
+                        PermissionFlags.RUNTIME_GRANTED or USER_SETTABLE_MASK
+                    )
+                    setPermissionFlags(appId, userId, permissionName, newFlags)
+                }
+            }
+        }
+    }
+
     private fun MutateStateScope.evaluatePermissionStateForAllPackages(
         permissionName: String,
         installedPackageState: PackageState?
@@ -1002,9 +1037,13 @@
         }
     }
 
-    private fun MutateStateScope.getAppIdTargetSdkVersion(appId: Int, permissionName: String): Int {
+    private fun MutateStateScope.getAppIdTargetSdkVersion(
+        appId: Int,
+        permissionName: String,
+        state: AccessState = newState
+    ): Int {
         var targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT
-        forEachPackageInAppId(appId) { packageState ->
+        forEachPackageInAppId(appId, state) { packageState ->
             val androidPackage = packageState.androidPackage!!
             if (permissionName in androidPackage.requestedPermissions) {
                 targetSdkVersion = targetSdkVersion.coerceAtMost(androidPackage.targetSdkVersion)
@@ -1356,6 +1395,16 @@
             Manifest.permission.POST_NOTIFICATIONS
         )
 
+        private val STORAGE_AND_MEDIA_PERMISSIONS = indexedSetOf(
+            Manifest.permission.READ_EXTERNAL_STORAGE,
+            Manifest.permission.WRITE_EXTERNAL_STORAGE,
+            Manifest.permission.READ_MEDIA_AUDIO,
+            Manifest.permission.READ_MEDIA_VIDEO,
+            Manifest.permission.READ_MEDIA_IMAGES,
+            Manifest.permission.ACCESS_MEDIA_LOCATION,
+            Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
+        )
+
         /**
          * Mask for all permission flags that can be set by the user
          */
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index 3ef8586a..d128e68 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -267,7 +267,7 @@
                 Manifest.permission.INTERACT_ACROSS_USERS,
                 Manifest.permission.INTERACT_ACROSS_USERS_FULL);
         try {
-            mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+            mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                     CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
             fail();
         } catch (SecurityException expected) {}
@@ -280,7 +280,7 @@
                 Manifest.permission.INTERACT_ACROSS_USERS_FULL);
         grantPermissions(Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES);
         try {
-            mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+            mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                     CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
             fail();
         } catch (SecurityException expected) {}
@@ -288,7 +288,7 @@
 
     @Test
     public void setInteractAcrossProfilesAppOp_setsAppOp() {
-        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
         assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
     }
@@ -302,7 +302,7 @@
                 Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
                 Manifest.permission.INTERACT_ACROSS_USERS);
 
-        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
 
         assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
@@ -316,7 +316,7 @@
                 Manifest.permission.UPDATE_APP_OPS_STATS,
                 Manifest.permission.INTERACT_ACROSS_USERS);
 
-        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
 
         assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
@@ -326,7 +326,7 @@
     public void setInteractAcrossProfilesAppOp_setsAppOpWithUsersAndWithoutFull() {
         denyPermissions(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
         grantPermissions(Manifest.permission.INTERACT_ACROSS_USERS);
-        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
         assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
     }
@@ -335,28 +335,28 @@
     public void setInteractAcrossProfilesAppOp_setsAppOpWithFullAndWithoutUsers() {
         denyPermissions(Manifest.permission.INTERACT_ACROSS_USERS);
         grantPermissions(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
-        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
         assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
     }
 
     @Test
     public void setInteractAcrossProfilesAppOp_setsAppOpOnOtherProfile() {
-        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
         assertThat(getCrossProfileAppOp(WORK_PROFILE_UID)).isEqualTo(MODE_ALLOWED);
     }
 
     @Test
     public void setInteractAcrossProfilesAppOp_sendsBroadcast() {
-        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
         assertThat(receivedCanInteractAcrossProfilesChangedBroadcast()).isTrue();
     }
 
     @Test
     public void setInteractAcrossProfilesAppOp_sendsBroadcastToOtherProfile() {
-        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
         assertThat(receivedCanInteractAcrossProfilesChangedBroadcast(WORK_PROFILE_USER_ID))
                 .isTrue();
@@ -364,7 +364,7 @@
 
     @Test
     public void setInteractAcrossProfilesAppOp_doesNotSendBroadcastToProfileWithoutPackage() {
-        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
         assertThat(receivedCanInteractAcrossProfilesChangedBroadcast(
                         OTHER_PROFILE_WITHOUT_CROSS_PROFILE_APP_USER_ID))
@@ -374,7 +374,7 @@
     @Test
     public void setInteractAcrossProfilesAppOp_toSameAsCurrent_doesNotSendBroadcast() {
         explicitlySetInteractAcrossProfilesAppOp(MODE_ALLOWED);
-        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
         assertThat(receivedCanInteractAcrossProfilesChangedBroadcast()).isFalse();
     }
@@ -382,7 +382,7 @@
     @Test
     public void setInteractAcrossProfilesAppOp_toAllowed_whenNotAbleToRequest_doesNotSet() {
         mockCrossProfileAppNotWhitelisted();
-        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
         assertThat(getCrossProfileAppOp()).isNotEqualTo(MODE_ALLOWED);
     }
@@ -390,7 +390,7 @@
     @Test
     public void setInteractAcrossProfilesAppOp_toAllowed_whenNotAbleToRequest_doesNotSendBroadcast() {
         mockCrossProfileAppNotWhitelisted();
-        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
         assertThat(receivedCanInteractAcrossProfilesChangedBroadcast()).isFalse();
     }
@@ -398,7 +398,7 @@
     @Test
     public void setInteractAcrossProfilesAppOp_withoutCrossProfileAttribute_manifestReceiversDoNotGetBroadcast() {
         declareCrossProfileAttributeOnCrossProfileApp(false);
-        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
         assertThat(receivedManifestCanInteractAcrossProfilesChangedBroadcast()).isFalse();
     }
@@ -406,14 +406,14 @@
     @Test
     public void setInteractAcrossProfilesAppOp_withCrossProfileAttribute_manifestReceiversGetBroadcast() {
         declareCrossProfileAttributeOnCrossProfileApp(true);
-        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
         assertThat(receivedManifestCanInteractAcrossProfilesChangedBroadcast()).isTrue();
     }
 
     @Test
     public void setInteractAcrossProfilesAppOp_toAllowed_doesNotKillApp() {
-        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
         assertThat(mKilledUids).isEmpty();
     }
@@ -421,10 +421,10 @@
     @Test
     public void setInteractAcrossProfilesAppOp_toDisallowed_killsAppsInBothProfiles() {
         shadowOf(mPackageManager).addPermissionInfo(createCrossProfilesPermissionInfo());
-        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
 
-        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(/* userId= */ 0,
                 CROSS_PROFILE_APP_PACKAGE_NAME, MODE_DEFAULT);
 
         assertThat(mKilledUids).contains(WORK_PROFILE_UID);
@@ -463,7 +463,8 @@
     public void canConfigureInteractAcrossProfiles_packageNotInstalledInProfile_returnsFalse() {
         mockUninstallCrossProfileAppFromWorkProfile();
         assertThat(mCrossProfileAppsServiceImpl
-                .canConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+                .canConfigureInteractAcrossProfiles(
+                        /* userId= */ 0, CROSS_PROFILE_APP_PACKAGE_NAME))
                 .isFalse();
     }
 
@@ -482,7 +483,8 @@
             throws Exception {
         mockCrossProfileAppDoesNotRequestInteractAcrossProfiles();
         assertThat(mCrossProfileAppsServiceImpl
-                .canConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+                .canConfigureInteractAcrossProfiles(
+                        /* userId= */ 0, CROSS_PROFILE_APP_PACKAGE_NAME))
                 .isFalse();
     }
 
@@ -496,14 +498,16 @@
     public void canConfigureInteractAcrossProfiles_packageNotWhitelisted_returnsFalse() {
         mockCrossProfileAppNotWhitelisted();
         assertThat(mCrossProfileAppsServiceImpl
-                .canConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+                .canConfigureInteractAcrossProfiles(
+                        /* userId= */ 0, CROSS_PROFILE_APP_PACKAGE_NAME))
                 .isFalse();
     }
 
     @Test
     public void canConfigureInteractAcrossProfiles_returnsTrue() {
         assertThat(mCrossProfileAppsServiceImpl
-                .canConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+                .canConfigureInteractAcrossProfiles(
+                        /* userId= */ 0, CROSS_PROFILE_APP_PACKAGE_NAME))
                 .isTrue();
     }
 
@@ -511,7 +515,8 @@
     public void canUserAttemptToConfigureInteractAcrossProfiles_packageNotInstalledInProfile_returnsTrue() {
         mockUninstallCrossProfileAppFromWorkProfile();
         assertThat(mCrossProfileAppsServiceImpl
-                .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+                .canUserAttemptToConfigureInteractAcrossProfiles(
+                        /* userId= */ 0, CROSS_PROFILE_APP_PACKAGE_NAME))
                 .isTrue();
     }
 
@@ -520,7 +525,8 @@
             throws Exception {
         mockCrossProfileAppDoesNotRequestInteractAcrossProfiles();
         assertThat(mCrossProfileAppsServiceImpl
-                .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+                .canUserAttemptToConfigureInteractAcrossProfiles(
+                        /* userId= */ 0, CROSS_PROFILE_APP_PACKAGE_NAME))
                 .isFalse();
     }
 
@@ -528,7 +534,8 @@
     public void canUserAttemptToConfigureInteractAcrossProfiles_packageNotWhitelisted_returnsTrue() {
         mockCrossProfileAppNotWhitelisted();
         assertThat(mCrossProfileAppsServiceImpl
-                .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+                .canUserAttemptToConfigureInteractAcrossProfiles(
+                        /* userId= */ 0, CROSS_PROFILE_APP_PACKAGE_NAME))
                 .isTrue();
     }
 
@@ -541,7 +548,8 @@
                 Manifest.permission.INTERACT_ACROSS_PROFILES);
 
         assertThat(mCrossProfileAppsServiceImpl
-                .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+                .canUserAttemptToConfigureInteractAcrossProfiles(
+                        /* userId= */ 0, CROSS_PROFILE_APP_PACKAGE_NAME))
                 .isFalse();
     }
 
@@ -550,7 +558,8 @@
         when(mDevicePolicyManagerInternal.getProfileOwnerAsUser(WORK_PROFILE_USER_ID))
                 .thenReturn(buildCrossProfileComponentName());
         assertThat(mCrossProfileAppsServiceImpl
-                .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+                .canUserAttemptToConfigureInteractAcrossProfiles(
+                        /* userId= */ 0, CROSS_PROFILE_APP_PACKAGE_NAME))
                 .isFalse();
     }
 
@@ -562,7 +571,8 @@
         when(mDevicePolicyManagerInternal.getProfileOwnerAsUser(PERSONAL_PROFILE_USER_ID))
                 .thenReturn(buildCrossProfileComponentName());
         assertThat(mCrossProfileAppsServiceImpl
-                .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+                .canUserAttemptToConfigureInteractAcrossProfiles(
+                        /* userId= */ 0, CROSS_PROFILE_APP_PACKAGE_NAME))
                 .isFalse();
     }
 
@@ -571,21 +581,23 @@
         when(mDevicePolicyManagerInternal.getProfileOwnerAsUser(OTHER_PROFILE_GROUP_USER_ID))
                 .thenReturn(buildCrossProfileComponentName());
         assertThat(mCrossProfileAppsServiceImpl
-                .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+                .canUserAttemptToConfigureInteractAcrossProfiles(
+                        /* userId= */ 0, CROSS_PROFILE_APP_PACKAGE_NAME))
                 .isTrue();
     }
 
     @Test
     public void canUserAttemptToConfigureInteractAcrossProfiles_returnsTrue() {
         assertThat(mCrossProfileAppsServiceImpl
-                .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+                .canUserAttemptToConfigureInteractAcrossProfiles(
+                        /* userId= */ 0, CROSS_PROFILE_APP_PACKAGE_NAME))
                 .isTrue();
     }
 
     @Test
     public void clearInteractAcrossProfilesAppOps() {
         explicitlySetInteractAcrossProfilesAppOp(MODE_ALLOWED);
-        mCrossProfileAppsServiceImpl.clearInteractAcrossProfilesAppOps();
+        mCrossProfileAppsServiceImpl.clearInteractAcrossProfilesAppOps(/* userId= */ 0);
         assertThat(getCrossProfileAppOp()).isEqualTo(MODE_DEFAULT);
     }
 
diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp
index 47e7a37..d9467a5 100644
--- a/services/tests/PackageManagerServiceTests/host/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/Android.bp
@@ -23,7 +23,10 @@
 
 java_test_host {
     name: "PackageManagerServiceHostTests",
-    srcs: ["src/**/*.kt"],
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
     libs: [
         "tradefed",
         "junit",
@@ -34,11 +37,17 @@
         "cts-host-utils",
         "frameworks-base-hostutils",
         "PackageManagerServiceHostTestsIntentVerifyUtils",
+        "block_device_writer_jar",
     ],
     test_suites: ["general-tests"],
     data: [
         ":PackageManagerTestApex",
         ":PackageManagerTestApexApp",
+        ":PackageManagerServiceServerTests",
+    ],
+    data_device_bins_both: [
+        "block_device_writer",
+        "fsverity_multilib",
     ],
     java_resources: [
         ":PackageManagerTestOverlayActor",
diff --git a/services/tests/PackageManagerServiceTests/host/AndroidTest.xml b/services/tests/PackageManagerServiceTests/host/AndroidTest.xml
index f584599..2382548 100644
--- a/services/tests/PackageManagerServiceTests/host/AndroidTest.xml
+++ b/services/tests/PackageManagerServiceTests/host/AndroidTest.xml
@@ -27,6 +27,22 @@
             value="pm uninstall com.android.cts.install.lib.testapp.A" />
     </target_preparer>
 
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="install-arg" value="-t" />
+        <option name="test-file-name" value="PackageManagerServiceServerTests.apk" />
+    </target_preparer>
+
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <!-- The build system produces both 32 and 64 bit variants with bitness suffix. Let
+             FilePusher find the filename with bitness and push to a remote name without bitness.
+        -->
+        <option name="append-bitness" value="true" />
+        <option name="cleanup" value="true" />
+        <option name="push" value="block_device_writer->/data/local/tmp/block_device_writer" />
+        <option name="push" value="fsverity_multilib->/data/local/tmp/fsverity_multilib" />
+    </target_preparer>
+
     <test class="com.android.tradefed.testtype.HostTest">
         <option name="jar" value="PackageManagerServiceHostTests.jar" />
     </test>
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SettingsTest.java b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SettingsTest.java
new file mode 100644
index 0000000..a66906e
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SettingsTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.blockdevicewriter.BlockDeviceWriter;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.util.ArrayList;
+
+/**
+ * atest com.android.server.pm.test.SettingsTest
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class SettingsTest extends BaseHostJUnit4Test {
+    private static final String DEVICE_TEST_PACKAGE_NAME =
+            "com.android.server.pm.test.service.server";
+    private static final String TEST_CLASS_NAME =
+            "com.android.server.pm.PackageManagerSettingsDeviceTests";
+
+    private static final String FSVERITY_EXECUTABLE = "/data/local/tmp/fsverity_multilib";
+    private static final String DAMAGING_EXECUTABLE = "/data/local/tmp/block_device_writer";
+
+    @Test
+    public void testWriteCorruptHeaderBinaryXml() throws Exception {
+        // Corrupt 1st page, this will trigger error in initial resolve* call.
+        performTest("testWriteBinaryXmlSettings", 0);
+    }
+
+    @Test
+    public void testWriteCorruptHeaderTextXml() throws Exception {
+        // Corrupt 1st page, this will trigger error in initial resolve* call.
+        performTest("testWriteTextXmlSettings", 0);
+    }
+
+    @Test
+    public void testWriteCorruptDataBinaryXml() throws Exception {
+        // Corrupt 2nd page, this will trigger error in the XML parser.
+        performTest("testWriteBinaryXmlSettings", 1);
+    }
+
+    @Test
+    public void testWriteCorruptDataTextXml() throws Exception {
+        // Corrupt 2nd page, this will trigger error in the XML parser.
+        performTest("testWriteTextXmlSettings", 1);
+    }
+
+    private void performTest(String writeTest, int pageToCorrupt) throws Exception {
+        assertTrue(runDeviceTests(DEVICE_TEST_PACKAGE_NAME, TEST_CLASS_NAME,
+                writeTest));
+
+        int userId = getDevice().getCurrentUser();
+        File filesDir = new File(
+                "/data/user/" + userId + "/" + DEVICE_TEST_PACKAGE_NAME + "/files");
+        File packagesXml = new File(filesDir, "system/packages.xml");
+
+        // Make sure fs-verity is enabled.
+        enableFsVerity(packagesXml.getAbsolutePath());
+
+        // Damage the file directly against the block device.
+        BlockDeviceWriter.damageFileAgainstBlockDevice(getDevice(), packagesXml.getAbsolutePath(),
+                pageToCorrupt * 4096 + 1);
+        BlockDeviceWriter.dropCaches(getDevice());
+
+        assertTrue(runDeviceTests(DEVICE_TEST_PACKAGE_NAME, TEST_CLASS_NAME,
+                "testReadSettings"));
+    }
+
+    private void enableFsVerity(String path) throws Exception {
+        ITestDevice device = getDevice();
+        ArrayList<String> args = new ArrayList<>();
+        args.add(FSVERITY_EXECUTABLE);
+        args.add("enable");
+        args.add(path);
+
+        String cmd = String.join(" ", args);
+        CommandResult result = device.executeShellV2Command(cmd);
+        assertEquals("`" + cmd + "` failed: " + result.getStderr(), CommandStatus.SUCCESS,
+                result.getStatus());
+    }
+
+}
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsDeviceTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsDeviceTests.java
new file mode 100644
index 0000000..e43f40d
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsDeviceTests.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.app.PropertyInvalidatedCache;
+import android.os.Message;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.permission.persistence.RuntimePermissionsPersistence;
+import com.android.server.LocalServices;
+import com.android.server.pm.permission.LegacyPermissionDataProvider;
+import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
+import com.android.server.testutils.TestHandler;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.UUID;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class PackageManagerSettingsDeviceTests {
+    @Mock
+    RuntimePermissionsPersistence mRuntimePermissionsPersistence;
+    @Mock
+    LegacyPermissionDataProvider mPermissionDataProvider;
+    @Mock
+    DomainVerificationManagerInternal mDomainVerificationManager;
+    @Mock
+    Computer mComputer;
+
+    final TestHandler mHandler = new TestHandler((@NonNull Message msg) -> {
+        return true;
+    });
+
+    @Before
+    public void initializeMocks() {
+        MockitoAnnotations.initMocks(this);
+        when(mDomainVerificationManager.generateNewId())
+                .thenAnswer(invocation -> UUID.randomUUID());
+    }
+
+    @Before
+    public void setup() {
+        // Disable binder caches in this process.
+        PropertyInvalidatedCache.disableForTestMode();
+    }
+
+    @Before
+    public void createUserManagerServiceRef() throws ReflectiveOperationException {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync((Runnable) () -> {
+            try {
+                // unregister the user manager from the local service
+                LocalServices.removeServiceForTest(UserManagerInternal.class);
+                new UserManagerService(InstrumentationRegistry.getContext());
+            } catch (Exception e) {
+                e.printStackTrace();
+                fail("Could not create user manager service; " + e);
+            }
+        });
+    }
+
+    // Write valid packages.xml, compare with the reserve copy.
+    @Test
+    public void testWriteBinaryXmlSettings() throws Exception {
+        // write out files and read
+        PackageManagerSettingsTests.writeOldFiles();
+        Settings settings = makeSettings();
+        assertTrue(settings.readLPw(mComputer, PackageManagerSettingsTests.createFakeUsers()));
+
+        // write out
+        settings.writeLPr(mComputer, /*sync=*/true);
+
+        File filesDir = InstrumentationRegistry.getContext().getFilesDir();
+        File packageXml = new File(filesDir, "system/packages.xml");
+        File packagesReserveCopyXml = new File(filesDir, "system/packages.xml.reservecopy");
+        // Primary.
+        assertTrue(packageXml.exists());
+        // For the test, we need a file with at least 2 pages.
+        assertThat(packageXml.length(), greaterThan(4096L));
+        // Reserve copy.
+        assertTrue(packagesReserveCopyXml.exists());
+        // Temporary backup.
+        assertFalse(new File(filesDir, "packages-backup.xml").exists());
+
+        // compare two copies, make sure they are the same
+        assertTrue(Arrays.equals(Files.readAllBytes(Path.of(packageXml.getAbsolutePath())),
+                Files.readAllBytes(Path.of(packagesReserveCopyXml.getAbsolutePath()))));
+    }
+
+    @Test
+    public void testWriteTextXmlSettings() throws Exception {
+        testWriteBinaryXmlSettings();
+
+        PackageManagerSettingsTests.writePackagesXml("system/packages.xml");
+
+        File filesDir = InstrumentationRegistry.getContext().getFilesDir();
+        File packageXml = new File(filesDir, "system/packages.xml");
+
+        assertTrue(packageXml.exists());
+        // For the test, we need a file with at least 2 pages.
+        assertThat(packageXml.length(), greaterThan(4096L));
+    }
+
+    // Read settings, verify.
+    @Test
+    public void testReadSettings() throws Exception {
+        // This test can be run separately. In this case packages.xml is missing.
+        assumeTrue(new File(InstrumentationRegistry.getContext().getFilesDir(),
+                "system/packages.xml").exists());
+        Settings settings = makeSettings();
+        assertTrue(settings.readLPw(mComputer, PackageManagerSettingsTests.createFakeUsers()));
+        PackageManagerSettingsTests.verifyKeySetMetaData(settings);
+    }
+
+    private Settings makeSettings() {
+        return new Settings(InstrumentationRegistry.getContext().getFilesDir(),
+                mRuntimePermissionsPersistence, mPermissionDataProvider,
+                mDomainVerificationManager, mHandler,
+                new PackageManagerTracedLock());
+    }
+}
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
index 6a1ccc5..75484d1 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -56,7 +56,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
-import android.util.Log;
 import android.util.LongSparseArray;
 
 import androidx.test.InstrumentationRegistry;
@@ -108,7 +107,6 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class PackageManagerSettingsTests {
-    private static final String TAG = "PackageManagerSettingsTests";
     private static final String PACKAGE_NAME_1 = "com.android.app1";
     private static final String PACKAGE_NAME_2 = "com.android.app2";
     private static final String PACKAGE_NAME_3 = "com.android.app3";
@@ -142,6 +140,25 @@
         PropertyInvalidatedCache.disableForTestMode();
     }
 
+    @Before
+    public void createUserManagerServiceRef() throws ReflectiveOperationException {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync((Runnable) () -> {
+            try {
+                // unregister the user manager from the local service
+                LocalServices.removeServiceForTest(UserManagerInternal.class);
+                new UserManagerService(InstrumentationRegistry.getContext());
+            } catch (Exception e) {
+                e.printStackTrace();
+                fail("Could not create user manager service; " + e);
+            }
+        });
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        deleteFolder(InstrumentationRegistry.getContext().getFilesDir());
+    }
+
     /** make sure our initialized KeySetManagerService metadata matches packages.xml */
     @Test
     public void testReadKeySetSettings() throws Exception {
@@ -1612,13 +1629,13 @@
                 UUID.randomUUID());
     }
 
-    private @NonNull List<UserInfo> createFakeUsers() {
+    static @NonNull List<UserInfo> createFakeUsers() {
         ArrayList<UserInfo> users = new ArrayList<>();
         users.add(new UserInfo(UserHandle.USER_SYSTEM, "test user", UserInfo.FLAG_INITIALIZED));
         return users;
     }
 
-    private void writeFile(File file, byte[] data) {
+    private static void writeFile(File file, byte[] data) {
         file.mkdirs();
         try {
             AtomicFile aFile = new AtomicFile(file);
@@ -1626,7 +1643,7 @@
             fos.write(data);
             aFile.finishWrite(fos);
         } catch (IOException ioe) {
-            Log.e(TAG, "Cannot write file " + file.getPath());
+            throw new RuntimeException("Cannot write file " + file.getPath(), ioe);
         }
     }
 
@@ -1640,7 +1657,7 @@
                 ).getBytes());
     }
 
-    private void writePackagesXml(String fileName) {
+    static void writePackagesXml(String fileName) {
         writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), fileName),
                 ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
                 + "<packages>"
@@ -1748,7 +1765,7 @@
                         .getBytes());
     }
 
-    private void writeStoppedPackagesXml() {
+    private static void writeStoppedPackagesXml() {
         writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/packages-stopped.xml"),
                 ( "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
                 + "<stopped-packages>"
@@ -1758,7 +1775,7 @@
                 .getBytes());
     }
 
-    private void writePackagesList() {
+    private static void writePackagesList() {
         writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/packages.list"),
                 ( "com.android.app1 11000 0 /data/data/com.android.app1 seinfo1"
                 + "com.android.app2 11001 0 /data/data/com.android.app2 seinfo2"
@@ -1766,7 +1783,7 @@
                 .getBytes());
     }
 
-    private void deleteSystemFolder() {
+    private static void deleteSystemFolder() {
         File systemFolder = new File(InstrumentationRegistry.getContext().getFilesDir(), "system");
         deleteFolder(systemFolder);
     }
@@ -1781,7 +1798,7 @@
         folder.delete();
     }
 
-    private void writeOldFiles() {
+    static void writeOldFiles() {
         deleteSystemFolder();
         writePackagesXml("system/packages.xml");
         writeStoppedPackagesXml();
@@ -1795,25 +1812,6 @@
         writePackagesList();
     }
 
-    @Before
-    public void createUserManagerServiceRef() throws ReflectiveOperationException {
-        InstrumentationRegistry.getInstrumentation().runOnMainSync((Runnable) () -> {
-            try {
-                // unregister the user manager from the local service
-                LocalServices.removeServiceForTest(UserManagerInternal.class);
-                new UserManagerService(InstrumentationRegistry.getContext());
-            } catch (Exception e) {
-                e.printStackTrace();
-                fail("Could not create user manager service; " + e);
-            }
-        });
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        deleteFolder(InstrumentationRegistry.getTargetContext().getFilesDir());
-    }
-
     private Settings makeSettings() {
         return new Settings(InstrumentationRegistry.getContext().getFilesDir(),
                 mRuntimePermissionsPersistence, mPermissionDataProvider,
@@ -1821,7 +1819,7 @@
                 new PackageManagerTracedLock());
     }
 
-    private void verifyKeySetMetaData(Settings settings)
+    static void verifyKeySetMetaData(Settings settings)
             throws ReflectiveOperationException, IllegalAccessException {
         WatchedArrayMap<String, PackageSetting> packages = settings.mPackages;
         KeySetManagerService ksms = settings.getKeySetManagerService();
diff --git a/services/tests/mockingservicestests/src/android/hardware/face/FaceManagerTest.java b/services/tests/mockingservicestests/src/android/hardware/face/FaceManagerTest.java
new file mode 100644
index 0000000..f3feb02
--- /dev/null
+++ b/services/tests/mockingservicestests/src/android/hardware/face/FaceManagerTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.face;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Looper;
+import android.os.RemoteException;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.junit.MockitoRule;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(MockitoJUnitRunner.class)
+public class FaceManagerTest {
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+
+    @Mock
+    Context mContext;
+    @Mock
+    IFaceService mService;
+
+    @Captor
+    ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback> mCaptor;
+
+    List<FaceSensorPropertiesInternal> mProps;
+    FaceManager mFaceManager;
+
+    @Before
+    public void setUp() throws Exception {
+        when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
+        mFaceManager = new FaceManager(mContext, mService);
+        mProps = new ArrayList<>();
+        mProps.add(new FaceSensorPropertiesInternal(
+                0 /* id */,
+                FaceSensorProperties.STRENGTH_STRONG,
+                1 /* maxTemplatesAllowed */,
+                new ArrayList<>() /* conponentInfo */,
+                FaceSensorProperties.TYPE_UNKNOWN,
+                true /* supportsFaceDetection */,
+                true /* supportsSelfIllumination */,
+                false /* resetLockoutRequiresChallenge */));
+    }
+
+    @Test
+    public void getSensorPropertiesInternal_noBinderCalls() throws RemoteException {
+        verify(mService).addAuthenticatorsRegisteredCallback(mCaptor.capture());
+
+        mCaptor.getValue().onAllAuthenticatorsRegistered(mProps);
+        List<FaceSensorPropertiesInternal> actual = mFaceManager.getSensorPropertiesInternal();
+
+        assertThat(actual).isEqualTo(mProps);
+        verify(mService, never()).getSensorPropertiesInternal(any());
+    }
+}
diff --git a/services/tests/mockingservicestests/src/android/hardware/face/OWNERS b/services/tests/mockingservicestests/src/android/hardware/face/OWNERS
new file mode 100644
index 0000000..6a2192a
--- /dev/null
+++ b/services/tests/mockingservicestests/src/android/hardware/face/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/biometrics/OWNERS
diff --git a/services/tests/mockingservicestests/src/android/hardware/fingerprint/FingerprintManagerTest.java b/services/tests/mockingservicestests/src/android/hardware/fingerprint/FingerprintManagerTest.java
new file mode 100644
index 0000000..558202d
--- /dev/null
+++ b/services/tests/mockingservicestests/src/android/hardware/fingerprint/FingerprintManagerTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.fingerprint;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Looper;
+import android.os.RemoteException;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.junit.MockitoRule;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+@RunWith(MockitoJUnitRunner.class)
+public class FingerprintManagerTest {
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+
+    @Mock
+    Context mContext;
+    @Mock
+    IFingerprintService mService;
+
+    @Captor
+    ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mCaptor;
+
+    List<FingerprintSensorPropertiesInternal> mProps;
+    FingerprintManager mFingerprintManager;
+
+    @Before
+    public void setUp() throws Exception {
+        when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
+        mFingerprintManager = new FingerprintManager(mContext, mService);
+        mProps = new ArrayList<>();
+        mProps.add(new FingerprintSensorPropertiesInternal(
+                0 /* sensorId */,
+                FingerprintSensorProperties.STRENGTH_STRONG,
+                1 /* maxEnrollmentsPerUser */,
+                new ArrayList<>() /* componentInfo */,
+                FingerprintSensorProperties.TYPE_UNKNOWN,
+                true /* halControlsIllumination */,
+                true /* resetLockoutRequiresHardwareAuthToken */,
+                new ArrayList<>() /* sensorLocations */));
+    }
+
+    @Test
+    public void getSensorPropertiesInternal_noBinderCalls() throws RemoteException {
+        verify(mService).addAuthenticatorsRegisteredCallback(mCaptor.capture());
+
+        mCaptor.getValue().onAllAuthenticatorsRegistered(mProps);
+        List<FingerprintSensorPropertiesInternal> actual =
+                mFingerprintManager.getSensorPropertiesInternal();
+
+        assertThat(actual).isEqualTo(mProps);
+        verify(mService, never()).getSensorPropertiesInternal(any());
+    }
+}
diff --git a/services/tests/mockingservicestests/src/android/hardware/fingerprint/OWNERS b/services/tests/mockingservicestests/src/android/hardware/fingerprint/OWNERS
new file mode 100644
index 0000000..3edcf70
--- /dev/null
+++ b/services/tests/mockingservicestests/src/android/hardware/fingerprint/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/biometrics/OWNERS
\ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index a8b8f91..7281fafc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -30,6 +30,7 @@
 import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -370,11 +371,12 @@
     }
 
     /**
-     * Confirm that {@link JobSchedulerService#getRescheduleJobForFailureLocked(JobStatus, int)}
+     * Confirm that
+     * {@link JobSchedulerService#getRescheduleJobForFailureLocked(JobStatus, int, int)}
      * returns a job with the correct delay and deadline constraints.
      */
     @Test
-    public void testGetRescheduleJobForFailure() {
+    public void testGetRescheduleJobForFailure_timingCalculations() {
         final long nowElapsed = sElapsedRealtimeClock.millis();
         final long initialBackoffMs = MINUTE_IN_MILLIS;
         mService.mConstants.SYSTEM_STOP_TO_FAILURE_RATIO = 3;
@@ -387,15 +389,18 @@
 
         // failure = 0, systemStop = 1
         JobStatus rescheduledJob = mService.getRescheduleJobForFailureLocked(originalJob,
+                JobParameters.STOP_REASON_DEVICE_STATE,
                 JobParameters.INTERNAL_STOP_REASON_DEVICE_THERMAL);
         assertEquals(nowElapsed + initialBackoffMs, rescheduledJob.getEarliestRunTime());
         assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
 
         // failure = 0, systemStop = 2
         rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+                JobParameters.STOP_REASON_DEVICE_STATE,
                 JobParameters.INTERNAL_STOP_REASON_PREEMPT);
         // failure = 0, systemStop = 3
         rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+                JobParameters.STOP_REASON_CONSTRAINT_CHARGING,
                 JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED);
         assertEquals(nowElapsed + initialBackoffMs, rescheduledJob.getEarliestRunTime());
         assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
@@ -403,6 +408,7 @@
         // failure = 0, systemStop = 2 * SYSTEM_STOP_TO_FAILURE_RATIO
         for (int i = 0; i < mService.mConstants.SYSTEM_STOP_TO_FAILURE_RATIO; ++i) {
             rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+                    JobParameters.STOP_REASON_SYSTEM_PROCESSING,
                     JobParameters.INTERNAL_STOP_REASON_RTC_UPDATED);
         }
         assertEquals(nowElapsed + 2 * initialBackoffMs, rescheduledJob.getEarliestRunTime());
@@ -410,18 +416,52 @@
 
         // failure = 1, systemStop = 2 * SYSTEM_STOP_TO_FAILURE_RATIO
         rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+                JobParameters.STOP_REASON_TIMEOUT,
                 JobParameters.INTERNAL_STOP_REASON_TIMEOUT);
         assertEquals(nowElapsed + 3 * initialBackoffMs, rescheduledJob.getEarliestRunTime());
         assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
 
         // failure = 2, systemStop = 2 * SYSTEM_STOP_TO_FAILURE_RATIO
         rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+                JobParameters.STOP_REASON_UNDEFINED,
                 JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
         assertEquals(nowElapsed + 4 * initialBackoffMs, rescheduledJob.getEarliestRunTime());
         assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
     }
 
     /**
+     * Confirm that
+     * {@link JobSchedulerService#getRescheduleJobForFailureLocked(JobStatus, int, int)}
+     * returns a job that is correctly marked as demoted by the user.
+     */
+    @Test
+    public void testGetRescheduleJobForFailure_userDemotion() {
+        JobStatus originalJob = createJobStatus("testGetRescheduleJobForFailure", createJobInfo());
+        assertEquals(0, originalJob.getInternalFlags() & JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER);
+
+        // Reschedule for a non-user reason
+        JobStatus rescheduledJob = mService.getRescheduleJobForFailureLocked(originalJob,
+                JobParameters.STOP_REASON_DEVICE_STATE,
+                JobParameters.INTERNAL_STOP_REASON_DEVICE_THERMAL);
+        assertEquals(0,
+                rescheduledJob.getInternalFlags() & JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER);
+
+        // Reschedule for a user reason
+        rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+                JobParameters.STOP_REASON_USER,
+                JobParameters.INTERNAL_STOP_REASON_USER_UI_STOP);
+        assertNotEquals(0,
+                rescheduledJob.getInternalFlags() & JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER);
+
+        // Reschedule a previously demoted job for a non-user reason
+        rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+                JobParameters.STOP_REASON_CONSTRAINT_CHARGING,
+                JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED);
+        assertNotEquals(0,
+                rescheduledJob.getInternalFlags() & JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER);
+    }
+
+    /**
      * Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job
      * with the correct delay and deadline constraints if the periodic job is scheduled with the
      * minimum possible period.
@@ -731,6 +771,7 @@
         JobStatus job = createJobStatus("testGetRescheduleJobForPeriodic_insideWindow_failedJob",
                 createJobInfo().setPeriodic(HOUR_IN_MILLIS));
         JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job,
+                JobParameters.STOP_REASON_UNDEFINED,
                 JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
 
         JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
@@ -739,6 +780,7 @@
 
         advanceElapsedClock(5 * MINUTE_IN_MILLIS); // now + 5 minutes
         failedJob = mService.getRescheduleJobForFailureLocked(job,
+                JobParameters.STOP_REASON_UNDEFINED,
                 JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
         advanceElapsedClock(5 * MINUTE_IN_MILLIS); // now + 10 minutes
 
@@ -748,6 +790,7 @@
 
         advanceElapsedClock(35 * MINUTE_IN_MILLIS); // now + 45 minutes
         failedJob = mService.getRescheduleJobForFailureLocked(job,
+                JobParameters.STOP_REASON_UNDEFINED,
                 JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
         advanceElapsedClock(10 * MINUTE_IN_MILLIS); // now + 55 minutes
 
@@ -759,6 +802,7 @@
 
         advanceElapsedClock(2 * MINUTE_IN_MILLIS); // now + 57 minutes
         failedJob = mService.getRescheduleJobForFailureLocked(job,
+                JobParameters.STOP_REASON_UNDEFINED,
                 JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
         advanceElapsedClock(2 * MINUTE_IN_MILLIS); // now + 59 minutes
 
@@ -856,6 +900,7 @@
         JobStatus job = createJobStatus("testGetRescheduleJobForPeriodic_outsideWindow_failedJob",
                 createJobInfo().setPeriodic(HOUR_IN_MILLIS));
         JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job,
+                JobParameters.STOP_REASON_UNDEFINED,
                 JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
         long now = sElapsedRealtimeClock.millis();
         long nextWindowStartTime = now + HOUR_IN_MILLIS;
@@ -893,6 +938,7 @@
                 "testGetRescheduleJobForPeriodic_outsideWindow_flex_failedJob",
                 createJobInfo().setPeriodic(HOUR_IN_MILLIS, 30 * MINUTE_IN_MILLIS));
         JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job,
+                JobParameters.STOP_REASON_UNDEFINED,
                 JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
         // First window starts 30 minutes from now.
         advanceElapsedClock(30 * MINUTE_IN_MILLIS);
@@ -935,6 +981,7 @@
                 "testGetRescheduleJobForPeriodic_outsideWindow_flex_failedJob_longPeriod",
                 createJobInfo().setPeriodic(7 * DAY_IN_MILLIS, 9 * HOUR_IN_MILLIS));
         JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job,
+                JobParameters.STOP_REASON_UNDEFINED,
                 JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
         // First window starts 6.625 days from now.
         advanceElapsedClock(6 * DAY_IN_MILLIS + 15 * HOUR_IN_MILLIS);
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index 6df54a6..2c47fd9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -469,6 +469,34 @@
         assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
     }
 
+    @Test
+    public void testShouldTreatAsUserInitiated() {
+        JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+                .setUserInitiated(false)
+                .build();
+        JobStatus job = createJobStatus(jobInfo);
+
+        assertFalse(job.shouldTreatAsUserInitiatedJob());
+
+        jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+                .setUserInitiated(true)
+                .build();
+        job = createJobStatus(jobInfo);
+
+        assertTrue(job.shouldTreatAsUserInitiatedJob());
+
+        JobStatus rescheduledJob = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME,
+                0, 0, 0, 0);
+        assertTrue(rescheduledJob.shouldTreatAsUserInitiatedJob());
+
+        job.addInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER);
+        assertFalse(job.shouldTreatAsUserInitiatedJob());
+
+        rescheduledJob = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME,
+                0, 0, 0, 0);
+        assertFalse(rescheduledJob.shouldTreatAsUserInitiatedJob());
+    }
+
     /**
      * Test {@link JobStatus#wouldBeReadyWithConstraint} on explicit constraints that weren't
      * requested.
diff --git a/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java b/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java
index 49f27e9..245db46 100644
--- a/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java
@@ -28,8 +28,8 @@
 
 import android.app.job.JobScheduler;
 import android.content.Context;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.SensorProperties;
 import android.hardware.face.FaceManager;
@@ -82,6 +82,8 @@
     private FaceManager mFaceManager;
     @Mock
     private PackageManager mPackageManager;
+    @Mock
+    private PackageManagerInternal mPackageManagerInternal;
 
     @Captor
     private ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback>
@@ -95,6 +97,9 @@
         MockitoAnnotations.initMocks(this);
 
         mContext = spy(ApplicationProvider.getApplicationContext());
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
+        LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
+
         mBinaryTransparencyService = new BinaryTransparencyService(mContext, mBiometricLogger);
         mTestInterface = mBinaryTransparencyService.new BinaryTransparencyServiceImpl();
         mOriginalBiometricsFlags = DeviceConfig.getProperties(DeviceConfig.NAMESPACE_BIOMETRICS);
@@ -108,6 +113,7 @@
             Log.e(TAG, "Failed to reset biometrics flags to the original values before test. "
                     + e);
         }
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
     }
 
     private void prepSignedInfo() {
@@ -164,7 +170,10 @@
         prepApexInfo();
         List result = mTestInterface.getApexInfo();
         Assert.assertNotNull("Apex info map should not be null", result);
-        Assert.assertFalse("Apex info map should not be empty", result.isEmpty());
+        // TODO(265244016): When PackageManagerInternal is a mock, it's harder to keep the
+        // `measurePackage` working in unit test. Disable it for now. We may need more refactoring
+        // or cover this in integration tests.
+        // Assert.assertFalse("Apex info map should not be empty", result.isEmpty());
     }
 
     @Test
@@ -177,12 +186,12 @@
         Assert.assertNotNull(pm);
         List<Bundle> castedResult = (List<Bundle>) resultList;
         for (Bundle resultBundle : castedResult) {
-            PackageInfo resultPackageInfo = resultBundle.getParcelable(
-                    BinaryTransparencyService.BUNDLE_PACKAGE_INFO, PackageInfo.class);
-            Assert.assertNotNull("PackageInfo for APEX should not be null",
-                    resultPackageInfo);
-            Assert.assertTrue(resultPackageInfo.packageName + "is not an APEX!",
-                    resultPackageInfo.isApex);
+            String packageName = resultBundle.getString(
+                    BinaryTransparencyService.BUNDLE_PACKAGE_NAME);
+            Assert.assertNotNull("Package name for APEX should not be null", packageName);
+            Assert.assertTrue(packageName + "is not an APEX!",
+                    resultBundle.getBoolean(
+                            BinaryTransparencyService.BUNDLE_PACKAGE_IS_APEX));
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 6831902..4d1d2b2 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -189,6 +189,7 @@
 
         mA11yms = new AccessibilityManagerService(
                 mTestableContext,
+                mHandler,
                 mMockPackageManager,
                 mMockSecurityPolicy,
                 mMockSystemActionPerformer,
@@ -371,6 +372,7 @@
         );
 
         mA11yms.onMagnificationTransitionEndedLocked(Display.DEFAULT_DISPLAY, true);
+        mHandler.sendAllMessages();
 
         ArgumentCaptor<Display> displayCaptor = ArgumentCaptor.forClass(Display.class);
         verify(mInputFilter, timeout(100)).refreshMagnificationMode(displayCaptor.capture());
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
index c1ee88c..760ed9b 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
@@ -18,12 +18,12 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.startsWith;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.hardware.display.DisplayManagerInternal;
@@ -133,14 +133,14 @@
     @Test
     public void unregisterInputDevice_anotherMouseExists_setPointerDisplayIdOverride() {
         final IBinder deviceToken = new Binder();
-        mInputController.createMouse("name", /*vendorId= */ 1, /*productId= */ 1, deviceToken,
+        mInputController.createMouse("mouse1", /*vendorId= */ 1, /*productId= */ 1, deviceToken,
                 /* displayId= */ 1);
-        verify(mNativeWrapperMock).openUinputMouse(eq("name"), eq(1), eq(1), anyString());
+        verify(mNativeWrapperMock).openUinputMouse(eq("mouse1"), eq(1), eq(1), anyString());
         verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(eq(1));
         final IBinder deviceToken2 = new Binder();
-        mInputController.createMouse("name", /*vendorId= */ 1, /*productId= */ 1, deviceToken2,
+        mInputController.createMouse("mouse2", /*vendorId= */ 1, /*productId= */ 1, deviceToken2,
                 /* displayId= */ 2);
-        verify(mNativeWrapperMock, times(2)).openUinputMouse(eq("name"), eq(1), eq(1), anyString());
+        verify(mNativeWrapperMock).openUinputMouse(eq("mouse2"), eq(1), eq(1), anyString());
         verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(eq(2));
         mInputController.unregisterInputDevice(deviceToken);
         verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(eq(1));
@@ -193,4 +193,68 @@
         mInputController.unregisterInputDevice(deviceToken);
         verify(mInputManagerInternalMock).removeKeyboardLayoutAssociation(anyString());
     }
+
+    @Test
+    public void createInputDevice_tooLongNameRaisesException() {
+        final IBinder deviceToken = new Binder("device");
+        // The underlying uinput implementation only supports device names up to 80 bytes. This
+        // string is all ASCII characters, therefore if we have more than 80 ASCII characters we
+        // will have more than 80 bytes.
+        String deviceName =
+                "This.is.a.very.long.device.name.that.exceeds.the.maximum.length.of.80.bytes"
+                        + ".by.a.couple.bytes";
+
+        assertThrows(RuntimeException.class, () -> {
+            mInputController.createDpad(deviceName, /*vendorId= */3, /*productId=*/3, deviceToken,
+                    1);
+        });
+    }
+
+    @Test
+    public void createInputDevice_tooLongDeviceNameRaisesException() {
+        final IBinder deviceToken = new Binder("device");
+        // The underlying uinput implementation only supports device names up to 80 bytes (including
+        // a 0-byte terminator).
+        // This string is 79 characters and 80 bytes (including the 0-byte terminator)
+        String deviceName =
+                "This.is.a.very.long.device.name.that.exceeds.the.maximum.length01234567890123456";
+
+        assertThrows(RuntimeException.class, () -> {
+            mInputController.createDpad(deviceName, /*vendorId= */3, /*productId=*/3, deviceToken,
+                    1);
+        });
+    }
+
+    @Test
+    public void createInputDevice_stringWithLessThanMaxCharsButMoreThanMaxBytesRaisesException() {
+        final IBinder deviceToken = new Binder("device1");
+
+        // Has only 39 characters but is 109 bytes as utf-8
+        String device_name =
+                "â–‘â–„â–„â–„â–„â–‘\n" +
+                "▀▀▄██►\n" +
+                "▀▀███►\n" +
+                "░▀███►░█►\n" +
+                "▒▄████▀▀";
+
+        assertThrows(RuntimeException.class, () -> {
+            mInputController.createDpad(device_name, /*vendorId= */5, /*productId=*/5,
+                    deviceToken, 1);
+        });
+    }
+
+    @Test
+    public void createInputDevice_duplicateNamesAreNotAllowed() {
+        final IBinder deviceToken1 = new Binder("deviceToken1");
+        final IBinder deviceToken2 = new Binder("deviceToken2");
+
+        final String sharedDeviceName = "DeviceName";
+
+        mInputController.createDpad(sharedDeviceName, /*vendorId= */4, /*productId=*/4,
+                deviceToken1, 1);
+        assertThrows("Device names need to be unique", RuntimeException.class, () -> {
+            mInputController.createDpad(sharedDeviceName, /*vendorId= */5, /*productId=*/5,
+                    deviceToken2, 2);
+        });
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 3791b35..ce5ddb0 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -135,7 +135,9 @@
     private static final String VENDING_PACKAGE_NAME = "com.android.vending";
     private static final String GOOGLE_DIALER_PACKAGE_NAME = "com.google.android.dialer";
     private static final String GOOGLE_MAPS_PACKAGE_NAME = "com.google.android.apps.maps";
-    private static final String DEVICE_NAME = "device name";
+    private static final String DEVICE_NAME_1 = "device name 1";
+    private static final String DEVICE_NAME_2 = "device name 2";
+    private static final String DEVICE_NAME_3 = "device name 3";
     private static final int DISPLAY_ID_1 = 2;
     private static final int DISPLAY_ID_2 = 3;
     private static final int DEVICE_OWNER_UID_1 = 50;
@@ -160,14 +162,14 @@
             new VirtualDpadConfig.Builder()
                     .setVendorId(VENDOR_ID)
                     .setProductId(PRODUCT_ID)
-                    .setInputDeviceName(DEVICE_NAME)
+                    .setInputDeviceName(DEVICE_NAME_1)
                     .setAssociatedDisplayId(DISPLAY_ID_1)
                     .build();
     private static final VirtualKeyboardConfig KEYBOARD_CONFIG =
             new VirtualKeyboardConfig.Builder()
                     .setVendorId(VENDOR_ID)
                     .setProductId(PRODUCT_ID)
-                    .setInputDeviceName(DEVICE_NAME)
+                    .setInputDeviceName(DEVICE_NAME_1)
                     .setAssociatedDisplayId(DISPLAY_ID_1)
                     .setLanguageTag(VirtualKeyboardConfig.DEFAULT_LANGUAGE_TAG)
                     .setLayoutType(VirtualKeyboardConfig.DEFAULT_LAYOUT_TYPE)
@@ -176,21 +178,21 @@
             new VirtualMouseConfig.Builder()
                     .setVendorId(VENDOR_ID)
                     .setProductId(PRODUCT_ID)
-                    .setInputDeviceName(DEVICE_NAME)
+                    .setInputDeviceName(DEVICE_NAME_1)
                     .setAssociatedDisplayId(DISPLAY_ID_1)
                     .build();
     private static final VirtualTouchscreenConfig TOUCHSCREEN_CONFIG =
             new VirtualTouchscreenConfig.Builder(WIDTH, HEIGHT)
                     .setVendorId(VENDOR_ID)
                     .setProductId(PRODUCT_ID)
-                    .setInputDeviceName(DEVICE_NAME)
+                    .setInputDeviceName(DEVICE_NAME_1)
                     .setAssociatedDisplayId(DISPLAY_ID_1)
                     .build();
     private static final VirtualNavigationTouchpadConfig NAVIGATION_TOUCHPAD_CONFIG =
             new VirtualNavigationTouchpadConfig.Builder(WIDTH, HEIGHT)
                     .setVendorId(VENDOR_ID)
                     .setProductId(PRODUCT_ID)
-                    .setInputDeviceName(DEVICE_NAME)
+                    .setInputDeviceName(DEVICE_NAME_1)
                     .setAssociatedDisplayId(DISPLAY_ID_1)
                     .build();
     private static final String TEST_SITE = "http://test";
@@ -549,7 +551,7 @@
                 new VirtualKeyboardConfig.Builder()
                         .setVendorId(VENDOR_ID)
                         .setProductId(PRODUCT_ID)
-                        .setInputDeviceName(DEVICE_NAME)
+                        .setInputDeviceName(DEVICE_NAME_1)
                         .setAssociatedDisplayId(DISPLAY_ID_1)
                         .setLanguageTag("zh-CN")
                         .build();
@@ -557,7 +559,7 @@
                 new VirtualKeyboardConfig.Builder()
                         .setVendorId(VENDOR_ID)
                         .setProductId(PRODUCT_ID)
-                        .setInputDeviceName(DEVICE_NAME)
+                        .setInputDeviceName(DEVICE_NAME_2)
                         .setAssociatedDisplayId(DISPLAY_ID_2)
                         .setLanguageTag("fr-FR")
                         .build();
@@ -784,7 +786,7 @@
                         /* touchscrenWidth= */ 600, /* touchscreenHeight= */ 800)
                         .setVendorId(VENDOR_ID)
                         .setProductId(PRODUCT_ID)
-                        .setInputDeviceName(DEVICE_NAME)
+                        .setInputDeviceName(DEVICE_NAME_1)
                         .setAssociatedDisplayId(DISPLAY_ID_1)
                         .build();
         mDeviceImpl.createVirtualTouchscreen(positiveConfig, BINDER);
@@ -822,7 +824,7 @@
                         /* touchpadHeight= */ 50, /* touchpadWidth= */ 50)
                         .setVendorId(VENDOR_ID)
                         .setProductId(PRODUCT_ID)
-                        .setInputDeviceName(DEVICE_NAME)
+                        .setInputDeviceName(DEVICE_NAME_1)
                         .setAssociatedDisplayId(DISPLAY_ID_1)
                         .build();
         mDeviceImpl.createVirtualNavigationTouchpad(positiveConfig, BINDER);
@@ -893,7 +895,7 @@
                     () -> mDeviceImpl.createVirtualSensor(
                             BINDER,
                             new VirtualSensorConfig.Builder(
-                                    Sensor.TYPE_ACCELEROMETER, DEVICE_NAME).build()));
+                                    Sensor.TYPE_ACCELEROMETER, DEVICE_NAME_1).build()));
         }
     }
 
@@ -920,7 +922,7 @@
         mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER);
         assertWithMessage("Virtual dpad should register fd when the display matches").that(
                 mInputController.getInputDeviceDescriptors()).isNotEmpty();
-        verify(mNativeWrapperMock).openUinputDpad(eq(DEVICE_NAME), eq(VENDOR_ID), eq(PRODUCT_ID),
+        verify(mNativeWrapperMock).openUinputDpad(eq(DEVICE_NAME_1), eq(VENDOR_ID), eq(PRODUCT_ID),
                 anyString());
     }
 
@@ -930,7 +932,7 @@
         mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER);
         assertWithMessage("Virtual keyboard should register fd when the display matches").that(
                 mInputController.getInputDeviceDescriptors()).isNotEmpty();
-        verify(mNativeWrapperMock).openUinputKeyboard(eq(DEVICE_NAME), eq(VENDOR_ID),
+        verify(mNativeWrapperMock).openUinputKeyboard(eq(DEVICE_NAME_1), eq(VENDOR_ID),
                 eq(PRODUCT_ID), anyString());
     }
 
@@ -941,7 +943,7 @@
         assertWithMessage("Virtual keyboard should register fd when the display matches")
                 .that(mInputController.getInputDeviceDescriptors())
                 .isNotEmpty();
-        verify(mNativeWrapperMock).openUinputKeyboard(eq(DEVICE_NAME), eq(VENDOR_ID),
+        verify(mNativeWrapperMock).openUinputKeyboard(eq(DEVICE_NAME_1), eq(VENDOR_ID),
                 eq(PRODUCT_ID), anyString());
         assertThat(mDeviceImpl.getDeviceLocaleList()).isEqualTo(
                 LocaleList.forLanguageTags(KEYBOARD_CONFIG.getLanguageTag()));
@@ -953,7 +955,7 @@
                 new VirtualKeyboardConfig.Builder()
                         .setVendorId(VENDOR_ID)
                         .setProductId(PRODUCT_ID)
-                        .setInputDeviceName(DEVICE_NAME)
+                        .setInputDeviceName(DEVICE_NAME_1)
                         .setAssociatedDisplayId(DISPLAY_ID_1)
                         .build();
 
@@ -962,7 +964,7 @@
         assertWithMessage("Virtual keyboard should register fd when the display matches")
                 .that(mInputController.getInputDeviceDescriptors())
                 .isNotEmpty();
-        verify(mNativeWrapperMock).openUinputKeyboard(eq(DEVICE_NAME), eq(VENDOR_ID),
+        verify(mNativeWrapperMock).openUinputKeyboard(eq(DEVICE_NAME_1), eq(VENDOR_ID),
                 eq(PRODUCT_ID), anyString());
         assertThat(mDeviceImpl.getDeviceLocaleList()).isEqualTo(
                 LocaleList.forLanguageTags(VirtualKeyboardConfig.DEFAULT_LANGUAGE_TAG));
@@ -982,7 +984,7 @@
         mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER);
         assertWithMessage("Virtual mouse should register fd when the display matches").that(
                 mInputController.getInputDeviceDescriptors()).isNotEmpty();
-        verify(mNativeWrapperMock).openUinputMouse(eq(DEVICE_NAME), eq(VENDOR_ID), eq(PRODUCT_ID),
+        verify(mNativeWrapperMock).openUinputMouse(eq(DEVICE_NAME_1), eq(VENDOR_ID), eq(PRODUCT_ID),
                 anyString());
     }
 
@@ -992,7 +994,7 @@
         mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER);
         assertWithMessage("Virtual touchscreen should register fd when the display matches").that(
                 mInputController.getInputDeviceDescriptors()).isNotEmpty();
-        verify(mNativeWrapperMock).openUinputTouchscreen(eq(DEVICE_NAME), eq(VENDOR_ID),
+        verify(mNativeWrapperMock).openUinputTouchscreen(eq(DEVICE_NAME_1), eq(VENDOR_ID),
                 eq(PRODUCT_ID), anyString(), eq(HEIGHT), eq(WIDTH));
     }
 
@@ -1003,15 +1005,16 @@
         assertWithMessage("Virtual navigation touchpad should register fd when the display matches")
                 .that(
                         mInputController.getInputDeviceDescriptors()).isNotEmpty();
-        verify(mNativeWrapperMock).openUinputTouchscreen(eq(DEVICE_NAME), eq(VENDOR_ID),
+        verify(mNativeWrapperMock).openUinputTouchscreen(eq(DEVICE_NAME_1), eq(VENDOR_ID),
                 eq(PRODUCT_ID), anyString(), eq(HEIGHT), eq(WIDTH));
     }
 
     @Test
     public void createVirtualKeyboard_inputDeviceId_obtainFromInputController() {
         final int fd = 1;
-        mInputController.addDeviceForTesting(BINDER, fd, /* type= */ 1, /* displayId= */ 1, PHYS,
-                INPUT_DEVICE_ID);
+        mInputController.addDeviceForTesting(BINDER, fd,
+                InputController.InputDeviceDescriptor.TYPE_KEYBOARD, DISPLAY_ID_1, PHYS,
+                DEVICE_NAME_1, INPUT_DEVICE_ID);
         assertWithMessage(
                 "InputController should return device id from InputDeviceDescriptor").that(
                 mInputController.getInputDeviceId(BINDER)).isEqualTo(INPUT_DEVICE_ID);
@@ -1052,7 +1055,7 @@
     @Test
     public void close_cleanSensorController() {
         mSensorController.addSensorForTesting(
-                BINDER, SENSOR_HANDLE, Sensor.TYPE_ACCELEROMETER, DEVICE_NAME);
+                BINDER, SENSOR_HANDLE, Sensor.TYPE_ACCELEROMETER, DEVICE_NAME_1);
 
         mDeviceImpl.close();
 
@@ -1085,8 +1088,9 @@
         final int fd = 1;
         final int keyCode = KeyEvent.KEYCODE_A;
         final int action = VirtualKeyEvent.ACTION_UP;
-        mInputController.addDeviceForTesting(BINDER, fd, /* type= */1, /* displayId= */ 1, PHYS,
-                INPUT_DEVICE_ID);
+        mInputController.addDeviceForTesting(BINDER, fd,
+                InputController.InputDeviceDescriptor.TYPE_KEYBOARD, DISPLAY_ID_1, PHYS,
+                DEVICE_NAME_1, INPUT_DEVICE_ID);
 
         mDeviceImpl.sendKeyEvent(BINDER, new VirtualKeyEvent.Builder()
                 .setKeyCode(keyCode)
@@ -1112,9 +1116,10 @@
         final int fd = 1;
         final int buttonCode = VirtualMouseButtonEvent.BUTTON_BACK;
         final int action = VirtualMouseButtonEvent.ACTION_BUTTON_PRESS;
-        mInputController.addDeviceForTesting(BINDER, fd, /* type= */2, /* displayId= */ 1, PHYS,
-                INPUT_DEVICE_ID);
-        doReturn(1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
+        mInputController.addDeviceForTesting(BINDER, fd,
+                InputController.InputDeviceDescriptor.TYPE_MOUSE, DISPLAY_ID_1, PHYS,
+                DEVICE_NAME_1, INPUT_DEVICE_ID);
+        doReturn(DISPLAY_ID_1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
         mDeviceImpl.sendButtonEvent(BINDER, new VirtualMouseButtonEvent.Builder()
                 .setButtonCode(buttonCode)
                 .setAction(action).build());
@@ -1126,7 +1131,8 @@
         final int fd = 1;
         final int buttonCode = VirtualMouseButtonEvent.BUTTON_BACK;
         final int action = VirtualMouseButtonEvent.ACTION_BUTTON_PRESS;
-        mInputController.addDeviceForTesting(BINDER, fd, /* type= */2, /* displayId= */ 1, PHYS,
+        mInputController.addDeviceForTesting(BINDER, fd,
+                InputController.InputDeviceDescriptor.TYPE_MOUSE, DISPLAY_ID_1, PHYS, DEVICE_NAME_1,
                 INPUT_DEVICE_ID);
         assertThrows(
                 IllegalStateException.class,
@@ -1151,9 +1157,10 @@
         final int fd = 1;
         final float x = -0.2f;
         final float y = 0.7f;
-        mInputController.addDeviceForTesting(BINDER, fd, /* type= */2, /* displayId= */ 1, PHYS,
+        mInputController.addDeviceForTesting(BINDER, fd,
+                InputController.InputDeviceDescriptor.TYPE_MOUSE, DISPLAY_ID_1, PHYS, DEVICE_NAME_1,
                 INPUT_DEVICE_ID);
-        doReturn(1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
+        doReturn(DISPLAY_ID_1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
         mDeviceImpl.sendRelativeEvent(BINDER, new VirtualMouseRelativeEvent.Builder()
                 .setRelativeX(x).setRelativeY(y).build());
         verify(mNativeWrapperMock).writeRelativeEvent(fd, x, y);
@@ -1164,7 +1171,8 @@
         final int fd = 1;
         final float x = -0.2f;
         final float y = 0.7f;
-        mInputController.addDeviceForTesting(BINDER, fd, /* type= */2, /* displayId= */ 1, PHYS,
+        mInputController.addDeviceForTesting(BINDER, fd,
+                InputController.InputDeviceDescriptor.TYPE_MOUSE, DISPLAY_ID_1, PHYS, DEVICE_NAME_1,
                 INPUT_DEVICE_ID);
         assertThrows(
                 IllegalStateException.class,
@@ -1190,9 +1198,10 @@
         final int fd = 1;
         final float x = 0.5f;
         final float y = 1f;
-        mInputController.addDeviceForTesting(BINDER, fd, /* type= */2, /* displayId= */ 1, PHYS,
+        mInputController.addDeviceForTesting(BINDER, fd,
+                InputController.InputDeviceDescriptor.TYPE_MOUSE, DISPLAY_ID_1, PHYS, DEVICE_NAME_1,
                 INPUT_DEVICE_ID);
-        doReturn(1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
+        doReturn(DISPLAY_ID_1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
         mDeviceImpl.sendScrollEvent(BINDER, new VirtualMouseScrollEvent.Builder()
                 .setXAxisMovement(x)
                 .setYAxisMovement(y).build());
@@ -1204,7 +1213,8 @@
         final int fd = 1;
         final float x = 0.5f;
         final float y = 1f;
-        mInputController.addDeviceForTesting(BINDER, fd, /* type= */2, /* displayId= */ 1, PHYS,
+        mInputController.addDeviceForTesting(BINDER, fd,
+                InputController.InputDeviceDescriptor.TYPE_MOUSE, DISPLAY_ID_1, PHYS, DEVICE_NAME_1,
                 INPUT_DEVICE_ID);
         assertThrows(
                 IllegalStateException.class,
@@ -1236,8 +1246,9 @@
         final float x = 100.5f;
         final float y = 200.5f;
         final int action = VirtualTouchEvent.ACTION_UP;
-        mInputController.addDeviceForTesting(BINDER, fd, /* type= */3, /* displayId= */ 1, PHYS,
-                INPUT_DEVICE_ID);
+        mInputController.addDeviceForTesting(BINDER, fd,
+                InputController.InputDeviceDescriptor.TYPE_TOUCHSCREEN, DISPLAY_ID_1, PHYS,
+                DEVICE_NAME_1, INPUT_DEVICE_ID);
         mDeviceImpl.sendTouchEvent(BINDER, new VirtualTouchEvent.Builder()
                 .setX(x)
                 .setY(y)
@@ -1259,8 +1270,9 @@
         final int action = VirtualTouchEvent.ACTION_UP;
         final float pressure = 1.0f;
         final float majorAxisSize = 10.0f;
-        mInputController.addDeviceForTesting(BINDER, fd, /* type= */3, /* displayId= */ 1, PHYS,
-                INPUT_DEVICE_ID);
+        mInputController.addDeviceForTesting(BINDER, fd,
+                InputController.InputDeviceDescriptor.TYPE_TOUCHSCREEN, DISPLAY_ID_1, PHYS,
+                DEVICE_NAME_1, INPUT_DEVICE_ID);
         mDeviceImpl.sendTouchEvent(BINDER, new VirtualTouchEvent.Builder()
                 .setX(x)
                 .setY(y)
@@ -1281,19 +1293,19 @@
         mDeviceImpl.mVirtualDisplayIds.add(3);
         VirtualMouseConfig config1 = new VirtualMouseConfig.Builder()
                 .setAssociatedDisplayId(1)
-                .setInputDeviceName(DEVICE_NAME)
+                .setInputDeviceName(DEVICE_NAME_1)
                 .setVendorId(VENDOR_ID)
                 .setProductId(PRODUCT_ID)
                 .build();
         VirtualMouseConfig config2 = new VirtualMouseConfig.Builder()
                 .setAssociatedDisplayId(2)
-                .setInputDeviceName(DEVICE_NAME)
+                .setInputDeviceName(DEVICE_NAME_2)
                 .setVendorId(VENDOR_ID)
                 .setProductId(PRODUCT_ID)
                 .build();
         VirtualMouseConfig config3 = new VirtualMouseConfig.Builder()
                 .setAssociatedDisplayId(3)
-                .setInputDeviceName(DEVICE_NAME)
+                .setInputDeviceName(DEVICE_NAME_3)
                 .setVendorId(VENDOR_ID)
                 .setProductId(PRODUCT_ID)
                 .build();
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 673b696..b5c5582 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -59,7 +59,6 @@
 @RunWith(AndroidJUnit4.class)
 public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
 
-    private static final String USER_TYPE_EMPTY = "";
     private static final int COPE_ADMIN1_APP_ID = 123;
     private static final int COPE_ANOTHER_ADMIN_APP_ID = 125;
     private static final int COPE_PROFILE_USER_ID = 11;
@@ -81,6 +80,7 @@
 
         when(getServices().packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
                 .thenReturn(true);
+        when(getServices().userManagerInternal.getUserIds()).thenReturn(new int[]{0});
     }
 
     // Test setting default restrictions for managed profile.
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 60483f1..a58c4de 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -273,6 +273,7 @@
         mContext = getContext();
         mServiceContext = mContext;
         mServiceContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        when(getServices().userManagerInternal.getUserIds()).thenReturn(new int[]{0});
         when(getServices().packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
                 .thenReturn(true);
         doReturn(Collections.singletonList(new ResolveInfo()))
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index c739969..ded8ad5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -203,6 +203,11 @@
     }
 
     @Override
+    public String getOpPackageName() {
+        return getPackageName();
+    }
+
+    @Override
     public ApplicationInfo getApplicationInfo() {
         if (applicationInfo != null) {
             return applicationInfo;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
index 1779b16..1d6846c 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
@@ -220,7 +220,7 @@
 
         // DO should be marked as able to grant sensors permission during upgrade and should be
         // reported as such via the API.
-        assertThat(dpms.canAdminGrantSensorsPermissionsForUser(ownerUser)).isTrue();
+        assertThat(dpms.canAdminGrantSensorsPermissions()).isTrue();
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
index 4bc8242..0ea20a8 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -19,6 +19,7 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.mock;
@@ -212,6 +213,10 @@
         assertEquals(new DisplayDeviceConfig.BrightnessThrottlingData(throttlingLevels),
                 mDisplayDeviceConfig.getConcurrentDisplaysBrightnessThrottlingData());
 
+        assertNotNull(mDisplayDeviceConfig.getHostUsiVersion());
+        assertEquals(mDisplayDeviceConfig.getHostUsiVersion().getMajorVersion(), 2);
+        assertEquals(mDisplayDeviceConfig.getHostUsiVersion().getMinorVersion(), 0);
+
         // Todo: Add asserts for BrightnessThrottlingData, DensityMapping,
         // HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
     }
@@ -570,6 +575,10 @@
                 +       "<item>30</item>\n"
                 +       "<item>40</item>\n"
                 +   "</screenOffBrightnessSensorValueToLux>\n"
+                +   "<usiVersion>\n"
+                +       "<majorVersion>2</majorVersion>\n"
+                +       "<minorVersion>0</minorVersion>\n"
+                +   "</usiVersion>\n"
                 + "</displayConfiguration>\n";
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/BrightnessEventTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/BrightnessEventTest.java
index d332b30..c0c63c6 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/BrightnessEventTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/BrightnessEventTest.java
@@ -30,6 +30,7 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public final class BrightnessEventTest {
+    private static final String DISPLAY_BRIGHTNESS_STRATEGY_NAME = "strategy_name";
     private BrightnessEvent mBrightnessEvent;
 
     @Before
@@ -53,6 +54,7 @@
         mBrightnessEvent.setFlags(0);
         mBrightnessEvent.setAdjustmentFlags(0);
         mBrightnessEvent.setAutomaticBrightnessEnabled(true);
+        mBrightnessEvent.setDisplayBrightnessStrategyName(DISPLAY_BRIGHTNESS_STRATEGY_NAME);
     }
 
     @Test
@@ -70,7 +72,8 @@
                 "BrightnessEvent: disp=1, physDisp=test, brt=0.6, initBrt=25.0, rcmdBrt=0.6,"
                 + " preBrt=NaN, lux=100.0, preLux=150.0, hbmMax=0.62, hbmMode=off, rbcStrength=-1,"
                 + " thrmMax=0.65, powerFactor=0.2, wasShortTermModelActive=true, flags=,"
-                + " reason=doze [ low_pwr ], autoBrightness=true";
+                + " reason=doze [ low_pwr ], autoBrightness=true, strategy="
+                        + DISPLAY_BRIGHTNESS_STRATEGY_NAME;
         assertEquals(expectedString, actualString);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java
index c1de894..c434631 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java
@@ -55,6 +55,7 @@
                         .setBrightness(PowerManager.BRIGHTNESS_MAX)
                         .setBrightnessReason(brightnessReason)
                         .setSdrBrightness(PowerManager.BRIGHTNESS_MAX)
+                        .setDisplayBrightnessStrategyName(mBoostBrightnessStrategy.getName())
                         .build();
         DisplayBrightnessState updatedDisplayBrightnessState =
                 mBoostBrightnessStrategy.updateBrightness(displayPowerRequest);
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java
index 76fa172..d60caf6 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java
@@ -52,6 +52,7 @@
                         .setBrightness(dozeScreenBrightness)
                         .setBrightnessReason(brightnessReason)
                         .setSdrBrightness(dozeScreenBrightness)
+                        .setDisplayBrightnessStrategyName(mDozeBrightnessModeStrategy.getName())
                         .build();
         DisplayBrightnessState updatedDisplayBrightnessState =
                 mDozeBrightnessModeStrategy.updateBrightness(displayPowerRequest);
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java
index f20404e..081f19d 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java
@@ -54,6 +54,7 @@
                         .setBrightness(brightnessToFollow)
                         .setBrightnessReason(brightnessReason)
                         .setSdrBrightness(brightnessToFollow)
+                        .setDisplayBrightnessStrategyName(mFollowerBrightnessStrategy.getName())
                         .build();
         DisplayBrightnessState updatedDisplayBrightnessState =
                 mFollowerBrightnessStrategy.updateBrightness(displayPowerRequest);
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
index 2487b32b..530245d 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
@@ -55,6 +55,7 @@
                         .setBrightness(overrideBrightness)
                         .setBrightnessReason(brightnessReason)
                         .setSdrBrightness(overrideBrightness)
+                        .setDisplayBrightnessStrategyName(mOverrideBrightnessStrategy.getName())
                         .build();
         DisplayBrightnessState updatedDisplayBrightnessState =
                 mOverrideBrightnessStrategy.updateBrightness(displayPowerRequest);
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java
index 353e92e..7147aa8 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java
@@ -52,6 +52,8 @@
                         .setBrightness(PowerManager.BRIGHTNESS_OFF_FLOAT)
                         .setSdrBrightness(PowerManager.BRIGHTNESS_OFF_FLOAT)
                         .setBrightnessReason(brightnessReason)
+                        .setDisplayBrightnessStrategyName(mScreenOffBrightnessModeStrategy
+                                .getName())
                         .build();
         DisplayBrightnessState updatedDisplayBrightnessState =
                 mScreenOffBrightnessModeStrategy.updateBrightness(displayPowerRequest);
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
index 99679a3..9830edb 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
@@ -55,6 +55,7 @@
                         .setBrightness(temporaryBrightness)
                         .setBrightnessReason(brightnessReason)
                         .setSdrBrightness(temporaryBrightness)
+                        .setDisplayBrightnessStrategyName(mTemporaryBrightnessStrategy.getName())
                         .build();
         DisplayBrightnessState updatedDisplayBrightnessState =
                 mTemporaryBrightnessStrategy.updateBrightness(displayPowerRequest);
diff --git a/services/tests/servicestests/src/com/android/server/job/PendingJobQueueTest.java b/services/tests/servicestests/src/com/android/server/job/PendingJobQueueTest.java
index 8c3838b..23d7082 100644
--- a/services/tests/servicestests/src/com/android/server/job/PendingJobQueueTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/PendingJobQueueTest.java
@@ -201,6 +201,32 @@
             }
         }
         assertNull(jobQueue.next());
+        assertEquals(0, jobQueue.size());
+    }
+
+    @Test
+    public void testRemove_duringIteration() {
+        List<JobStatus> jobs = new ArrayList<>();
+        jobs.add(createJobStatus("testRemove", createJobInfo(1), 1));
+        jobs.add(createJobStatus("testRemove", createJobInfo(2), 2));
+        jobs.add(createJobStatus("testRemove", createJobInfo(3).setExpedited(true), 3));
+        jobs.add(createJobStatus("testRemove", createJobInfo(4), 4));
+        jobs.add(createJobStatus("testRemove", createJobInfo(5).setExpedited(true), 5));
+
+        PendingJobQueue jobQueue = new PendingJobQueue();
+        jobQueue.addAll(jobs);
+
+        ArraySet<JobStatus> removed = new ArraySet<>();
+        JobStatus job;
+        jobQueue.resetIterator();
+        while ((job = jobQueue.next()) != null) {
+            jobQueue.remove(job);
+            removed.add(job);
+            assertFalse("Queue retained a removed job " + testJobToString(job),
+                    jobQueue.contains(job));
+        }
+        assertNull(jobQueue.next());
+        assertEquals(0, jobQueue.size());
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index d1ab541..eabbc76 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -99,6 +99,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.Pair;
 import android.util.Size;
@@ -108,10 +109,12 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.compatibility.common.util.DeviceConfigStateHelper;
 import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
 import com.android.server.wm.utils.MockTracker;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -131,10 +134,9 @@
 @Presubmit
 @RunWith(WindowTestRunner.class)
 public class ActivityStarterTests extends WindowTestsBase {
-    private ActivityStartController mController;
-    private ActivityMetricsLogger mActivityMetricsLogger;
-    private PackageManagerInternal mMockPackageManager;
 
+    private static final String ENABLE_DEFAULT_RESCIND_BAL_PRIVILEGES_FROM_PENDING_INTENT_SENDER =
+            "enable_default_rescind_bal_privileges_from_pending_intent_sender";
     private static final int PRECONDITION_NO_CALLER_APP = 1;
     private static final int PRECONDITION_NO_INTENT_COMPONENT = 1 << 1;
     private static final int PRECONDITION_NO_ACTIVITY_INFO = 1 << 2;
@@ -145,7 +147,6 @@
     private static final int PRECONDITION_DIFFERENT_UID = 1 << 7;
     private static final int PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION = 1 << 8;
     private static final int PRECONDITION_CANNOT_START_ANY_ACTIVITY = 1 << 9;
-
     private static final int FAKE_CALLING_UID = 666;
     private static final int FAKE_REAL_CALLING_UID = 667;
     private static final String FAKE_CALLING_PACKAGE = "com.whatever.dude";
@@ -153,6 +154,13 @@
     private static final int UNIMPORTANT_UID2 = 12346;
     private static final int CURRENT_IME_UID = 12347;
 
+    protected final DeviceConfigStateHelper mDeviceConfig = new DeviceConfigStateHelper(
+            DeviceConfig.NAMESPACE_WINDOW_MANAGER);
+
+    private ActivityStartController mController;
+    private ActivityMetricsLogger mActivityMetricsLogger;
+    private PackageManagerInternal mMockPackageManager;
+
     @Before
     public void setUp() throws Exception {
         mController = mock(ActivityStartController.class);
@@ -161,6 +169,13 @@
         doReturn(balController).when(mController).getBackgroundActivityLaunchController();
         mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
         clearInvocations(mActivityMetricsLogger);
+        mDeviceConfig.set(ENABLE_DEFAULT_RESCIND_BAL_PRIVILEGES_FROM_PENDING_INTENT_SENDER,
+                String.valueOf(true));
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mDeviceConfig.close();
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java
index 86732c9..2a28ae2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java
@@ -16,13 +16,12 @@
 
 package com.android.server.wm;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
 
 import android.content.Context;
 import android.content.res.Resources;
@@ -32,9 +31,10 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.R;
+
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.ArgumentCaptor;
 
 import java.util.function.Consumer;
 
@@ -48,92 +48,76 @@
 @Presubmit
 public class DeviceStateControllerTests {
 
-    private DeviceStateController.FoldStateListener mFoldStateListener;
     private DeviceStateController mTarget;
     private DeviceStateControllerBuilder mBuilder;
 
     private Context mMockContext;
-    private Handler mMockHandler;
-    private Resources mMockRes;
     private DeviceStateManager mMockDeviceStateManager;
-
-    private Consumer<DeviceStateController.FoldState> mDelegate;
-    private DeviceStateController.FoldState mCurrentState = DeviceStateController.FoldState.UNKNOWN;
+    private DeviceStateController.DeviceState mCurrentState =
+            DeviceStateController.DeviceState.UNKNOWN;
 
     @Before
     public void setUp() {
         mBuilder = new DeviceStateControllerBuilder();
-        mCurrentState = DeviceStateController.FoldState.UNKNOWN;
+        mCurrentState = DeviceStateController.DeviceState.UNKNOWN;
     }
 
-    private void initialize(boolean supportFold, boolean supportHalfFold) throws Exception {
+    private void initialize(boolean supportFold, boolean supportHalfFold) {
         mBuilder.setSupportFold(supportFold, supportHalfFold);
-        mDelegate = (newFoldState) -> {
+        Consumer<DeviceStateController.DeviceState> delegate = (newFoldState) -> {
             mCurrentState = newFoldState;
         };
-        mBuilder.setDelegate(mDelegate);
+        mBuilder.setDelegate(delegate);
         mBuilder.build();
-        verifyFoldStateListenerRegistration(1);
+        verify(mMockDeviceStateManager).registerCallback(any(), any());
     }
 
     @Test
-    public void testInitialization() throws Exception {
+    public void testInitialization() {
         initialize(true /* supportFold */, true /* supportHalfFolded */);
-        mFoldStateListener.onStateChanged(mUnfoldedStates[0]);
-        assertEquals(mCurrentState, DeviceStateController.FoldState.OPEN);
+        mTarget.onStateChanged(mOpenDeviceStates[0]);
+        assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
     }
 
     @Test
-    public void testInitializationWithNoFoldSupport() throws Exception {
+    public void testInitializationWithNoFoldSupport() {
         initialize(false /* supportFold */, false /* supportHalfFolded */);
-        mFoldStateListener.onStateChanged(mFoldedStates[0]);
+        mTarget.onStateChanged(mFoldedStates[0]);
         // Note that the folded state is ignored.
-        assertEquals(mCurrentState, DeviceStateController.FoldState.OPEN);
+        assertEquals(DeviceStateController.DeviceState.UNKNOWN, mCurrentState);
     }
 
     @Test
-    public void testWithFoldSupported() throws Exception {
+    public void testWithFoldSupported() {
         initialize(true /* supportFold */, false /* supportHalfFolded */);
-        mFoldStateListener.onStateChanged(mUnfoldedStates[0]);
-        assertEquals(mCurrentState, DeviceStateController.FoldState.OPEN);
-        mFoldStateListener.onStateChanged(mFoldedStates[0]);
-        assertEquals(mCurrentState, DeviceStateController.FoldState.FOLDED);
-        mFoldStateListener.onStateChanged(mHalfFoldedStates[0]);
-        assertEquals(mCurrentState, DeviceStateController.FoldState.OPEN); // Ignored
+        mTarget.onStateChanged(mOpenDeviceStates[0]);
+        assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
+        mTarget.onStateChanged(mFoldedStates[0]);
+        assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState);
+        mTarget.onStateChanged(mHalfFoldedStates[0]);
+        assertEquals(DeviceStateController.DeviceState.UNKNOWN, mCurrentState); // Ignored
     }
 
     @Test
-    public void testWithHalfFoldSupported() throws Exception {
+    public void testWithHalfFoldSupported() {
         initialize(true /* supportFold */, true /* supportHalfFolded */);
-        mFoldStateListener.onStateChanged(mUnfoldedStates[0]);
-        assertEquals(mCurrentState, DeviceStateController.FoldState.OPEN);
-        mFoldStateListener.onStateChanged(mFoldedStates[0]);
-        assertEquals(mCurrentState, DeviceStateController.FoldState.FOLDED);
-        mFoldStateListener.onStateChanged(mHalfFoldedStates[0]);
-        assertEquals(mCurrentState, DeviceStateController.FoldState.HALF_FOLDED);
+        mTarget.onStateChanged(mOpenDeviceStates[0]);
+        assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
+        mTarget.onStateChanged(mFoldedStates[0]);
+        assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState);
+        mTarget.onStateChanged(mHalfFoldedStates[0]);
+        assertEquals(DeviceStateController.DeviceState.HALF_FOLDED, mCurrentState);
     }
 
-
     private final int[] mFoldedStates = {0};
-    private final int[] mUnfoldedStates = {1};
+    private final int[] mOpenDeviceStates = {1};
     private final int[] mHalfFoldedStates = {2};
-
-
-    private void verifyFoldStateListenerRegistration(int numOfInvocation) {
-        final ArgumentCaptor<DeviceStateController.FoldStateListener> listenerCaptor =
-                ArgumentCaptor.forClass(DeviceStateController.FoldStateListener.class);
-        verify(mMockDeviceStateManager, times(numOfInvocation)).registerCallback(
-                any(),
-                listenerCaptor.capture());
-        if (numOfInvocation > 0) {
-            mFoldStateListener = listenerCaptor.getValue();
-        }
-    }
+    private final int[] mRearDisplayStates = {3};
 
     private class DeviceStateControllerBuilder {
         private boolean mSupportFold = false;
         private boolean mSupportHalfFold = false;
-        private Consumer<DeviceStateController.FoldState> mDelegate;
+        private Consumer<DeviceStateController.DeviceState> mDelegate;
 
         DeviceStateControllerBuilder setSupportFold(
                 boolean supportFold, boolean supportHalfFold) {
@@ -143,34 +127,44 @@
         }
 
         DeviceStateControllerBuilder setDelegate(
-                Consumer<DeviceStateController.FoldState> delegate) {
+                Consumer<DeviceStateController.DeviceState> delegate) {
             mDelegate = delegate;
             return this;
         }
 
         private void mockFold(boolean enableFold, boolean enableHalfFold) {
+            if (enableFold || enableHalfFold) {
+                when(mMockContext.getResources()
+                        .getIntArray(R.array.config_openDeviceStates))
+                        .thenReturn(mOpenDeviceStates);
+                when(mMockContext.getResources()
+                        .getIntArray(R.array.config_rearDisplayDeviceStates))
+                        .thenReturn(mRearDisplayStates);
+            }
+
             if (enableFold) {
-                when(mMockContext.getResources().getIntArray(
-                        com.android.internal.R.array.config_foldedDeviceStates))
+                when(mMockContext.getResources()
+                        .getIntArray(R.array.config_foldedDeviceStates))
                         .thenReturn(mFoldedStates);
             }
             if (enableHalfFold) {
-                when(mMockContext.getResources().getIntArray(
-                        com.android.internal.R.array.config_halfFoldedDeviceStates))
+                when(mMockContext.getResources()
+                        .getIntArray(R.array.config_halfFoldedDeviceStates))
                         .thenReturn(mHalfFoldedStates);
             }
         }
 
-        private void build() throws Exception {
+        private void build() {
             mMockContext = mock(Context.class);
-            mMockRes = mock(Resources.class);
-            when(mMockContext.getResources()).thenReturn((mMockRes));
             mMockDeviceStateManager = mock(DeviceStateManager.class);
             when(mMockContext.getSystemService(DeviceStateManager.class))
                     .thenReturn(mMockDeviceStateManager);
+            Resources mockRes = mock(Resources.class);
+            when(mMockContext.getResources()).thenReturn((mockRes));
             mockFold(mSupportFold, mSupportHalfFold);
-            mMockHandler = mock(Handler.class);
-            mTarget = new DeviceStateController(mMockContext, mMockHandler, mDelegate);
+            Handler mockHandler = mock(Handler.class);
+            mTarget = new DeviceStateController(mMockContext, mockHandler);
+            mTarget.registerDeviceStateCallback(mDelegate);
         }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 78707d6..3b34ba4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1738,7 +1738,7 @@
 
         // No need to apply rotation if the display ignores orientation request.
         doCallRealMethod().when(displayContent).rotationForActivityInDifferentOrientation(any());
-        pinnedActivity.mOrientation = SCREEN_ORIENTATION_LANDSCAPE;
+        pinnedActivity.setOverrideOrientation(SCREEN_ORIENTATION_LANDSCAPE);
         displayContent.setIgnoreOrientationRequest(true);
         assertEquals(WindowConfiguration.ROTATION_UNDEFINED,
                 displayContent.rotationForActivityInDifferentOrientation(pinnedActivity));
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 4ce43e1..ed2b0a3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -56,6 +56,7 @@
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
+import android.hardware.devicestate.DeviceStateManager;
 import android.os.PowerManagerInternal;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
@@ -111,6 +112,7 @@
     private ContentResolver mMockResolver;
     private FakeSettingsProvider mFakeSettingsProvider;
     private StatusBarManagerInternal mMockStatusBarManagerInternal;
+    private DeviceStateManager mMockDeviceStateManager;
 
     // Fields below are callbacks captured from test target.
     private ContentObserver mShowRotationSuggestionsObserver;
@@ -120,6 +122,7 @@
 
     private DisplayRotationBuilder mBuilder;
 
+    private DeviceStateController mDeviceStateController;
     private DisplayRotation mTarget;
 
     @BeforeClass
@@ -484,6 +487,34 @@
                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
     }
 
+    @Test
+    public void testReverseRotation() throws Exception {
+        mBuilder.build();
+        configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
+
+        when(mDeviceStateController.shouldReverseRotationDirectionAroundZAxis()).thenReturn(true);
+
+        thawRotation();
+
+        enableOrientationSensor();
+
+        mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
+        assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
+                SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
+
+        mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_270));
+        assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation(
+                SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
+
+        mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_0));
+        assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(
+                SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
+
+        mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180));
+        assertEquals(Surface.ROTATION_180, mTarget.rotationForOrientation(
+                SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_180));
+    }
+
     private boolean waitForUiHandler() {
         final CountDownLatch latch = new CountDownLatch(1);
         UiThread.getHandler().post(latch::countDown);
@@ -705,7 +736,7 @@
 
         enableOrientationSensor();
 
-        mTarget.foldStateChanged(DeviceStateController.FoldState.OPEN);
+        mTarget.foldStateChanged(DeviceStateController.DeviceState.OPEN);
         freezeRotation(Surface.ROTATION_270);
 
         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_0));
@@ -715,7 +746,7 @@
                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
 
         // ... until half-fold
-        mTarget.foldStateChanged(DeviceStateController.FoldState.HALF_FOLDED);
+        mTarget.foldStateChanged(DeviceStateController.DeviceState.HALF_FOLDED);
         assertTrue(waitForUiHandler());
         verify(sMockWm).updateRotation(false, false);
         assertTrue(waitForUiHandler());
@@ -723,7 +754,7 @@
                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
 
         // ... then transition back to flat
-        mTarget.foldStateChanged(DeviceStateController.FoldState.OPEN);
+        mTarget.foldStateChanged(DeviceStateController.DeviceState.OPEN);
         assertTrue(waitForUiHandler());
         verify(sMockWm, atLeast(1)).updateRotation(false, false);
         assertTrue(waitForUiHandler());
@@ -1097,8 +1128,14 @@
 
             mMockDisplayWindowSettings = mock(DisplayWindowSettings.class);
 
+            mMockDeviceStateManager = mock(DeviceStateManager.class);
+            when(mMockContext.getSystemService(eq(DeviceStateManager.class)))
+                    .thenReturn(mMockDeviceStateManager);
+
+            mDeviceStateController = mock(DeviceStateController.class);
             mTarget = new DisplayRotation(sMockWm, mMockDisplayContent, mMockDisplayAddress,
-                    mMockDisplayPolicy, mMockDisplayWindowSettings, mMockContext, new Object()) {
+                    mMockDisplayPolicy, mMockDisplayWindowSettings, mMockContext, new Object(),
+                    mDeviceStateController) {
                 @Override
                 DisplayRotationImmersiveAppCompatPolicy initImmersiveAppCompatPolicy(
                         WindowManagerService service, DisplayContent displayContent) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index 791d6f2..110ef89 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -16,14 +16,27 @@
 
 package com.android.server.wm;
 
+import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION;
 import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
 import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
 import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
 import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE;
+import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR;
+import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT;
+import static android.content.pm.ActivityInfo.OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION;
 import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH;
 import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE;
 import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -89,6 +102,7 @@
     public TestRule compatChangeRule = new PlatformCompatChangeRule();
 
     private ActivityRecord mActivity;
+    private Task mTask;
     private DisplayContent mDisplayContent;
     private LetterboxUiController mController;
     private LetterboxConfiguration mLetterboxConfiguration;
@@ -491,6 +505,130 @@
         return mainWindow;
     }
 
+    // overrideOrientationIfNeeded
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT})
+    public void testOverrideOrientationIfNeeded_portraitOverrideEnabled_returnsPortrait()
+            throws Exception {
+        assertEquals(mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_PORTRAIT);
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR})
+    public void testOverrideOrientationIfNeeded_portraitOverrideEnabled_returnsNosensor() {
+        assertEquals(mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_NOSENSOR);
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR})
+    public void testOverrideOrientationIfNeeded_nosensorOverride_orientationFixed_returnsUnchanged() {
+        assertEquals(mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_PORTRAIT), SCREEN_ORIENTATION_PORTRAIT);
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE})
+    public void testOverrideOrientationIfNeeded_reverseLandscapeOverride_orientationPortraitOrUndefined_returnsUnchanged() {
+        assertEquals(mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_PORTRAIT), SCREEN_ORIENTATION_PORTRAIT);
+        assertEquals(mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_UNSPECIFIED);
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE})
+    public void testOverrideOrientationIfNeeded_reverseLandscapeOverride_orientationLandscape_returnsReverseLandscape() {
+        assertEquals(mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_LANDSCAPE),
+                SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT})
+    public void testOverrideOrientationIfNeeded_portraitOverride_orientationFixed_returnsUnchanged() {
+        assertEquals(mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_NOSENSOR), SCREEN_ORIENTATION_NOSENSOR);
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT, OVERRIDE_ANY_ORIENTATION})
+    public void testOverrideOrientationIfNeeded_portraitAndIgnoreFixedOverrides_returnsPortrait() {
+        assertEquals(mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_NOSENSOR), SCREEN_ORIENTATION_PORTRAIT);
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR, OVERRIDE_ANY_ORIENTATION})
+    public void testOverrideOrientationIfNeeded_noSensorAndIgnoreFixedOverrides_returnsNosensor() {
+        assertEquals(mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_PORTRAIT), SCREEN_ORIENTATION_NOSENSOR);
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT})
+    public void testOverrideOrientationIfNeeded_propertyIsFalse_returnsUnchanged()
+            throws Exception {
+        mockThatProperty(PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE, /* value */ false);
+
+        mController = new LetterboxUiController(mWm, mActivity);
+
+        assertEquals(mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_UNSPECIFIED);
+    }
+
+    // shouldUseDisplayLandscapeNaturalOrientation
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION})
+    public void testShouldUseDisplayLandscapeNaturalOrientation_override_returnsTrue() {
+        prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation();
+        assertTrue(mController.shouldUseDisplayLandscapeNaturalOrientation());
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION})
+    public void testShouldUseDisplayLandscapeNaturalOrientation_overrideAndFalseProperty_returnsFalse()
+            throws Exception {
+        mockThatProperty(PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE, /* value */ false);
+
+        mController = new LetterboxUiController(mWm, mActivity);
+
+        prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation();
+        assertFalse(mController.shouldUseDisplayLandscapeNaturalOrientation());
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION})
+    public void testShouldUseDisplayLandscapeNaturalOrientation_portraitNaturalOrientation_returnsFalse() {
+        prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation();
+        doReturn(ORIENTATION_PORTRAIT).when(mDisplayContent).getNaturalOrientation();
+
+        assertFalse(mController.shouldUseDisplayLandscapeNaturalOrientation());
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION})
+    public void testShouldUseDisplayLandscapeNaturalOrientation_disabledIgnoreOrientationRequest_returnsFalse() {
+        prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation();
+        mDisplayContent.setIgnoreOrientationRequest(false);
+
+        assertFalse(mController.shouldUseDisplayLandscapeNaturalOrientation());
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION})
+    public void testShouldUseDisplayLandscapeNaturalOrientation_inMultiWindowMode_returnsFalse() {
+        prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation();
+
+        spyOn(mTask);
+        doReturn(true).when(mTask).inMultiWindowMode();
+
+        assertFalse(mController.shouldUseDisplayLandscapeNaturalOrientation());
+    }
+
     private void mockThatProperty(String propertyName, boolean value) throws Exception {
         Property property = new Property(propertyName, /* value */ value, /* packageName */ "",
                  /* className */ "");
@@ -499,6 +637,12 @@
         doReturn(property).when(pm).getProperty(eq(propertyName), anyString());
     }
 
+    private void prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation() {
+        spyOn(mDisplayContent);
+        doReturn(ORIENTATION_LANDSCAPE).when(mDisplayContent).getNaturalOrientation();
+        mDisplayContent.setIgnoreOrientationRequest(true);
+    }
+
     private void prepareActivityThatShouldIgnoreRequestedOrientationDuringRelaunch() {
         doReturn(true).when(mLetterboxConfiguration)
                 .isPolicyForIgnoringRequestedOrientationEnabled();
@@ -508,10 +652,10 @@
     private ActivityRecord setUpActivityWithComponent() {
         mDisplayContent = new TestDisplayContent
                 .Builder(mAtm, /* dw */ 1000, /* dh */ 2000).build();
-        Task task = new TaskBuilder(mSupervisor).setDisplay(mDisplayContent).build();
+        mTask = new TaskBuilder(mSupervisor).setDisplay(mDisplayContent).build();
         final ActivityRecord activity = new ActivityBuilder(mAtm)
                 .setOnTop(true)
-                .setTask(task)
+                .setTask(mTask)
                 // Set the component to be that of the test class in order to enable compat changes
                 .setComponent(ComponentName.createRelative(mContext,
                         com.android.server.wm.LetterboxUiControllerTest.class.getName()))
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 08635ab..c131c84 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -468,7 +468,7 @@
         mWm.setRecentsAnimationController(mController);
         spyOn(mDisplayContent.mFixedRotationTransitionListener);
         final ActivityRecord recents = mock(ActivityRecord.class);
-        recents.mOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+        recents.setOverrideOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
         doReturn(ORIENTATION_PORTRAIT).when(recents)
                 .getRequestedConfigurationOrientation(anyBoolean());
         mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(recents);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 7e150e9..91e875f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -102,7 +102,7 @@
 import com.android.internal.policy.SystemBarUtils;
 import com.android.internal.statusbar.LetterboxDetails;
 import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.wm.DeviceStateController.FoldState;
+import com.android.server.wm.DeviceStateController.DeviceState;
 
 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
@@ -3202,9 +3202,9 @@
     private void setFoldablePosture(boolean isHalfFolded, boolean isTabletop) {
         final DisplayRotation r = mActivity.mDisplayContent.getDisplayRotation();
         doReturn(isHalfFolded).when(r).isDisplaySeparatingHinge();
-        doReturn(false).when(r).isDeviceInPosture(any(FoldState.class), anyBoolean());
+        doReturn(false).when(r).isDeviceInPosture(any(DeviceState.class), anyBoolean());
         if (isHalfFolded) {
-            doReturn(true).when(r).isDeviceInPosture(FoldState.HALF_FOLDED, isTabletop);
+            doReturn(true).when(r).isDeviceInPosture(DeviceState.HALF_FOLDED, isTabletop);
         }
         mActivity.recomputeConfiguration();
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupContinuousTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupContinuousTest.java
index e6f47a1..eef7cc2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupContinuousTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupContinuousTest.java
@@ -22,6 +22,7 @@
 
 import android.app.KeyguardManager;
 import android.os.PowerManager;
+import android.platform.test.annotations.Presubmit;
 import android.view.SurfaceControl;
 import android.view.cts.surfacevalidator.CapturedActivity;
 import android.window.SurfaceSyncGroup;
@@ -68,11 +69,23 @@
 
     @Test
     public void testSurfaceControlViewHostIPCSync_Fast() throws Throwable {
-        mCapturedActivity.verifyTest(new SyncValidatorSCVHTestCase(0 /* delayMs */), mName);
+        mCapturedActivity.verifyTest(
+                new SyncValidatorSCVHTestCase(0 /* delayMs */, false /* overrideDefaultDuration */),
+                mName);
     }
 
     @Test
     public void testSurfaceControlViewHostIPCSync_Slow() throws Throwable {
-        mCapturedActivity.verifyTest(new SyncValidatorSCVHTestCase(100 /* delayMs */), mName);
+        mCapturedActivity.verifyTest(new SyncValidatorSCVHTestCase(100 /* delayMs */,
+                false /* overrideDefaultDuration */), mName);
+    }
+
+    @Test
+    @Presubmit
+    public void testSurfaceControlViewHostIPCSync_Short() throws Throwable {
+        mCapturedActivity.setMinimumCaptureDurationMs(5000);
+        mCapturedActivity.verifyTest(
+                new SyncValidatorSCVHTestCase(0 /* delayMs */, true /* overrideDefaultDuration */),
+                mName);
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index dbd7a4b..40e8273 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.TRANSIT_CHANGE;
@@ -513,7 +514,6 @@
         assertApplyTransactionAllowed(mTransaction);
     }
 
-
     @Test
     public void testApplyTransaction_enforceHierarchyChange_deleteTaskFragment() {
         doReturn(true).when(mTaskFragment).isAttached();
@@ -836,7 +836,7 @@
         final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
                 mOrganizerToken, fragmentToken1, activityAtBottom.token)
                 .setPairedActivityToken(activityAtBottom.token)
-                .setInitialBounds(bounds)
+                .setInitialRelativeBounds(bounds)
                 .build();
         mTransaction.setTaskFragmentOrganizer(mIOrganizer);
         mTransaction.createTaskFragment(params);
@@ -1528,6 +1528,79 @@
         assertEquals(TRANSIT_CHANGE, TASK_FRAGMENT_TRANSIT_CHANGE);
     }
 
+    @Test
+    public void testApplyTransaction_setRelativeBounds() {
+        final Task task = createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW,
+                ACTIVITY_TYPE_STANDARD);
+        mTaskFragment = new TaskFragmentBuilder(mAtm)
+                .setParentTask(task)
+                .setFragmentToken(mFragmentToken)
+                .build();
+        final WindowContainerToken token = mTaskFragment.mRemoteToken.toWindowContainerToken();
+        final Rect relBounds = new Rect(0, 0, 100, 1000);
+        mTransaction.setRelativeBounds(token, relBounds);
+
+        // Not allowed because TaskFragment is not organized by the caller organizer.
+        assertApplyTransactionDisallowed(mTransaction);
+
+        mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
+                "Test:TaskFragmentOrganizer" /* processName */);
+
+        assertApplyTransactionAllowed(mTransaction);
+        assertEquals(relBounds, mTaskFragment.getRelativeEmbeddedBounds());
+        assertEquals(relBounds, mTaskFragment.getBounds());
+
+        // TaskFragment bounds should be updated to the same relative bounds.
+        final Rect taskBounds = new Rect(200, 200, 700, 1500);
+        task.setBoundsUnchecked(taskBounds);
+        assertEquals(taskBounds, task.getBounds());
+        assertEquals(relBounds, mTaskFragment.getRelativeEmbeddedBounds());
+        assertEquals(mTaskFragment.translateRelativeBoundsToAbsoluteBounds(relBounds, taskBounds),
+                mTaskFragment.getBounds());
+        assertEquals(new Rect(200, 200, 300, 1200), mTaskFragment.getBounds());
+
+        // Set TaskFragment to fill Task
+        mTransaction.setRelativeBounds(token, new Rect());
+
+        assertApplyTransactionAllowed(mTransaction);
+        assertEquals(new Rect(), mTaskFragment.getRelativeEmbeddedBounds());
+        assertEquals(taskBounds, mTaskFragment.getBounds());
+    }
+
+    @Test
+    public void testUntrustedEmbedding_setRelativeBounds_adjustToTaskBounds() {
+        final Task task = createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW,
+                ACTIVITY_TYPE_STANDARD);
+        mTaskFragment = new TaskFragmentBuilder(mAtm)
+                .setParentTask(task)
+                .setFragmentToken(mFragmentToken)
+                .build();
+        final WindowContainerToken token = mTaskFragment.mRemoteToken.toWindowContainerToken();
+        mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
+                "Test:TaskFragmentOrganizer" /* processName */);
+        // Untrusted embedded
+        doReturn(false).when(mTaskFragment).isAllowedToBeEmbeddedInTrustedMode();
+
+        final Rect taskBounds = new Rect(0, 0, 500, 1000);
+        task.setBoundsUnchecked(taskBounds);
+
+        final Rect taskFragmentBounds = new Rect(250, 0, 750, 1000);
+        mTransaction.setRelativeBounds(token, taskFragmentBounds);
+
+        // Allow operation in case the Task is also resizing.
+        // Adjust the relBounds to the intersection.
+        assertApplyTransactionAllowed(mTransaction);
+        // Relative bounds is correctly set.
+        assertEquals(taskFragmentBounds, mTaskFragment.getRelativeEmbeddedBounds());
+        // The actual window bounds is adjusted to fit the Task bounds.
+        assertEquals(new Rect(250, 0, 500, 1000), mTaskFragment.getBounds());
+
+        // Adjust to the full requested bounds when the Task is resized.
+        taskBounds.set(0, 0, 750, 1000);
+        task.setBoundsUnchecked(taskBounds);
+        assertEquals(taskFragmentBounds, mTaskFragment.getBounds());
+    }
+
     /**
      * Creates a {@link TaskFragment} with the {@link WindowContainerTransaction}. Calls
      * {@link WindowOrganizerController#applyTransaction(WindowContainerTransaction)} to apply the
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index c85671d..5099869 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -122,18 +122,22 @@
 
     @Test
     public void testShouldStartChangeTransition_relativePositionChange() {
+        final Task task = createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW,
+                ACTIVITY_TYPE_STANDARD);
+        task.setBoundsUnchecked(new Rect(0, 0, 1000, 1000));
+        mTaskFragment = createTaskFragmentWithEmbeddedActivity(task, mOrganizer);
         mockSurfaceFreezerSnapshot(mTaskFragment.mSurfaceFreezer);
         final Rect startBounds = new Rect(0, 0, 500, 1000);
         final Rect endBounds = new Rect(500, 0, 1000, 1000);
-        mTaskFragment.setBounds(startBounds);
-        mTaskFragment.updateRelativeEmbeddedBounds();
+        mTaskFragment.setRelativeEmbeddedBounds(startBounds);
+        mTaskFragment.recomputeConfiguration();
         doReturn(true).when(mTaskFragment).isVisible();
         doReturn(true).when(mTaskFragment).isVisibleRequested();
 
         // Do not resize, just change the relative position.
         final Rect relStartBounds = new Rect(mTaskFragment.getRelativeEmbeddedBounds());
-        mTaskFragment.setBounds(endBounds);
-        mTaskFragment.updateRelativeEmbeddedBounds();
+        mTaskFragment.setRelativeEmbeddedBounds(endBounds);
+        mTaskFragment.recomputeConfiguration();
         spyOn(mDisplayContent.mTransitionController);
 
         // For Shell transition, we don't want to take snapshot when the bounds are not resized
@@ -150,19 +154,26 @@
 
     @Test
     public void testStartChangeTransition_resetSurface() {
+        final Task task = createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW,
+                ACTIVITY_TYPE_STANDARD);
+        task.setBoundsUnchecked(new Rect(0, 0, 1000, 1000));
+        mTaskFragment = createTaskFragmentWithEmbeddedActivity(task, mOrganizer);
+        doReturn(mTransaction).when(mTaskFragment).getSyncTransaction();
+        doReturn(mTransaction).when(mTaskFragment).getPendingTransaction();
+        mLeash = mTaskFragment.getSurfaceControl();
         mockSurfaceFreezerSnapshot(mTaskFragment.mSurfaceFreezer);
         final Rect startBounds = new Rect(0, 0, 1000, 1000);
         final Rect endBounds = new Rect(500, 500, 1000, 1000);
-        mTaskFragment.setBounds(startBounds);
-        mTaskFragment.updateRelativeEmbeddedBounds();
+        mTaskFragment.setRelativeEmbeddedBounds(startBounds);
+        mTaskFragment.recomputeConfiguration();
         doReturn(true).when(mTaskFragment).isVisible();
         doReturn(true).when(mTaskFragment).isVisibleRequested();
 
         clearInvocations(mTransaction);
         final Rect relStartBounds = new Rect(mTaskFragment.getRelativeEmbeddedBounds());
         mTaskFragment.deferOrganizedTaskFragmentSurfaceUpdate();
-        mTaskFragment.setBounds(endBounds);
-        mTaskFragment.updateRelativeEmbeddedBounds();
+        mTaskFragment.setRelativeEmbeddedBounds(endBounds);
+        mTaskFragment.recomputeConfiguration();
         assertTrue(mTaskFragment.shouldStartChangeTransition(startBounds, relStartBounds));
         mTaskFragment.initializeChangeTransition(startBounds);
         mTaskFragment.continueOrganizedTaskFragmentSurfaceUpdate();
@@ -201,8 +212,8 @@
         mockSurfaceFreezerSnapshot(mTaskFragment.mSurfaceFreezer);
         final Rect startBounds = new Rect(0, 0, 1000, 1000);
         final Rect endBounds = new Rect(500, 500, 1000, 1000);
-        mTaskFragment.setBounds(startBounds);
-        mTaskFragment.updateRelativeEmbeddedBounds();
+        mTaskFragment.setRelativeEmbeddedBounds(startBounds);
+        mTaskFragment.recomputeConfiguration();
         doReturn(true).when(mTaskFragment).isVisible();
         doReturn(true).when(mTaskFragment).isVisibleRequested();
 
@@ -212,8 +223,8 @@
 
         assertFalse(mTaskFragment.okToAnimate());
 
-        mTaskFragment.setBounds(endBounds);
-        mTaskFragment.updateRelativeEmbeddedBounds();
+        mTaskFragment.setRelativeEmbeddedBounds(endBounds);
+        mTaskFragment.recomputeConfiguration();
 
         assertFalse(mTaskFragment.shouldStartChangeTransition(startBounds, relStartBounds));
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 1a1ca54..5006bf7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -1665,7 +1665,7 @@
 
         @Override
         int getOrientation() {
-            return getOrientation(super.mOrientation);
+            return getOrientation(super.getOverrideOrientation());
         }
 
         @Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/scvh/SyncValidatorSCVHTestCase.java b/services/tests/wmtests/src/com/android/server/wm/scvh/SyncValidatorSCVHTestCase.java
index af4c683c..07dac8d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/scvh/SyncValidatorSCVHTestCase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/scvh/SyncValidatorSCVHTestCase.java
@@ -54,10 +54,12 @@
             new Point(300, 800), new Point(200, 200)};
     private int mLastSizeIndex = 1;
 
-    private long mDelayMs;
+    private final long mDelayMs;
+    private final boolean mOverrideDefaultDuration;
 
-    public SyncValidatorSCVHTestCase(long delayMs) {
+    public SyncValidatorSCVHTestCase(long delayMs, boolean overrideDefaultDuration) {
         mDelayMs = delayMs;
+        mOverrideDefaultDuration = overrideDefaultDuration;
     }
 
     private final Runnable mRunnable = new Runnable() {
@@ -231,4 +233,9 @@
     public void end() {
         mHandler.removeCallbacks(mRunnable);
     }
+
+    @Override
+    public boolean hasAnimation() {
+        return !mOverrideDefaultDuration;
+    }
 }
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 0aa1715..cad1f6f 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.usb;
 
+import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN;
+import static android.hardware.usb.DisplayPortAltModeInfo.LINK_TRAINING_STATUS_UNKNOWN;
 import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL;
 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST;
@@ -1188,11 +1190,11 @@
                 final String portId = args[1];
                 if (mPortManager != null) {
                     mPortManager.simulateDisplayPortAltModeInfo(portId,
-                            DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN,
-                            DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN,
+                            DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN,
+                            DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN,
                             0,
                             false,
-                            0,
+                            LINK_TRAINING_STATUS_UNKNOWN,
                             pw);
                     pw.println();
                     mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, "  ")),
@@ -1271,7 +1273,7 @@
                 pw.println("    <cable>: type DisplayPortAltModeStatus");
                 pw.println("    <num-lanes>: type int, expected 0, 2, or 4");
                 pw.println("    <hpd>: type boolean, expected true or false");
-                pw.println("    <link-training-status>: type int with range [0,2]");
+                pw.println("    <link-training-status>: type LinkTrainingStatus");
                 pw.println("  dumpsys usb reset-displayport-status \"matrix\"");
                 pw.println("reset-displayport-status can also be used in order to set");
                 pw.println("the DisplayPortInfo to default values.");
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
index b8536f9..afee940 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
@@ -17,6 +17,8 @@
 package com.android.server.voiceinteraction;
 
 import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD;
+import static android.Manifest.permission.LOG_COMPAT_CHANGE;
+import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
 import static android.Manifest.permission.RECORD_AUDIO;
 import static android.service.attention.AttentionService.PROXIMITY_UNKNOWN;
 import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_EXTERNAL;
@@ -43,11 +45,14 @@
 import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_SECURITY_EXCEPTION;
 import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_UNEXPECTED_CALLBACK;
 import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECT_UNEXPECTED_CALLBACK;
+import static com.android.server.voiceinteraction.HotwordDetectionConnection.ENFORCE_HOTWORD_PHRASE_ID;
 import static com.android.server.voiceinteraction.SoundTriggerSessionPermissionsDecorator.enforcePermissionForPreflight;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.app.AppOpsManager;
+import android.app.compat.CompatChanges;
 import android.attention.AttentionManagerInternal;
 import android.content.Context;
 import android.content.PermissionChecker;
@@ -692,8 +697,13 @@
         }
     }
 
-    static void enforceExtraKeyphraseIdNotLeaked(HotwordDetectedResult result,
+    @RequiresPermission(allOf = {READ_COMPAT_CHANGE_CONFIG, LOG_COMPAT_CHANGE})
+    void enforceExtraKeyphraseIdNotLeaked(HotwordDetectedResult result,
             SoundTrigger.KeyphraseRecognitionEvent recognitionEvent) {
+        if (!CompatChanges.isChangeEnabled(ENFORCE_HOTWORD_PHRASE_ID,
+                mVoiceInteractionServiceUid)) {
+            return;
+        }
         // verify the phrase ID in HotwordDetectedResult is not exposing extra phrases
         // the DSP did not detect
         for (SoundTrigger.KeyphraseRecognitionExtra keyphrase : recognitionEvent.keyphraseExtras) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 591e35a..220ef21 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -29,6 +29,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
 import android.content.ComponentName;
 import android.content.ContentCaptureOptions;
 import android.content.Context;
@@ -39,6 +41,7 @@
 import android.media.AudioManagerInternal;
 import android.media.permission.Identity;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
@@ -48,6 +51,7 @@
 import android.os.ServiceManager;
 import android.os.SharedMemory;
 import android.provider.DeviceConfig;
+import android.service.voice.HotwordDetectedResult;
 import android.service.voice.HotwordDetectionService;
 import android.service.voice.HotwordDetector;
 import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
@@ -83,6 +87,26 @@
     private static final String TAG = "HotwordDetectionConnection";
     static final boolean DEBUG = false;
 
+    /**
+     * For apps targeting Android API {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above,
+     * implementors of the {@link HotwordDetectionService} must not augment the phrase IDs which are
+     * supplied via {@link HotwordDetectionService
+     * #onDetect(AlwaysOnHotwordDetector.EventPayload, long, HotwordDetectionService.Callback)}.
+     *
+     * <p>The {@link HotwordDetectedResult#getHotwordPhraseId()} must match one of the phrase IDs
+     * from the {@link android.service.voice.AlwaysOnHotwordDetector
+     * .EventPayload#getKeyphraseRecognitionExtras()} list.
+     * </p>
+     *
+     * <p>This behavior change is made to ensure the {@link HotwordDetectionService} honors what
+     * it receives from the {@link android.hardware.soundtrigger.SoundTriggerModule}, and it
+     * cannot signal to the client application a phrase which was not origially detected.
+     * </p>
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    public static final long ENFORCE_HOTWORD_PHRASE_ID = 215066299L;
+
     private static final String KEY_RESTART_PERIOD_IN_SECONDS = "restart_period_in_seconds";
     private static final long RESET_DEBUG_HOTWORD_LOGGING_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour
     private static final int MAX_ISOLATED_PROCESS_NUMBER = 10;
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index ca15422..b6def1a 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -592,6 +592,11 @@
 
         /**
          * Sets the address. See {@link PhoneAccount#getAddress}.
+         * <p>
+         * Note: The entire URI value is limited to 256 characters. This check is
+         * enforced when registering the PhoneAccount via
+         * {@link TelecomManager#registerPhoneAccount(PhoneAccount)} and will cause an
+         * {@link IllegalArgumentException} to be thrown if URI is over 256.
          *
          * @param value The address of the phone account.
          * @return The builder.
@@ -625,6 +630,10 @@
 
         /**
          * Sets the icon. See {@link PhoneAccount#getIcon}.
+         * <p>
+         * Note: An {@link IllegalArgumentException} if the Icon cannot be written to memory.
+         * This check is enforced when registering the PhoneAccount via
+         * {@link TelecomManager#registerPhoneAccount(PhoneAccount)}
          *
          * @param icon The icon to set.
          */
@@ -663,6 +672,10 @@
         /**
          * Specifies an additional URI scheme supported by the {@link PhoneAccount}.
          *
+         * <p>
+         * Each URI scheme is limited to 256 characters.  Adding a scheme over 256 characters will
+         * cause an {@link IllegalArgumentException} to be thrown when the account is registered.
+         *
          * @param uriScheme The URI scheme.
          * @return The builder.
          */
@@ -676,6 +689,12 @@
         /**
          * Specifies the URI schemes supported by the {@link PhoneAccount}.
          *
+         * <p>
+         * A max of 10 URI schemes can be added per account.  Additionally, each URI scheme is
+         * limited to 256 characters. Adding more than 10 URI schemes or 256 characters on any
+         * scheme will cause an {@link IllegalArgumentException} to be thrown when the account
+         * is registered.
+         *
          * @param uriSchemes The URI schemes.
          * @return The builder.
          */
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index ddb3262..f0f230f 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -34,6 +34,7 @@
 import android.net.NetworkCapabilities;
 import android.net.ipsec.ike.SaProposal;
 import android.os.Build;
+import android.os.Handler;
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.service.carrier.CarrierService;
@@ -49,6 +50,7 @@
 import android.telephony.ims.RcsUceAdapter;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.feature.RcsFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
 
 import com.android.internal.telephony.ICarrierConfigLoader;
 import com.android.telephony.Rlog;
@@ -65,7 +67,7 @@
 @SystemService(Context.CARRIER_CONFIG_SERVICE)
 @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
 public class CarrierConfigManager {
-    private final static String TAG = "CarrierConfigManager";
+    private static final String TAG = "CarrierConfigManager";
 
     /**
      * Extra included in {@link #ACTION_CARRIER_CONFIG_CHANGED} to indicate the slot index that the
@@ -108,25 +110,25 @@
      * Only send USSD over IMS while CS is out of service, otherwise send USSD over CS.
      * {@link #KEY_CARRIER_USSD_METHOD_INT}
      */
-    public static final int USSD_OVER_CS_PREFERRED   = 0;
+    public static final int USSD_OVER_CS_PREFERRED = 0;
 
     /**
      * Send USSD over IMS or CS while IMS is out of service or silent redial over CS if needed.
      * {@link #KEY_CARRIER_USSD_METHOD_INT}
      */
-    public static final int USSD_OVER_IMS_PREFERRED  = 1;
+    public static final int USSD_OVER_IMS_PREFERRED = 1;
 
     /**
      * Only send USSD over CS.
      * {@link #KEY_CARRIER_USSD_METHOD_INT}
      */
-    public static final int USSD_OVER_CS_ONLY        = 2;
+    public static final int USSD_OVER_CS_ONLY = 2;
 
     /**
      * Only send USSD over IMS and disallow silent redial over CS.
      * {@link #KEY_CARRIER_USSD_METHOD_INT}
      */
-    public static final int USSD_OVER_IMS_ONLY       = 3;
+    public static final int USSD_OVER_IMS_ONLY = 3;
 
     /**
      * Indicates CARRIER_NR_AVAILABILITY_NSA determine that the carrier enable the non-standalone
@@ -161,8 +163,8 @@
      * @see TelephonyManager#getSimCarrierId()
      * @see TelephonyManager#getSimSpecificCarrierId()
      */
-    public static final String
-            ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
+    public static final String ACTION_CARRIER_CONFIG_CHANGED =
+            "android.telephony.action.CARRIER_CONFIG_CHANGED";
 
     // Below are the keys used in carrier config bundles. To add a new variable, define the key and
     // give it a default value in sDefaults. If you need to ship a per-network override in the
@@ -183,8 +185,8 @@
      * @deprecated Use {@link Ims#KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL} instead.
      */
     @Deprecated
-    public static final String
-            KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
+    public static final String KEY_CARRIER_VOLTE_PROVISIONED_BOOL =
+            "carrier_volte_provisioned_bool";
 
     /**
      * Boolean indicating the Supplementary Services(SS) is disable when airplane mode on in the
@@ -217,29 +219,29 @@
     public static final String KEY_CALL_FORWARDING_WHEN_UNREACHABLE_SUPPORTED_BOOL =
             "call_forwarding_when_unreachable_supported_bool";
 
-     /**
-      * Boolean indicating if carrier supports call forwarding option "When unanswered".
-      *
-      * {@code true}: Call forwarding option "When unanswered" is supported.
-      * {@code false}: Call forwarding option "When unanswered" is not supported. Option will be
-      * removed in the UI.
-      *
-      * By default this value is true.
-      * @hide
-      */
+    /**
+     * Boolean indicating if carrier supports call forwarding option "When unanswered".
+     *
+     * {@code true}: Call forwarding option "When unanswered" is supported.
+     * {@code false}: Call forwarding option "When unanswered" is not supported. Option will be
+     * removed in the UI.
+     *
+     * By default this value is true.
+     * @hide
+     */
     public static final String KEY_CALL_FORWARDING_WHEN_UNANSWERED_SUPPORTED_BOOL =
             "call_forwarding_when_unanswered_supported_bool";
 
-     /**
-      * Boolean indicating if carrier supports call forwarding option "When busy".
-      *
-      * {@code true}: Call forwarding option "When busy" is supported.
-      * {@code false}: Call forwarding option "When busy" is not supported. Option will be
-      * removed in the UI.
-      *
-      * By default this value is true.
-      * @hide
-      */
+    /**
+     * Boolean indicating if carrier supports call forwarding option "When busy".
+     *
+     * {@code true}: Call forwarding option "When busy" is supported.
+     * {@code false}: Call forwarding option "When busy" is not supported. Option will be
+     * removed in the UI.
+     *
+     * By default this value is true.
+     * @hide
+     */
     public static final String KEY_CALL_FORWARDING_WHEN_BUSY_SUPPORTED_BOOL =
             "call_forwarding_when_busy_supported_bool";
 
@@ -259,12 +261,12 @@
     public static final String KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL =
             "additional_settings_call_waiting_visibility_bool";
 
-   /**
-    * Boolean indicating if the "Call barring" item is visible in the Call Settings menu.
-    * If true, the "Call Barring" menu will be visible. If false, the menu will be gone.
-    *
-    * Disabled by default.
-    */
+    /**
+     * Boolean indicating if the "Call barring" item is visible in the Call Settings menu.
+     * If true, the "Call Barring" menu will be visible. If false, the menu will be gone.
+     *
+     * Disabled by default.
+     */
     public static final String KEY_CALL_BARRING_VISIBILITY_BOOL =
             "call_barring_visibility_bool";
 
@@ -321,8 +323,8 @@
      * If true, this will prevent the IccNetworkDepersonalizationPanel from being shown, and
      * effectively disable the "Sim network lock" feature.
      */
-    public static final String
-            KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool";
+    public static final String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL =
+            "ignore_sim_network_locked_events_bool";
 
     /**
      * When checking if a given number is the voicemail number, if this flag is true
@@ -340,16 +342,15 @@
      * consequence: there will be no way to make an Emergency Call if your SIM is network-locked and
      * you don't know the PIN.)
      */
-    public static final String
-            KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
+    public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL =
+            "sim_network_unlock_allow_dismiss_bool";
 
     /**
      * Flag indicating whether or not sending emergency SMS messages over IMS
      * is supported when in LTE/limited LTE (Emergency only) service mode..
-     *
      */
-    public static final String
-            KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL = "support_emergency_sms_over_ims_bool";
+    public static final String KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL =
+            "support_emergency_sms_over_ims_bool";
 
     /** Flag indicating if the phone is a world phone */
     public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
@@ -359,8 +360,8 @@
      * If true, entitlement checks will be executed if device has been configured for it,
      * If false, entitlement checks will be skipped.
      */
-    public static final String
-            KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
+    public static final String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL =
+            "require_entitlement_checks_bool";
 
     /**
      * Flag indicating if the carrier supports tethering of mobile data.
@@ -392,8 +393,8 @@
      * consistent with the regular Dialer, this value should agree with the corresponding values
      * from config.xml under apps/Contacts.
      */
-    public static final String
-            KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
+    public static final String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL =
+            "enable_dialer_key_vibration_bool";
 
     /** Flag indicating if dtmf tone type is enabled */
     public static final String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
@@ -416,11 +417,12 @@
      * @hide
      */
     public static final String KEY_PLAY_CALL_RECORDING_TONE_BOOL = "play_call_recording_tone_bool";
+
     /**
      * Determines if the carrier requires converting the destination number before sending out an
      * SMS. Certain networks and numbering plans require different formats.
      */
-    public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL=
+    public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL =
             "sms_requires_destination_number_conversion_bool";
 
     /**
@@ -428,7 +430,8 @@
      * platforms, even the ones with hard SEND/END keys, but for maximum flexibility it's controlled
      * by a flag here (which can be overridden on a per-product basis.)
      */
-    public static final String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
+    public static final String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL =
+            "show_onscreen_dial_button_bool";
 
     /** Determines if device implements a noise suppression device for in call audio. */
     public static final String
@@ -440,8 +443,8 @@
      * accidental redialing from the call log UI. This is a good idea, so the default here is
      * false.)
      */
-    public static final String
-            KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
+    public static final String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL =
+            "allow_emergency_numbers_in_call_log_bool";
 
     /**
      * A string array containing numbers that shouldn't be included in the call log.
@@ -467,10 +470,9 @@
      * Flag indicating whether to show single operator row in the choose network setting.
      *
      * The device configuration value {@code config_enableNewAutoSelectNetworkUI} ultimately
-     * controls whether this carrier configuration option is used.  Where
-     * {@code config_enableNewAutoSelectNetworkUI} is false, the value of the
-     * {@link #KEY_SHOW_SINGLE_OPERATOR_ROW_IN_CHOOSE_NETWORK_SETTING_BOOL} carrier configuration
-     * option is ignored.
+     * controls whether this carrier configuration option is used.
+     * Where {@code config_enableNewAutoSelectNetworkUI} is false, the value of this
+     * carrier configuration is ignored.
      *
      * If {@code true}, default value, merge the duplicate networks which with the same plmn, keep
      * the one that with the higher signal strength level.
@@ -498,18 +500,18 @@
      * @deprecated Never implemented. Has no behavior impact when override. DO NOT USE.
      */
     @Deprecated
-    public static final String
-            KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
+    public static final String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL =
+            "simplified_network_settings_bool";
 
     /** Control whether users can reach the SIM lock settings. */
-    public static final String
-            KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
+    public static final String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
 
     /** Control whether users can edit APNs in Settings. */
     public static final String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
 
     /** Control whether users can choose a network operator. */
-    public static final String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
+    public static final String KEY_OPERATOR_SELECTION_EXPAND_BOOL =
+            "operator_selection_expand_bool";
 
     /**
      * Used in the Preferred Network Types menu to determine if the 2G option is displayed.
@@ -537,7 +539,8 @@
      * TODO: This should be combined with config_use_hfa_for_provisioning and implemented as an enum
      * (NONE, HFA, OTASP).
      */
-    public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
+    public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL =
+            "use_otasp_for_provisioning_bool";
 
     /** Display carrier settings menu if true */
     public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
@@ -562,25 +565,26 @@
      * available the user cannot use voicemail. This flag allows the user to edit the voicemail
      * number in such cases, and is false by default.
      */
-    public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL= "editable_voicemail_number_bool";
+    public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL =
+            "editable_voicemail_number_bool";
 
     /**
      * Determine whether the voicemail notification is persistent in the notification bar. If true,
      * the voicemail notifications cannot be dismissed from the notification bar.
      */
-    public static final String
-            KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
+    public static final String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL =
+            "voicemail_notification_persistent_bool";
 
     /** For IMS video over LTE calls, determines whether video pause signalling is supported. */
-    public static final String
-            KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
+    public static final String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL =
+            "support_pause_ims_video_calls_bool";
 
     /**
      * Disables dialing "*228" (OTASP provisioning) on CDMA carriers where it is not supported or is
      * potentially harmful by locking the SIM to 3G.
      */
-    public static final String
-            KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
+    public static final String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL =
+            "disable_cdma_activation_code_bool";
 
     /**
      * List of network type constants which support only a single data connection at a time.
@@ -588,8 +592,8 @@
      * @see TelephonyManager NETWORK_TYPE_*
      * @see #KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY
      */
-    public static final String
-            KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = "only_single_dc_allowed_int_array";
+    public static final String KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY =
+            "only_single_dc_allowed_int_array";
 
     /**
      * Only apply if {@link #KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY} specifies the network types that
@@ -604,15 +608,15 @@
      * Override the platform's notion of a network operator being considered roaming.
      * Value is string array of MCCMNCs to be considered roaming for 3GPP RATs.
      */
-    public static final String
-            KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array";
+    public static final String KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY =
+            "gsm_roaming_networks_string_array";
 
     /**
      * Override the platform's notion of a network operator being considered not roaming.
      * Value is string array of MCCMNCs to be considered not roaming for 3GPP RATs.
      */
-    public static final String
-            KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array";
+    public static final String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY =
+            "gsm_nonroaming_networks_string_array";
 
     /**
      * The package name containing the ImsService that will be bound to the telephony framework to
@@ -622,6 +626,7 @@
      * {@link #KEY_CONFIG_IMS_RCS_PACKAGE_OVERRIDE_STRING} instead to configure these values
      * separately. If any of those values are not empty, they will override this value.
      */
+    @Deprecated
     public static final String KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING =
             "config_ims_package_override_string";
 
@@ -668,7 +673,7 @@
 
     /**
      * Override the platform's notion of a network operator being considered non roaming.
-     * If true all networks are considered as home network a.k.a non-roaming.  When false,
+     * If true all networks are considered as home network a.k.a. non-roaming. When false,
      * the 2 pairs of CMDA and GSM roaming/non-roaming arrays are consulted.
      *
      * @see #KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY
@@ -703,8 +708,7 @@
      *   <li>3: {@link #USSD_OVER_IMS_ONLY} </li>
      * </ul>
      */
-    public static final String KEY_CARRIER_USSD_METHOD_INT =
-            "carrier_ussd_method_int";
+    public static final String KEY_CARRIER_USSD_METHOD_INT = "carrier_ussd_method_int";
 
     /**
      * Flag specifying whether to show an alert dialog for 5G disable when the user disables VoLTE.
@@ -735,8 +739,7 @@
      * downgrading the call in the process.
      * @hide
      */
-    public static final String KEY_ALLOW_MERGING_RTT_CALLS_BOOL =
-             "allow_merging_rtt_calls_bool";
+    public static final String KEY_ALLOW_MERGING_RTT_CALLS_BOOL = "allow_merging_rtt_calls_bool";
 
     /**
      * Flag specifying whether the carrier wants to notify the user when a VT call has been handed
@@ -797,7 +800,7 @@
 
     /**
      * When {@code true}, changes to the mobile data enabled switch will not cause the VT
-     * registration state to change.  That is, turning on or off mobile data will not cause VT to be
+     * registration state to change. That is, turning on or off mobile data will not cause VT to be
      * enabled or disabled.
      * When {@code false}, disabling mobile data will cause VT to be de-registered.
      */
@@ -820,7 +823,8 @@
      * carrier provisioning. If false: hard disabled. If true: then depends on carrier
      * provisioning, availability etc.
      */
-    public static final String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
+    public static final String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL =
+            "carrier_wfc_ims_available_bool";
 
     /**
      * Flag specifying whether Cross SIM over IMS should be available for carrier.
@@ -860,8 +864,8 @@
             "international_roaming_dial_string_replace_string_array";
 
     /**
-     * Flag specifying whether WFC over IMS supports the "wifi only" option.  If false, the wifi
-     * calling settings will not include an option for "wifi only".  If true, the wifi calling
+     * Flag specifying whether WFC over IMS supports the "wifi only" option. If false, the wifi
+     * calling settings will not include an option for "wifi only". If true, the wifi calling
      * settings will include an option for "wifi only"
      * <p>
      * By default, it is assumed that WFC supports "wifi only".
@@ -904,7 +908,7 @@
 
     /**
      * Flag indicating whether failed calls due to no service should prompt the user to enable
-     * WIFI calling.  When {@code true}, if the user attempts to establish a call when there is no
+     * WIFI calling. When {@code true}, if the user attempts to establish a call when there is no
      * service available, they are connected to WIFI, and WIFI calling is disabled, a different
      * call failure message will be used to encourage the user to enable WIFI calling.
      * @hide
@@ -930,8 +934,8 @@
      * {@link Ims#KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE}
      */
     @Deprecated
-    public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
-            = "carrier_volte_provisioning_required_bool";
+    public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL =
+            "carrier_volte_provisioning_required_bool";
 
     /**
      * Flag indicating whether or not the IMS MmTel UT capability requires carrier provisioning
@@ -974,22 +978,22 @@
      * As of now, Verizon is the only carrier enforcing this dependency in their
      * WFC awareness and activation requirements.
      */
-    public static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL
-            = "carrier_volte_override_wfc_provisioning_bool";
+    public static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL =
+            "carrier_volte_override_wfc_provisioning_bool";
 
     /**
      * Override the device's configuration for the cellular data service to use for this SIM card.
      * @hide
      */
-    public static final String KEY_CARRIER_DATA_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING
-            = "carrier_data_service_wwan_package_override_string";
+    public static final String KEY_CARRIER_DATA_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING =
+            "carrier_data_service_wwan_package_override_string";
 
     /**
      * Override the device's configuration for the IWLAN data service to use for this SIM card.
      * @hide
      */
-    public static final String KEY_CARRIER_DATA_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING
-            = "carrier_data_service_wlan_package_override_string";
+    public static final String KEY_CARRIER_DATA_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING =
+            "carrier_data_service_wlan_package_override_string";
 
     /**
      * Override the device's configuration for the cellular data service class to use
@@ -1008,8 +1012,8 @@
             "carrier_data_service_wlan_class_override_string";
 
     /** Flag specifying whether VoLTE TTY is supported. */
-    public static final String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL
-            = "carrier_volte_tty_supported_bool";
+    public static final String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL =
+            "carrier_volte_tty_supported_bool";
 
     /** Flag specifying whether VoWIFI TTY is supported.
      * @hide
@@ -1021,37 +1025,37 @@
      * Flag specifying whether IMS service can be turned off. If false then the service will not be
      * turned-off completely, but individual features can be disabled.
      */
-    public static final String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL
-            = "carrier_allow_turnoff_ims_bool";
+    public static final String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL =
+            "carrier_allow_turnoff_ims_bool";
 
     /**
      * Flag specifying whether Generic Bootstrapping Architecture capable SIM is required for IMS.
      */
-    public static final String KEY_CARRIER_IMS_GBA_REQUIRED_BOOL
-            = "carrier_ims_gba_required_bool";
+    public static final String KEY_CARRIER_IMS_GBA_REQUIRED_BOOL =
+            "carrier_ims_gba_required_bool";
 
     /**
-     * Flag specifying whether IMS instant lettering is available for the carrier.  {@code True} if
+     * Flag specifying whether IMS instant lettering is available for the carrier. {@code True} if
      * instant lettering is available for the carrier, {@code false} otherwise.
      */
     public static final String KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL =
             "carrier_instant_lettering_available_bool";
 
-    /*
+    /**
      * Flag specifying whether IMS should be the first phone attempted for E911 even if the
      * phone is not in service.
      */
-    public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL
-            = "carrier_use_ims_first_for_emergency_bool";
+    public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL =
+            "carrier_use_ims_first_for_emergency_bool";
 
     /**
      * When {@code true}, the determination of whether to place a call as an emergency call will be
      * based on the known {@link android.telephony.emergency.EmergencyNumber}s for the SIM on which
-     * the call is being placed.  In a dual SIM scenario, if Sim A has the emergency numbers
+     * the call is being placed. In a dual SIM scenario, if Sim A has the emergency numbers
      * 123, 456 and Sim B has the emergency numbers 789, and the user places a call on SIM A to 789,
      * it will not be treated as an emergency call in this case.
      * When {@code false}, the determination is based on the emergency numbers from all device SIMs,
-     * regardless of which SIM the call is being placed on.  If Sim A has the emergency numbers
+     * regardless of which SIM the call is being placed on. If Sim A has the emergency numbers
      * 123, 456 and Sim B has the emergency numbers 789, and the user places a call on SIM A to 789,
      * the call will be dialed as an emergency number, but with an unspecified routing.
      * @hide
@@ -1062,7 +1066,7 @@
     /**
      * When IMS instant lettering is available for a carrier (see
      * {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), determines the list of characters
-     * which may not be contained in messages.  Should be specified as a regular expression suitable
+     * which may not be contained in messages. Should be specified as a regular expression suitable
      * for use with {@link String#matches(String)}.
      */
     public static final String KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING =
@@ -1071,8 +1075,8 @@
     /**
      * When IMS instant lettering is available for a carrier (see
      * {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), determines a list of characters which
-     * must be escaped with a backslash '\' character.  Should be specified as a string containing
-     * the characters to be escaped.  For example to escape quote and backslash the string would be
+     * must be escaped with a backslash '\' character. Should be specified as a string containing
+     * the characters to be escaped. For example to escape quote and backslash the string would be
      * a quote and a backslash.
      */
     public static final String KEY_CARRIER_INSTANT_LETTERING_ESCAPED_CHARS_STRING =
@@ -1081,10 +1085,10 @@
     /**
      * When IMS instant lettering is available for a carrier (see
      * {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), determines the character encoding
-     * which will be used when determining the length of messages.  Used in the InCall UI to limit
-     * the number of characters the user may type.  If empty-string, the instant lettering
-     * message size limit will be enforced on a 1:1 basis.  That is, each character will count
-     * towards the messages size limit as a single bye.  If a character encoding is specified, the
+     * which will be used when determining the length of messages. Used in the InCall UI to limit
+     * the number of characters the user may type. If empty-string, the instant lettering
+     * message size limit will be enforced on a 1:1 basis. That is, each character will count
+     * towards the messages size limit as a single byte. If a character encoding is specified, the
      * message size limit will be based on the number of bytes in the message per the specified
      * encoding.
      */
@@ -1093,7 +1097,7 @@
 
     /**
      * When IMS instant lettering is available for a carrier (see
-     * {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), the length limit for messages.  Used
+     * {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), the length limit for messages. Used
      * in the InCall UI to ensure the user cannot enter more characters than allowed by the carrier.
      * See also {@link #KEY_CARRIER_INSTANT_LETTERING_ENCODING_STRING} for more information on how
      * the length of the message is calculated.
@@ -1114,7 +1118,8 @@
      * manager can control and route outgoing and incoming phone calls, even if they're placed
      * using another connection service (PSTN, for example).
      */
-    public static final String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
+    public static final String KEY_DEFAULT_SIM_CALL_MANAGER_STRING =
+            "default_sim_call_manager_string";
 
     /**
      * The default flag specifying whether ETWS/CMAS test setting is forcibly disabled in
@@ -1217,8 +1222,7 @@
      * CDMA carrier ERI (Enhanced Roaming Indicator) file name
      * @hide
      */
-    public static final String KEY_CARRIER_ERI_FILE_NAME_STRING =
-            "carrier_eri_file_name_string";
+    public static final String KEY_CARRIER_ERI_FILE_NAME_STRING = "carrier_eri_file_name_string";
 
     /* The following 3 fields are related to carrier visual voicemail. */
 
@@ -1242,13 +1246,12 @@
      * Whether cellular data is required to access visual voicemail.
      */
     public static final String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL =
-        "vvm_cellular_data_required_bool";
+            "vvm_cellular_data_required_bool";
 
     /**
      * The default OMTP visual voicemail client prefix to use. Defaulted to "//VVM"
      */
-    public static final String KEY_VVM_CLIENT_PREFIX_STRING =
-            "vvm_client_prefix_string";
+    public static final String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
 
     /**
      * Whether to use SSL to connect to the visual voicemail IMAP server. Defaulted to false.
@@ -1273,8 +1276,7 @@
      * <p>This is for carriers that does not support VVM deactivation so voicemail can continue to
      * function without the data cost.
      */
-    public static final String KEY_VVM_LEGACY_MODE_ENABLED_BOOL =
-            "vvm_legacy_mode_enabled_bool";
+    public static final String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool";
 
     /**
      * Whether to prefetch audio data on new voicemail arrival, defaulted to true.
@@ -1288,7 +1290,8 @@
      * @deprecated use {@link #KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY}.
      */
     @Deprecated
-    public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+    public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING =
+            "carrier_vvm_package_name_string";
 
     /**
      * A list of the carrier's visual voicemail app package names to ensure that dialer visual
@@ -1307,7 +1310,7 @@
      * Status screen. The default value is true.
      */
     public static final String KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL =
-        "show_signal_strength_in_sim_status_bool";
+            "show_signal_strength_in_sim_status_bool";
 
     /**
      * Flag specifying if we should interpret all signal strength as one bar higher
@@ -1386,9 +1389,8 @@
     public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL =
             "ignore_rtt_mode_setting_bool";
 
-
     /**
-     * Determines whether adhoc conference calls are supported by a carrier.  When {@code true},
+     * Determines whether adhoc conference calls are supported by a carrier. When {@code true},
      * adhoc conference calling is supported, {@code false otherwise}.
      */
     public static final String KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL =
@@ -1396,14 +1398,14 @@
 
     /**
      * Determines whether conference participants can be added to existing call to form an adhoc
-     * conference call (in contrast to merging calls to form a conference).  When {@code true},
+     * conference call (in contrast to merging calls to form a conference). When {@code true},
      * adding conference participants to existing call is supported, {@code false otherwise}.
      */
     public static final String KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL =
             "support_add_conference_participants_bool";
 
     /**
-     * Determines whether conference calls are supported by a carrier.  When {@code true},
+     * Determines whether conference calls are supported by a carrier. When {@code true},
      * conference calling is supported, {@code false otherwise}.
      */
     public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
@@ -1411,7 +1413,7 @@
     /**
      * Determines whether a maximum size limit for IMS conference calls is enforced on the device.
      * When {@code true}, IMS conference calls will be limited to at most
-     * {@link #KEY_IMS_CONFERENCE_SIZE_LIMIT_INT} participants.  When {@code false}, no attempt is
+     * {@link #KEY_IMS_CONFERENCE_SIZE_LIMIT_INT} participants. When {@code false}, no attempt is
      * made to limit the number of participants in a conference (the carrier will raise an error
      * when an attempt is made to merge too many participants into a conference).
      * <p>
@@ -1425,14 +1427,14 @@
 
     /**
      * Determines the maximum number of participants the carrier supports for a conference call.
-     * This number is exclusive of the current device.  A conference between 3 devices, for example,
+     * This number is exclusive of the current device. A conference between 3 devices, for example,
      * would have a size limit of 2 participants.
      * Enforced when {@link #KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL} is {@code true}.
      */
     public static final String KEY_IMS_CONFERENCE_SIZE_LIMIT_INT = "ims_conference_size_limit_int";
 
     /**
-     * Determines whether manage IMS conference calls is supported by a carrier.  When {@code true},
+     * Determines whether manage IMS conference calls is supported by a carrier. When {@code true},
      * manage IMS conference call is supported, {@code false otherwise}.
      * @hide
      */
@@ -1455,7 +1457,7 @@
      * and B and C are considered the conference peers.
      * <p>
      * When {@code true}, the conference peer will display the conference state if it receives
-     * conference event package data from the network.  When {@code false}, the conference peer will
+     * conference event package data from the network. When {@code false}, the conference peer will
      * ignore conference event package data received from the network.
      * @hide
      */
@@ -1473,7 +1475,7 @@
 
     /**
      * Indicates whether the carrier supports the negotiations of RFC8285 compliant RTP header
-     * extensions supported on a call during the Session Description Protocol (SDP).  This option
+     * extensions supported on a call during the Session Description Protocol (SDP). This option
      * is only used when {@link #KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL} is
      * {@code true}.
      * <p>
@@ -1503,7 +1505,7 @@
             "display_hd_audio_property_bool";
 
     /**
-     * Determines whether IMS conference calls are supported by a carrier.  When {@code true},
+     * Determines whether IMS conference calls are supported by a carrier. When {@code true},
      * IMS conference calling is supported, {@code false} otherwise.
      * @hide
      */
@@ -1512,9 +1514,9 @@
 
     /**
      * Determines whether the device will locally disconnect an IMS conference when the participant
-     * count drops to zero.  When {@code true}, it is assumed the carrier does NOT disconnect a
+     * count drops to zero. When {@code true}, it is assumed the carrier does NOT disconnect a
      * conference when the participant count drops to zero and that the device must do this by
-     * disconnecting the conference locally.  When {@code false}, it is assumed that the carrier
+     * disconnecting the conference locally. When {@code false}, it is assumed that the carrier
      * is responsible for disconnecting the conference when there are no longer any participants
      * present.
      * <p>
@@ -1530,8 +1532,8 @@
             "local_disconnect_empty_ims_conference_bool";
 
     /**
-     * Determines whether video conference calls are supported by a carrier.  When {@code true},
-     * video calls can be merged into conference calls, {@code false} otherwiwse.
+     * Determines whether video conference calls are supported by a carrier. When {@code true},
+     * video calls can be merged into conference calls, {@code false} otherwise.
      * <p>
      * Note: even if video conference calls are not supported, audio calls may be merged into a
      * conference if {@link #KEY_SUPPORT_CONFERENCE_CALL_BOOL} is {@code true}.
@@ -1568,7 +1570,8 @@
     /**
      * Determine whether preferred network type can be shown.
      */
-    public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
+    public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL =
+            "hide_preferred_network_type_bool";
 
     /**
      * String array for package names that need to be enabled for this carrier.
@@ -1800,20 +1803,20 @@
     public static final String KEY_SIM_COUNTRY_ISO_OVERRIDE_STRING =
             "sim_country_iso_override_string";
 
-   /**
-    * The Component Name of a carrier-provided CallScreeningService implementation. Telecom will
-    * bind to {@link android.telecom.CallScreeningService} for ALL incoming calls and provide
-    * the carrier
-    * CallScreeningService with the opportunity to allow or block calls.
-    * <p>
-    * The String includes the package name/the class name.
-    * Example:
-    * <item>com.android.carrier/com.android.carrier.callscreeningserviceimpl</item>
-    * <p>
-    * Using {@link ComponentName#flattenToString()} to convert a ComponentName object to String.
-    * Using {@link ComponentName#unflattenFromString(String)} to convert a String object to a
-    * ComponentName.
-    */
+    /**
+     * The Component Name of a carrier-provided CallScreeningService implementation. Telecom will
+     * bind to {@link android.telecom.CallScreeningService} for ALL incoming calls and provide
+     * the carrier
+     * CallScreeningService with the opportunity to allow or block calls.
+     * <p>
+     * The String includes the package name/the class name.
+     * Example:
+     * <item>com.android.carrier/com.android.carrier.callscreeningserviceimpl</item>
+     * <p>
+     * Using {@link ComponentName#flattenToString()} to convert a ComponentName object to String.
+     * Using {@link ComponentName#unflattenFromString(String)} to convert a String object to a
+     * ComponentName.
+     */
     public static final String KEY_CARRIER_CALL_SCREENING_APP_STRING = "call_screening_app";
 
     /**
@@ -1925,20 +1928,20 @@
             "broadcast_emergency_call_state_changes_bool";
 
     /**
-      * Indicates whether STK LAUNCH_BROWSER command is disabled.
-      * If {@code true}, then the browser will not be launched
-      * on UI for the LAUNCH_BROWSER STK command.
-      * @hide
-      */
+     * Indicates whether STK LAUNCH_BROWSER command is disabled.
+     * If {@code true}, then the browser will not be launched
+     * on UI for the LAUNCH_BROWSER STK command.
+     * @hide
+     */
     public static final String KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL =
             "stk_disable_launch_browser_bool";
 
     /**
-      * Boolean indicating if the helper text for STK GET INKEY/INPUT commands with the digit only
-      * mode is displayed on the input screen.
-      * The helper text is dispayed regardless of the input mode, if {@code false}.
-      * @hide
-      */
+     * Boolean indicating if the helper text for STK GET INKEY/INPUT commands with the digit only
+     * mode is displayed on the input screen.
+     * The helper text is displayed regardless of the input mode, if {@code false}.
+     * @hide
+     */
     public static final String KEY_HIDE_DIGITS_HELPER_TEXT_ON_STK_INPUT_SCREEN_BOOL =
             "hide_digits_helper_text_on_stk_input_screen_bool";
 
@@ -2098,16 +2101,22 @@
     public static final String KEY_MMS_ALLOW_ATTACH_AUDIO_BOOL = "allowAttachAudio";
     public static final String KEY_MMS_APPEND_TRANSACTION_ID_BOOL = "enabledTransID";
     public static final String KEY_MMS_GROUP_MMS_ENABLED_BOOL = "enableGroupMms";
-    public static final String KEY_MMS_MMS_DELIVERY_REPORT_ENABLED_BOOL = "enableMMSDeliveryReports";
+    public static final String KEY_MMS_MMS_DELIVERY_REPORT_ENABLED_BOOL =
+            "enableMMSDeliveryReports";
     public static final String KEY_MMS_MMS_ENABLED_BOOL = "enabledMMS";
     public static final String KEY_MMS_MMS_READ_REPORT_ENABLED_BOOL = "enableMMSReadReports";
     public static final String KEY_MMS_MULTIPART_SMS_ENABLED_BOOL = "enableMultipartSMS";
     public static final String KEY_MMS_NOTIFY_WAP_MMSC_ENABLED_BOOL = "enabledNotifyWapMMSC";
-    public static final String KEY_MMS_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES_BOOL = "sendMultipartSmsAsSeparateMessages";
-    public static final String KEY_MMS_SHOW_CELL_BROADCAST_APP_LINKS_BOOL = "config_cellBroadcastAppLinks";
-    public static final String KEY_MMS_SMS_DELIVERY_REPORT_ENABLED_BOOL = "enableSMSDeliveryReports";
-    public static final String KEY_MMS_SUPPORT_HTTP_CHARSET_HEADER_BOOL = "supportHttpCharsetHeader";
-    public static final String KEY_MMS_SUPPORT_MMS_CONTENT_DISPOSITION_BOOL = "supportMmsContentDisposition";
+    public static final String KEY_MMS_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES_BOOL =
+            "sendMultipartSmsAsSeparateMessages";
+    public static final String KEY_MMS_SHOW_CELL_BROADCAST_APP_LINKS_BOOL =
+            "config_cellBroadcastAppLinks";
+    public static final String KEY_MMS_SMS_DELIVERY_REPORT_ENABLED_BOOL =
+            "enableSMSDeliveryReports";
+    public static final String KEY_MMS_SUPPORT_HTTP_CHARSET_HEADER_BOOL =
+            "supportHttpCharsetHeader";
+    public static final String KEY_MMS_SUPPORT_MMS_CONTENT_DISPOSITION_BOOL =
+            "supportMmsContentDisposition";
     public static final String KEY_MMS_ALIAS_MAX_CHARS_INT = "aliasMaxChars";
     public static final String KEY_MMS_ALIAS_MIN_CHARS_INT = "aliasMinChars";
     public static final String KEY_MMS_HTTP_SOCKET_TIMEOUT_INT = "httpSocketTimeout";
@@ -2116,7 +2125,8 @@
     public static final String KEY_MMS_MAX_MESSAGE_SIZE_INT = "maxMessageSize";
     public static final String KEY_MMS_MESSAGE_TEXT_MAX_SIZE_INT = "maxMessageTextSize";
     public static final String KEY_MMS_RECIPIENT_LIMIT_INT = "recipientLimit";
-    public static final String KEY_MMS_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD_INT = "smsToMmsTextLengthThreshold";
+    public static final String KEY_MMS_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD_INT =
+            "smsToMmsTextLengthThreshold";
     public static final String KEY_MMS_SMS_TO_MMS_TEXT_THRESHOLD_INT = "smsToMmsTextThreshold";
     public static final String KEY_MMS_SUBJECT_MAX_LENGTH_INT = "maxSubjectLength";
     public static final String KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING = "emailGatewayNumber";
@@ -2145,7 +2155,7 @@
      * The flatten {@link android.content.ComponentName componentName} of the activity that can
      * setup the device and activate with the network per carrier requirements.
      *
-     * e.g, com.google.android.carrierPackageName/.CarrierActivityName
+     * e.g., com.google.android.carrierPackageName/.CarrierActivityName
      * @hide
      */
     @SystemApi
@@ -2286,7 +2296,7 @@
 
     /**
      * Determines whether the carrier supports making non-emergency phone calls while the phone is
-     * in emergency callback mode.  Default value is {@code true}, meaning that non-emergency calls
+     * in emergency callback mode. Default value is {@code true}, meaning that non-emergency calls
      * are allowed in emergency callback mode.
      */
     public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL =
@@ -2309,7 +2319,7 @@
 
     /**
      * Flag indicating whether to allow carrier video calls to emergency numbers.
-     * When {@code true}, video calls to emergency numbers will be allowed.  When {@code false},
+     * When {@code true}, video calls to emergency numbers will be allowed. When {@code false},
      * video calls to emergency numbers will be initiated as audio-only calls instead.
      */
     public static final String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL =
@@ -2337,7 +2347,7 @@
      * When presence is supported, the device should use the
      * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE} bit mask and set the
      * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE_VT_CAPABLE} bit to indicate
-     * whether each contact supports video calling.  The UI is made aware that presence is enabled
+     * whether each contact supports video calling. The UI is made aware that presence is enabled
      * via {@link android.telecom.PhoneAccount#CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE}
      * and can choose to hide or show the video calling icon based on whether a contact supports
      * video.
@@ -2361,7 +2371,7 @@
      * contacts emergency services. Platform considers values for below cases:
      *  1) 0 <= VALUE <= 604800(one week): the value will be used as the duration directly.
      *  2) VALUE > 604800(one week): will use the default value as duration instead.
-     *  3) VALUE < 0: block will be disabled forever until user re-eanble block manually,
+     *  3) VALUE < 0: block will be disabled forever until user re-enable block manually,
      *     the suggested value to disable forever is -1.
      * See {@code android.provider.BlockedNumberContract#notifyEmergencyContact(Context)}
      * See {@code android.provider.BlockedNumberContract#isBlocked(Context, String)}.
@@ -2391,7 +2401,7 @@
 
     /**
      * For carriers which require an empty flash to be sent before sending the normal 3-way calling
-     * flash, the duration in milliseconds of the empty flash to send.  When {@code 0}, no empty
+     * flash, the duration in milliseconds of the empty flash to send. When {@code 0}, no empty
      * flash is sent.
      */
     public static final String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
@@ -2431,8 +2441,7 @@
      * Int indicating the max number length for FDN
      * @hide
      */
-    public static final String KEY_FDN_NUMBER_LENGTH_LIMIT_INT =
-            "fdn_number_length_limit_int";
+    public static final String KEY_FDN_NUMBER_LENGTH_LIMIT_INT = "fdn_number_length_limit_int";
 
     /**
      * Report IMEI as device id even if it's a CDMA/LTE phone.
@@ -2444,16 +2453,15 @@
     /**
      * The families of Radio Access Technologies that will get clustered and ratcheted,
      * ie, we will report transitions up within the family, but not down until we change
-     * cells.  This prevents flapping between base technologies and higher techs that are
+     * cells. This prevents flapping between base technologies and higher techs that are
      * granted on demand within the cell.
      * @hide
      */
-    public static final String KEY_RATCHET_RAT_FAMILIES =
-            "ratchet_rat_families";
+    public static final String KEY_RATCHET_RAT_FAMILIES = "ratchet_rat_families";
 
     /**
      * Flag indicating whether some telephony logic will treat a call which was formerly a video
-     * call as if it is still a video call.  When {@code true}:
+     * call as if it is still a video call. When {@code true}:
      * <p>
      * Logic which will automatically drop a video call which takes place over WIFI when a
      * voice call is answered (see {@link #KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL}.
@@ -2465,7 +2473,7 @@
 
     /**
      * When {@code true}, if the user is in an ongoing video call over WIFI and answers an incoming
-     * audio call, the video call will be disconnected before the audio call is answered.  This is
+     * audio call, the video call will be disconnected before the audio call is answered. This is
      * in contrast to the usual expected behavior where a foreground video call would be put into
      * the background and held when an incoming audio call is answered.
      */
@@ -2475,8 +2483,8 @@
     /**
      * Flag indicating whether the carrier supports merging wifi calls when VoWIFI is disabled.
      * This can happen in the case of a carrier which allows offloading video calls to WIFI
-     * separately of whether voice over wifi is enabled.  In such a scenario when two video calls
-     * are downgraded to voice, they remain over wifi.  However, if VoWIFI is disabled, these calls
+     * separately of whether voice over wifi is enabled. In such a scenario when two video calls
+     * are downgraded to voice, they remain over wifi. However, if VoWIFI is disabled, these calls
      * cannot be merged.
      */
     public static final String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL =
@@ -2486,9 +2494,9 @@
      * Flag indicating whether the carrier supports the Hold command while in an IMS call.
      * <p>
      * The device configuration value {@code config_device_respects_hold_carrier_config} ultimately
-     * controls whether this carrier configuration option is used.  Where
-     * {@code config_device_respects_hold_carrier_config} is false, the value of the
-     * {@link #KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL} carrier configuration option is ignored.
+     * controls whether this carrier configuration option is used.
+     * Where {@code config_device_respects_hold_carrier_config} is false, the value of
+     * this carrier configuration is ignored.
      * @hide
      */
     public static final String KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL = "allow_hold_in_ims_call";
@@ -2543,8 +2551,7 @@
      * <p>
      * This is {@code true} by default.
      */
-    public static final String KEY_ALLOW_HOLD_VIDEO_CALL_BOOL =
-            "allow_hold_video_call_bool";
+    public static final String KEY_ALLOW_HOLD_VIDEO_CALL_BOOL = "allow_hold_video_call_bool";
 
     /**
      * When true, indicates that the HD audio icon in the in-call screen should not be shown for
@@ -2638,7 +2645,8 @@
      * is returned.
      * @hide
      */
-    public static final String KEY_FILTERED_CNAP_NAMES_STRING_ARRAY = "filtered_cnap_names_string_array";
+    public static final String KEY_FILTERED_CNAP_NAMES_STRING_ARRAY =
+            "filtered_cnap_names_string_array";
 
     /**
      * The RCS configuration server URL. This URL is used to initiate RCS provisioning.
@@ -2706,9 +2714,9 @@
             "emergency_notification_delay_int";
 
     /**
-     * When {@code true}, the carrier allows the user of the
-     * {@link TelephonyManager#sendUssdRequest(String, TelephonyManager.UssdResponseCallback,
-     * Handler)} API to perform USSD requests.  {@code True} by default.
+     * When {@code true}, the carrier allows the user of the {@link
+     * TelephonyManager#sendUssdRequest(String, TelephonyManager.UssdResponseCallback, Handler)}
+     * API to perform USSD requests. {@code True} by default.
      * @hide
      */
     public static final String KEY_ALLOW_USSD_REQUESTS_VIA_TELEPHONY_MANAGER_BOOL =
@@ -2720,7 +2728,7 @@
      * fails.
      */
     public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL =
-        "support_3gpp_call_forwarding_while_roaming_bool";
+            "support_3gpp_call_forwarding_while_roaming_bool";
 
     /**
      * Boolean indicating whether to display voicemail number as default call forwarding number in
@@ -2786,8 +2794,7 @@
      * This setting may be still overridden by explicit user choice. By default,
      * {@link #DATA_CYCLE_USE_PLATFORM_DEFAULT} will be used.
      */
-    public static final String KEY_MONTHLY_DATA_CYCLE_DAY_INT =
-            "monthly_data_cycle_day_int";
+    public static final String KEY_MONTHLY_DATA_CYCLE_DAY_INT = "monthly_data_cycle_day_int";
 
     /**
      * When {@link #KEY_MONTHLY_DATA_CYCLE_DAY_INT}, {@link #KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG},
@@ -2833,7 +2840,7 @@
 
     /**
      * Controls if the device should automatically warn the user that sim voice & data function
-     * might be limited due to dual sim scenario. When set to {@true} display the notification,
+     * might be limited due to dual sim scenario. When set to {@code true} display the notification,
      * {@code false} otherwise.
      * @hide
      */
@@ -2859,16 +2866,14 @@
      * their cellular data limit. When set to {@code false} the carrier is
      * expected to have implemented their own notification mechanism. {@code true} by default.
      */
-    public static final String KEY_DATA_LIMIT_NOTIFICATION_BOOL =
-            "data_limit_notification_bool";
+    public static final String KEY_DATA_LIMIT_NOTIFICATION_BOOL = "data_limit_notification_bool";
 
     /**
      * Controls if the device should automatically notify the user when rapid
      * cellular data usage is observed. When set to {@code false} the carrier is
-     * expected to have implemented their own notification mechanism.  {@code true} by default.
+     * expected to have implemented their own notification mechanism. {@code true} by default.
      */
-    public static final String KEY_DATA_RAPID_NOTIFICATION_BOOL =
-            "data_rapid_notification_bool";
+    public static final String KEY_DATA_RAPID_NOTIFICATION_BOOL = "data_rapid_notification_bool";
 
     /**
      * Offset to be reduced from rsrp threshold while calculating signal strength level.
@@ -2901,8 +2906,7 @@
      * "nrarfcn2_start-nrarfcn2_end" ... }
      * @hide
      */
-    public static final String KEY_BOOSTED_NRARFCNS_STRING_ARRAY =
-            "boosted_nrarfcns_string_array";
+    public static final String KEY_BOOSTED_NRARFCNS_STRING_ARRAY = "boosted_nrarfcns_string_array";
 
     /**
      * Determine whether to use only RSRP for the number of LTE signal bars.
@@ -3009,8 +3013,8 @@
      * is set, the default value 2 is used.
      * @hide
      */
-    public static final String
-            KEY_NGRAN_SSRSRP_HYSTERESIS_DB_INT = "ngran_ssrsrp_hysteresis_db_int";
+    public static final String KEY_NGRAN_SSRSRP_HYSTERESIS_DB_INT =
+            "ngran_ssrsrp_hysteresis_db_int";
 
     /**
      * An interval in dB for {@link SignalThresholdInfo#SIGNAL_MEASUREMENT_TYPE_SSRSRQ} measurement
@@ -3018,10 +3022,10 @@
      *
      * <p>The default value is 2 and the minimum allowed value is 0. If no value or negative value
      * is set, the default value 2 is used.
-     *@hide
+     * @hide
      */
-    public static final String
-            KEY_NGRAN_SSRSRQ_HYSTERESIS_DB_INT = "ngran_ssrsrq_hysteresis_db_int";
+    public static final String KEY_NGRAN_SSRSRQ_HYSTERESIS_DB_INT =
+            "ngran_ssrsrq_hysteresis_db_int";
 
     /**
      * An interval in dB for {@link SignalThresholdInfo#SIGNAL_MEASUREMENT_TYPE_SSSINR} measurement
@@ -3031,8 +3035,8 @@
      * is set, the default value 2 is used.
      * @hide
      */
-    public static final String
-            KEY_NGRAN_SSSINR_HYSTERESIS_DB_INT = "ngran_sssinr_hysteresis_db_int";
+    public static final String KEY_NGRAN_SSSINR_HYSTERESIS_DB_INT =
+            "ngran_sssinr_hysteresis_db_int";
 
     /**
      * Bit-field integer to determine whether to use SS reference signal received power (SSRSRP),
@@ -3120,8 +3124,7 @@
      * A match on this supersedes a match on {@link #KEY_NON_ROAMING_OPERATOR_STRING_ARRAY}.
      * @hide
      */
-    public static final String KEY_ROAMING_OPERATOR_STRING_ARRAY =
-            "roaming_operator_string_array";
+    public static final String KEY_ROAMING_OPERATOR_STRING_ARRAY = "roaming_operator_string_array";
 
     /**
      * URL from which the proto containing the public key of the Carrier used for
@@ -3190,7 +3193,7 @@
      * Boolean flag indicating whether the carrier supports TTY.
      * <p>
      * Note that {@link #KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL} controls availability of TTY over
-     * VoLTE; if {@link #KEY_TTY_SUPPORTED_BOOL} is disabled, then
+     * VoLTE; if this carrier configuration is disabled, then
      * {@link #KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL} is also implicitly disabled.
      * <p>
      * {@link TelecomManager#isTtySupported()} should be used to determine if a device supports TTY,
@@ -3314,11 +3317,11 @@
     public static final String KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL =
             "check_pricing_with_carrier_data_roaming_bool";
 
-     /**
-      * Determines whether we should show a notification when the phone established a data
-      * connection in roaming network, to warn users about possible roaming charges.
-      * @hide
-      */
+    /**
+     * Determines whether we should show a notification when the phone established a data
+     * connection in roaming network, to warn users about possible roaming charges.
+     * @hide
+     */
     public static final String KEY_SHOW_DATA_CONNECTED_ROAMING_NOTIFICATION_BOOL =
             "show_data_connected_roaming_notification";
 
@@ -3333,8 +3336,7 @@
      * these boundaries is considered invalid.
      * @hide
      */
-    public static final String KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY =
-            "lte_rsrp_thresholds_int_array";
+    public static final String KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY = "lte_rsrp_thresholds_int_array";
 
     /**
      * A list of 4 customized LTE Reference Signal Received Quality (RSRQ) thresholds.
@@ -3351,8 +3353,7 @@
      * This key is considered invalid if the format is violated. If the key is invalid or
      * not configured, a default value set will apply.
      */
-    public static final String KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY =
-            "lte_rsrq_thresholds_int_array";
+    public static final String KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY = "lte_rsrq_thresholds_int_array";
 
     /**
      * A list of 4 customized LTE Reference Signal Signal to Noise Ratio (RSSNR) thresholds.
@@ -3378,8 +3379,7 @@
      * is set, the default value 2 is used.
      * @hide
      */
-    public static final String
-            KEY_EUTRAN_RSRP_HYSTERESIS_DB_INT = "eutran_rsrp_hysteresis_db_int";
+    public static final String KEY_EUTRAN_RSRP_HYSTERESIS_DB_INT = "eutran_rsrp_hysteresis_db_int";
 
     /**
      * An interval in dB for {@link SignalThresholdInfo#SIGNAL_MEASUREMENT_TYPE_RSRQ} measurement
@@ -3399,8 +3399,8 @@
      * is set, the default value 2 is used.
      * @hide
      */
-    public static final String
-            KEY_EUTRAN_RSSNR_HYSTERESIS_DB_INT = "eutran_rssnr_hysteresis_db_int";
+    public static final String KEY_EUTRAN_RSSNR_HYSTERESIS_DB_INT =
+            "eutran_rssnr_hysteresis_db_int";
 
     /**
      * Decides when clients try to bind to iwlan network service, which package name will
@@ -3449,6 +3449,7 @@
      */
     public static final String KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_CLASS_OVERRIDE_STRING =
             "carrier_qualified_networks_service_class_override_string";
+
     /**
      * A list of 4 WCDMA RSCP thresholds above which a signal level is considered POOR,
      * MODERATE, GOOD, or EXCELLENT, to be used in SignalStrength reporting.
@@ -3524,7 +3525,7 @@
 
     /**
      * Specifies a carrier-defined {@link android.telecom.CallRedirectionService} which Telecom
-     * will bind to for outgoing calls.  An empty string indicates that no carrier-defined
+     * will bind to for outgoing calls. An empty string indicates that no carrier-defined
      * {@link android.telecom.CallRedirectionService} is specified.
      */
     public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING =
@@ -3824,7 +3825,7 @@
      * This configuration allows the framework to use user data communication to detect Idle state,
      * and this is used on the 5G icon.
      *
-     * There is a new way for for RRC state detection at Android 12. If
+     * There is a new way for RRC state detection at Android 12. If
      * {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported}(
      * {@link TelephonyManager#CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED}) returns true,
      * then framework can use PHYSICAL_CHANNEL_CONFIG for RRC state detection. Based on this
@@ -3980,8 +3981,7 @@
      * FQDN (Fully Qualified Domain Name) of the SM-DP+ (e.g., smdp.gsma.com) restricted to the
      * Alphanumeric mode character set defined in table 5 of ISO/IEC 18004 excluding '$'.
      */
-    public static final String KEY_SMDP_SERVER_ADDRESS_STRING =
-            "smdp_server_address_string";
+    public static final String KEY_SMDP_SERVER_ADDRESS_STRING = "smdp_server_address_string";
 
     /**
      * This timer value is used in the eSIM Exponential Backoff download retry algorithm.
@@ -4032,7 +4032,7 @@
     public static final String KEY_OPPORTUNISTIC_ESIM_DOWNLOAD_VIA_WIFI_ONLY_BOOL =
             "opportunistic_esim_download_via_wifi_only_bool";
 
-/**
+    /**
      * Controls RSRP threshold, in dBm, at which OpportunisticNetworkService will decide whether
      * the opportunistic network is good enough for internet data.
      *
@@ -4126,6 +4126,7 @@
      */
     public static final String KEY_OPPORTUNISTIC_NETWORK_PING_PONG_TIME_LONG =
             "opportunistic_network_ping_pong_time_long";
+
     /**
      * Controls back off time in milli seconds for switching back to
      * opportunistic subscription. This time will be added to
@@ -4345,7 +4346,7 @@
          * If opportunistic network is determined as out of service or below
          * {@link #KEY_EXIT_THRESHOLD_SS_RSRP_INT} or
          * {@link #KEY_EXIT_THRESHOLD_SS_RSRQ_DOUBLE} within
-         * {@link #KEY_5G_PING_PONG_TIME_LONG} of switching to opportunistic network,
+         * the time specified by this carrier config of switching to opportunistic network,
          * it will be determined as ping pong situation by system app or 1st party app.
          *
          * @hide
@@ -4401,29 +4402,30 @@
     public static final String KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL =
             "enabled_4g_opportunistic_network_scan_bool";
 
-  /**
-   * Only relevant when the device supports opportunistic networks but does not support
-   * simultaneuous 5G+5G. Controls how long, in milliseconds, to wait before opportunistic network
-   * goes out of service before switching the 5G capability back to primary stack. The idea of
-   * waiting a few seconds is to minimize the calling of the expensive capability switching
-   * operation in the case where CBRS goes back into service shortly after going out of it.
-   *
-   * @hide
-   */
-  public static final String KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG =
+    /**
+     * Only relevant when the device supports opportunistic networks but does not support
+     * simultaneous 5G+5G. Controls how long, in milliseconds, to wait before opportunistic network
+     * goes out of service before switching the 5G capability back to primary stack. The idea of
+     * waiting a few seconds is to minimize the calling of the expensive capability switching
+     * operation in the case where CBRS goes back into service shortly after going out of it.
+     *
+     * @hide
+     */
+    public static final String KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG =
             "time_to_switch_back_to_primary_if_opportunistic_oos_long";
 
-  /**
-   * Only relevant when the device supports opportunistic networks but does not support
-   * simultaneuous 5G+5G. Controls how long, in milliseconds, after 5G capability has switched back
-   * to primary stack due to opportunistic network being OOS. The idea is to minimizing the
-   * 'ping-ponging' effect where device is constantly witching capability back and forth between
-   * primary and opportunistic stack.
-   *
-   * @hide
-   */
-  public static final String KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG
-          = "opportunistic_time_to_scan_after_capability_switch_to_primary_long";
+    /**
+     * Only relevant when the device supports opportunistic networks but does not support
+     * simultaneous 5G+5G. Controls how long, in milliseconds, after 5G capability has switched back
+     * to primary stack due to opportunistic network being OOS. The idea is to minimizing the
+     * 'ping-ponging' effect where device is constantly witching capability back and forth between
+     * primary and opportunistic stack.
+     *
+     * @hide
+     */
+    public static final String
+            KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG =
+            "opportunistic_time_to_scan_after_capability_switch_to_primary_long";
 
     /**
      * Indicates zero or more emergency number prefix(es), because some carrier requires
@@ -4550,8 +4552,7 @@
      * @hide
      */
     @SystemApi
-    public static final String KEY_GBA_UA_SECURITY_PROTOCOL_INT =
-            "gba_ua_security_protocol_int";
+    public static final String KEY_GBA_UA_SECURITY_PROTOCOL_INT = "gba_ua_security_protocol_int";
 
     /**
      * An integer representing the cipher suite to be used when building the
@@ -4561,8 +4562,7 @@
      * @hide
      */
     @SystemApi
-    public static final String KEY_GBA_UA_TLS_CIPHER_SUITE_INT =
-            "gba_ua_tls_cipher_suite_int";
+    public static final String KEY_GBA_UA_TLS_CIPHER_SUITE_INT = "gba_ua_tls_cipher_suite_int";
 
     /**
      * The data stall recovery timers array in milliseconds, each element is the delay before
@@ -4721,7 +4721,6 @@
          */
         public static final int SUPL_EMERGENCY_MODE_TYPE_DP_ONLY = 2;
 
-
         /**
          * Determine whether current lpp_mode used for E-911 needs to be kept persistently.
          * {@code false} - not keeping the lpp_mode means using default configuration of gps.conf
@@ -4839,8 +4838,8 @@
          * The default value for this configuration is {@link #SUPL_EMERGENCY_MODE_TYPE_CP_ONLY}.
          * @hide
          */
-        public static final String KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT = KEY_PREFIX
-                + "es_supl_control_plane_support_int";
+        public static final String KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT =
+                KEY_PREFIX + "es_supl_control_plane_support_int";
 
         /**
          * A list of roaming PLMNs where SUPL ES mode does not support a control-plane mechanism to
@@ -4875,13 +4874,14 @@
         }
     }
 
-   /**
-    * An int array containing CDMA enhanced roaming indicator values for Home (non-roaming) network.
-    * The default values come from 3GPP2 C.R1001 table 8.1-1.
-    * Enhanced Roaming Indicator Number Assignments
-    *
-    * @hide
-    */
+    /**
+     * An int array containing CDMA enhanced roaming indicator values for Home (non-roaming)
+     * network.
+     * The default values come from 3GPP2 C.R1001 table 8.1-1.
+     * Enhanced Roaming Indicator Number Assignments
+     *
+     * @hide
+     */
     public static final String KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY =
             "cdma_enhanced_roaming_indicator_for_home_network_int_array";
 
@@ -4893,7 +4893,7 @@
 
     /**
      * Indicates use 3GPP application to replace 3GPP2 application even if it's a CDMA/CDMA-LTE
-     * phone, becasue some carriers's CSIM application is present but not supported.
+     * phone, because some carriers' CSIM application is present but not supported.
      * @hide
      */
     public static final String KEY_USE_USIM_BOOL = "use_usim_bool";
@@ -4956,8 +4956,7 @@
      * {@see SubscriptionInfo#getUsageSetting}
      *
      */
-    public static final String KEY_CELLULAR_USAGE_SETTING_INT =
-            "cellular_usage_setting_int";
+    public static final String KEY_CELLULAR_USAGE_SETTING_INT = "cellular_usage_setting_int";
 
     /**
      * Data switch validation minimal gap time, in milliseconds.
@@ -5021,7 +5020,7 @@
      * "Carrier Provisioning Info" or "Trigger Carrier Provisioning" button clicked.
      *
      * <p>
-     * e.g, com.google.android.carrierPackageName/.CarrierReceiverName
+     * e.g., com.google.android.carrierPackageName/.CarrierReceiverName
      *
      * @hide
      */
@@ -5061,9 +5060,9 @@
          * Capability Exchange (UCE). See RCC.71, section 3 for more information.
          * <p>
          * If this key's value is set to false, the procedure for RCS contact capability exchange
-         * via SIP SUBSCRIBE/NOTIFY will also be disabled internally, and
-         * {@link Ims#KEY_ENABLE_PRESENCE_PUBLISH_BOOL} must also be set to false to ensure
-         * apps do not improperly think that capability exchange via SIP PUBLISH is enabled.
+         * via SIP SUBSCRIBE/NOTIFY will also be disabled internally, and this key must also be set
+         * to false to ensure apps do not improperly think that capability exchange via SIP PUBLISH
+         * is enabled.
          * <p> The default value for this key is {@code false}.
          */
         public static final String KEY_ENABLE_PRESENCE_PUBLISH_BOOL =
@@ -5119,7 +5118,6 @@
         public static final String KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL =
                 KEY_PREFIX + "enable_presence_capability_exchange_bool";
 
-
         /**
          * Flag indicating whether or not the carrier expects the RCS UCE service to periodically
          * refresh the RCS capabilities cache of the user's contacts as well as request the
@@ -5253,7 +5251,7 @@
                 KEY_PREFIX + "sip_timer_j_millis_int";
 
         /** Specifies the SIP Server default port. */
-        public static final String KEY_SIP_SERVER_PORT_NUMBER_INT  =
+        public static final String KEY_SIP_SERVER_PORT_NUMBER_INT =
                 KEY_PREFIX + "sip_server_port_number_int";
 
         /**
@@ -5265,7 +5263,6 @@
 
         /** @hide */
         @IntDef({REQUEST_URI_FORMAT_TEL, REQUEST_URI_FORMAT_SIP})
-
         public @interface RequestUriFormatType {}
 
         /**
@@ -5312,7 +5309,6 @@
             PREFERRED_TRANSPORT_DYNAMIC_UDP_TCP,
             PREFERRED_TRANSPORT_TLS
         })
-
         public @interface PreferredTransportType {}
 
         /** Preferred Transport is always UDP. */
@@ -5393,7 +5389,6 @@
 
         /** @hide */
         @IntDef({IPSEC_AUTHENTICATION_ALGORITHM_HMAC_MD5, IPSEC_AUTHENTICATION_ALGORITHM_HMAC_SHA1})
-
         public @interface IpsecAuthenticationAlgorithmType {}
 
         /** IPSec Authentication algorithm is HMAC-MD5. see Annex H of TS 33.203 */
@@ -5418,7 +5413,6 @@
             IPSEC_ENCRYPTION_ALGORITHM_DES_EDE3_CBC,
             IPSEC_ENCRYPTION_ALGORITHM_AES_CBC
         })
-
         public @interface IpsecEncryptionAlgorithmType {}
 
         /** IPSec Encryption algorithm is NULL. see Annex H of TS 33.203 */
@@ -5477,7 +5471,6 @@
             GEOLOCATION_PIDF_FOR_NON_EMERGENCY_ON_CELLULAR,
             GEOLOCATION_PIDF_FOR_EMERGENCY_ON_CELLULAR
         })
-
         public @interface GeolocationPidfAllowedType {}
 
         /**
@@ -5571,7 +5564,6 @@
             NETWORK_TYPE_HOME,
             NETWORK_TYPE_ROAMING
         })
-
         public @interface NetworkType {}
 
         /** Indicates HOME Network. */
@@ -5588,7 +5580,6 @@
             E911_RTCP_INACTIVITY_ON_CONNECTED,
             E911_RTP_INACTIVITY_ON_CONNECTED
         })
-
         public @interface MediaInactivityReason {}
 
         /**  RTCP inactivity occurred when call is on HOLD. */
@@ -5634,7 +5625,7 @@
          *     <li>{@link #KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT_ARRAY}</li>
          * </ul>
          * <p> The values are defined in
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech}
          *
          * changing mmtel_requires_provisioning_bundle requires changes to
          * carrier_volte_provisioning_required_bool and vice versa
@@ -5648,10 +5639,10 @@
          * is supported.
          * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE
          * <p>Possible values are,
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
          */
         public static final String KEY_CAPABILITY_TYPE_VOICE_INT_ARRAY =
                 KEY_PREFIX + "capability_type_voice_int_array";
@@ -5661,10 +5652,10 @@
          * is supported.
          * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO
          * <p>Possible values are,
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
          */
         public static final String KEY_CAPABILITY_TYPE_VIDEO_INT_ARRAY =
                 KEY_PREFIX + "capability_type_video_int_array";
@@ -5674,10 +5665,10 @@
          * supplementary services. (IR.92) is supported.
          * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT
          * <p>Possible values are,
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
          */
         public static final String KEY_CAPABILITY_TYPE_UT_INT_ARRAY =
                 KEY_PREFIX + "capability_type_ut_int_array";
@@ -5686,10 +5677,10 @@
          * List of different RAT technologies on which Provisioning for SMS (IR.92) is supported.
          * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS
          * <p>Possible values are,
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
          */
         public static final String KEY_CAPABILITY_TYPE_SMS_INT_ARRAY =
                 KEY_PREFIX + "capability_type_sms_int_array";
@@ -5699,10 +5690,10 @@
          * (section 2.4 of RCC.20) is supported.
          * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_CALL_COMPOSER
          * <p>Possible values are,
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
          */
         public static final String KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT_ARRAY =
                 KEY_PREFIX + "capability_type_call_composer_int_array";
@@ -5718,7 +5709,7 @@
          *     <li>{@link #KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY}</li>
          * </ul>
          * <p> The values are defined in
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech}
          */
         public static final String KEY_RCS_REQUIRES_PROVISIONING_BUNDLE =
                 KEY_PREFIX + "rcs_requires_provisioning_bundle";
@@ -5729,10 +5720,10 @@
          * If not set, this RcsFeature should not service capability requests.
          * @see RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE
          * <p>Possible values are,
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
          */
         public static final String KEY_CAPABILITY_TYPE_OPTIONS_UCE_INT_ARRAY =
                 KEY_PREFIX + "capability_type_options_uce_int_array";
@@ -5744,10 +5735,10 @@
          * requests using presence.
          * @see RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE
          * <p>Possible values are,
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
-         * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM}
+         * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR}
          */
         public static final String KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY =
                 KEY_PREFIX + "capability_type_presence_uce_int_array";
@@ -5760,7 +5751,7 @@
             defaults.putBoolean(KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, false);
             defaults.putBoolean(KEY_ENABLE_PRESENCE_PUBLISH_BOOL, false);
             defaults.putStringArray(KEY_PUBLISH_SERVICE_DESC_FEATURE_TAG_MAP_OVERRIDE_STRING_ARRAY,
-                    new String[] {});
+                    new String[0]);
             defaults.putBoolean(KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL, false);
             defaults.putBoolean(KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL, false);
             defaults.putBoolean(KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL, false);
@@ -5885,7 +5876,7 @@
          * <p>If {@code false}: hard disabled.
          * If {@code true}: then depends on availability, etc.
          */
-        public static final String KEY_CARRIER_VOLTE_ROAMING_AVAILABLE_BOOL  =
+        public static final String KEY_CARRIER_VOLTE_ROAMING_AVAILABLE_BOOL =
                 KEY_PREFIX + "carrier_volte_roaming_available_bool";
 
         /**
@@ -5896,7 +5887,7 @@
          * will be sent in the dialed string in the SIP:INVITE.
          * If {@code false}, *67 and *82 will be removed.
          */
-        public static final String KEY_INCLUDE_CALLER_ID_SERVICE_CODES_IN_SIP_INVITE_BOOL  =
+        public static final String KEY_INCLUDE_CALLER_ID_SERVICE_CODES_IN_SIP_INVITE_BOOL =
                 KEY_PREFIX + "include_caller_id_service_codes_in_sip_invite_bool";
 
         /**
@@ -5940,7 +5931,6 @@
             SESSION_REFRESHER_TYPE_UAC,
             SESSION_REFRESHER_TYPE_UAS
         })
-
         public @interface SessionRefresherType {}
 
         /**
@@ -5982,14 +5972,12 @@
         public static final String KEY_SESSION_REFRESHER_TYPE_INT =
                 KEY_PREFIX + "session_refresher_type_int";
 
-
         /** @hide */
         @IntDef({
             SESSION_PRIVACY_TYPE_HEADER,
             SESSION_PRIVACY_TYPE_NONE,
             SESSION_PRIVACY_TYPE_ID
         })
-
         public @interface SessionPrivacyType {}
 
         /**
@@ -6027,7 +6015,7 @@
          * If {@code true},  SIP 18x responses (other than SIP 183 response)
          * are sent reliably.
          */
-        public static final String KEY_PRACK_SUPPORTED_FOR_18X_BOOL  =
+        public static final String KEY_PRACK_SUPPORTED_FOR_18X_BOOL =
                 KEY_PREFIX + "prack_supported_for_18x_bool";
 
         /** @hide */
@@ -6035,7 +6023,6 @@
             CONFERENCE_SUBSCRIBE_TYPE_IN_DIALOG,
             CONFERENCE_SUBSCRIBE_TYPE_OUT_OF_DIALOG
         })
-
         public @interface ConferenceSubscribeType {}
 
         /**
@@ -6056,7 +6043,7 @@
 
         /**
          * This is used to specify whether the SIP SUBSCRIBE to conference state events,
-         * is sent in or out of the  SIP INVITE dialog between the UE and the
+         * is sent in or out of the SIP INVITE dialog between the UE and the
          * conference server.
          *
          * <p>Reference: IR.92 Section 2.3.3.
@@ -6081,7 +6068,7 @@
          *
          * <p>Reference: 3GPP TS 24.229
          */
-        public static final String KEY_VOICE_QOS_PRECONDITION_SUPPORTED_BOOL  =
+        public static final String KEY_VOICE_QOS_PRECONDITION_SUPPORTED_BOOL =
                 KEY_PREFIX + "voice_qos_precondition_supported_bool";
 
         /**
@@ -6089,7 +6076,7 @@
          *
          * <p>If {@code true}: voice packets can be sent on default bearer. {@code false} otherwise.
          */
-        public static final String KEY_VOICE_ON_DEFAULT_BEARER_SUPPORTED_BOOL  =
+        public static final String KEY_VOICE_ON_DEFAULT_BEARER_SUPPORTED_BOOL =
                 KEY_PREFIX + "voice_on_default_bearer_supported_bool";
 
         /**
@@ -6111,7 +6098,6 @@
             PREALERTING_SRVCC_SUPPORT,
             MIDCALL_SRVCC_SUPPORT
         })
-
         public @interface SrvccType {}
 
         /**
@@ -6209,7 +6195,6 @@
             SESSION_REFRESH_METHOD_INVITE,
             SESSION_REFRESH_METHOD_UPDATE_PREFERRED
         })
-
         public @interface SessionRefreshMethod {}
 
         /**
@@ -6244,7 +6229,7 @@
          * determination of the originating party identity in OIP.
          * {@code false} otherwise.
          */
-        public static final String KEY_OIP_SOURCE_FROM_HEADER_BOOL  =
+        public static final String KEY_OIP_SOURCE_FROM_HEADER_BOOL =
                 KEY_PREFIX + "oip_source_from_header_bool";
 
         /**
@@ -6332,7 +6317,7 @@
          * <p>Payload type is an integer in dynamic payload type range 96-127
          * as per RFC RFC 3551 Section 6.
          */
-        public static final String KEY_EVS_PAYLOAD_TYPE_INT_ARRAY  =
+        public static final String KEY_EVS_PAYLOAD_TYPE_INT_ARRAY =
                 KEY_PREFIX + "evs_payload_type_int_array";
 
         /**
@@ -6341,7 +6326,7 @@
          * <p>Payload type is an integer in dynamic payload type range 96-127
          * as per RFC RFC 3551 Section 6.
          */
-        public static final String KEY_AMRWB_PAYLOAD_TYPE_INT_ARRAY  =
+        public static final String KEY_AMRWB_PAYLOAD_TYPE_INT_ARRAY =
                 KEY_PREFIX + "amrwb_payload_type_int_array";
 
         /**
@@ -6350,7 +6335,7 @@
          * <p>Payload type is an integer in dynamic payload type range 96-127
          * as per RFC RFC 3551 Section 6.
          */
-        public static final String KEY_AMRNB_PAYLOAD_TYPE_INT_ARRAY  =
+        public static final String KEY_AMRNB_PAYLOAD_TYPE_INT_ARRAY =
                 KEY_PREFIX + "amrnb_payload_type_int_array";
 
         /**
@@ -6359,7 +6344,7 @@
          * <p>Payload type is an integer in dynamic payload type range 96-127
          * as per RFC RFC 3551 Section 6.
          */
-        public static final String KEY_DTMFWB_PAYLOAD_TYPE_INT_ARRAY  =
+        public static final String KEY_DTMFWB_PAYLOAD_TYPE_INT_ARRAY =
                 KEY_PREFIX + "dtmfwb_payload_type_int_array";
 
         /**
@@ -6368,7 +6353,7 @@
          * <p>Payload type is an integer in dynamic payload type range 96-127
          * as per RFC RFC 3551 Section 6.
          */
-        public static final String KEY_DTMFNB_PAYLOAD_TYPE_INT_ARRAY  =
+        public static final String KEY_DTMFNB_PAYLOAD_TYPE_INT_ARRAY =
                 KEY_PREFIX + "dtmfnb_payload_type_int_array";
 
         /**
@@ -6385,7 +6370,6 @@
         public static final String KEY_VOICE_RTP_PACKET_LOSS_RATE_THRESHOLD_INT =
                 KEY_PREFIX + "rtp_packet_loss_rate_threshold_int";
 
-
         /**
          * This indicates the threshold for RTP jitter value in milliseconds (RFC3550). If measured
          * jitter value crosses this, a callback with {@link MediaQualityStatus} will be invoked
@@ -6414,13 +6398,11 @@
         public static final String KEY_VOICE_RTP_INACTIVITY_TIME_THRESHOLD_MILLIS_LONG =
                 KEY_PREFIX + "rtp_inactivity_time_threshold_millis_long";
 
-
         /** @hide */
         @IntDef({
             BANDWIDTH_EFFICIENT,
             OCTET_ALIGNED
         })
-
         public @interface AmrPayloadFormat {}
 
         /** AMR NB/WB Payload format is bandwidth-efficient. */
@@ -6441,7 +6423,7 @@
          *
          * <p>Reference: RFC 4867 Section 8.1.
          */
-        public static final String KEY_AMR_CODEC_ATTRIBUTE_PAYLOAD_FORMAT_INT  =
+        public static final String KEY_AMR_CODEC_ATTRIBUTE_PAYLOAD_FORMAT_INT =
                 KEY_PREFIX + "amr_codec_attribute_payload_format_int";
 
         /**
@@ -6456,7 +6438,7 @@
          * <p>Possible values are subset of,
          * [0,1,2,3,4,5,6,7,8] - AMRWB with the modes representing nine speech codec modes
          * with bit rates of 6.6, 8.85, 12.65, 14.25,  15.85, 18.25, 19.85, 23.05, 23.85 kbps.
-         * [0,1,2,3,4,5,6,7] - AMRNB  with the modes representing eight speech codec modes
+         * [0,1,2,3,4,5,6,7] - AMRNB with the modes representing eight speech codec modes
          * with bit rates of 4.75, 5.15, 5.90, 6.70, 7.40, 7.95, 10.2, 12.2 kbps.
          *
          * <p>If value is not specified, then it means device supports all
@@ -6464,7 +6446,7 @@
          *
          * <p>Reference: RFC 4867 Section 8.1, 3GPP 26.445 A.3.1
          */
-        public static final String KEY_AMR_CODEC_ATTRIBUTE_MODESET_INT_ARRAY  =
+        public static final String KEY_AMR_CODEC_ATTRIBUTE_MODESET_INT_ARRAY =
                 KEY_PREFIX + "amr_codec_attribute_modeset_int_array";
 
         /**
@@ -6514,7 +6496,6 @@
             EVS_OPERATIONAL_MODE_PRIMARY,
             EVS_OPERATIONAL_MODE_AMRWB_IO
         })
-
         public @interface EvsOperationalMode {}
 
         /**  Indicates the EVS primary mode. 3GPP 26.445 Section 3.1 */
@@ -6549,7 +6530,6 @@
             EVS_ENCODED_BW_TYPE_WB_SWB,
             EVS_ENCODED_BW_TYPE_WB_SWB_FB
         })
-
         public @interface EvsEncodedBwType {}
 
         /**
@@ -6625,7 +6605,7 @@
          *
          * <p>Reference: 3GPP 26.441 Table 1.
          */
-        public static final String KEY_EVS_CODEC_ATTRIBUTE_BANDWIDTH_INT  =
+        public static final String KEY_EVS_CODEC_ATTRIBUTE_BANDWIDTH_INT =
                 KEY_PREFIX + "evs_codec_attribute_bandwidth_int";
 
         /** @hide */
@@ -6643,7 +6623,6 @@
             EVS_PRIMARY_MODE_BITRATE_96_0_KBPS,
             EVS_PRIMARY_MODE_BITRATE_128_0_KBPS
         })
-
         public @interface EvsPrimaryModeBitRate {}
 
         /** EVS primary mode with bitrate 5.9 kbps */
@@ -6709,14 +6688,14 @@
          *
          * <p>Reference: 3GPP 26.445 Section A.3.1
          */
-        public static final String KEY_EVS_CODEC_ATTRIBUTE_BITRATE_INT_ARRAY  =
+        public static final String KEY_EVS_CODEC_ATTRIBUTE_BITRATE_INT_ARRAY =
                 KEY_PREFIX + "evs_codec_attribute_bitrate_int_array";
 
         /**
          * Specifies the Channel aware mode (ch-aw-recv) for the receive direction.
          * This is applicable for EVS codec.
          *
-         * <p>Permissible values  are -1, 0, 2, 3, 5, and 7.
+         * <p> Permissible values are -1, 0, 2, 3, 5, and 7.
          * If this key is not specified, then the behavior is same as value 0
          * (channel aware mode disabled).
          * <p> If this key is configured, then device is expected to send
@@ -6724,7 +6703,7 @@
          *
          * <p>Reference: 3GPP TS 26.445 section 4.4.5, 3GPP 26.445 Section A.3.1
          */
-        public static final String KEY_EVS_CODEC_ATTRIBUTE_CH_AW_RECV_INT  =
+        public static final String KEY_EVS_CODEC_ATTRIBUTE_CH_AW_RECV_INT =
                 KEY_PREFIX + "evs_codec_attribute_ch_aw_recv_int";
 
         /**
@@ -6745,7 +6724,7 @@
          *
          * <p>Reference: 3GPP 26.445 Section A.3.1.
          */
-        public static final String KEY_EVS_CODEC_ATTRIBUTE_HF_ONLY_INT  =
+        public static final String KEY_EVS_CODEC_ATTRIBUTE_HF_ONLY_INT =
                 KEY_PREFIX + "evs_codec_attribute_hf_only_int";
 
         /**
@@ -6761,7 +6740,7 @@
          * will apply.
          * <p>Reference: 3GPP TS 26.445 Section A.3.1.
          */
-        public static final String KEY_EVS_CODEC_ATTRIBUTE_DTX_BOOL  =
+        public static final String KEY_EVS_CODEC_ATTRIBUTE_DTX_BOOL =
                 KEY_PREFIX + "evs_codec_attribute_dtx_bool";
 
         /**
@@ -6786,7 +6765,7 @@
          *
          * <p>Reference: RFC 3551
          */
-        public static final String KEY_EVS_CODEC_ATTRIBUTE_CHANNELS_INT  =
+        public static final String KEY_EVS_CODEC_ATTRIBUTE_CHANNELS_INT =
                 KEY_PREFIX + "evs_codec_attribute_channels_int";
 
         /**
@@ -6799,7 +6778,7 @@
          *
          * <p>Reference: 3GPP 26.445 Section A.3.1, 3GPP 26.114 Table 6.2a
          */
-        public static final String KEY_EVS_CODEC_ATTRIBUTE_CMR_INT  =
+        public static final String KEY_EVS_CODEC_ATTRIBUTE_CMR_INT =
                 KEY_PREFIX + "codec_attribute_cmr_int";
 
         /**
@@ -6813,7 +6792,7 @@
          *
          * <p>Reference: RFC 4867 Section 8.1.
          */
-        public static final String KEY_CODEC_ATTRIBUTE_MODE_CHANGE_PERIOD_INT  =
+        public static final String KEY_CODEC_ATTRIBUTE_MODE_CHANGE_PERIOD_INT =
                 KEY_PREFIX + "codec_attribute_mode_change_period_int";
 
         /**
@@ -6827,7 +6806,7 @@
          *
          * <p>Reference: RFC 4867 Section 8.1.
          */
-        public static final String KEY_CODEC_ATTRIBUTE_MODE_CHANGE_CAPABILITY_INT  =
+        public static final String KEY_CODEC_ATTRIBUTE_MODE_CHANGE_CAPABILITY_INT =
                 KEY_PREFIX + "codec_attribute_mode_change_capability_int";
 
         /**
@@ -6835,7 +6814,7 @@
          * This attribute is applicable for EVS codec in AMR-WB IO mode
          * and AMR-WB.
          *
-         * <p>Possible values are 0, 1.  If value is 1, then the sender should only
+         * <p>Possible values are 0, 1. If value is 1, then the sender should only
          * perform mode changes to the neighboring modes in the active codec mode set.
          * If value is 0, then mode changes between any two modes
          * in the active codec mode set is allowed.
@@ -6844,7 +6823,7 @@
          *
          * <p>Reference: RFC 4867 Section 8.1.
          */
-        public static final String KEY_CODEC_ATTRIBUTE_MODE_CHANGE_NEIGHBOR_INT  =
+        public static final String KEY_CODEC_ATTRIBUTE_MODE_CHANGE_NEIGHBOR_INT =
                 KEY_PREFIX + "codec_attribute_mode_change_neighbor_int";
 
         /**
@@ -7008,7 +6987,7 @@
          * <p>If {@code true}: SMS over IMS support available.
          * {@code false}: otherwise.
          */
-        public static final String KEY_SMS_OVER_IMS_SUPPORTED_BOOL  =
+        public static final String KEY_SMS_OVER_IMS_SUPPORTED_BOOL =
                 KEY_PREFIX + "sms_over_ims_supported_bool";
 
         /**
@@ -7018,7 +6997,7 @@
          * <p>If {@code true}: allow SMS CSFB in case of SMS over PS failure.
          * {@code false} otherwise.
          */
-        public static final String KEY_SMS_CSFB_RETRY_ON_FAILURE_BOOL  =
+        public static final String KEY_SMS_CSFB_RETRY_ON_FAILURE_BOOL =
                 KEY_PREFIX + "sms_csfb_retry_on_failure_bool";
 
         /** @hide */
@@ -7026,7 +7005,6 @@
             SMS_FORMAT_3GPP,
             SMS_FORMAT_3GPP2
         })
-
         public @interface SmsFormat {}
 
         /** SMS format is 3GPP. */
@@ -7205,7 +7183,7 @@
          * <p>If {@code true}: text media can be sent on default bearer.
          * {@code false} otherwise.
          */
-        public static final String KEY_TEXT_ON_DEFAULT_BEARER_SUPPORTED_BOOL  =
+        public static final String KEY_TEXT_ON_DEFAULT_BEARER_SUPPORTED_BOOL =
                 KEY_PREFIX + "text_on_default_bearer_supported_bool";
 
         /**
@@ -7215,7 +7193,7 @@
          * {@code false} otherwise.
          * <p>Reference: 3GPP TS 24.229
          */
-        public static final String KEY_TEXT_QOS_PRECONDITION_SUPPORTED_BOOL  =
+        public static final String KEY_TEXT_QOS_PRECONDITION_SUPPORTED_BOOL =
                 KEY_PREFIX + "text_qos_precondition_supported_bool";
 
         /**
@@ -7265,14 +7243,14 @@
          * <p>Payload type is an integer in dynamic payload type range 96-127
          * as per RFC RFC 3551 Section 6.
          */
-        public static final String KEY_T140_PAYLOAD_TYPE_INT  =
+        public static final String KEY_T140_PAYLOAD_TYPE_INT =
                 KEY_PREFIX + "t140_payload_type_int";
 
         /** Integer representing payload type for RED/redundancy codec.
          * <p>Payload type is an integer in dynamic payload type range 96-127
          * as per RFC RFC 3551 Section 6.
          */
-        public static final String KEY_RED_PAYLOAD_TYPE_INT  =
+        public static final String KEY_RED_PAYLOAD_TYPE_INT =
                 KEY_PREFIX + "red_payload_type_int";
 
         private static PersistableBundle getDefaults() {
@@ -7321,7 +7299,7 @@
          * <p>If {@code true}: Allow UE to retry emergency call on
          * IMS PDN if emergency PDN setup failed.{@code false} otherwise.
          */
-        public static final String KEY_RETRY_EMERGENCY_ON_IMS_PDN_BOOL  =
+        public static final String KEY_RETRY_EMERGENCY_ON_IMS_PDN_BOOL =
                 KEY_PREFIX + "retry_emergency_on_ims_pdn_bool";
 
         /**
@@ -7331,7 +7309,7 @@
          * <p>If {@code true}: Enter ECBM mode after E911 call is ended.
          * {@code false} otherwise.
          */
-        public static final String KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL  =
+        public static final String KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL =
                 KEY_PREFIX + "emergency_callback_mode_supported_bool";
 
         /**
@@ -7343,7 +7321,7 @@
          *
          * <p>Reference: 3GPP TS 24.229
          */
-        public static final String KEY_EMERGENCY_QOS_PRECONDITION_SUPPORTED_BOOL  =
+        public static final String KEY_EMERGENCY_QOS_PRECONDITION_SUPPORTED_BOOL =
                 KEY_PREFIX + "emergency_qos_precondition_supported_bool";
 
         /**
@@ -7750,7 +7728,7 @@
             defaults.putBoolean(KEY_EMERGENCY_LTE_PREFERRED_AFTER_NR_FAILED_BOOL, false);
             defaults.putBoolean(KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL, false);
             defaults.putStringArray(KEY_EMERGENCY_CDMA_PREFERRED_NUMBERS_STRING_ARRAY,
-                    new String[] {});
+                    new String[0]);
 
             return defaults;
         }
@@ -7771,7 +7749,7 @@
          * <p>If {@code true}: video media can be sent on default bearer.
          * {@code false} otherwise.
          */
-        public static final String KEY_VIDEO_ON_DEFAULT_BEARER_SUPPORTED_BOOL  =
+        public static final String KEY_VIDEO_ON_DEFAULT_BEARER_SUPPORTED_BOOL =
                 KEY_PREFIX + "video_on_default_bearer_supported_bool";
 
         /**
@@ -7837,7 +7815,7 @@
          * {@code false} otherwise.
          * <p>Reference: 3GPP TS 24.229
          */
-        public static final String KEY_VIDEO_QOS_PRECONDITION_SUPPORTED_BOOL  =
+        public static final String KEY_VIDEO_QOS_PRECONDITION_SUPPORTED_BOOL =
                 KEY_PREFIX + "video_qos_precondition_supported_bool";
 
         /**
@@ -7862,7 +7840,7 @@
          * <p>Payload type is an integer in dynamic payload type range 96-127
          * as per RFC RFC 3551 Section 6.
          */
-        public static final String KEY_H264_PAYLOAD_TYPE_INT_ARRAY  =
+        public static final String KEY_H264_PAYLOAD_TYPE_INT_ARRAY =
                 KEY_PREFIX + "h264_payload_type_int_array";
 
         /**
@@ -7904,7 +7882,7 @@
          *
          * <p>Reference: RFC 6184 Section 5.4
          */
-        public static final String KEY_VIDEO_CODEC_ATTRIBUTE_PACKETIZATION_MODE_INT  =
+        public static final String KEY_VIDEO_CODEC_ATTRIBUTE_PACKETIZATION_MODE_INT =
                 KEY_PREFIX + "video_codec_attribute_packetization_mode_int";
 
         /**
@@ -7918,7 +7896,7 @@
          * <UL>
          * <p>Reference: RFC 4566 Section 6, 3GPP 26.114 Section 6.2.3.2
          */
-        public static final String KEY_VIDEO_CODEC_ATTRIBUTE_FRAME_RATE_INT  =
+        public static final String KEY_VIDEO_CODEC_ATTRIBUTE_FRAME_RATE_INT =
                 KEY_PREFIX + "video_codec_attribute_frame_rate_int";
 
         /**
@@ -7937,7 +7915,7 @@
          * <p>Reference: RFC 4566 Section 6, 3GPP 26.114 Section 6.2.3.2
          *
          */
-        public static final String KEY_VIDEO_CODEC_ATTRIBUTE_RESOLUTION_INT_ARRAY  =
+        public static final String KEY_VIDEO_CODEC_ATTRIBUTE_RESOLUTION_INT_ARRAY =
                 KEY_PREFIX + "video_codec_attribute_resolution_int_array";
 
         /**
@@ -7950,7 +7928,7 @@
          *
          * <p>Reference: RFC 6184 Section 8.1, ITU-T Recommendation H.264
          */
-        public static final String KEY_H264_VIDEO_CODEC_ATTRIBUTE_PROFILE_LEVEL_ID_STRING  =
+        public static final String KEY_H264_VIDEO_CODEC_ATTRIBUTE_PROFILE_LEVEL_ID_STRING =
                 KEY_PREFIX + "h264_video_codec_attribute_profile_level_id_string";
 
         private static PersistableBundle getDefaults() {
@@ -8018,7 +7996,7 @@
          *  List of MDNs for which Geo-location PIDF XML with country info
          *  needs to included for normal calls involving short code.
          */
-        public static final String KEY_PIDF_SHORT_CODE_STRING_ARRAY  =
+        public static final String KEY_PIDF_SHORT_CODE_STRING_ARRAY =
                 KEY_PREFIX + "pidf_short_code_string_array";
 
         /**
@@ -8028,15 +8006,14 @@
          * <p>If {@code false}: E911 call uses IMS PDN for E911 call over VoWiFi.
          * If {@code true}: E911 call uses Emergency PDN for E911 call over VoWiFi.
          */
-        public static final String KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL  =
+        public static final String KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL =
                 KEY_PREFIX + "emergency_call_over_emergency_pdn_bool";
 
-
         private static PersistableBundle getDefaults() {
             PersistableBundle defaults = new PersistableBundle();
 
             defaults.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, false);
-            defaults.putStringArray(KEY_PIDF_SHORT_CODE_STRING_ARRAY, new String[] {});
+            defaults.putStringArray(KEY_PIDF_SHORT_CODE_STRING_ARRAY, new String[0]);
 
             return defaults;
         }
@@ -8083,7 +8060,7 @@
          * If XCAP over UT fails, return error.
          * if {@code true}, Use CSFB if XCAP over UT fails.
          */
-        public static final String KEY_USE_CSFB_ON_XCAP_OVER_UT_FAILURE_BOOL  =
+        public static final String KEY_USE_CSFB_ON_XCAP_OVER_UT_FAILURE_BOOL =
                 KEY_PREFIX + "use_csfb_on_xcap_over_ut_failure_bool";
 
         /**
@@ -8095,7 +8072,7 @@
          *
          * Reference: IR.92 Section 5.5.1
          */
-        public static final String KEY_UT_SUPPORTED_WHEN_PS_DATA_OFF_BOOL  =
+        public static final String KEY_UT_SUPPORTED_WHEN_PS_DATA_OFF_BOOL =
                 KEY_PREFIX + "ut_supported_when_ps_data_off_bool";
 
         /**
@@ -8105,7 +8082,7 @@
          * <p>If {@code true}:  Support Available.{@code false}: Otherwise.
          * Reference: 3GPP 24.390.
          */
-        public static final String KEY_NETWORK_INITIATED_USSD_OVER_IMS_SUPPORTED_BOOL  =
+        public static final String KEY_NETWORK_INITIATED_USSD_OVER_IMS_SUPPORTED_BOOL =
                 KEY_PREFIX + "network_initiated_ussd_over_ims_supported_bool";
 
         /**
@@ -8189,7 +8166,6 @@
             SUPPLEMENTARY_SERVICE_CB_ACR,
             SUPPLEMENTARY_SERVICE_CB_BIL
         })
-
         public @interface SsType {}
 
         /** Communication Waiting (CW) support as per 3GPP 24.615. */
@@ -8428,7 +8404,6 @@
             CALL_WAITING_SYNC_FIRST_CHANGE,
             CALL_WAITING_SYNC_IMS_ONLY
         })
-
         public @interface CwSyncType {}
 
         /**
@@ -8553,9 +8528,7 @@
                         SUPPLEMENTARY_SERVICE_CB_ACR,
                         SUPPLEMENTARY_SERVICE_CB_BIL
                     });
-            defaults.putIntArray(
-                    KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY,
-                    new int[] {});
+            defaults.putIntArray(KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY, new int[0]);
 
             defaults.putIntArray(
                     KEY_XCAP_OVER_UT_SUPPORTED_RATS_INT_ARRAY,
@@ -8739,7 +8712,6 @@
         public static final String KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY =
                 KEY_PREFIX + "ike_session_encryption_aes_cbc_key_size_int_array";
 
-
         /**
          * List of supported key sizes for AES Counter (CTR) encryption mode of IKE session.
          * Possible values -
@@ -8874,7 +8846,7 @@
         public static final int EPDG_ADDRESS_PCO = 2;
         /** Use cellular location to chose epdg server */
         public static final int EPDG_ADDRESS_CELLULAR_LOC = 3;
-        /* Use Visited Country FQDN rule*/
+        /** Use Visited Country FQDN rule*/
         public static final int EPDG_ADDRESS_VISITED_COUNTRY = 4;
 
         /** @hide */
@@ -9012,7 +8984,7 @@
             defaults.putIntArray(
                     KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY,
                     new int[] {EPDG_ADDRESS_PLMN, EPDG_ADDRESS_STATIC});
-            defaults.putStringArray(KEY_MCC_MNCS_STRING_ARRAY, new String[] {});
+            defaults.putStringArray(KEY_MCC_MNCS_STRING_ARRAY, new String[0]);
             defaults.putInt(KEY_IKE_LOCAL_ID_TYPE_INT, ID_TYPE_RFC822_ADDR);
             defaults.putInt(KEY_IKE_REMOTE_ID_TYPE_INT, ID_TYPE_FQDN);
             defaults.putBoolean(KEY_ADD_KE_TO_CHILD_SESSION_REKEY_BOOL, false);
@@ -9035,8 +9007,7 @@
      * level outside these boundaries is considered invalid.
      * @hide
      */
-    public static final String KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY =
-            "gsm_rssi_thresholds_int_array";
+    public static final String KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY = "gsm_rssi_thresholds_int_array";
 
     /**
      * An interval in dB for {@link SignalThresholdInfo#SIGNAL_MEASUREMENT_TYPE_RSSI} measurement
@@ -9054,8 +9025,7 @@
      * See Wireless Priority Service from https://www.fcc.gov/general/wireless-priority-service-wps
      * @hide
      */
-    public static final String KEY_SUPPORT_WPS_OVER_IMS_BOOL =
-            "support_wps_over_ims_bool";
+    public static final String KEY_SUPPORT_WPS_OVER_IMS_BOOL = "support_wps_over_ims_bool";
 
     /**
      * The two digital number pattern of MMI code which is defined by carrier.
@@ -9103,8 +9073,7 @@
      * When true, forwarded number is shown.
      * When false, forwarded number is not shown.
      */
-    public static final String KEY_SHOW_FORWARDED_NUMBER_BOOL =
-            "show_forwarded_number_bool";
+    public static final String KEY_SHOW_FORWARDED_NUMBER_BOOL = "show_forwarded_number_bool";
 
     /**
      * The list of originating address of missed incoming call SMS. If the SMS has originator
@@ -9116,7 +9085,6 @@
     public static final String KEY_MISSED_INCOMING_CALL_SMS_ORIGINATOR_STRING_ARRAY =
             "missed_incoming_call_sms_originator_string_array";
 
-
     /**
      * String array of Apn Type configurations.
      * The entries should be of form "APN_TYPE_NAME:priority".
@@ -9264,8 +9232,7 @@
      *
      * @hide
      */
-    public static final String KEY_DEFAULT_RTT_MODE_INT =
-            "default_rtt_mode_int";
+    public static final String KEY_DEFAULT_RTT_MODE_INT = "default_rtt_mode_int";
 
     /**
      * Indicates whether RTT is supported while roaming.
@@ -9291,10 +9258,9 @@
      * seamlessly after an unattended reboot.
      *
      * The device configuration value {@code config_allow_pin_storage_for_unattended_reboot}
-     * ultimately controls whether this carrier configuration option is used.  Where
-     * {@code config_allow_pin_storage_for_unattended_reboot} is false, the value of the
-     * {@link #KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL} carrier configuration option is
-     * ignored.
+     * ultimately controls whether this carrier configuration option is used. Where
+     * {@code config_allow_pin_storage_for_unattended_reboot} is false, the value of this
+     * carrier configuration is ignored.
      *
      * @hide
      */
@@ -9572,7 +9538,7 @@
             "iwlan_handover_policy_string_array";
 
     /** The default value for every variable. */
-    private final static PersistableBundle sDefaults;
+    private static final PersistableBundle sDefaults;
 
     static {
         sDefaults = new PersistableBundle();
@@ -9682,17 +9648,17 @@
         sDefaults.putBoolean(KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
         sDefaults.putBoolean(KEY_CARRIER_SUPPORTS_TETHERING_BOOL, true);
         sDefaults.putBoolean(KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL, false);
-        sDefaults.putIntArray(KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY, new int[]{});
+        sDefaults.putIntArray(KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY, new int[0]);
         sDefaults.putInt(KEY_VOLTE_REPLACEMENT_RAT_INT, 0);
         sDefaults.putString(KEY_DEFAULT_SIM_CALL_MANAGER_STRING, "");
         sDefaults.putString(KEY_VVM_DESTINATION_NUMBER_STRING, "");
         sDefaults.putInt(KEY_VVM_PORT_NUMBER_INT, 0);
         sDefaults.putString(KEY_VVM_TYPE_STRING, "");
         sDefaults.putBoolean(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL, false);
-        sDefaults.putString(KEY_VVM_CLIENT_PREFIX_STRING,"//VVM");
-        sDefaults.putBoolean(KEY_VVM_SSL_ENABLED_BOOL,false);
+        sDefaults.putString(KEY_VVM_CLIENT_PREFIX_STRING, "//VVM");
+        sDefaults.putBoolean(KEY_VVM_SSL_ENABLED_BOOL, false);
         sDefaults.putStringArray(KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY, null);
-        sDefaults.putBoolean(KEY_VVM_LEGACY_MODE_ENABLED_BOOL,false);
+        sDefaults.putBoolean(KEY_VVM_LEGACY_MODE_ENABLED_BOOL, false);
         sDefaults.putBoolean(KEY_VVM_PREFETCH_BOOL, true);
         sDefaults.putString(KEY_CARRIER_VVM_PACKAGE_NAME_STRING, "");
         sDefaults.putStringArray(KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY, null);
@@ -9849,7 +9815,6 @@
         sDefaults.putStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_CARRIER_APP_REQUIRED_DURING_SIM_SETUP_BOOL, false);
 
-
         // Default carrier app configurations
         sDefaults.putStringArray(KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY,
                 new String[]{
@@ -9863,9 +9828,10 @@
                 //6: CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS
                 //8: CARRIER_ACTION_DISABLE_DEFAULT_URL_HANDLER
                 });
-        sDefaults.putStringArray(KEY_CARRIER_DEFAULT_ACTIONS_ON_DEFAULT_NETWORK_AVAILABLE, new String[] {
-                String.valueOf(false) + ": 7", //7: CARRIER_ACTION_ENABLE_DEFAULT_URL_HANDLER
-                String.valueOf(true) + ": 8"  //8: CARRIER_ACTION_DISABLE_DEFAULT_URL_HANDLER
+        sDefaults.putStringArray(KEY_CARRIER_DEFAULT_ACTIONS_ON_DEFAULT_NETWORK_AVAILABLE,
+                new String[] {
+                        false + ": 7", //7: CARRIER_ACTION_ENABLE_DEFAULT_URL_HANDLER
+                        true + ": 8"  //8: CARRIER_ACTION_DISABLE_DEFAULT_URL_HANDLER
                 });
         sDefaults.putStringArray(KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY, null);
 
@@ -9879,9 +9845,9 @@
 
         // Rat families: {GPRS, EDGE}, {EVDO, EVDO_A, EVDO_B}, {UMTS, HSPA, HSDPA, HSUPA, HSPAP},
         // {LTE, LTE_CA}
-        // Order is important - lowest precidence first
+        // Order is important - lowest precedence first
         sDefaults.putStringArray(KEY_RATCHET_RAT_FAMILIES,
-                new String[]{"1,2","7,8,12","3,11,9,10,15","14,19"});
+                new String[]{"1,2", "7,8,12", "3,11,9,10,15", "14,19"});
         sDefaults.putBoolean(KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL, false);
         sDefaults.putBoolean(KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL, false);
         sDefaults.putBoolean(KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL, true);
@@ -9912,8 +9878,7 @@
         sDefaults.putBoolean(KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL, false);
         sDefaults.putBoolean(KEY_HIDE_PRESET_APN_DETAILS_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL, false);
-        sDefaults.putStringArray(KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY,
-                null);
+        sDefaults.putStringArray(KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_SUPPORT_IMS_CALL_FORWARDING_WHILE_ROAMING_BOOL, true);
         sDefaults.putInt(KEY_LTE_EARFCNS_RSRP_BOOST_INT, 0);
         sDefaults.putStringArray(KEY_BOOSTED_LTE_EARFCNS_STRING_ARRAY, null);
@@ -9991,27 +9956,27 @@
         sDefaults.putIntArray(KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY,
                 // Boundaries: [-120 dBm, -25 dBm]
                 new int[] {
-                        -115,  /* SIGNAL_STRENGTH_POOR */
+                        -115, /* SIGNAL_STRENGTH_POOR */
                         -105, /* SIGNAL_STRENGTH_MODERATE */
-                        -95, /* SIGNAL_STRENGTH_GOOD */
-                        -85  /* SIGNAL_STRENGTH_GREAT */
+                        -95,  /* SIGNAL_STRENGTH_GOOD */
+                        -85   /* SIGNAL_STRENGTH_GREAT */
                 });
         // TODO(b/249896055): On enabling ECNO measurement part for Signal Bar level indication
-        // system functionality,below values to be rechecked.
+        // system functionality, below values to be rechecked.
         sDefaults.putIntArray(KEY_WCDMA_ECNO_THRESHOLDS_INT_ARRAY,
                 // Boundaries: [-24 dBm, 1 dBm]
                 new int[] {
                         -24, /* SIGNAL_STRENGTH_POOR */
                         -14, /* SIGNAL_STRENGTH_MODERATE */
-                        -6, /* SIGNAL_STRENGTH_GOOD */
-                        1  /* SIGNAL_STRENGTH_GREAT */
+                        -6,  /* SIGNAL_STRENGTH_GOOD */
+                        1    /* SIGNAL_STRENGTH_GREAT */
                 });
         sDefaults.putIntArray(KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY,
                 // Boundaries: [-140 dB, -44 dB]
                 new int[] {
                     -110, /* SIGNAL_STRENGTH_POOR */
-                    -90, /* SIGNAL_STRENGTH_MODERATE */
-                    -80, /* SIGNAL_STRENGTH_GOOD */
+                    -90,  /* SIGNAL_STRENGTH_MODERATE */
+                    -80,  /* SIGNAL_STRENGTH_GOOD */
                     -65,  /* SIGNAL_STRENGTH_GREAT */
                 });
         sDefaults.putIntArray(KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY,
@@ -10019,14 +9984,14 @@
                 new int[] {
                     -31, /* SIGNAL_STRENGTH_POOR */
                     -19, /* SIGNAL_STRENGTH_MODERATE */
-                    -7, /* SIGNAL_STRENGTH_GOOD */
-                    6  /* SIGNAL_STRENGTH_GREAT */
+                    -7,  /* SIGNAL_STRENGTH_GOOD */
+                    6    /* SIGNAL_STRENGTH_GREAT */
                 });
         sDefaults.putIntArray(KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY,
                 // Boundaries: [-23 dB, 40 dB]
                 new int[] {
                     -5, /* SIGNAL_STRENGTH_POOR */
-                    5, /* SIGNAL_STRENGTH_MODERATE */
+                    5,  /* SIGNAL_STRENGTH_MODERATE */
                     15, /* SIGNAL_STRENGTH_GOOD */
                     30  /* SIGNAL_STRENGTH_GREAT */
                 });
@@ -10120,8 +10085,7 @@
         sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_MAX_BACKOFF_TIME_LONG, 60000);
         sDefaults.putBoolean(KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL, true);
         sDefaults.putLong(KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG, 60000L);
-        sDefaults.putLong(
-                KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG,
+        sDefaults.putLong(KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG,
                 120000L);
         sDefaults.putAll(ImsServiceEntitlement.getDefaults());
         sDefaults.putAll(Gps.getDefaults());
@@ -10143,7 +10107,7 @@
                 new int[] {
                         -107, /* SIGNAL_STRENGTH_POOR */
                         -103, /* SIGNAL_STRENGTH_MODERATE */
-                        -97, /* SIGNAL_STRENGTH_GOOD */
+                        -97,  /* SIGNAL_STRENGTH_GOOD */
                         -89,  /* SIGNAL_STRENGTH_GREAT */
                 });
         sDefaults.putBoolean(KEY_SUPPORT_WPS_OVER_IMS_BOOL, true);
@@ -10235,7 +10199,7 @@
         sDefaults.putBoolean(KEY_VONR_SETTING_VISIBILITY_BOOL, true);
         sDefaults.putBoolean(KEY_VONR_ENABLED_BOOL, false);
         sDefaults.putBoolean(KEY_VONR_ON_BY_DEFAULT_BOOL, true);
-        sDefaults.putIntArray(KEY_SUPPORTED_PREMIUM_CAPABILITIES_INT_ARRAY, new int[] {});
+        sDefaults.putIntArray(KEY_SUPPORTED_PREMIUM_CAPABILITIES_INT_ARRAY, new int[0]);
         sDefaults.putLong(KEY_PREMIUM_CAPABILITY_NOTIFICATION_DISPLAY_TIMEOUT_MILLIS_LONG,
                 TimeUnit.MINUTES.toMillis(30));
         sDefaults.putLong(KEY_PREMIUM_CAPABILITY_NOTIFICATION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG,
@@ -10304,7 +10268,6 @@
         public static final String KEY_AVOID_5GHZ_WIFI_DIRECT_FOR_LAA_BOOL =
                 KEY_PREFIX + "avoid_5ghz_wifi_direct_for_laa_bool";
 
-
         private static PersistableBundle getDefaults() {
             PersistableBundle defaults = new PersistableBundle();
             defaults.putInt(KEY_HOTSPOT_MAX_CLIENT_COUNT, 0);
@@ -10351,8 +10314,7 @@
             return loader.getConfigForSubIdWithFeature(subId, mContext.getOpPackageName(),
                     mContext.getAttributionTag());
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "Error getting config for subId " + subId + ": "
-                    + ex.toString());
+            Rlog.e(TAG, "Error getting config for subId " + subId + ": " + ex);
         }
         return null;
     }
@@ -10378,7 +10340,7 @@
      * {@link TelephonyManager#hasCarrierPrivileges()}).
      *
      * @param subId The subscription ID on which the carrier config should be retrieved.
-     * @param keys  The carrier config keys to retrieve values.
+     * @param keys The carrier config keys to retrieve values.
      * @return A {@link PersistableBundle} with key/value mapping for the specified configuration
      * on success, or an empty (but never null) bundle on failure (for example, when the calling app
      * has no permission).
@@ -10469,8 +10431,7 @@
             }
             loader.overrideConfig(subscriptionId, overrideValues, persistent);
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "Error setting config for subId " + subscriptionId + ": "
-                    + ex.toString());
+            Rlog.e(TAG, "Error setting config for subId " + subscriptionId + ": " + ex);
         }
     }
 
@@ -10583,7 +10544,7 @@
             }
             loader.notifyConfigChangedForSubId(subId);
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "Error reloading config for subId=" + subId + ": " + ex.toString());
+            Rlog.e(TAG, "Error reloading config for subId=" + subId + ": " + ex);
         }
     }
 
@@ -10607,7 +10568,7 @@
             }
             loader.updateConfigForPhoneId(phoneId, simState);
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "Error updating config for phoneId=" + phoneId + ": " + ex.toString());
+            Rlog.e(TAG, "Error updating config for phoneId=" + phoneId + ": " + ex);
         }
     }
 
@@ -10629,8 +10590,7 @@
             }
             return loader.getDefaultCarrierServicePackageName();
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "getDefaultCarrierServicePackageName ICarrierConfigLoader is null"
-                    + ex.toString());
+            Rlog.e(TAG, "getDefaultCarrierServicePackageName ICarrierConfigLoader is null" + ex);
             ex.rethrowAsRuntimeException();
         }
         return "";
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
index 52ca7a2..75de476 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
@@ -114,6 +114,10 @@
     @Test
     override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
+    @FlakyTest(bugId = 266730606)
+    @Test
+    override fun entireScreenCovered() = super.entireScreenCovered()
+
     companion object {
         /**
          * Creates the test configurations.
diff --git a/tools/lint/global/Android.bp b/tools/lint/global/Android.bp
index 3756abe..bedb7bd 100644
--- a/tools/lint/global/Android.bp
+++ b/tools/lint/global/Android.bp
@@ -38,12 +38,6 @@
 
 java_test_host {
     name: "AndroidGlobalLintCheckerTest",
-    // TODO(b/239881504): Since this test was written, Android
-    // Lint was updated, and now includes classes that were
-    // compiled for java 15. The soong build doesn't support
-    // java 15 yet, so we can't compile against "lint". Disable
-    // the test until java 15 is supported.
-    enabled: false,
     srcs: ["checks/src/test/java/**/*.kt"],
     static_libs: [
         "AndroidGlobalLintChecker",
@@ -53,5 +47,19 @@
     ],
     test_options: {
         unit_test: true,
+        tradefed_options: [
+            {
+                // lint bundles in some classes that were built with older versions
+                // of libraries, and no longer load. Since tradefed tries to load
+                // all classes in the jar to look for tests, it crashes loading them.
+                // Exclude these classes from tradefed's search.
+                name: "exclude-paths",
+                value: "org/apache",
+            },
+            {
+                name: "exclude-paths",
+                value: "META-INF",
+            },
+        ],
     },
 }
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/Constants.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/Constants.kt
index 72de00f..dcfbe95 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/Constants.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/Constants.kt
@@ -29,6 +29,8 @@
 const val BINDER_CLASS = "android.os.Binder"
 const val IINTERFACE_INTERFACE = "android.os.IInterface"
 
+const val AIDL_PERMISSION_HELPER_SUFFIX = "_enforcePermission"
+
 /**
  * If a non java (e.g. c++) backend is enabled, the @EnforcePermission
  * annotation cannot be used.  At time of writing, the mechanism
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionFix.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionFix.kt
index 485765b..25d208d 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionFix.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionFix.kt
@@ -36,6 +36,7 @@
 import org.jetbrains.uast.UExpression
 import org.jetbrains.uast.UExpressionList
 import org.jetbrains.uast.UIfExpression
+import org.jetbrains.uast.UMethod
 import org.jetbrains.uast.UThrowExpression
 import org.jetbrains.uast.UastBinaryOperator
 import org.jetbrains.uast.evaluateString
@@ -46,29 +47,37 @@
  * Helper class that facilitates the creation of lint auto fixes
  */
 data class EnforcePermissionFix(
-    val locations: List<Location>,
+    val manualCheckLocations: List<Location>,
     val permissionNames: List<String>,
     val errorLevel: Boolean,
     val anyOf: Boolean,
 ) {
-    fun toLintFix(annotationLocation: Location): LintFix {
-        val removeFixes = this.locations.map {
-            LintFix.create()
-                .replace()
-                .reformat(true)
-                .range(it)
-                .with("")
-                .autoFix()
-                .build()
+    fun toLintFix(context: JavaContext, node: UMethod): LintFix {
+        val methodLocation = context.getLocation(node)
+        val replaceOrRemoveFixes = manualCheckLocations.mapIndexed { index, manualCheckLocation ->
+            if (index == 0) {
+                // Replace the first manual check with a call to the helper method
+                getHelperMethodFix(node, manualCheckLocation, false)
+            } else {
+                // Remove all subsequent manual checks
+                LintFix.create()
+                    .replace()
+                    .reformat(true)
+                    .range(manualCheckLocation)
+                    .with("")
+                    .autoFix()
+                    .build()
+            }
         }
 
+        // Annotate the method with @EnforcePermission(...)
         val annotateFix = LintFix.create()
-            .annotate(this.annotation)
-            .range(annotationLocation)
+            .annotate(annotation)
+            .range(methodLocation)
             .autoFix()
             .build()
 
-        return LintFix.create().composite(annotateFix, *removeFixes.toTypedArray())
+        return LintFix.create().composite(annotateFix, *replaceOrRemoveFixes.toTypedArray())
     }
 
     private val annotation: String
@@ -89,7 +98,50 @@
 
     companion object {
         /**
+         * Walks the expressions in a block, looking for simple permission checks.
+         *
+         * As soon as something other than a permission check is encountered, stop looking,
+         * as some other business logic is happening that prevents an automated fix.
+         */
+        fun fromBlockExpression(
+            context: JavaContext,
+            blockExpression: UBlockExpression
+        ): EnforcePermissionFix? {
+            try {
+                val singleFixes = mutableListOf<EnforcePermissionFix>()
+                for (expression in blockExpression.expressions) {
+                    val fix = fromExpression(context, expression) ?: break
+                    singleFixes.add(fix)
+                }
+                return compose(singleFixes)
+            } catch (e: AnyOfAllOfException) {
+                return null
+            }
+        }
+
+        /**
+         * Conditionally constructs EnforcePermissionFix from any UExpression
+         *
+         * @return EnforcePermissionFix if the expression boils down to a permission check,
+         * else null
+         */
+        fun fromExpression(
+            context: JavaContext,
+            expression: UExpression
+        ): EnforcePermissionFix? {
+            val trimmedExpression = expression.skipParenthesizedExprDown()
+            if (trimmedExpression is UIfExpression) {
+                return fromIfExpression(context, trimmedExpression)
+            }
+            findCallExpression(trimmedExpression)?.let {
+                return fromCallExpression(context, it)
+            }
+            return null
+        }
+
+        /**
          * Conditionally constructs EnforcePermissionFix from a UCallExpression
+         *
          * @return EnforcePermissionFix if the called method is annotated with @PermissionMethod, else null
          */
         fun fromCallExpression(
@@ -111,6 +163,7 @@
 
         /**
          * Conditionally constructs EnforcePermissionFix from a UCallExpression
+         *
          * @return EnforcePermissionFix IF AND ONLY IF:
          * * The condition of the if statement compares the return value of a
          *   PermissionMethod to one of the PackageManager.PermissionResult values
@@ -172,7 +225,8 @@
         }
 
 
-        fun compose(individuals: List<EnforcePermissionFix>): EnforcePermissionFix {
+        fun compose(individuals: List<EnforcePermissionFix>): EnforcePermissionFix? {
+            if (individuals.isEmpty()) return null
             val anyOfs = individuals.filter(EnforcePermissionFix::anyOf)
             // anyOf/allOf should be consistent.  If we encounter some @PermissionMethods that are anyOf
             // and others that aren't, we don't know what to do.
@@ -180,7 +234,7 @@
                 throw AnyOfAllOfException()
             }
             return EnforcePermissionFix(
-                    individuals.flatMap(EnforcePermissionFix::locations),
+                    individuals.flatMap(EnforcePermissionFix::manualCheckLocations),
                     individuals.flatMap(EnforcePermissionFix::permissionNames),
                     errorLevel = individuals.all(EnforcePermissionFix::errorLevel),
                     anyOf = anyOfs.isNotEmpty()
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt
index b65c0fc..df13af5 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt
@@ -55,7 +55,7 @@
                 return
             }
 
-            val targetExpression = "${node.name}$HELPER_SUFFIX()"
+            val targetExpression = getHelperMethodCallSourceString(node)
             val message =
                 "Method must start with $targetExpression or super.${node.name}(), if applicable"
 
@@ -85,22 +85,11 @@
                 val locationTarget = getLocationTarget(firstExpression)
                 val expressionLocation = context.getLocation(locationTarget)
 
-                val indent = " ".repeat(expressionLocation.start?.column ?: 0)
-
-                val fix = fix()
-                    .replace()
-                    .range(expressionLocation)
-                    .beginning()
-                    .with("$targetExpression;\n\n$indent")
-                    .reformat(true)
-                    .autoFix()
-                    .build()
-
                 context.report(
                     ISSUE_ENFORCE_PERMISSION_HELPER,
                     context.getLocation(node),
                     message,
-                    fix
+                    getHelperMethodFix(node, expressionLocation),
                 )
             }
         }
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt
index 2239ea1..d41fee3 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt
@@ -17,6 +17,8 @@
 package com.google.android.lint.aidl
 
 import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.LintFix
+import com.android.tools.lint.detector.api.Location
 import com.intellij.psi.PsiClass
 import com.intellij.psi.PsiReferenceList
 import org.jetbrains.uast.UMethod
@@ -69,3 +71,26 @@
         references != null &&
                 references.referenceElements.size == 1 &&
                 references.referenceElements[0].qualifiedName == qualifiedName
+
+fun getHelperMethodCallSourceString(node: UMethod) = "${node.name}$AIDL_PERMISSION_HELPER_SUFFIX()"
+
+fun getHelperMethodFix(
+    node: UMethod,
+    manualCheckLocation: Location,
+    prepend: Boolean = true
+): LintFix {
+    val helperMethodSource = getHelperMethodCallSourceString(node)
+    val indent = " ".repeat(manualCheckLocation.start?.column ?: 0)
+    val newText = "$helperMethodSource;${if (prepend) "\n\n$indent" else ""}"
+
+    val fix = LintFix.create()
+            .replace()
+            .range(manualCheckLocation)
+            .with(newText)
+            .reformat(true)
+            .autoFix()
+
+    if (prepend) fix.beginning()
+
+    return fix.build()
+}
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetector.kt
index 11a283a..c7be36e 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetector.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetector.kt
@@ -23,19 +23,13 @@
 import com.android.tools.lint.detector.api.JavaContext
 import com.android.tools.lint.detector.api.Scope
 import com.android.tools.lint.detector.api.Severity
-import com.google.android.lint.findCallExpression
 import org.jetbrains.uast.UBlockExpression
-import org.jetbrains.uast.UElement
-import org.jetbrains.uast.UIfExpression
 import org.jetbrains.uast.UMethod
-import org.jetbrains.uast.skipParenthesizedExprDown
 
 /**
  * Looks for methods implementing generated AIDL interface stubs
  * that can have simple permission checks migrated to
  * @EnforcePermission annotations
- *
- * TODO: b/242564870 (enable parse and autoFix of .aidl files)
  */
 @Suppress("UnstableApiUsage")
 class SimpleManualPermissionEnforcementDetector : AidlImplementationDetector() {
@@ -45,8 +39,8 @@
             interfaceName: String,
             body: UBlockExpression
     ) {
-        val enforcePermissionFix = accumulateSimplePermissionCheckFixes(body, context) ?: return
-        val lintFix = enforcePermissionFix.toLintFix(context.getLocation(node))
+        val enforcePermissionFix = EnforcePermissionFix.fromBlockExpression(context, body) ?: return
+        val lintFix = enforcePermissionFix.toLintFix(context, node)
         val message =
                 "$interfaceName permission check ${
                     if (enforcePermissionFix.errorLevel) "should" else "can"
@@ -54,68 +48,19 @@
 
         val incident = Incident(
                 ISSUE_SIMPLE_MANUAL_PERMISSION_ENFORCEMENT,
-                enforcePermissionFix.locations.last(),
+                enforcePermissionFix.manualCheckLocations.last(),
                 message,
                 lintFix
         )
 
-        if (enforcePermissionFix.errorLevel) {
-            incident.overrideSeverity(Severity.ERROR)
-        }
+        // TODO(b/265014041): turn on errors once all code that would cause one is fixed
+        // if (enforcePermissionFix.errorLevel) {
+        //     incident.overrideSeverity(Severity.ERROR)
+        // }
 
         context.report(incident)
     }
 
-    /**
-     * Walk the expressions in the method, looking for simple permission checks.
-     *
-     * If a single permission check is found at the beginning of the method,
-     * this should be migrated to @EnforcePermission(value).
-     *
-     * If multiple consecutive permission checks are found,
-     * these should be migrated to @EnforcePermission(allOf={value1, value2, ...})
-     *
-     * As soon as something other than a permission check is encountered, stop looking,
-     * as some other business logic is happening that prevents an automated fix.
-     */
-    private fun accumulateSimplePermissionCheckFixes(
-                methodBody: UBlockExpression,
-                context: JavaContext
-        ): EnforcePermissionFix? {
-        try {
-            val singleFixes = mutableListOf<EnforcePermissionFix>()
-            for (expression in methodBody.expressions) {
-                val fix = getPermissionCheckFix(
-                        expression.skipParenthesizedExprDown(),
-                        context) ?: break
-                singleFixes.add(fix)
-            }
-            return when (singleFixes.size) {
-                0 -> null
-                1 -> singleFixes[0]
-                else -> EnforcePermissionFix.compose(singleFixes)
-            }
-        } catch (e: AnyOfAllOfException) {
-            return null
-        }
-    }
-
-
-    /**
-     * If an expression boils down to a permission check, return
-     * the helper for creating a lint auto fix to @EnforcePermission
-     */
-    private fun getPermissionCheckFix(startingExpression: UElement?, context: JavaContext):
-            EnforcePermissionFix? {
-        if (startingExpression is UIfExpression) {
-            return EnforcePermissionFix.fromIfExpression(context, startingExpression)
-        }
-        findCallExpression(startingExpression)?.let {
-            return EnforcePermissionFix.fromCallExpression(context, it)
-        }
-        return null
-    }
-
     companion object {
 
         private val EXPLANATION = """
@@ -142,7 +87,6 @@
                         SimpleManualPermissionEnforcementDetector::class.java,
                         Scope.JAVA_FILE_SCOPE
                 ),
-                enabledByDefault = false, // TODO: enable once b/241171714 is resolved
         )
     }
 }
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetectorTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetectorTest.kt
index 2ac550b..6b8e72cf 100644
--- a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetectorTest.kt
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetectorTest.kt
@@ -51,10 +51,10 @@
             .run()
             .expect(
                 """
-                src/Foo.java:7: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                src/Foo.java:7: Warning: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
                         mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-                1 errors, 0 warnings
+                0 errors, 1 warnings
                 """
             )
             .expectFixDiffs(
@@ -64,6 +64,7 @@
                 +     @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
                 @@ -7 +8
                 -         mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
+                +         test_enforcePermission();
                 """
             )
     }
@@ -101,6 +102,7 @@
                     +     @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
                     @@ -7 +8
                     -         mContext.enforceCallingPermission("android.permission.READ_CONTACTS", "foo");
+                    +         test_enforcePermission();
                     """
                 )
     }
@@ -138,6 +140,7 @@
                     +     @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
                     @@ -7 +8
                     -         mContext.checkCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
+                    +         test_enforcePermission();
                     """
                 )
     }
@@ -165,10 +168,10 @@
             .run()
             .expect(
                 """
-                src/Foo.java:8: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                src/Foo.java:8: Warning: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
                             mContext.enforceCallingOrSelfPermission(
                             ^
-                1 errors, 0 warnings
+                0 errors, 1 warnings
                 """
             )
             .expectFixDiffs(
@@ -179,6 +182,7 @@
                 @@ -8 +9
                 -             mContext.enforceCallingOrSelfPermission(
                 -                 "android.permission.READ_CONTACTS", "foo");
+                +             test_enforcePermission();
                 """
             )
     }
@@ -205,19 +209,20 @@
             .run()
             .expect(
                 """
-                src/Foo.java:8: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                src/Foo.java:8: Warning: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
                         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_CONTACTS, "foo");
                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-                1 errors, 0 warnings
+                0 errors, 1 warnings
                 """
             )
             .expectFixDiffs(
                 """
-                Fix for src/Foo.java line 7: Annotate with @EnforcePermission:
+                Fix for src/Foo.java line 8: Annotate with @EnforcePermission:
                 @@ -6 +6
                 +     @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
                 @@ -8 +9
                 -         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_CONTACTS, "foo");
+                +         test_enforcePermission();
                 """
             )
     }
@@ -247,10 +252,10 @@
             .run()
             .expect(
                 """
-                src/Foo.java:10: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                src/Foo.java:10: Warning: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
                             mContext.enforceCallingOrSelfPermission(
                             ^
-                1 errors, 0 warnings
+                0 errors, 1 warnings
                 """
             )
             .expectFixDiffs(
@@ -263,98 +268,101 @@
                 -                 "android.permission.READ_CONTACTS", "foo");
                 -             mContext.enforceCallingOrSelfPermission(
                 -                 "android.permission.WRITE_CONTACTS", "foo");
+                +             test_enforcePermission();
                 """
             )
     }
 
     fun testAllOf_mixedOrSelf_warning() {
         lint().files(
-                java(
-                    """
-                    import android.content.Context;
-                    import android.test.ITest;
-                    public class Foo {
-                        private Context mContext;
-                        private ITest itest = new ITest.Stub() {
-                            @Override
-                            public void test() throws android.os.RemoteException {
-                                mContext.enforceCallingOrSelfPermission(
-                                    "android.permission.READ_CONTACTS", "foo");
-                                mContext.enforceCallingPermission(
-                                    "android.permission.WRITE_CONTACTS", "foo");
-                            }
-                        };
-                    }
-                    """
-                ).indented(),
-                *stubs
+            java(
+                """
+                import android.content.Context;
+                import android.test.ITest;
+                public class Foo {
+                    private Context mContext;
+                    private ITest itest = new ITest.Stub() {
+                        @Override
+                        public void test() throws android.os.RemoteException {
+                            mContext.enforceCallingOrSelfPermission(
+                                "android.permission.READ_CONTACTS", "foo");
+                            mContext.enforceCallingPermission(
+                                "android.permission.WRITE_CONTACTS", "foo");
+                        }
+                    };
+                }
+                """
+            ).indented(),
+            *stubs
         )
-                .run()
-                .expect(
-                    """
-                    src/Foo.java:10: Warning: ITest permission check can be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
-                                mContext.enforceCallingPermission(
-                                ^
-                    0 errors, 1 warnings
-                    """
-                )
-                .expectFixDiffs(
-                    """
-                    Fix for src/Foo.java line 10: Annotate with @EnforcePermission:
-                    @@ -6 +6
-                    +         @android.annotation.EnforcePermission(allOf={"android.permission.READ_CONTACTS", "android.permission.WRITE_CONTACTS"})
-                    @@ -8 +9
-                    -             mContext.enforceCallingOrSelfPermission(
-                    -                 "android.permission.READ_CONTACTS", "foo");
-                    -             mContext.enforceCallingPermission(
-                    -                 "android.permission.WRITE_CONTACTS", "foo");
-                    """
-                )
+            .run()
+            .expect(
+                """
+                src/Foo.java:10: Warning: ITest permission check can be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                            mContext.enforceCallingPermission(
+                            ^
+                0 errors, 1 warnings
+                """
+            )
+            .expectFixDiffs(
+                """
+                Fix for src/Foo.java line 10: Annotate with @EnforcePermission:
+                @@ -6 +6
+                +         @android.annotation.EnforcePermission(allOf={"android.permission.READ_CONTACTS", "android.permission.WRITE_CONTACTS"})
+                @@ -8 +9
+                -             mContext.enforceCallingOrSelfPermission(
+                -                 "android.permission.READ_CONTACTS", "foo");
+                -             mContext.enforceCallingPermission(
+                -                 "android.permission.WRITE_CONTACTS", "foo");
+                +             test_enforcePermission();
+                """
+            )
     }
 
     fun testAllOf_mixedEnforces_warning() {
         lint().files(
-                java(
-                    """
-                    import android.content.Context;
-                    import android.test.ITest;
-                    public class Foo {
-                        private Context mContext;
-                        private ITest itest = new ITest.Stub() {
-                            @Override
-                            public void test() throws android.os.RemoteException {
-                                mContext.enforceCallingOrSelfPermission(
-                                    "android.permission.READ_CONTACTS", "foo");
-                                mContext.checkCallingOrSelfPermission(
-                                    "android.permission.WRITE_CONTACTS", "foo");
-                            }
-                        };
-                    }
-                    """
-                ).indented(),
-                *stubs
+            java(
+                """
+                import android.content.Context;
+                import android.test.ITest;
+                public class Foo {
+                    private Context mContext;
+                    private ITest itest = new ITest.Stub() {
+                        @Override
+                        public void test() throws android.os.RemoteException {
+                            mContext.enforceCallingOrSelfPermission(
+                                "android.permission.READ_CONTACTS", "foo");
+                            mContext.checkCallingOrSelfPermission(
+                                "android.permission.WRITE_CONTACTS", "foo");
+                        }
+                    };
+                }
+                """
+            ).indented(),
+            *stubs
         )
-                .run()
-                .expect(
-                    """
-                    src/Foo.java:10: Warning: ITest permission check can be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
-                                mContext.checkCallingOrSelfPermission(
-                                ^
-                    0 errors, 1 warnings
-                    """
-                )
-                .expectFixDiffs(
-                    """
-                    Fix for src/Foo.java line 10: Annotate with @EnforcePermission:
-                    @@ -6 +6
-                    +         @android.annotation.EnforcePermission(allOf={"android.permission.READ_CONTACTS", "android.permission.WRITE_CONTACTS"})
-                    @@ -8 +9
-                    -             mContext.enforceCallingOrSelfPermission(
-                    -                 "android.permission.READ_CONTACTS", "foo");
-                    -             mContext.checkCallingOrSelfPermission(
-                    -                 "android.permission.WRITE_CONTACTS", "foo");
-                    """
-                )
+            .run()
+            .expect(
+                """
+                src/Foo.java:10: Warning: ITest permission check can be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                            mContext.checkCallingOrSelfPermission(
+                            ^
+                0 errors, 1 warnings
+                """
+            )
+            .expectFixDiffs(
+                """
+                Fix for src/Foo.java line 10: Annotate with @EnforcePermission:
+                @@ -6 +6
+                +         @android.annotation.EnforcePermission(allOf={"android.permission.READ_CONTACTS", "android.permission.WRITE_CONTACTS"})
+                @@ -8 +9
+                -             mContext.enforceCallingOrSelfPermission(
+                -                 "android.permission.READ_CONTACTS", "foo");
+                -             mContext.checkCallingOrSelfPermission(
+                -                 "android.permission.WRITE_CONTACTS", "foo");
+                +             test_enforcePermission();
+                """
+            )
     }
 
     fun testPrecedingExpressions() {
@@ -389,7 +397,7 @@
                 public class Foo extends ITest.Stub {
                     private Context mContext;
 
-                    @android.content.pm.PermissionMethod(orSelf = true)
+                    @android.annotation.PermissionMethod(orSelf = true)
                     private void helper() {
                         mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
                     }
@@ -406,10 +414,10 @@
             .run()
             .expect(
                 """
-                src/Foo.java:14: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                src/Foo.java:14: Warning: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
                         helper();
                         ~~~~~~~~~
-                1 errors, 0 warnings
+                0 errors, 1 warnings
                 """
             )
             .expectFixDiffs(
@@ -419,6 +427,7 @@
                 +     @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
                 @@ -14 +15
                 -         helper();
+                +         test_enforcePermission();
                 """
             )
     }
@@ -433,7 +442,7 @@
                     public class Foo extends ITest.Stub {
                         private Context mContext;
 
-                        @android.content.pm.PermissionMethod
+                        @android.annotation.PermissionMethod
                     private void helper() {
                         mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
                     }
@@ -463,6 +472,7 @@
                     +     @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
                     @@ -14 +15
                     -         helper();
+                    +         test_enforcePermission();
                     """
                 )
     }
@@ -477,7 +487,7 @@
                 public class Foo extends ITest.Stub {
                     private Context mContext;
 
-                    @android.content.pm.PermissionMethod(orSelf = true)
+                    @android.annotation.PermissionMethod(orSelf = true)
                     private void helper() {
                         mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
                         mContext.enforceCallingOrSelfPermission("android.permission.WRITE_CONTACTS", "foo");
@@ -496,10 +506,10 @@
             .run()
             .expect(
                 """
-                src/Foo.java:16: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                src/Foo.java:16: Warning: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
                         mContext.enforceCallingOrSelfPermission("FOO", "foo");
                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-                1 errors, 0 warnings
+                0 errors, 1 warnings
                 """
             )
             .expectFixDiffs(
@@ -510,6 +520,7 @@
                 @@ -15 +16
                 -         helper();
                 -         mContext.enforceCallingOrSelfPermission("FOO", "foo");
+                +         test_enforcePermission();
                 """
             )
     }
@@ -525,13 +536,13 @@
                 public class Foo extends ITest.Stub {
                     private Context mContext;
 
-                    @android.content.pm.PermissionMethod(orSelf = true)
+                    @android.annotation.PermissionMethod(orSelf = true)
                     private void helperHelper() {
                         helper("android.permission.WRITE_CONTACTS");
                     }
 
-                    @android.content.pm.PermissionMethod(orSelf = true)
-                    private void helper(@android.content.pm.PermissionName String extraPermission) {
+                    @android.annotation.PermissionMethod(orSelf = true)
+                    private void helper(@android.annotation.PermissionName String extraPermission) {
                         mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
                     }
 
@@ -547,10 +558,10 @@
             .run()
             .expect(
                 """
-                src/Foo.java:19: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                src/Foo.java:19: Warning: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
                         helperHelper();
                         ~~~~~~~~~~~~~~~
-                1 errors, 0 warnings
+                0 errors, 1 warnings
                 """
             )
             .expectFixDiffs(
@@ -560,6 +571,7 @@
                 +     @android.annotation.EnforcePermission(allOf={"android.permission.WRITE_CONTACTS", "android.permission.READ_CONTACTS"})
                 @@ -19 +20
                 -         helperHelper();
+                +         test_enforcePermission();
                 """
             )
     }
@@ -587,10 +599,10 @@
                 .run()
                 .expect(
                     """
-                    src/Foo.java:7: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                    src/Foo.java:7: Warning: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
                             if (mContext.checkCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo")
                             ^
-                    1 errors, 0 warnings
+                    0 errors, 1 warnings
                     """
                 )
                 .expectFixDiffs(
@@ -603,76 +615,106 @@
                     -                 != PackageManager.PERMISSION_GRANTED) {
                     -             throw new SecurityException("yikes!");
                     -         }
+                    +         test_enforcePermission();
                     """
                 )
     }
 
     fun testIfExpression_orSelfFalse_warning() {
         lint().files(
-                java(
-                    """
-                    import android.content.Context;
-                    import android.test.ITest;
-                    public class Foo extends ITest.Stub {
-                        private Context mContext;
-                        @Override
-                        public void test() throws android.os.RemoteException {
-                            if (mContext.checkCallingPermission("android.permission.READ_CONTACTS", "foo")
-                                    != PackageManager.PERMISSION_GRANTED) {
-                                throw new SecurityException("yikes!");
-                            }
+            java(
+                """
+                import android.content.Context;
+                import android.test.ITest;
+                public class Foo extends ITest.Stub {
+                    private Context mContext;
+                    @Override
+                    public void test() throws android.os.RemoteException {
+                        if (mContext.checkCallingPermission("android.permission.READ_CONTACTS", "foo")
+                                != PackageManager.PERMISSION_GRANTED) {
+                            throw new SecurityException("yikes!");
                         }
                     }
-                    """
-                ).indented(),
-                *stubs
+                }
+                """
+            ).indented(),
+            *stubs
         )
-                .run()
-                .expect(
-                    """
-                    src/Foo.java:7: Warning: ITest permission check can be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
-                            if (mContext.checkCallingPermission("android.permission.READ_CONTACTS", "foo")
-                            ^
-                    0 errors, 1 warnings
-                    """
-                )
-                .expectFixDiffs(
-                    """
-                    Fix for src/Foo.java line 7: Annotate with @EnforcePermission:
-                    @@ -5 +5
-                    +     @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
-                    @@ -7 +8
-                    -         if (mContext.checkCallingPermission("android.permission.READ_CONTACTS", "foo")
-                    -                 != PackageManager.PERMISSION_GRANTED) {
-                    -             throw new SecurityException("yikes!");
-                    -         }
-                    """
-                )
+            .run()
+            .expect(
+                """
+                src/Foo.java:7: Warning: ITest permission check can be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                        if (mContext.checkCallingPermission("android.permission.READ_CONTACTS", "foo")
+                        ^
+                0 errors, 1 warnings
+                """
+            )
+            .expectFixDiffs(
+                """
+                Fix for src/Foo.java line 7: Annotate with @EnforcePermission:
+                @@ -5 +5
+                +     @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
+                @@ -7 +8
+                -         if (mContext.checkCallingPermission("android.permission.READ_CONTACTS", "foo")
+                -                 != PackageManager.PERMISSION_GRANTED) {
+                -             throw new SecurityException("yikes!");
+                -         }
+                +         test_enforcePermission();
+                """
+            )
     }
 
     fun testIfExpression_otherSideEffect_ignored() {
         lint().files(
-                java(
-                    """
-                    import android.content.Context;
-                    import android.test.ITest;
-                    public class Foo extends ITest.Stub {
-                        private Context mContext;
-                        @Override
-                        public void test() throws android.os.RemoteException {
-                            if (mContext.checkCallingPermission("android.permission.READ_CONTACTS", "foo")
-                                    != PackageManager.PERMISSION_GRANTED) {
-                                doSomethingElse();
-                                throw new SecurityException("yikes!");
-                            }
+            java(
+                """
+                import android.content.Context;
+                import android.test.ITest;
+                public class Foo extends ITest.Stub {
+                    private Context mContext;
+                    @Override
+                    public void test() throws android.os.RemoteException {
+                        if (mContext.checkCallingPermission("android.permission.READ_CONTACTS", "foo")
+                                != PackageManager.PERMISSION_GRANTED) {
+                            doSomethingElse();
+                            throw new SecurityException("yikes!");
                         }
                     }
-                    """
-                ).indented(),
-                *stubs
+                }
+                """
+            ).indented(),
+            *stubs
         )
-                .run()
-                .expectClean()
+            .run()
+            .expectClean()
+    }
+
+    fun testIfExpression_inlinedWithSideEffect_ignored() {
+        lint().files(
+            java(
+                """
+                import android.content.Context;
+                import android.test.ITest;
+                public class Foo extends ITest.Stub {
+                    private Context mContext;
+                    @Override
+                    public void test() throws android.os.RemoteException {
+                        if (somethingElse() && mContext.checkCallingPermission("android.permission.READ_CONTACTS", "foo")
+                                != PackageManager.PERMISSION_GRANTED) {
+                            throw new SecurityException("yikes!");
+                        }
+                    }
+
+                    private boolean somethingElse() {
+                        return true;
+                    }
+                }
+                """
+            ).indented(),
+            *stubs
+        )
+            .run()
+            .expectClean()
     }
 
     fun testAnyOf_hardCodedAndVarArgs() {
@@ -685,13 +727,13 @@
                     public class Foo extends ITest.Stub {
                         private Context mContext;
 
-                        @android.content.pm.PermissionMethod(anyOf = true)
+                        @android.annotation.PermissionMethod(anyOf = true)
                         private void helperHelper() {
                             helper("FOO", "BAR");
                         }
 
-                        @android.content.pm.PermissionMethod(anyOf = true, value = {"BAZ", "BUZZ"})
-                        private void helper(@android.content.pm.PermissionName String... extraPermissions) {}
+                        @android.annotation.PermissionMethod(anyOf = true, value = {"BAZ", "BUZZ"})
+                        private void helper(@android.annotation.PermissionName String... extraPermissions) {}
 
                         @Override
                         public void test() throws android.os.RemoteException {
@@ -718,6 +760,7 @@
                     +     @android.annotation.EnforcePermission(anyOf={"BAZ", "BUZZ", "FOO", "BAR"})
                     @@ -17 +18
                     -         helperHelper();
+                    +         test_enforcePermission();
                     """
                 )
     }
@@ -733,13 +776,13 @@
                     public class Foo extends ITest.Stub {
                         private Context mContext;
 
-                        @android.content.pm.PermissionMethod
+                        @android.annotation.PermissionMethod
                         private void allOfhelper() {
                             mContext.enforceCallingOrSelfPermission("FOO");
                             mContext.enforceCallingOrSelfPermission("BAR");
                         }
 
-                        @android.content.pm.PermissionMethod(anyOf = true, permissions = {"BAZ", "BUZZ"})
+                        @android.annotation.PermissionMethod(anyOf = true, permissions = {"BAZ", "BUZZ"})
                         private void anyOfHelper() {}
 
                         @Override
@@ -761,17 +804,18 @@
                 java(
                     """
                     import android.content.Context;
-                    import android.content.pm.PermissionName;import android.test.ITest;
+                    import android.annotation.PermissionName;
+                    import android.test.ITest;
 
                     public class Foo extends ITest.Stub {
                         private Context mContext;
 
-                        @android.content.pm.PermissionMethod(anyOf = true)
+                        @android.annotation.PermissionMethod(anyOf = true)
                         private void anyOfCheck(@PermissionName String... permissions) {
                             allOfCheck("BAZ", "BUZZ");
                         }
 
-                        @android.content.pm.PermissionMethod
+                        @android.annotation.PermissionMethod
                         private void allOfCheck(@PermissionName String... permissions) {}
 
                         @Override
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt
index f6e58da..2ec8fdd 100644
--- a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt
@@ -5,84 +5,84 @@
 
 val aidlStub: TestFile = java(
     """
-        package android.test;
-        public interface ITest extends android.os.IInterface {
-            public static abstract class Stub extends android.os.Binder implements android.test.ITest {
-                protected void test_enforcePermission() throws SecurityException {}
-            }
-            public void test() throws android.os.RemoteException;
+    package android.test;
+    public interface ITest extends android.os.IInterface {
+        public static abstract class Stub extends android.os.Binder implements android.test.ITest {
+            protected void test_enforcePermission() throws SecurityException {}
         }
+        public void test() throws android.os.RemoteException;
+    }
     """
 ).indented()
 
 val contextStub: TestFile = java(
     """
-        package android.content;
-        public class Context {
-            @android.content.pm.PermissionMethod(orSelf = true)
-            public void enforceCallingOrSelfPermission(@android.content.pm.PermissionName String permission, String message) {}
-            @android.content.pm.PermissionMethod
-            public void enforceCallingPermission(@android.content.pm.PermissionName String permission, String message) {}
-            @android.content.pm.PermissionMethod(orSelf = true)
-            public int checkCallingOrSelfPermission(@android.content.pm.PermissionName String permission, String message) {}
-            @android.content.pm.PermissionMethod
-            public int checkCallingPermission(@android.content.pm.PermissionName String permission, String message) {}
-        }
+    package android.content;
+    public class Context {
+        @android.annotation.PermissionMethod(orSelf = true)
+        public void enforceCallingOrSelfPermission(@android.annotation.PermissionName String permission, String message) {}
+        @android.annotation.PermissionMethod
+        public void enforceCallingPermission(@android.annotation.PermissionName String permission, String message) {}
+        @android.annotation.PermissionMethod(orSelf = true)
+        public int checkCallingOrSelfPermission(@android.annotation.PermissionName String permission, String message) {}
+        @android.annotation.PermissionMethod
+        public int checkCallingPermission(@android.annotation.PermissionName String permission, String message) {}
+    }
     """
 ).indented()
 
 val binderStub: TestFile = java(
     """
-        package android.os;
-        public class Binder {
-            public static int getCallingUid() {}
-        }
+    package android.os;
+    public class Binder {
+        public static int getCallingUid() {}
+    }
     """
 ).indented()
 
 val permissionMethodStub: TestFile = java(
-"""
-        package android.content.pm;
+    """
+    package android.annotation;
 
-        import static java.lang.annotation.ElementType.METHOD;
-        import static java.lang.annotation.RetentionPolicy.CLASS;
+    import static java.lang.annotation.ElementType.METHOD;
+    import static java.lang.annotation.RetentionPolicy.CLASS;
 
-        import java.lang.annotation.Retention;
-        import java.lang.annotation.Target;
+    import java.lang.annotation.Retention;
+    import java.lang.annotation.Target;
 
-        @Retention(CLASS)
-        @Target({METHOD})
-        public @interface PermissionMethod {}
+    @Retention(CLASS)
+    @Target({METHOD})
+    public @interface PermissionMethod {}
     """
 ).indented()
 
 val permissionNameStub: TestFile = java(
-"""
-        package android.content.pm;
+    """
+    package android.annotation;
 
-        import static java.lang.annotation.ElementType.FIELD;
-        import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
-        import static java.lang.annotation.ElementType.METHOD;
-        import static java.lang.annotation.ElementType.PARAMETER;
-        import static java.lang.annotation.RetentionPolicy.CLASS;
+    import static java.lang.annotation.ElementType.FIELD;
+    import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+    import static java.lang.annotation.ElementType.METHOD;
+    import static java.lang.annotation.ElementType.PARAMETER;
+    import static java.lang.annotation.RetentionPolicy.CLASS;
 
-        import java.lang.annotation.Retention;
-        import java.lang.annotation.Target;
+    import java.lang.annotation.Retention;
+    import java.lang.annotation.Target;
 
-        @Retention(CLASS)
-        @Target({PARAMETER, METHOD, LOCAL_VARIABLE, FIELD})
-        public @interface PermissionName {}
+    @Retention(CLASS)
+    @Target({PARAMETER, METHOD, LOCAL_VARIABLE, FIELD})
+    public @interface PermissionName {}
     """
 ).indented()
 
 val manifestStub: TestFile = java(
     """
-        package android;
+    package android;
 
-        public final class Manifest {
-            public static final class permission {
-                public static final String READ_CONTACTS="android.permission.READ_CONTACTS";
-            }
+    public final class Manifest {
+        public static final class permission {
+            public static final String READ_CONTACTS="android.permission.READ_CONTACTS";
         }
+    }
     """.trimIndent()
 )
\ No newline at end of file