Merge "Add hyphenation pattern for sv"
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobInfo.java b/apex/blobstore/framework/java/android/app/blob/BlobInfo.java
index 73ef310..ba92d95 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobInfo.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobInfo.java
@@ -48,7 +48,6 @@
         mLeaseInfos = leaseInfos;
     }
 
-    @SuppressWarnings("UnsafeParcelApi")
     private BlobInfo(Parcel in) {
         mId = in.readLong();
         mExpiryTimeMs = in.readLong();
diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
index 66767e2..9c0c365 100644
--- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java
+++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
@@ -1408,7 +1408,6 @@
          * Use the {@link #CREATOR}
          * @hide
          */
-        @SuppressWarnings("UnsafeParcelApi")
         AlarmClockInfo(Parcel in) {
             mTriggerTime = in.readLong();
             mShowIntent = in.readParcelable(PendingIntent.class.getClassLoader());
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index b9673f2..0e6006a 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -881,7 +881,6 @@
         return hashCode;
     }
 
-    @SuppressWarnings("UnsafeParcelApi")
     private JobInfo(Parcel in) {
         jobId = in.readInt();
         extras = in.readPersistableBundle();
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 86d7a5a..3fb1fad 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -54,6 +54,8 @@
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ServiceInfo;
 import android.net.Uri;
+import android.os.BatteryManager;
+import android.os.BatteryManagerInternal;
 import android.os.BatteryStats;
 import android.os.BatteryStatsInternal;
 import android.os.Binder;
@@ -250,8 +252,6 @@
      */
     private final List<RestrictingController> mRestrictiveControllers;
     /** Need direct access to this for testing. */
-    private final BatteryController mBatteryController;
-    /** Need direct access to this for testing. */
     private final StorageController mStorageController;
     /** Need directly for sending uid state changes */
     private final DeviceIdleJobsController mDeviceIdleJobsController;
@@ -268,6 +268,9 @@
      */
     private final List<JobRestriction> mJobRestrictions;
 
+    @GuardedBy("mLock")
+    private final BatteryStateTracker mBatteryStateTracker;
+
     @NonNull
     private final String mSystemGalleryPackage;
 
@@ -1697,6 +1700,9 @@
         // Initialize the job store and set up any persisted jobs
         mJobs = JobStore.initAndGet(this);
 
+        mBatteryStateTracker = new BatteryStateTracker();
+        mBatteryStateTracker.startTracking();
+
         // Create the controllers.
         mControllers = new ArrayList<StateController>();
         final ConnectivityController connectivityController = new ConnectivityController(this);
@@ -1704,8 +1710,8 @@
         mControllers.add(new TimeController(this));
         final IdleController idleController = new IdleController(this);
         mControllers.add(idleController);
-        mBatteryController = new BatteryController(this);
-        mControllers.add(mBatteryController);
+        final BatteryController batteryController = new BatteryController(this);
+        mControllers.add(batteryController);
         mStorageController = new StorageController(this);
         mControllers.add(mStorageController);
         final BackgroundJobsController backgroundJobsController =
@@ -1725,7 +1731,7 @@
         mControllers.add(mTareController);
 
         mRestrictiveControllers = new ArrayList<>();
-        mRestrictiveControllers.add(mBatteryController);
+        mRestrictiveControllers.add(batteryController);
         mRestrictiveControllers.add(connectivityController);
         mRestrictiveControllers.add(idleController);
 
@@ -2818,6 +2824,129 @@
         return adjustJobBias(bias, job);
     }
 
+    private final class BatteryStateTracker extends BroadcastReceiver {
+        /**
+         * Track whether we're "charging", where charging means that we're ready to commit to
+         * doing work.
+         */
+        private boolean mCharging;
+        /** Keep track of whether the battery is charged enough that we want to do work. */
+        private boolean mBatteryNotLow;
+        /** Sequence number of last broadcast. */
+        private int mLastBatterySeq = -1;
+
+        private BroadcastReceiver mMonitor;
+
+        BatteryStateTracker() {
+        }
+
+        public void startTracking() {
+            IntentFilter filter = new IntentFilter();
+
+            // Battery health.
+            filter.addAction(Intent.ACTION_BATTERY_LOW);
+            filter.addAction(Intent.ACTION_BATTERY_OKAY);
+            // Charging/not charging.
+            filter.addAction(BatteryManager.ACTION_CHARGING);
+            filter.addAction(BatteryManager.ACTION_DISCHARGING);
+            getTestableContext().registerReceiver(this, filter);
+
+            // Initialise tracker state.
+            BatteryManagerInternal batteryManagerInternal =
+                    LocalServices.getService(BatteryManagerInternal.class);
+            mBatteryNotLow = !batteryManagerInternal.getBatteryLevelLow();
+            mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
+        }
+
+        public void setMonitorBatteryLocked(boolean enabled) {
+            if (enabled) {
+                if (mMonitor == null) {
+                    mMonitor = new BroadcastReceiver() {
+                        @Override
+                        public void onReceive(Context context, Intent intent) {
+                            onReceiveInternal(intent);
+                        }
+                    };
+                    IntentFilter filter = new IntentFilter();
+                    filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+                    getTestableContext().registerReceiver(mMonitor, filter);
+                }
+            } else if (mMonitor != null) {
+                getTestableContext().unregisterReceiver(mMonitor);
+                mMonitor = null;
+            }
+        }
+
+        public boolean isCharging() {
+            return mCharging;
+        }
+
+        public boolean isBatteryNotLow() {
+            return mBatteryNotLow;
+        }
+
+        public boolean isMonitoring() {
+            return mMonitor != null;
+        }
+
+        public int getSeq() {
+            return mLastBatterySeq;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            onReceiveInternal(intent);
+        }
+
+        @VisibleForTesting
+        public void onReceiveInternal(Intent intent) {
+            synchronized (mLock) {
+                final String action = intent.getAction();
+                boolean changed = false;
+                if (Intent.ACTION_BATTERY_LOW.equals(action)) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Battery life too low @ " + sElapsedRealtimeClock.millis());
+                    }
+                    if (mBatteryNotLow) {
+                        mBatteryNotLow = false;
+                        changed = true;
+                    }
+                } else if (Intent.ACTION_BATTERY_OKAY.equals(action)) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Battery high enough @ " + sElapsedRealtimeClock.millis());
+                    }
+                    if (!mBatteryNotLow) {
+                        mBatteryNotLow = true;
+                        changed = true;
+                    }
+                } else if (BatteryManager.ACTION_CHARGING.equals(action)) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Battery charging @ " + sElapsedRealtimeClock.millis());
+                    }
+                    if (!mCharging) {
+                        mCharging = true;
+                        changed = true;
+                    }
+                } else if (BatteryManager.ACTION_DISCHARGING.equals(action)) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Disconnected from power @ " + sElapsedRealtimeClock.millis());
+                    }
+                    if (mCharging) {
+                        mCharging = false;
+                        changed = true;
+                    }
+                }
+                mLastBatterySeq =
+                        intent.getIntExtra(BatteryManager.EXTRA_SEQUENCE, mLastBatterySeq);
+                if (changed) {
+                    for (int c = mControllers.size() - 1; c >= 0; --c) {
+                        mControllers.get(c).onBatteryStateChangedLocked();
+                    }
+                }
+            }
+        }
+    }
+
     final class LocalService implements JobSchedulerInternal {
 
         /**
@@ -3417,29 +3546,27 @@
 
     void setMonitorBattery(boolean enabled) {
         synchronized (mLock) {
-            if (mBatteryController != null) {
-                mBatteryController.getTracker().setMonitorBatteryLocked(enabled);
-            }
+            mBatteryStateTracker.setMonitorBatteryLocked(enabled);
         }
     }
 
     int getBatterySeq() {
         synchronized (mLock) {
-            return mBatteryController != null ? mBatteryController.getTracker().getSeq() : -1;
+            return mBatteryStateTracker.getSeq();
         }
     }
 
-    boolean getBatteryCharging() {
+    /** Return {@code true} if the device is currently charging. */
+    public boolean isBatteryCharging() {
         synchronized (mLock) {
-            return mBatteryController != null
-                    ? mBatteryController.getTracker().isOnStablePower() : false;
+            return mBatteryStateTracker.isCharging();
         }
     }
 
-    boolean getBatteryNotLow() {
+    /** Return {@code true} if the battery is not low. */
+    public boolean isBatteryNotLow() {
         synchronized (mLock) {
-            return mBatteryController != null
-                    ? mBatteryController.getTracker().isBatteryNotLow() : false;
+            return mBatteryStateTracker.isBatteryNotLow();
         }
     }
 
@@ -3614,6 +3741,16 @@
             mQuotaTracker.dump(pw);
             pw.println();
 
+            pw.print("Battery charging: ");
+            pw.println(mBatteryStateTracker.isCharging());
+            pw.print("Battery not low: ");
+            pw.println(mBatteryStateTracker.isBatteryNotLow());
+            if (mBatteryStateTracker.isMonitoring()) {
+                pw.print("MONITORING: seq=");
+                pw.println(mBatteryStateTracker.getSeq());
+            }
+            pw.println();
+
             pw.println("Started users: " + Arrays.toString(mStartedUsers));
             pw.print("Registered ");
             pw.print(mJobs.size());
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
index cc20213..27268d2 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -293,13 +293,13 @@
     }
 
     private int getBatteryCharging(PrintWriter pw) {
-        boolean val = mInternal.getBatteryCharging();
+        boolean val = mInternal.isBatteryCharging();
         pw.println(val);
         return 0;
     }
 
     private int getBatteryNotLow(PrintWriter pw) {
-        boolean val = mInternal.getBatteryNotLow();
+        boolean val = mInternal.isBatteryNotLow();
         pw.println(val);
         return 0;
     }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
index 657f470..f733849 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
@@ -18,12 +18,6 @@
 
 import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
 
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.BatteryManager;
-import android.os.BatteryManagerInternal;
 import android.os.UserHandle;
 import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
@@ -31,8 +25,8 @@
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.LocalServices;
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.JobSchedulerBackgroundThread;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.job.StateControllerProto;
 
@@ -49,17 +43,9 @@
             || Log.isLoggable(TAG, Log.DEBUG);
 
     private final ArraySet<JobStatus> mTrackedTasks = new ArraySet<>();
-    private ChargingTracker mChargeTracker;
-
-    @VisibleForTesting
-    public ChargingTracker getTracker() {
-        return mChargeTracker;
-    }
 
     public BatteryController(JobSchedulerService service) {
         super(service);
-        mChargeTracker = new ChargingTracker();
-        mChargeTracker.startTracking();
     }
 
     @Override
@@ -68,9 +54,9 @@
             final long nowElapsed = sElapsedRealtimeClock.millis();
             mTrackedTasks.add(taskStatus);
             taskStatus.setTrackingController(JobStatus.TRACKING_BATTERY);
-            taskStatus.setChargingConstraintSatisfied(nowElapsed, mChargeTracker.isOnStablePower());
-            taskStatus.setBatteryNotLowConstraintSatisfied(
-                    nowElapsed, mChargeTracker.isBatteryNotLow());
+            taskStatus.setChargingConstraintSatisfied(nowElapsed,
+                    mService.isBatteryCharging() && mService.isBatteryNotLow());
+            taskStatus.setBatteryNotLowConstraintSatisfied(nowElapsed, mService.isBatteryNotLow());
         }
     }
 
@@ -93,9 +79,21 @@
         }
     }
 
+    @Override
+    @GuardedBy("mLock")
+    public void onBatteryStateChangedLocked() {
+        // Update job bookkeeping out of band.
+        JobSchedulerBackgroundThread.getHandler().post(() -> {
+            synchronized (mLock) {
+                maybeReportNewChargingStateLocked();
+            }
+        });
+    }
+
+    @GuardedBy("mLock")
     private void maybeReportNewChargingStateLocked() {
-        final boolean stablePower = mChargeTracker.isOnStablePower();
-        final boolean batteryNotLow = mChargeTracker.isBatteryNotLow();
+        final boolean stablePower = mService.isBatteryCharging() && mService.isBatteryNotLow();
+        final boolean batteryNotLow = mService.isBatteryNotLow();
         if (DEBUG) {
             Slog.d(TAG, "maybeReportNewChargingStateLocked: " + stablePower);
         }
@@ -116,133 +114,11 @@
         }
     }
 
-    public final class ChargingTracker extends BroadcastReceiver {
-        /**
-         * Track whether we're "charging", where charging means that we're ready to commit to
-         * doing work.
-         */
-        private boolean mCharging;
-        /** Keep track of whether the battery is charged enough that we want to do work. */
-        private boolean mBatteryHealthy;
-        /** Sequence number of last broadcast. */
-        private int mLastBatterySeq = -1;
-
-        private BroadcastReceiver mMonitor;
-
-        public ChargingTracker() {
-        }
-
-        public void startTracking() {
-            IntentFilter filter = new IntentFilter();
-
-            // Battery health.
-            filter.addAction(Intent.ACTION_BATTERY_LOW);
-            filter.addAction(Intent.ACTION_BATTERY_OKAY);
-            // Charging/not charging.
-            filter.addAction(BatteryManager.ACTION_CHARGING);
-            filter.addAction(BatteryManager.ACTION_DISCHARGING);
-            mContext.registerReceiver(this, filter);
-
-            // Initialise tracker state.
-            BatteryManagerInternal batteryManagerInternal =
-                    LocalServices.getService(BatteryManagerInternal.class);
-            mBatteryHealthy = !batteryManagerInternal.getBatteryLevelLow();
-            mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
-        }
-
-        public void setMonitorBatteryLocked(boolean enabled) {
-            if (enabled) {
-                if (mMonitor == null) {
-                    mMonitor = new BroadcastReceiver() {
-                        @Override public void onReceive(Context context, Intent intent) {
-                            ChargingTracker.this.onReceive(context, intent);
-                        }
-                    };
-                    IntentFilter filter = new IntentFilter();
-                    filter.addAction(Intent.ACTION_BATTERY_CHANGED);
-                    mContext.registerReceiver(mMonitor, filter);
-                }
-            } else {
-                if (mMonitor != null) {
-                    mContext.unregisterReceiver(mMonitor);
-                    mMonitor = null;
-                }
-            }
-        }
-
-        public boolean isOnStablePower() {
-            return mCharging && mBatteryHealthy;
-        }
-
-        public boolean isBatteryNotLow() {
-            return mBatteryHealthy;
-        }
-
-        public boolean isMonitoring() {
-            return mMonitor != null;
-        }
-
-        public int getSeq() {
-            return mLastBatterySeq;
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            onReceiveInternal(intent);
-        }
-
-        @VisibleForTesting
-        public void onReceiveInternal(Intent intent) {
-            synchronized (mLock) {
-                final String action = intent.getAction();
-                if (Intent.ACTION_BATTERY_LOW.equals(action)) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "Battery life too low to do work. @ "
-                                + sElapsedRealtimeClock.millis());
-                    }
-                    // If we get this action, the battery is discharging => it isn't plugged in so
-                    // there's no work to cancel. We track this variable for the case where it is
-                    // charging, but hasn't been for long enough to be healthy.
-                    mBatteryHealthy = false;
-                    maybeReportNewChargingStateLocked();
-                } else if (Intent.ACTION_BATTERY_OKAY.equals(action)) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "Battery life healthy enough to do work. @ "
-                                + sElapsedRealtimeClock.millis());
-                    }
-                    mBatteryHealthy = true;
-                    maybeReportNewChargingStateLocked();
-                } else if (BatteryManager.ACTION_CHARGING.equals(action)) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "Received charging intent, fired @ "
-                                + sElapsedRealtimeClock.millis());
-                    }
-                    mCharging = true;
-                    maybeReportNewChargingStateLocked();
-                } else if (BatteryManager.ACTION_DISCHARGING.equals(action)) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "Disconnected from power.");
-                    }
-                    mCharging = false;
-                    maybeReportNewChargingStateLocked();
-                }
-                mLastBatterySeq = intent.getIntExtra(BatteryManager.EXTRA_SEQUENCE,
-                        mLastBatterySeq);
-            }
-        }
-    }
-
     @Override
     public void dumpControllerStateLocked(IndentingPrintWriter pw,
             Predicate<JobStatus> predicate) {
-        pw.println("Stable power: " + mChargeTracker.isOnStablePower());
-        pw.println("Not low: " + mChargeTracker.isBatteryNotLow());
-
-        if (mChargeTracker.isMonitoring()) {
-            pw.print("MONITORING: seq=");
-            pw.println(mChargeTracker.getSeq());
-        }
-        pw.println();
+        pw.println("Stable power: " + (mService.isBatteryCharging() && mService.isBatteryNotLow()));
+        pw.println("Not low: " + mService.isBatteryNotLow());
 
         for (int i = 0; i < mTrackedTasks.size(); i++) {
             final JobStatus js = mTrackedTasks.valueAt(i);
@@ -264,14 +140,9 @@
         final long mToken = proto.start(StateControllerProto.BATTERY);
 
         proto.write(StateControllerProto.BatteryController.IS_ON_STABLE_POWER,
-                mChargeTracker.isOnStablePower());
+                mService.isBatteryCharging() && mService.isBatteryNotLow());
         proto.write(StateControllerProto.BatteryController.IS_BATTERY_NOT_LOW,
-                mChargeTracker.isBatteryNotLow());
-
-        proto.write(StateControllerProto.BatteryController.IS_MONITORING,
-                mChargeTracker.isMonitoring());
-        proto.write(StateControllerProto.BatteryController.LAST_BROADCAST_SEQUENCE_NUMBER,
-                mChargeTracker.getSeq());
+                mService.isBatteryNotLow());
 
         for (int i = 0; i < mTrackedTasks.size(); i++) {
             final JobStatus js = mTrackedTasks.valueAt(i);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index 524d68f..9fb7ab5 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -25,18 +25,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.job.JobInfo;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkRequest;
-import android.os.BatteryManager;
-import android.os.BatteryManagerInternal;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -55,6 +49,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.JobSchedulerBackgroundThread;
 import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.job.JobSchedulerService.Constants;
@@ -107,8 +102,6 @@
     private final ConnectivityManager mConnManager;
     private final NetworkPolicyManagerInternal mNetPolicyManagerInternal;
 
-    private final ChargingTracker mChargingTracker;
-
     /** List of tracked jobs keyed by source UID. */
     @GuardedBy("mLock")
     private final SparseArray<ArraySet<JobStatus>> mTrackedJobs = new SparseArray<>();
@@ -237,9 +230,6 @@
         // network changes against the active network for each UID with jobs.
         final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
         mConnManager.registerNetworkCallback(request, mNetworkCallback);
-
-        mChargingTracker = new ChargingTracker();
-        mChargingTracker.startTracking();
     }
 
     @GuardedBy("mLock")
@@ -535,6 +525,17 @@
         }
     }
 
+    @Override
+    @GuardedBy("mLock")
+    public void onBatteryStateChangedLocked() {
+        // Update job bookkeeping out of band to avoid blocking broadcast progress.
+        JobSchedulerBackgroundThread.getHandler().post(() -> {
+            synchronized (mLock) {
+                updateTrackedJobsLocked(-1, null);
+            }
+        });
+    }
+
     private boolean isUsable(NetworkCapabilities capabilities) {
         return capabilities != null
                 && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
@@ -591,7 +592,7 @@
         // Minimum chunk size isn't defined. Check using the estimated upload/download sizes.
 
         if (capabilities.hasCapability(NET_CAPABILITY_NOT_METERED)
-                && mChargingTracker.isCharging()) {
+                && mService.isBatteryCharging()) {
             // We're charging and on an unmetered network. We don't have to be as conservative about
             // making sure the job will run within its max execution time. Let's just hope the app
             // supports interruptible work.
@@ -1072,51 +1073,6 @@
         }
     }
 
-    private final class ChargingTracker extends BroadcastReceiver {
-        /**
-         * Track whether we're "charging", where charging means that we're ready to commit to
-         * doing work.
-         */
-        private boolean mCharging;
-
-        ChargingTracker() {}
-
-        public void startTracking() {
-            IntentFilter filter = new IntentFilter();
-            filter.addAction(BatteryManager.ACTION_CHARGING);
-            filter.addAction(BatteryManager.ACTION_DISCHARGING);
-            mContext.registerReceiver(this, filter);
-
-            // Initialise tracker state.
-            final BatteryManagerInternal batteryManagerInternal =
-                    LocalServices.getService(BatteryManagerInternal.class);
-            mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
-        }
-
-        public boolean isCharging() {
-            return mCharging;
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            synchronized (mLock) {
-                final String action = intent.getAction();
-                if (BatteryManager.ACTION_CHARGING.equals(action)) {
-                    if (mCharging) {
-                        return;
-                    }
-                    mCharging = true;
-                } else if (BatteryManager.ACTION_DISCHARGING.equals(action)) {
-                    if (!mCharging) {
-                        return;
-                    }
-                    mCharging = false;
-                }
-                updateTrackedJobsLocked(-1, null);
-            }
-        }
-    }
-
     private final NetworkCallback mNetworkCallback = new NetworkCallback() {
         @Override
         public void onAvailable(Network network) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index c147ef8..65e1d49 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -39,15 +39,11 @@
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManagerInternal;
 import android.app.usage.UsageStatsManagerInternal.UsageEventListener;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.os.BatteryManager;
-import android.os.BatteryManagerInternal;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -319,7 +315,6 @@
     private final SparseLongArray mTopAppGraceCache = new SparseLongArray();
 
     private final AlarmManager mAlarmManager;
-    private final ChargingTracker mChargeTracker;
     private final QcHandler mHandler;
     private final QcConstants mQcConstants;
 
@@ -542,8 +537,6 @@
             @NonNull ConnectivityController connectivityController) {
         super(service);
         mHandler = new QcHandler(mContext.getMainLooper());
-        mChargeTracker = new ChargingTracker();
-        mChargeTracker.startTracking();
         mAlarmManager = mContext.getSystemService(AlarmManager.class);
         mQcConstants = new QcConstants();
         mBackgroundJobsController = backgroundJobsController;
@@ -705,6 +698,11 @@
         mTopAppTrackers.delete(userId);
     }
 
+    @Override
+    public void onBatteryStateChangedLocked() {
+        handleNewChargingStateLocked();
+    }
+
     /** Drop all historical stats and stop tracking any active sessions for the specified app. */
     public void clearAppStatsLocked(int userId, @NonNull String packageName) {
         mTrackedJobs.delete(userId, packageName);
@@ -766,7 +764,7 @@
         if (!jobStatus.shouldTreatAsExpeditedJob()) {
             // If quota is currently "free", then the job can run for the full amount of time,
             // regardless of bucket (hence using charging instead of isQuotaFreeLocked()).
-            if (mChargeTracker.isChargingLocked()
+            if (mService.isBatteryCharging()
                     || mTopAppCache.get(jobStatus.getSourceUid())
                     || isTopStartedJobLocked(jobStatus)
                     || isUidInForeground(jobStatus.getSourceUid())) {
@@ -777,7 +775,7 @@
         }
 
         // Expedited job.
-        if (mChargeTracker.isChargingLocked()) {
+        if (mService.isBatteryCharging()) {
             return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
         }
         if (mTopAppCache.get(jobStatus.getSourceUid()) || isTopStartedJobLocked(jobStatus)) {
@@ -864,7 +862,7 @@
     @GuardedBy("mLock")
     private boolean isQuotaFreeLocked(final int standbyBucket) {
         // Quota constraint is not enforced while charging.
-        if (mChargeTracker.isChargingLocked()) {
+        if (mService.isBatteryCharging()) {
             // Restricted jobs require additional constraints when charging, so don't immediately
             // mark quota as free when charging.
             return standbyBucket != RESTRICTED_INDEX;
@@ -1538,15 +1536,19 @@
 
     private void handleNewChargingStateLocked() {
         mTimerChargingUpdateFunctor.setStatus(sElapsedRealtimeClock.millis(),
-                mChargeTracker.isChargingLocked());
+                mService.isBatteryCharging());
         if (DEBUG) {
-            Slog.d(TAG, "handleNewChargingStateLocked: " + mChargeTracker.isChargingLocked());
+            Slog.d(TAG, "handleNewChargingStateLocked: " + mService.isBatteryCharging());
         }
         // Deal with Timers first.
         mEJPkgTimers.forEach(mTimerChargingUpdateFunctor);
         mPkgTimers.forEach(mTimerChargingUpdateFunctor);
-        // Now update jobs.
-        maybeUpdateAllConstraintsLocked();
+        // Now update jobs out of band so broadcast processing can proceed.
+        JobSchedulerBackgroundThread.getHandler().post(() -> {
+            synchronized (mLock) {
+                maybeUpdateAllConstraintsLocked();
+            }
+        });
     }
 
     private void maybeUpdateAllConstraintsLocked() {
@@ -1811,58 +1813,6 @@
         return false;
     }
 
-    private final class ChargingTracker extends BroadcastReceiver {
-        /**
-         * Track whether we're charging. This has a slightly different definition than that of
-         * BatteryController.
-         */
-        @GuardedBy("mLock")
-        private boolean mCharging;
-
-        ChargingTracker() {
-        }
-
-        public void startTracking() {
-            IntentFilter filter = new IntentFilter();
-
-            // Charging/not charging.
-            filter.addAction(BatteryManager.ACTION_CHARGING);
-            filter.addAction(BatteryManager.ACTION_DISCHARGING);
-            mContext.registerReceiver(this, filter);
-
-            // Initialise tracker state.
-            BatteryManagerInternal batteryManagerInternal =
-                    LocalServices.getService(BatteryManagerInternal.class);
-            mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
-        }
-
-        @GuardedBy("mLock")
-        public boolean isChargingLocked() {
-            return mCharging;
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            synchronized (mLock) {
-                final String action = intent.getAction();
-                if (BatteryManager.ACTION_CHARGING.equals(action)) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "Received charging intent, fired @ "
-                                + sElapsedRealtimeClock.millis());
-                    }
-                    mCharging = true;
-                    handleNewChargingStateLocked();
-                } else if (BatteryManager.ACTION_DISCHARGING.equals(action)) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "Disconnected from power.");
-                    }
-                    mCharging = false;
-                    handleNewChargingStateLocked();
-                }
-            }
-        }
-    }
-
     @VisibleForTesting
     static final class TimingSession {
         // Start timestamp in elapsed realtime timebase.
@@ -2127,6 +2077,12 @@
             final long topAppGracePeriodEndElapsed = mTopAppGraceCache.get(mUid);
             final boolean hasTopAppExemption = !mRegularJobTimer
                     && (mTopAppCache.get(mUid) || nowElapsed < topAppGracePeriodEndElapsed);
+            if (DEBUG) {
+                Slog.d(TAG, "quotaFree=" + isQuotaFreeLocked(standbyBucket)
+                        + " isFG=" + mForegroundUids.get(mUid)
+                        + " tempEx=" + hasTempAllowlistExemption
+                        + " topEx=" + hasTopAppExemption);
+            }
             return !isQuotaFreeLocked(standbyBucket)
                     && !mForegroundUids.get(mUid) && !hasTempAllowlistExemption
                     && !hasTopAppExemption;
@@ -3938,7 +3894,6 @@
     public void dumpControllerStateLocked(final IndentingPrintWriter pw,
             final Predicate<JobStatus> predicate) {
         pw.println("Is enabled: " + mIsEnabled);
-        pw.println("Is charging: " + mChargeTracker.isChargingLocked());
         pw.println("Current elapsed time: " + sElapsedRealtimeClock.millis());
         pw.println();
 
@@ -4116,7 +4071,7 @@
         final long mToken = proto.start(StateControllerProto.QUOTA);
 
         proto.write(StateControllerProto.QuotaController.IS_CHARGING,
-                mChargeTracker.isChargingLocked());
+                mService.isBatteryCharging());
         proto.write(StateControllerProto.QuotaController.ELAPSED_REALTIME,
                 sElapsedRealtimeClock.millis());
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
index 5e73f42..509fb69 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
@@ -133,6 +133,13 @@
     }
 
     /**
+     * Called when the battery status changes.
+     */
+    @GuardedBy("mLock")
+    public void onBatteryStateChangedLocked() {
+    }
+
+    /**
      * Called when a UID's base bias has changed. The more positive the bias, the more
      * important the UID is.
      */
diff --git a/apex/media/OWNERS b/apex/media/OWNERS
index bed3895..2c5965c 100644
--- a/apex/media/OWNERS
+++ b/apex/media/OWNERS
@@ -1,6 +1,5 @@
 # Bug component: 1344
 hdmoon@google.com
-hkuang@google.com
 jinpark@google.com
 klhyun@google.com
 lnilsson@google.com
diff --git a/apex/media/framework/jarjar_rules.txt b/apex/media/framework/jarjar_rules.txt
index 1bd5b36..91489dc 100644
--- a/apex/media/framework/jarjar_rules.txt
+++ b/apex/media/framework/jarjar_rules.txt
@@ -1,4 +1,2 @@
 rule com.android.modules.** android.media.internal.@1
 rule com.google.android.exoplayer2.** android.media.internal.exo.@1
-rule com.google.common.** android.media.internal.guava_common.@1
-rule com.google.thirdparty.** android.media.internal.guava_thirdparty.@1
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index 7daebd0..b6f85c7 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -62,8 +62,8 @@
 import com.google.android.exoplayer2.upstream.DataReader;
 import com.google.android.exoplayer2.util.ParsableByteArray;
 import com.google.android.exoplayer2.util.TimestampAdjuster;
+import com.google.android.exoplayer2.util.Util;
 import com.google.android.exoplayer2.video.ColorInfo;
-import com.google.common.base.Ascii;
 
 import java.io.EOFException;
 import java.io.IOException;
@@ -978,7 +978,7 @@
     @ParserName
     public static List<String> getParserNames(@NonNull MediaFormat mediaFormat) {
         String mimeType = mediaFormat.getString(MediaFormat.KEY_MIME);
-        mimeType = mimeType == null ? null : Ascii.toLowerCase(mimeType);
+        mimeType = mimeType == null ? null : Util.toLowerInvariant(mimeType.trim());
         if (TextUtils.isEmpty(mimeType)) {
             // No MIME type provided. Return all.
             return Collections.unmodifiableList(
@@ -1420,7 +1420,7 @@
         int flags = 0;
         TimestampAdjuster timestampAdjuster = null;
         if (mIgnoreTimestampOffset) {
-            timestampAdjuster = new TimestampAdjuster(TimestampAdjuster.MODE_NO_OFFSET);
+            timestampAdjuster = new TimestampAdjuster(TimestampAdjuster.DO_NOT_OFFSET);
         }
         switch (parserName) {
             case PARSER_NAME_MATROSKA:
diff --git a/core/api/current.txt b/core/api/current.txt
index f38c237..8557e90 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9743,13 +9743,14 @@
     field public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2; // 0x2
     field public static final int ERROR_BLUETOOTH_NOT_ENABLED = 1; // 0x1
     field public static final int ERROR_DEVICE_NOT_BONDED = 3; // 0x3
-    field public static final int ERROR_FEATURE_NOT_SUPPORTED = 10; // 0xa
-    field public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 101; // 0x65
-    field public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 102; // 0x66
+    field public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 200; // 0xc8
+    field public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 201; // 0xc9
     field public static final int ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION = 6; // 0x6
     field public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8; // 0x8
     field public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9; // 0x9
     field public static final int ERROR_UNKNOWN = 2147483647; // 0x7fffffff
+    field public static final int FEATURE_NOT_SUPPORTED = 11; // 0xb
+    field public static final int FEATURE_SUPPORTED = 10; // 0xa
     field public static final int SUCCESS = 0; // 0x0
   }
 
@@ -10876,6 +10877,8 @@
     method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void removeStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
     method public abstract void revokeUriPermission(android.net.Uri, int);
     method public abstract void revokeUriPermission(String, android.net.Uri, int);
+    method public void selfRevokePermission(@NonNull String);
+    method public void selfRevokePermissions(@NonNull java.util.Collection<java.lang.String>);
     method public abstract void sendBroadcast(@RequiresPermission android.content.Intent);
     method public abstract void sendBroadcast(@RequiresPermission android.content.Intent, @Nullable String);
     method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
@@ -12762,11 +12765,16 @@
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionInfo> CREATOR;
     field public static final int INVALID_ID = -1; // 0xffffffff
-    field public static final int STAGED_SESSION_ACTIVATION_FAILED = 2; // 0x2
-    field public static final int STAGED_SESSION_CONFLICT = 4; // 0x4
-    field public static final int STAGED_SESSION_NO_ERROR = 0; // 0x0
-    field public static final int STAGED_SESSION_UNKNOWN = 3; // 0x3
-    field public static final int STAGED_SESSION_VERIFICATION_FAILED = 1; // 0x1
+    field public static final int SESSION_ACTIVATION_FAILED = 2; // 0x2
+    field public static final int SESSION_CONFLICT = 4; // 0x4
+    field public static final int SESSION_NO_ERROR = 0; // 0x0
+    field public static final int SESSION_UNKNOWN_ERROR = 3; // 0x3
+    field public static final int SESSION_VERIFICATION_FAILED = 1; // 0x1
+    field @Deprecated public static final int STAGED_SESSION_ACTIVATION_FAILED = 2; // 0x2
+    field @Deprecated public static final int STAGED_SESSION_CONFLICT = 4; // 0x4
+    field @Deprecated public static final int STAGED_SESSION_NO_ERROR = 0; // 0x0
+    field @Deprecated public static final int STAGED_SESSION_UNKNOWN = 3; // 0x3
+    field @Deprecated public static final int STAGED_SESSION_VERIFICATION_FAILED = 1; // 0x1
   }
 
   public static class PackageInstaller.SessionParams implements android.os.Parcelable {
@@ -15978,6 +15986,8 @@
     method public String getFontFeatureSettings();
     method public float getFontMetrics(android.graphics.Paint.FontMetrics);
     method public android.graphics.Paint.FontMetrics getFontMetrics();
+    method public void getFontMetricsInt(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, boolean, @NonNull android.graphics.Paint.FontMetricsInt);
+    method public void getFontMetricsInt(@NonNull char[], @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, boolean, @NonNull android.graphics.Paint.FontMetricsInt);
     method public int getFontMetricsInt(android.graphics.Paint.FontMetricsInt);
     method public android.graphics.Paint.FontMetricsInt getFontMetricsInt();
     method public float getFontSpacing();
@@ -21892,16 +21902,29 @@
     method public android.media.Image acquireNextImage();
     method public void close();
     method public void discardFreeBuffers();
+    method public long getDataSpace();
+    method public int getHardwareBufferFormat();
     method public int getHeight();
     method public int getImageFormat();
     method public int getMaxImages();
     method public android.view.Surface getSurface();
+    method public long getUsage();
     method public int getWidth();
     method @NonNull public static android.media.ImageReader newInstance(@IntRange(from=1) int, @IntRange(from=1) int, int, @IntRange(from=1) int);
     method @NonNull public static android.media.ImageReader newInstance(@IntRange(from=1) int, @IntRange(from=1) int, int, @IntRange(from=1) int, long);
     method public void setOnImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler);
   }
 
+  public static final class ImageReader.Builder {
+    ctor public ImageReader.Builder(@IntRange(from=1) int, @IntRange(from=1) int);
+    method @NonNull public android.media.ImageReader build();
+    method @NonNull public android.media.ImageReader.Builder setDefaultDataSpace(long);
+    method @NonNull public android.media.ImageReader.Builder setDefaultHardwareBufferFormat(int);
+    method @NonNull public android.media.ImageReader.Builder setImageFormat(int);
+    method @NonNull public android.media.ImageReader.Builder setMaxImages(int);
+    method @NonNull public android.media.ImageReader.Builder setUsage(long);
+  }
+
   public static interface ImageReader.OnImageAvailableListener {
     method public void onImageAvailable(android.media.ImageReader);
   }
@@ -27362,11 +27385,13 @@
     method @NonNull public android.net.VpnService.Builder addDnsServer(@NonNull java.net.InetAddress);
     method @NonNull public android.net.VpnService.Builder addDnsServer(@NonNull String);
     method @NonNull public android.net.VpnService.Builder addRoute(@NonNull java.net.InetAddress, int);
+    method @NonNull public android.net.VpnService.Builder addRoute(@NonNull android.net.IpPrefix);
     method @NonNull public android.net.VpnService.Builder addRoute(@NonNull String, int);
     method @NonNull public android.net.VpnService.Builder addSearchDomain(@NonNull String);
     method @NonNull public android.net.VpnService.Builder allowBypass();
     method @NonNull public android.net.VpnService.Builder allowFamily(int);
     method @Nullable public android.os.ParcelFileDescriptor establish();
+    method @NonNull public android.net.VpnService.Builder excludeRoute(@NonNull android.net.IpPrefix);
     method @NonNull public android.net.VpnService.Builder setBlocking(boolean);
     method @NonNull public android.net.VpnService.Builder setConfigureIntent(@NonNull android.app.PendingIntent);
     method @NonNull public android.net.VpnService.Builder setHttpProxy(@NonNull android.net.ProxyInfo);
@@ -44936,6 +44961,7 @@
   public class BoringLayout extends android.text.Layout implements android.text.TextUtils.EllipsizeCallback {
     ctor public BoringLayout(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean);
     ctor public BoringLayout(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean, android.text.TextUtils.TruncateAt, int);
+    ctor public BoringLayout(@NonNull CharSequence, @NonNull android.text.TextPaint, @IntRange(from=0) int, @NonNull android.text.Layout.Alignment, float, float, @NonNull android.text.BoringLayout.Metrics, boolean, @NonNull android.text.TextUtils.TruncateAt, @IntRange(from=0) int, boolean);
     method public void ellipsized(int, int);
     method public int getBottomPadding();
     method public int getEllipsisCount(int);
@@ -44950,9 +44976,12 @@
     method public int getTopPadding();
     method public static android.text.BoringLayout.Metrics isBoring(CharSequence, android.text.TextPaint);
     method public static android.text.BoringLayout.Metrics isBoring(CharSequence, android.text.TextPaint, android.text.BoringLayout.Metrics);
+    method @Nullable public static android.text.BoringLayout.Metrics isBoring(@NonNull CharSequence, @NonNull android.text.TextPaint, @NonNull android.text.TextDirectionHeuristic, boolean, @Nullable android.text.BoringLayout.Metrics);
     method public static android.text.BoringLayout make(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean);
     method public static android.text.BoringLayout make(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean, android.text.TextUtils.TruncateAt, int);
+    method @NonNull public static android.text.BoringLayout make(@NonNull CharSequence, @NonNull android.text.TextPaint, @IntRange(from=0) int, @NonNull android.text.Layout.Alignment, @NonNull android.text.BoringLayout.Metrics, boolean, @NonNull android.text.TextUtils.TruncateAt, @IntRange(from=0) int, boolean);
     method public android.text.BoringLayout replaceOrMake(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean);
+    method @NonNull public android.text.BoringLayout replaceOrMake(@NonNull CharSequence, @NonNull android.text.TextPaint, @IntRange(from=0) int, @NonNull android.text.Layout.Alignment, @NonNull android.text.BoringLayout.Metrics, boolean, @NonNull android.text.TextUtils.TruncateAt, @IntRange(from=0) int, boolean);
     method public android.text.BoringLayout replaceOrMake(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean, android.text.TextUtils.TruncateAt, int);
   }
 
@@ -45161,6 +45190,7 @@
     method public abstract int getTopPadding();
     method public final int getWidth();
     method public final void increaseWidthTo(int);
+    method public boolean isFallbackLineSpacingEnabled();
     method public boolean isRtlCharAt(int);
     method protected final boolean isSpanned();
     field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 53bc8a6..4d84537 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -88,6 +88,14 @@
     field public static final String TEST_NETWORK_SERVICE = "test_network";
   }
 
+  public class Intent implements java.lang.Cloneable android.os.Parcelable {
+    field public static final String ACTION_SETTING_RESTORED = "android.os.action.SETTING_RESTORED";
+    field public static final String EXTRA_SETTING_NAME = "setting_name";
+    field public static final String EXTRA_SETTING_NEW_VALUE = "new_value";
+    field public static final String EXTRA_SETTING_PREVIOUS_VALUE = "previous_value";
+    field public static final String EXTRA_SETTING_RESTORED_FROM_SDK_INT = "restored_from_sdk_int";
+  }
+
 }
 
 package android.content.pm {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 1794c131..3a7077d 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1047,6 +1047,7 @@
     field @Deprecated public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL";
     field public static final String EXTRA_PROVISIONING_ORGANIZATION_NAME = "android.app.extra.PROVISIONING_ORGANIZATION_NAME";
     field public static final String EXTRA_PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE = "android.app.extra.PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE";
+    field public static final String EXTRA_PROVISIONING_ROLE_HOLDER_CUSTOM_USER_CONSENT_INTENT = "android.app.extra.PROVISIONING_ROLE_HOLDER_CUSTOM_USER_CONSENT_INTENT";
     field public static final String EXTRA_PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER = "android.app.extra.PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER";
     field public static final String EXTRA_PROVISIONING_SUPPORTED_MODES = "android.app.extra.PROVISIONING_SUPPORTED_MODES";
     field public static final String EXTRA_PROVISIONING_SUPPORT_URL = "android.app.extra.PROVISIONING_SUPPORT_URL";
@@ -2220,9 +2221,12 @@
 
   public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean connect(android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int connectAudio();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnect(android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int disconnectAudio();
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getAudioState(@NonNull android.bluetooth.BluetoothDevice);
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInbandRingingEnabled();
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean isInbandRingingEnabled();
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean startScoUsingVirtualVoiceCall();
     method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean stopScoUsingVirtualVoiceCall();
@@ -2301,6 +2305,14 @@
 
   public final class BluetoothStatusCodes {
     field public static final int ERROR_ANOTHER_ACTIVE_OOB_REQUEST = 1000; // 0x3e8
+    field public static final int ERROR_AUDIO_DEVICE_ALREADY_CONNECTED = 1116; // 0x45c
+    field public static final int ERROR_AUDIO_DEVICE_ALREADY_DISCONNECTED = 1117; // 0x45d
+    field public static final int ERROR_AUDIO_ROUTE_BLOCKED = 1118; // 0x45e
+    field public static final int ERROR_CALL_ACTIVE = 1119; // 0x45f
+    field public static final int ERROR_NOT_ACTIVE_DEVICE = 12; // 0xc
+    field public static final int ERROR_NO_ACTIVE_DEVICES = 13; // 0xd
+    field public static final int ERROR_PROFILE_NOT_CONNECTED = 14; // 0xe
+    field public static final int ERROR_TIMEOUT = 15; // 0xf
   }
 
   public final class BluetoothUuid {
@@ -6337,6 +6349,7 @@
     method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean captureFrame(String, android.view.Surface, android.media.tv.TvStreamConfig);
     method @NonNull public java.util.List<java.lang.String> getAvailableExtensionInterfaceNames(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(String);
+    method public int getClientPriority(int, @Nullable String);
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TUNED_INFO) public java.util.List<android.media.tv.TunedInfo> getCurrentTunedInfos();
     method @NonNull @RequiresPermission("android.permission.DVB_DEVICE") public java.util.List<android.media.tv.DvbDeviceInfo> getDvbDeviceList();
     method @Nullable public android.os.IBinder getExtensionInterface(@NonNull String, @NonNull String);
@@ -6456,7 +6469,9 @@
   }
 
   public class Lnb implements java.lang.AutoCloseable {
+    method public void addCallback(@NonNull android.media.tv.tuner.LnbCallback, @NonNull java.util.concurrent.Executor);
     method public void close();
+    method public boolean removeCallback(@NonNull android.media.tv.tuner.LnbCallback);
     method public int sendDiseqcMessage(@NonNull byte[]);
     method public int setSatellitePosition(int);
     method public int setTone(int);
@@ -6493,6 +6508,7 @@
     method public void clearOnTuneEventListener();
     method public void clearResourceLostListener();
     method public void close();
+    method public void closeFrontend();
     method public int connectCiCam(int);
     method public int connectFrontendToCiCam(int);
     method public int disconnectCiCam();
@@ -6521,6 +6537,7 @@
     method public void setOnTuneEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.OnTuneEventListener);
     method public void setResourceLostListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.Tuner.OnResourceLostListener);
     method public void shareFrontendFromTuner(@NonNull android.media.tv.tuner.Tuner);
+    method public int transferOwner(@NonNull android.media.tv.tuner.Tuner);
     method public int tune(@NonNull android.media.tv.tuner.frontend.FrontendSettings);
     method @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public void updateResourcePriority(int, int);
     field public static final int INVALID_AV_SYNC_ID = -1; // 0xffffffff
@@ -9603,6 +9620,7 @@
     method @Deprecated @BinderThread public void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
     method @BinderThread public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String, @NonNull Runnable);
     method @BinderThread public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.util.List<java.lang.String>>>);
+    method @BinderThread public void onSelfRevokePermissions(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable);
     method @Deprecated @BinderThread public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @BinderThread public void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull android.permission.AdminPermissionControlParams, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @BinderThread public void onStageAndApplyRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
@@ -10818,7 +10836,7 @@
 
   public class GameService extends android.app.Service {
     ctor public GameService();
-    method @Nullable public android.os.IBinder onBind(@Nullable android.content.Intent);
+    method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
     method public void onConnected();
     method public void onDisconnected();
     field public static final String ACTION_GAME_SERVICE = "android.service.games.action.GAME_SERVICE";
@@ -10833,7 +10851,7 @@
 
   public abstract class GameSessionService extends android.app.Service {
     ctor public GameSessionService();
-    method @Nullable public android.os.IBinder onBind(@Nullable android.content.Intent);
+    method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
     method @NonNull public abstract android.service.games.GameSession onNewSession(@NonNull android.service.games.CreateGameSessionRequest);
     field public static final String ACTION_GAME_SESSION_SERVICE = "android.service.games.action.GAME_SESSION_SERVICE";
   }
diff --git a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
index 8e01779..3c9b232 100644
--- a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
+++ b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
@@ -172,7 +172,7 @@
     private AccessibilityGestureEvent(@NonNull Parcel parcel) {
         mGestureId = parcel.readInt();
         mDisplayId = parcel.readInt();
-        ParceledListSlice<MotionEvent> slice = parcel.readParcelable(getClass().getClassLoader(), android.content.pm.ParceledListSlice.class);
+        ParceledListSlice<MotionEvent> slice = parcel.readParcelable(getClass().getClassLoader());
         mMotionEvents = slice.getList();
     }
 
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 1167d0b..04c784e 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -1094,8 +1094,8 @@
         mInteractiveUiTimeout = parcel.readInt();
         flags = parcel.readInt();
         crashed = parcel.readInt() != 0;
-        mComponentName = parcel.readParcelable(this.getClass().getClassLoader(), android.content.ComponentName.class);
-        mResolveInfo = parcel.readParcelable(null, android.content.pm.ResolveInfo.class);
+        mComponentName = parcel.readParcelable(this.getClass().getClassLoader());
+        mResolveInfo = parcel.readParcelable(null);
         mSettingsActivityName = parcel.readString();
         mCapabilities = parcel.readInt();
         mSummaryResId = parcel.readInt();
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index a140983..9f8d246 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1903,7 +1903,7 @@
         public void readFromParcel(Parcel source) {
             id = source.readInt();
             persistentId = source.readInt();
-            childrenTaskInfos = source.readArrayList(RecentTaskInfo.class.getClassLoader(), android.app.ActivityManager.RecentTaskInfo.class);
+            childrenTaskInfos = source.readArrayList(RecentTaskInfo.class.getClassLoader());
             lastSnapshotData.taskSize = source.readTypedObject(Point.CREATOR);
             lastSnapshotData.contentInsets = source.readTypedObject(Rect.CREATOR);
             lastSnapshotData.bufferSize = source.readTypedObject(Point.CREATOR);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 68c69e5..565f690 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -4058,7 +4058,7 @@
                 LongSparseArray<NoteOpEvent> array = new LongSparseArray<>(numEntries);
 
                 for (int i = 0; i < numEntries; i++) {
-                    array.put(source.readLong(), source.readParcelable(null, android.app.AppOpsManager.NoteOpEvent.class));
+                    array.put(source.readLong(), source.readParcelable(null));
                 }
 
                 return array;
@@ -5178,7 +5178,7 @@
             final int[] uids = parcel.createIntArray();
             if (!ArrayUtils.isEmpty(uids)) {
                 final ParceledListSlice<HistoricalUidOps> listSlice = parcel.readParcelable(
-                        HistoricalOps.class.getClassLoader(), android.content.pm.ParceledListSlice.class);
+                        HistoricalOps.class.getClassLoader());
                 final List<HistoricalUidOps> uidOps = (listSlice != null)
                         ? listSlice.getList() : null;
                 if (uidOps == null) {
@@ -10000,7 +10000,7 @@
 
     private static @Nullable List<AttributedOpEntry> readDiscreteAccessArrayFromParcel(
             @NonNull Parcel parcel) {
-        final ParceledListSlice<AttributedOpEntry> listSlice = parcel.readParcelable(null, android.content.pm.ParceledListSlice.class);
+        final ParceledListSlice<AttributedOpEntry> listSlice = parcel.readParcelable(null);
         return listSlice == null ? null : listSlice.getList();
     }
 
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index c0aebee..7a806bd 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -118,11 +118,11 @@
             name = source.readString();
         }
         interruptionFilter = source.readInt();
-        conditionId = source.readParcelable(null, android.net.Uri.class);
-        owner = source.readParcelable(null, android.content.ComponentName.class);
-        configurationActivity = source.readParcelable(null, android.content.ComponentName.class);
+        conditionId = source.readParcelable(null);
+        owner = source.readParcelable(null);
+        configurationActivity = source.readParcelable(null);
         creationTime = source.readLong();
-        mZenPolicy = source.readParcelable(null, android.service.notification.ZenPolicy.class);
+        mZenPolicy = source.readParcelable(null);
         mModified = source.readInt() == ENABLED;
         mPkg = source.readString();
     }
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 0bb6ffa..7812aba 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -430,8 +430,8 @@
      * permissions set by {@link #setRequireAllOfPermissions(String[])}, and none of the
      * permissions set by {@link #setRequireNoneOfPermissions(String[])} to get the broadcast.
      *
-     * @param requiredPermissions a list of Strings of permission the receiver must have, or null
-     *                            to clear any previously set value.
+     * @param requiredPermissions a list of Strings of permission the receiver must have. Set to
+     *                            null or an empty array to clear any previously set value.
      * @hide
      */
     @SystemApi
@@ -449,8 +449,8 @@
      * permissions set by {@link #setRequireAllOfPermissions(String[])}, and none of the
      * permissions set by {@link #setRequireNoneOfPermissions(String[])} to get the broadcast.
      *
-     * @param excludedPermissions a list of Strings of permission the receiver must not have,
-     *                            or null to clear any previously set value.
+     * @param excludedPermissions a list of Strings of permission the receiver must not have. Set to
+     *                            null or an empty array to clear any previously set value.
      * @hide
      */
     @SystemApi
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f3e9f10..fe512ff 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -113,6 +113,7 @@
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -2170,6 +2171,11 @@
     }
 
     @Override
+    public void selfRevokePermissions(@NonNull Collection<String> permissions) {
+        getSystemService(PermissionManager.class).selfRevokePermissions(permissions);
+    }
+
+    @Override
     public int checkCallingPermission(String permission) {
         if (permission == null) {
             throw new IllegalArgumentException("permission is null");
diff --git a/core/java/android/app/GrantedUriPermission.java b/core/java/android/app/GrantedUriPermission.java
index a71cb4a..48d5b8c 100644
--- a/core/java/android/app/GrantedUriPermission.java
+++ b/core/java/android/app/GrantedUriPermission.java
@@ -68,7 +68,7 @@
             };
 
     private GrantedUriPermission(Parcel in) {
-        uri = in.readParcelable(null, android.net.Uri.class);
+        uri = in.readParcelable(null);
         packageName = in.readString();
     }
 }
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index f97415c..cd6df0b 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -100,7 +100,7 @@
         } else {
             mDescription = null;
         }
-        in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader(), android.app.NotificationChannel.class);
+        in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader());
         mBlocked = in.readBoolean();
         mUserLockedFields = in.readInt();
     }
diff --git a/core/java/android/app/RemoteInputHistoryItem.java b/core/java/android/app/RemoteInputHistoryItem.java
index 32f8981..091db3f 100644
--- a/core/java/android/app/RemoteInputHistoryItem.java
+++ b/core/java/android/app/RemoteInputHistoryItem.java
@@ -48,7 +48,7 @@
     protected RemoteInputHistoryItem(Parcel in) {
         mText = in.readCharSequence();
         mMimeType = in.readStringNoHelper();
-        mUri = in.readParcelable(Uri.class.getClassLoader(), android.net.Uri.class);
+        mUri = in.readParcelable(Uri.class.getClassLoader());
     }
 
     public static final Creator<RemoteInputHistoryItem> CREATOR =
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 7969cda..73ebdf6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2885,6 +2885,38 @@
     public static final int RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR = 2;
 
     /**
+     * An {@link Intent} extra which resolves to a custom user consent screen.
+     *
+     * <p>If this extra is provided to the device management role holder via either {@link
+     * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} or {@link
+     * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_PROFILE}, the device management role holder must
+     * launch this intent which shows the custom user consent screen, replacing its own standard
+     * consent screen.
+     *
+     * <p>If this extra is provided, it is the responsibility of the intent handler to show the
+     * list of disclaimers which are normally shown by the standard consent screen:
+     * <ul>
+     *     <li>Disclaimers set by the IT admin via the {@link #EXTRA_PROVISIONING_DISCLAIMERS}
+     *     provisioning extra</li>
+     *     <li>For fully-managed device provisioning, disclaimers defined in system apps via the
+     *     {@link #EXTRA_PROVISIONING_DISCLAIMER_HEADER} and {@link
+     *     #EXTRA_PROVISIONING_DISCLAIMER_CONTENT} metadata in their manifests</li>
+     *     <li>General disclaimer relevant to the provisioning mode</li>
+     * </ul>
+     *
+     * <p>If the custom consent screens are granted by the user {@link Activity#RESULT_OK} is
+     * returned, otherwise {@link Activity#RESULT_CANCELED} is returned. The device management
+     * role holder should ensure that the provisioning flow terminates immediately if consent
+     * is not granted by the user.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    @SystemApi
+    public static final String EXTRA_PROVISIONING_ROLE_HOLDER_CUSTOM_USER_CONSENT_INTENT =
+            "android.app.extra.PROVISIONING_ROLE_HOLDER_CUSTOM_USER_CONSENT_INTENT";
+
+    /**
      * Maximum supported password length. Kind-of arbitrary.
      * @hide
      */
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 6e49e95..e1f6af0 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -815,13 +815,13 @@
                     mAutofillHints = in.readStringArray();
                 }
                 if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_VALUE) != 0) {
-                    mAutofillValue = in.readParcelable(null, android.view.autofill.AutofillValue.class);
+                    mAutofillValue = in.readParcelable(null);
                 }
                 if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_OPTIONS) != 0) {
                     mAutofillOptions = in.readCharSequenceArray();
                 }
                 if ((autofillFlags & AUTOFILL_FLAGS_HAS_HTML_INFO) != 0) {
-                    mHtmlInfo = in.readParcelable(null, android.view.ViewStructure.HtmlInfo.class);
+                    mHtmlInfo = in.readParcelable(null);
                 }
                 if ((autofillFlags & AUTOFILL_FLAGS_HAS_MIN_TEXT_EMS) != 0) {
                     mMinEms = in.readInt();
@@ -886,7 +886,7 @@
                 mWebDomain = in.readString();
             }
             if ((flags&FLAGS_HAS_LOCALE_LIST) != 0) {
-                mLocaleList = in.readParcelable(null, android.os.LocaleList.class);
+                mLocaleList = in.readParcelable(null);
             }
             if ((flags & FLAGS_HAS_MIME_TYPES) != 0) {
                 mReceiveContentMimeTypes = in.readStringArray();
diff --git a/core/java/android/app/people/ConversationChannel.java b/core/java/android/app/people/ConversationChannel.java
index ab350f2..2bf71b0 100644
--- a/core/java/android/app/people/ConversationChannel.java
+++ b/core/java/android/app/people/ConversationChannel.java
@@ -83,16 +83,16 @@
     }
 
     public ConversationChannel(Parcel in) {
-        mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader(), android.content.pm.ShortcutInfo.class);
+        mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader());
         mUid = in.readInt();
-        mNotificationChannel = in.readParcelable(NotificationChannel.class.getClassLoader(), android.app.NotificationChannel.class);
+        mNotificationChannel = in.readParcelable(NotificationChannel.class.getClassLoader());
         mNotificationChannelGroup =
-                in.readParcelable(NotificationChannelGroup.class.getClassLoader(), android.app.NotificationChannelGroup.class);
+                in.readParcelable(NotificationChannelGroup.class.getClassLoader());
         mLastEventTimestamp = in.readLong();
         mHasActiveNotifications = in.readBoolean();
         mHasBirthdayToday = in.readBoolean();
         mStatuses = new ArrayList<>();
-        in.readParcelableList(mStatuses, ConversationStatus.class.getClassLoader(), android.app.people.ConversationStatus.class);
+        in.readParcelableList(mStatuses, ConversationStatus.class.getClassLoader());
     }
 
     @Override
diff --git a/core/java/android/app/people/ConversationStatus.java b/core/java/android/app/people/ConversationStatus.java
index a7b61b3..8038158 100644
--- a/core/java/android/app/people/ConversationStatus.java
+++ b/core/java/android/app/people/ConversationStatus.java
@@ -126,7 +126,7 @@
         mActivity = p.readInt();
         mAvailability = p.readInt();
         mDescription = p.readCharSequence();
-        mIcon = p.readParcelable(Icon.class.getClassLoader(), android.graphics.drawable.Icon.class);
+        mIcon = p.readParcelable(Icon.class.getClassLoader());
         mStartTimeMs = p.readLong();
         mEndTimeMs = p.readLong();
     }
diff --git a/core/java/android/app/people/PeopleSpaceTile.java b/core/java/android/app/people/PeopleSpaceTile.java
index 4337111..e11861f 100644
--- a/core/java/android/app/people/PeopleSpaceTile.java
+++ b/core/java/android/app/people/PeopleSpaceTile.java
@@ -472,9 +472,9 @@
     public PeopleSpaceTile(Parcel in) {
         mId = in.readString();
         mUserName = in.readCharSequence();
-        mUserIcon = in.readParcelable(Icon.class.getClassLoader(), android.graphics.drawable.Icon.class);
-        mContactUri = in.readParcelable(Uri.class.getClassLoader(), android.net.Uri.class);
-        mUserHandle = in.readParcelable(UserHandle.class.getClassLoader(), android.os.UserHandle.class);
+        mUserIcon = in.readParcelable(Icon.class.getClassLoader());
+        mContactUri = in.readParcelable(Uri.class.getClassLoader());
+        mUserHandle = in.readParcelable(UserHandle.class.getClassLoader());
         mPackageName = in.readString();
         mBirthdayText = in.readString();
         mLastInteractionTimestamp = in.readLong();
@@ -483,12 +483,12 @@
         mNotificationContent = in.readCharSequence();
         mNotificationSender = in.readCharSequence();
         mNotificationCategory = in.readString();
-        mNotificationDataUri = in.readParcelable(Uri.class.getClassLoader(), android.net.Uri.class);
+        mNotificationDataUri = in.readParcelable(Uri.class.getClassLoader());
         mMessagesCount = in.readInt();
-        mIntent = in.readParcelable(Intent.class.getClassLoader(), android.content.Intent.class);
+        mIntent = in.readParcelable(Intent.class.getClassLoader());
         mNotificationTimestamp = in.readLong();
         mStatuses = new ArrayList<>();
-        in.readParcelableList(mStatuses, ConversationStatus.class.getClassLoader(), android.app.people.ConversationStatus.class);
+        in.readParcelableList(mStatuses, ConversationStatus.class.getClassLoader());
         mCanBypassDnd = in.readBoolean();
         mIsPackageSuspended = in.readBoolean();
         mIsUserQuieted = in.readBoolean();
diff --git a/core/java/android/app/prediction/AppTargetEvent.java b/core/java/android/app/prediction/AppTargetEvent.java
index 51e3953..963e750 100644
--- a/core/java/android/app/prediction/AppTargetEvent.java
+++ b/core/java/android/app/prediction/AppTargetEvent.java
@@ -72,7 +72,7 @@
     }
 
     private AppTargetEvent(Parcel parcel) {
-        mTarget = parcel.readParcelable(null, android.app.prediction.AppTarget.class);
+        mTarget = parcel.readParcelable(null);
         mLocation = parcel.readString();
         mAction = parcel.readInt();
     }
diff --git a/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java
index 30a6c31..fbb37db 100644
--- a/core/java/android/app/servertransaction/ClientTransaction.java
+++ b/core/java/android/app/servertransaction/ClientTransaction.java
@@ -197,11 +197,11 @@
         if (readActivityToken) {
             mActivityToken = in.readStrongBinder();
         }
-        mLifecycleStateRequest = in.readParcelable(getClass().getClassLoader(), android.app.servertransaction.ActivityLifecycleItem.class);
+        mLifecycleStateRequest = in.readParcelable(getClass().getClassLoader());
         final boolean readActivityCallbacks = in.readBoolean();
         if (readActivityCallbacks) {
             mActivityCallbacks = new ArrayList<>();
-            in.readParcelableList(mActivityCallbacks, getClass().getClassLoader(), android.app.servertransaction.ClientTransactionItem.class);
+            in.readParcelableList(mActivityCallbacks, getClass().getClassLoader());
         }
     }
 
diff --git a/core/java/android/app/smartspace/SmartspaceTargetEvent.java b/core/java/android/app/smartspace/SmartspaceTargetEvent.java
index 89caab7..61f8723 100644
--- a/core/java/android/app/smartspace/SmartspaceTargetEvent.java
+++ b/core/java/android/app/smartspace/SmartspaceTargetEvent.java
@@ -96,7 +96,7 @@
     }
 
     private SmartspaceTargetEvent(Parcel parcel) {
-        mSmartspaceTarget = parcel.readParcelable(null, android.app.smartspace.SmartspaceTarget.class);
+        mSmartspaceTarget = parcel.readParcelable(null);
         mSmartspaceActionId = parcel.readString();
         mEventType = parcel.readInt();
     }
diff --git a/core/java/android/app/time/ExternalTimeSuggestion.java b/core/java/android/app/time/ExternalTimeSuggestion.java
index 0f98b44..8e281c0 100644
--- a/core/java/android/app/time/ExternalTimeSuggestion.java
+++ b/core/java/android/app/time/ExternalTimeSuggestion.java
@@ -101,11 +101,11 @@
     }
 
     private static ExternalTimeSuggestion createFromParcel(Parcel in) {
-        TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */, android.os.TimestampedValue.class);
+        TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
         ExternalTimeSuggestion suggestion =
                 new ExternalTimeSuggestion(utcTime.getReferenceTimeMillis(), utcTime.getValue());
         @SuppressWarnings("unchecked")
-        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */, java.lang.String.class);
+        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
         suggestion.mDebugInfo = debugInfo;
         return suggestion;
     }
diff --git a/core/java/android/app/time/TimeCapabilitiesAndConfig.java b/core/java/android/app/time/TimeCapabilitiesAndConfig.java
index 71fce14..4a10447 100644
--- a/core/java/android/app/time/TimeCapabilitiesAndConfig.java
+++ b/core/java/android/app/time/TimeCapabilitiesAndConfig.java
@@ -59,8 +59,8 @@
 
     @NonNull
     private static TimeCapabilitiesAndConfig readFromParcel(Parcel in) {
-        TimeCapabilities capabilities = in.readParcelable(null, android.app.time.TimeCapabilities.class);
-        TimeConfiguration configuration = in.readParcelable(null, android.app.time.TimeConfiguration.class);
+        TimeCapabilities capabilities = in.readParcelable(null);
+        TimeConfiguration configuration = in.readParcelable(null);
         return new TimeCapabilitiesAndConfig(capabilities, configuration);
     }
 
diff --git a/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java b/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java
index cd91b04..a9ea76f 100644
--- a/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java
+++ b/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java
@@ -61,8 +61,8 @@
 
     @NonNull
     private static TimeZoneCapabilitiesAndConfig createFromParcel(Parcel in) {
-        TimeZoneCapabilities capabilities = in.readParcelable(null, android.app.time.TimeZoneCapabilities.class);
-        TimeZoneConfiguration configuration = in.readParcelable(null, android.app.time.TimeZoneConfiguration.class);
+        TimeZoneCapabilities capabilities = in.readParcelable(null);
+        TimeZoneConfiguration configuration = in.readParcelable(null);
         return new TimeZoneCapabilitiesAndConfig(capabilities, configuration);
     }
 
diff --git a/core/java/android/app/timedetector/GnssTimeSuggestion.java b/core/java/android/app/timedetector/GnssTimeSuggestion.java
index 8ccff62..6478a2d 100644
--- a/core/java/android/app/timedetector/GnssTimeSuggestion.java
+++ b/core/java/android/app/timedetector/GnssTimeSuggestion.java
@@ -66,10 +66,10 @@
     }
 
     private static GnssTimeSuggestion createFromParcel(Parcel in) {
-        TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */, android.os.TimestampedValue.class);
+        TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
         GnssTimeSuggestion suggestion = new GnssTimeSuggestion(utcTime);
         @SuppressWarnings("unchecked")
-        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */, java.lang.String.class);
+        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
         suggestion.mDebugInfo = debugInfo;
         return suggestion;
     }
diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java
index 1699a5f..299e951 100644
--- a/core/java/android/app/timedetector/ManualTimeSuggestion.java
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java
@@ -66,10 +66,10 @@
     }
 
     private static ManualTimeSuggestion createFromParcel(Parcel in) {
-        TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */, android.os.TimestampedValue.class);
+        TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
         ManualTimeSuggestion suggestion = new ManualTimeSuggestion(utcTime);
         @SuppressWarnings("unchecked")
-        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */, java.lang.String.class);
+        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
         suggestion.mDebugInfo = debugInfo;
         return suggestion;
     }
diff --git a/core/java/android/app/timedetector/NetworkTimeSuggestion.java b/core/java/android/app/timedetector/NetworkTimeSuggestion.java
index 2030083..a5259c2 100644
--- a/core/java/android/app/timedetector/NetworkTimeSuggestion.java
+++ b/core/java/android/app/timedetector/NetworkTimeSuggestion.java
@@ -66,10 +66,10 @@
     }
 
     private static NetworkTimeSuggestion createFromParcel(Parcel in) {
-        TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */, android.os.TimestampedValue.class);
+        TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
         NetworkTimeSuggestion suggestion = new NetworkTimeSuggestion(utcTime);
         @SuppressWarnings("unchecked")
-        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */, java.lang.String.class);
+        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
         suggestion.mDebugInfo = debugInfo;
         return suggestion;
     }
diff --git a/core/java/android/app/timedetector/TelephonyTimeSuggestion.java b/core/java/android/app/timedetector/TelephonyTimeSuggestion.java
index 52d0bbe..6c3a304 100644
--- a/core/java/android/app/timedetector/TelephonyTimeSuggestion.java
+++ b/core/java/android/app/timedetector/TelephonyTimeSuggestion.java
@@ -77,10 +77,10 @@
     private static TelephonyTimeSuggestion createFromParcel(Parcel in) {
         int slotIndex = in.readInt();
         TelephonyTimeSuggestion suggestion = new TelephonyTimeSuggestion.Builder(slotIndex)
-                .setUtcTime(in.readParcelable(null /* classLoader */, android.os.TimestampedValue.class))
+                .setUtcTime(in.readParcelable(null /* classLoader */))
                 .build();
         @SuppressWarnings("unchecked")
-        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */, java.lang.String.class);
+        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
         if (debugInfo != null) {
             suggestion.addDebugInfo(debugInfo);
         }
diff --git a/core/java/android/app/timezone/RulesState.java b/core/java/android/app/timezone/RulesState.java
index 516ad03..ee88ec54 100644
--- a/core/java/android/app/timezone/RulesState.java
+++ b/core/java/android/app/timezone/RulesState.java
@@ -195,12 +195,12 @@
 
     private static RulesState createFromParcel(Parcel in) {
         String baseRulesVersion = in.readString();
-        DistroFormatVersion distroFormatVersionSupported = in.readParcelable(null, android.app.timezone.DistroFormatVersion.class);
+        DistroFormatVersion distroFormatVersionSupported = in.readParcelable(null);
         boolean operationInProgress = in.readByte() == BYTE_TRUE;
         int distroStagedState = in.readByte();
-        DistroRulesVersion stagedDistroRulesVersion = in.readParcelable(null, android.app.timezone.DistroRulesVersion.class);
+        DistroRulesVersion stagedDistroRulesVersion = in.readParcelable(null);
         int installedDistroStatus = in.readByte();
-        DistroRulesVersion installedDistroRulesVersion = in.readParcelable(null, android.app.timezone.DistroRulesVersion.class);
+        DistroRulesVersion installedDistroRulesVersion = in.readParcelable(null);
         return new RulesState(baseRulesVersion, distroFormatVersionSupported, operationInProgress,
                 distroStagedState, stagedDistroRulesVersion,
                 installedDistroStatus, installedDistroRulesVersion);
diff --git a/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java b/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java
index 387319e..01a60b1 100644
--- a/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java
+++ b/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java
@@ -65,7 +65,7 @@
         String zoneId = in.readString();
         ManualTimeZoneSuggestion suggestion = new ManualTimeZoneSuggestion(zoneId);
         @SuppressWarnings("unchecked")
-        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */, java.lang.String.class);
+        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
         suggestion.mDebugInfo = debugInfo;
         return suggestion;
     }
diff --git a/core/java/android/app/timezonedetector/TelephonyTimeZoneSuggestion.java b/core/java/android/app/timezonedetector/TelephonyTimeZoneSuggestion.java
index e5b4e46..eb6750f 100644
--- a/core/java/android/app/timezonedetector/TelephonyTimeZoneSuggestion.java
+++ b/core/java/android/app/timezonedetector/TelephonyTimeZoneSuggestion.java
@@ -165,7 +165,7 @@
                 .setQuality(in.readInt())
                 .build();
         List<String> debugInfo =
-                in.readArrayList(TelephonyTimeZoneSuggestion.class.getClassLoader(), java.lang.String.class);
+                in.readArrayList(TelephonyTimeZoneSuggestion.class.getClassLoader());
         if (debugInfo != null) {
             suggestion.addDebugInfo(debugInfo);
         }
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 65b2775..177de83 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -156,7 +156,7 @@
 
                 @Override
                 public void onTrustError(CharSequence message) {
-                    Message m = mHandler.obtainMessage(MSG_TRUST_ERROR);
+                    Message m = mHandler.obtainMessage(MSG_TRUST_ERROR, trustListener);
                     m.getData().putCharSequence(DATA_MESSAGE, message);
                     m.sendToTarget();
                 }
diff --git a/core/java/android/app/usage/CacheQuotaHint.java b/core/java/android/app/usage/CacheQuotaHint.java
index ba6bcdc..0ccb058 100644
--- a/core/java/android/app/usage/CacheQuotaHint.java
+++ b/core/java/android/app/usage/CacheQuotaHint.java
@@ -148,7 +148,7 @@
                     return builder.setVolumeUuid(in.readString())
                             .setUid(in.readInt())
                             .setQuota(in.readLong())
-                            .setUsageStats(in.readParcelable(UsageStats.class.getClassLoader(), android.app.usage.UsageStats.class))
+                            .setUsageStats(in.readParcelable(UsageStats.class.getClassLoader()))
                             .build();
                 }
 
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 7e5e96d..a695f6d 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2249,17 +2249,17 @@
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {
-            BluetoothStatusCodes.SUCCESS,
+            BluetoothStatusCodes.FEATURE_SUPPORTED,
             BluetoothStatusCodes.ERROR_UNKNOWN,
             BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
-            BluetoothStatusCodes.ERROR_FEATURE_NOT_SUPPORTED,
+            BluetoothStatusCodes.FEATURE_NOT_SUPPORTED,
     })
     public @interface LeFeatureReturnValues {}
 
     /**
-     * Returns {@link BluetoothStatusCodes#SUCCESS} if the LE audio feature is
-     * supported, returns {@link BluetoothStatusCodes#ERROR_FEATURE_NOT_SUPPORTED} if
-     * the feature is not supported or an error code.
+     * Returns {@link BluetoothStatusCodes#FEATURE_SUPPORTED} if the LE audio feature is
+     * supported, {@link BluetoothStatusCodes#FEATURE_NOT_SUPPORTED} if the feature is not
+     * supported, or an error code.
      *
      * @return whether the LE audio is supported
      */
@@ -2282,9 +2282,10 @@
     }
 
     /**
-     * Returns {@link BluetoothStatusCodes#SUCCESS} if LE Periodic Advertising Sync Transfer Sender
-     * feature is supported, returns {@link BluetoothStatusCodes#ERROR_FEATURE_NOT_SUPPORTED} if the
-     * feature is not supported or an error code
+     * Returns {@link BluetoothStatusCodes#FEATURE_SUPPORTED} if LE Periodic Advertising Sync
+     * Transfer Sender feature is supported,
+     * {@link BluetoothStatusCodes#FEATURE_NOT_SUPPORTED} if the feature is not supported, or
+     * an error code
      *
      * @return whether the chipset supports the LE Periodic Advertising Sync Transfer Sender feature
      */
diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
index 053e0db..c5e986e 100644
--- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java
+++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
@@ -313,7 +313,7 @@
     };
 
     private BluetoothGattCharacteristic(Parcel in) {
-        mUuid = ((ParcelUuid) in.readParcelable(null, android.os.ParcelUuid.class)).getUuid();
+        mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid();
         mInstance = in.readInt();
         mProperties = in.readInt();
         mPermissions = in.readInt();
diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.java b/core/java/android/bluetooth/BluetoothGattDescriptor.java
index 6ed4706..a35d5b9 100644
--- a/core/java/android/bluetooth/BluetoothGattDescriptor.java
+++ b/core/java/android/bluetooth/BluetoothGattDescriptor.java
@@ -187,7 +187,7 @@
     };
 
     private BluetoothGattDescriptor(Parcel in) {
-        mUuid = ((ParcelUuid) in.readParcelable(null, android.os.ParcelUuid.class)).getUuid();
+        mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid();
         mInstance = in.readInt();
         mPermissions = in.readInt();
     }
diff --git a/core/java/android/bluetooth/BluetoothGattIncludedService.java b/core/java/android/bluetooth/BluetoothGattIncludedService.java
index 1ae2ca0..5580619 100644
--- a/core/java/android/bluetooth/BluetoothGattIncludedService.java
+++ b/core/java/android/bluetooth/BluetoothGattIncludedService.java
@@ -76,7 +76,7 @@
     };
 
     private BluetoothGattIncludedService(Parcel in) {
-        mUuid = ((ParcelUuid) in.readParcelable(null, android.os.ParcelUuid.class)).getUuid();
+        mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid();
         mInstanceId = in.readInt();
         mServiceType = in.readInt();
     }
diff --git a/core/java/android/bluetooth/BluetoothGattService.java b/core/java/android/bluetooth/BluetoothGattService.java
index 36bc477..f64d09f 100644
--- a/core/java/android/bluetooth/BluetoothGattService.java
+++ b/core/java/android/bluetooth/BluetoothGattService.java
@@ -180,7 +180,7 @@
     };
 
     private BluetoothGattService(Parcel in) {
-        mUuid = ((ParcelUuid) in.readParcelable(null, android.os.ParcelUuid.class)).getUuid();
+        mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid();
         mInstanceId = in.readInt();
         mServiceType = in.readInt();
 
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index f2a6276..2ed1eb4 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -18,6 +18,7 @@
 
 import static android.bluetooth.BluetoothUtils.getSyncTimeout;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -44,6 +45,8 @@
 
 import com.android.modules.utils.SynchronousResultReceiver;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeoutException;
@@ -895,17 +898,36 @@
                 com.android.internal.R.bool.config_bluetooth_sco_off_call);
     }
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
+            BluetoothHeadset.STATE_AUDIO_CONNECTING,
+            BluetoothHeadset.STATE_AUDIO_CONNECTED,
+            BluetoothStatusCodes.ERROR_TIMEOUT
+    })
+    public @interface GetAudioStateReturnValues {}
+
     /**
      * Get the current audio state of the Headset.
-     * Note: This is an internal function and shouldn't be exposed
+     *
+     * @param device is the Bluetooth device for which the audio state is being queried
+     * @return the audio state of the device or an error code
+     * @throws IllegalArgumentException if the device is null
      *
      * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    @SystemApi
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
-    public int getAudioState(BluetoothDevice device) {
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public @GetAudioStateReturnValues int getAudioState(@NonNull BluetoothDevice device) {
         if (VDBG) log("getAudioState");
+        if (device == null) {
+            throw new IllegalArgumentException("device cannot be null");
+        }
         final IBluetoothHeadset service = mService;
         final int defaultValue = BluetoothHeadset.STATE_AUDIO_DISCONNECTED;
         if (service == null) {
@@ -916,8 +938,12 @@
                 final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
                 service.getAudioState(device, mAttributionSource, recv);
                 return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
-            } catch (RemoteException | TimeoutException e) {
+            } catch (RemoteException e) {
                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+                throw e.rethrowFromSystemServer();
+            } catch (TimeoutException e) {
+                Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+                return BluetoothStatusCodes.ERROR_TIMEOUT;
             }
         }
         return defaultValue;
@@ -1005,103 +1031,112 @@
         }
     }
 
-    /**
-     * Check if at least one headset's SCO audio is connected or connecting
-     *
-     * @return true if at least one device's SCO audio is connected or connecting, false otherwise
-     * or on error
-     * @hide
-     */
-    @RequiresLegacyBluetoothPermission
-    @RequiresBluetoothConnectPermission
-    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
-    public boolean isAudioOn() {
-        if (VDBG) log("isAudioOn()");
-        final IBluetoothHeadset service = mService;
-        final boolean defaultValue = false;
-        if (service == null) {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) log(Log.getStackTraceString(new Throwable()));
-        } else if (isEnabled()) {
-            try {
-                final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
-                service.isAudioOn(mAttributionSource, recv);
-                return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
-            } catch (RemoteException | TimeoutException e) {
-                Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
-            }
-        }
-        return defaultValue;
-    }
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            BluetoothStatusCodes.SUCCESS,
+            BluetoothStatusCodes.ERROR_UNKNOWN,
+            BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
+            BluetoothStatusCodes.ERROR_TIMEOUT,
+            BluetoothStatusCodes.ERROR_AUDIO_DEVICE_ALREADY_CONNECTED,
+            BluetoothStatusCodes.ERROR_NO_ACTIVE_DEVICES,
+            BluetoothStatusCodes.ERROR_NOT_ACTIVE_DEVICE,
+            BluetoothStatusCodes.ERROR_AUDIO_ROUTE_BLOCKED,
+            BluetoothStatusCodes.ERROR_CALL_ACTIVE,
+            BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED
+    })
+    public @interface ConnectAudioReturnValues {}
 
     /**
-     * Initiates a connection of headset audio to the current active device
+     * Initiates a connection of SCO audio to the current active HFP device. The active HFP device
+     * can be identified with {@link BluetoothAdapter#getActiveDevices(int)}.
+ * <p>
+     * If this function returns {@link BluetoothStatusCodes#SUCCESS}, the intent
+     * {@link #ACTION_AUDIO_STATE_CHANGED} will be broadcasted twice. First with {@link #EXTRA_STATE}
+     * set to {@link #STATE_AUDIO_CONNECTING}. This will be followed by a broadcast with
+     * {@link #EXTRA_STATE} set to either {@link #STATE_AUDIO_CONNECTED} if the audio connection is
+     * established or {@link #STATE_AUDIO_DISCONNECTED} if there was a failure in establishing the
+     * audio connection.
      *
-     * <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
-     * If this function returns true, this intent will be broadcasted with
-     * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_CONNECTING}.
-     *
-     * <p> {@link #EXTRA_STATE} will transition from
-     * {@link #STATE_AUDIO_CONNECTING} to {@link #STATE_AUDIO_CONNECTED} when
-     * audio connection is established and to {@link #STATE_AUDIO_DISCONNECTED}
-     * in case of failure to establish the audio connection.
-     *
-     * Note that this intent will not be sent if {@link BluetoothHeadset#isAudioOn()} is true
-     * before calling this method
-     *
-     * @return false if there was some error such as there is no active headset
+     * @return whether the connection was successfully initiated or an error code on failure
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
-    public boolean connectAudio() {
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public @ConnectAudioReturnValues int connectAudio() {
         if (VDBG) log("connectAudio()");
         final IBluetoothHeadset service = mService;
-        final boolean defaultValue = false;
+        final int defaultValue = BluetoothStatusCodes.ERROR_UNKNOWN;
         if (service == null) {
             Log.w(TAG, "Proxy not attached to service");
             if (DBG) log(Log.getStackTraceString(new Throwable()));
         } else if (isEnabled()) {
             try {
-                final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
+                final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
                 service.connectAudio(mAttributionSource, recv);
                 return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
-            } catch (RemoteException | TimeoutException e) {
+            } catch (RemoteException e) {
                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+                throw e.rethrowFromSystemServer();
+            } catch (TimeoutException e) {
+                Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+                return BluetoothStatusCodes.ERROR_TIMEOUT;
             }
         }
         return defaultValue;
     }
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            BluetoothStatusCodes.SUCCESS,
+            BluetoothStatusCodes.ERROR_UNKNOWN,
+            BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
+            BluetoothStatusCodes.ERROR_TIMEOUT,
+            BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED,
+            BluetoothStatusCodes.ERROR_AUDIO_DEVICE_ALREADY_DISCONNECTED
+    })
+    public @interface DisconnectAudioReturnValues {}
+
     /**
-     * Initiates a disconnection of HFP SCO audio.
-     * Tear down voice recognition or virtual voice call if any.
+     * Initiates a disconnection of HFP SCO audio from actively connected devices. It also tears
+     * down voice recognition or virtual voice call, if any exists.
      *
-     * <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
-     * If this function returns true, this intent will be broadcasted with
-     * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_DISCONNECTED}.
+     * <p> If this function returns {@link BluetoothStatusCodes#SUCCESS}, the intent
+     * {@link #ACTION_AUDIO_STATE_CHANGED} will be broadcasted with {@link #EXTRA_STATE} set to
+     * {@link #STATE_AUDIO_DISCONNECTED}.
      *
-     * @return false if audio is not connected, or on error, true otherwise
+     * @return whether the disconnection was initiated successfully or an error code on failure
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
-    public boolean disconnectAudio() {
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public @DisconnectAudioReturnValues int disconnectAudio() {
         if (VDBG) log("disconnectAudio()");
         final IBluetoothHeadset service = mService;
-        final boolean defaultValue = false;
+        final int defaultValue = BluetoothStatusCodes.ERROR_UNKNOWN;
         if (service == null) {
             Log.w(TAG, "Proxy not attached to service");
             if (DBG) log(Log.getStackTraceString(new Throwable()));
         } else if (isEnabled()) {
             try {
-                final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
+                final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
                 service.disconnectAudio(mAttributionSource, recv);
                 return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
-            } catch (RemoteException | TimeoutException e) {
+            } catch (RemoteException e) {
                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+                throw e.rethrowFromSystemServer();
+            } catch (TimeoutException e) {
+                Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+                return BluetoothStatusCodes.ERROR_TIMEOUT;
             }
         }
         return defaultValue;
@@ -1386,7 +1421,10 @@
     @SystemApi
     @RequiresLegacyBluetoothPermission
     @RequiresBluetoothConnectPermission
-    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
     public boolean isInbandRingingEnabled() {
         if (DBG) log("isInbandRingingEnabled()");
         final IBluetoothHeadset service = mService;
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
index e9dd761..032b507 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
@@ -292,7 +292,7 @@
             new Parcelable.Creator<BluetoothHeadsetClientCall>() {
                 @Override
                 public BluetoothHeadsetClientCall createFromParcel(Parcel in) {
-                    return new BluetoothHeadsetClientCall((BluetoothDevice) in.readParcelable(null, android.bluetooth.BluetoothDevice.class),
+                    return new BluetoothHeadsetClientCall((BluetoothDevice) in.readParcelable(null),
                             in.readInt(), UUID.fromString(in.readString()), in.readInt(),
                             in.readString(), in.readInt() == 1, in.readInt() == 1,
                             in.readInt() == 1);
diff --git a/core/java/android/bluetooth/BluetoothStatusCodes.java b/core/java/android/bluetooth/BluetoothStatusCodes.java
index fff32ff..a8ce4b4 100644
--- a/core/java/android/bluetooth/BluetoothStatusCodes.java
+++ b/core/java/android/bluetooth/BluetoothStatusCodes.java
@@ -20,7 +20,7 @@
 
 /**
  * A class with constants representing possible return values for Bluetooth APIs. General return
- * values occupy the range 0 to 99. Profile-specific return values occupy the range 100-999.
+ * values occupy the range 0 to 199. Profile-specific return values occupy the range 200-999.
  * API-specific return values start at 1000. The exception to this is the "UNKNOWN" error code which
  * occupies the max integer value.
  */
@@ -29,28 +29,28 @@
     private BluetoothStatusCodes() {}
 
     /**
-     * Indicates that the API call was successful
+     * Indicates that the API call was successful.
      */
     public static final int SUCCESS = 0;
 
     /**
-     * Error code indicating that Bluetooth is not enabled
+     * Error code indicating that Bluetooth is not enabled.
      */
     public static final int ERROR_BLUETOOTH_NOT_ENABLED = 1;
 
     /**
      * Error code indicating that the API call was initiated by neither the system nor the active
-     * user
+     * user.
      */
     public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2;
 
     /**
-     * Error code indicating that the Bluetooth Device specified is not bonded
+     * Error code indicating that the Bluetooth Device specified is not bonded.
      */
     public static final int ERROR_DEVICE_NOT_BONDED = 3;
 
     /**
-     * Error code indicating that the Bluetooth Device specified is not connected, but is bonded
+     * Error code indicating that the Bluetooth Device specified is not connected, but is bonded.
      *
      * @hide
      */
@@ -58,7 +58,7 @@
 
     /**
      * Error code indicating that the caller does not have the
-     * {@link android.Manifest.permission#BLUETOOTH_ADVERTISE} permission
+     * {@link android.Manifest.permission#BLUETOOTH_ADVERTISE} permission.
      *
      * @hide
      */
@@ -66,13 +66,13 @@
 
     /**
      * Error code indicating that the caller does not have the
-     * {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission
+     * {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission.
      */
     public static final int ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION = 6;
 
     /**
      * Error code indicating that the caller does not have the
-     * {@link android.Manifest.permission#BLUETOOTH_SCAN} permission
+     * {@link android.Manifest.permission#BLUETOOTH_SCAN} permission.
      *
      * @hide
      */
@@ -80,30 +80,67 @@
 
     /**
      * Error code indicating that the caller does not have the
-     * {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission
+     * {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission.
      */
     public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8;
 
     /**
      * Error code indicating that the profile service is not bound. You can bind a profile service
-     * by calling {@link BluetoothAdapter#getProfileProxy}
+     * by calling {@link BluetoothAdapter#getProfileProxy}.
      */
     public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9;
 
     /**
-     * Error code indicating that the feature is not supported.
+     * Indicates that the feature is supported.
      */
-    public static final int ERROR_FEATURE_NOT_SUPPORTED = 10;
+    public static final int FEATURE_SUPPORTED = 10;
+
+    /**
+     * Indicates that the feature is not supported.
+     */
+    public static final int FEATURE_NOT_SUPPORTED = 11;
+
+    /**
+     * Error code indicating that the device is not the active device for this profile.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_NOT_ACTIVE_DEVICE = 12;
+
+    /**
+     * Error code indicating that there are no active devices for the profile.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_NO_ACTIVE_DEVICES = 13;
+
+    /**
+     * Indicates that the Bluetooth profile is not connected to this device.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_PROFILE_NOT_CONNECTED = 14;
+
+    /**
+     * Error code indicating that the requested operation timed out.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_TIMEOUT = 15;
 
     /**
      * A GATT writeCharacteristic request is not permitted on the remote device.
      */
-    public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 101;
+    public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 200;
 
     /**
      * A GATT writeCharacteristic request is issued to a busy remote device.
      */
-    public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 102;
+    public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 201;
 
     /**
      * If another application has already requested {@link OobData} then another fetch will be
@@ -286,6 +323,38 @@
     public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_DISABLE_ENCRYPTION_FAILED = 1115;
 
     /**
+     * Indicates that there is already one device for which SCO audio is connected or connecting.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_AUDIO_DEVICE_ALREADY_CONNECTED = 1116;
+
+    /**
+     * Indicates that SCO audio was already not connected for this device.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_AUDIO_DEVICE_ALREADY_DISCONNECTED = 1117;
+
+    /**
+     * Indicates that there audio route is currently blocked by the system.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_AUDIO_ROUTE_BLOCKED = 1118;
+
+    /**
+     * Indicates that there is an active call preventing this operation from succeeding.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_CALL_ACTIVE = 1119;
+
+    /**
      * Indicates that an unknown error has occurred has occurred.
      */
     public static final int ERROR_UNKNOWN = Integer.MAX_VALUE;
diff --git a/core/java/android/bluetooth/BufferConstraints.java b/core/java/android/bluetooth/BufferConstraints.java
index 06b45ee..97d9723 100644
--- a/core/java/android/bluetooth/BufferConstraints.java
+++ b/core/java/android/bluetooth/BufferConstraints.java
@@ -55,7 +55,7 @@
     BufferConstraints(Parcel in) {
         mBufferConstraintList = new ArrayList<BufferConstraint>();
         mBufferConstraints = new HashMap<Integer, BufferConstraint>();
-        in.readList(mBufferConstraintList, BufferConstraint.class.getClassLoader(), android.bluetooth.BufferConstraint.class);
+        in.readList(mBufferConstraintList, BufferConstraint.class.getClassLoader());
         for (int i = 0; i < mBufferConstraintList.size(); i++) {
             mBufferConstraints.put(i, mBufferConstraintList.get(i));
         }
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 675fe05..b059193 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -200,28 +200,28 @@
                 address = in.readString();
             }
             if (in.readInt() == 1) {
-                ParcelUuid uuid = in.readParcelable(ParcelUuid.class.getClassLoader(), android.os.ParcelUuid.class);
+                ParcelUuid uuid = in.readParcelable(ParcelUuid.class.getClassLoader());
                 builder.setServiceUuid(uuid);
                 if (in.readInt() == 1) {
                     ParcelUuid uuidMask = in.readParcelable(
-                            ParcelUuid.class.getClassLoader(), android.os.ParcelUuid.class);
+                            ParcelUuid.class.getClassLoader());
                     builder.setServiceUuid(uuid, uuidMask);
                 }
             }
             if (in.readInt() == 1) {
                 ParcelUuid solicitationUuid = in.readParcelable(
-                        ParcelUuid.class.getClassLoader(), android.os.ParcelUuid.class);
+                        ParcelUuid.class.getClassLoader());
                 builder.setServiceSolicitationUuid(solicitationUuid);
                 if (in.readInt() == 1) {
                     ParcelUuid solicitationUuidMask = in.readParcelable(
-                            ParcelUuid.class.getClassLoader(), android.os.ParcelUuid.class);
+                            ParcelUuid.class.getClassLoader());
                     builder.setServiceSolicitationUuid(solicitationUuid,
                             solicitationUuidMask);
                 }
             }
             if (in.readInt() == 1) {
                 ParcelUuid servcieDataUuid =
-                        in.readParcelable(ParcelUuid.class.getClassLoader(), android.os.ParcelUuid.class);
+                        in.readParcelable(ParcelUuid.class.getClassLoader());
                 if (in.readInt() == 1) {
                     int serviceDataLength = in.readInt();
                     byte[] serviceData = new byte[serviceDataLength];
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index 1d2f06d..18a59d8 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -595,7 +595,7 @@
         boolean forceConfirmation = (flg & 0x20) != 0;
         boolean skipPrompt = (flg & 0x400) != 0;
         List<DeviceFilter<?>> deviceFilters = new ArrayList<>();
-        in.readParcelableList(deviceFilters, DeviceFilter.class.getClassLoader(), (Class<android.companion.DeviceFilter<?>>) (Class<?>) android.companion.DeviceFilter.class);
+        in.readParcelableList(deviceFilters, DeviceFilter.class.getClassLoader());
         String deviceProfile = (flg & 0x4) == 0 ? null : in.readString();
         CharSequence displayName = (flg & 0x8) == 0 ? null : (CharSequence) in.readCharSequence();
         String packageName = (flg & 0x40) == 0 ? null : in.readString();
diff --git a/core/java/android/companion/BluetoothDeviceFilter.java b/core/java/android/companion/BluetoothDeviceFilter.java
index e0018f4..be663f7 100644
--- a/core/java/android/companion/BluetoothDeviceFilter.java
+++ b/core/java/android/companion/BluetoothDeviceFilter.java
@@ -70,7 +70,7 @@
     }
 
     private static List<ParcelUuid> readUuids(Parcel in) {
-        return in.readParcelableList(new ArrayList<>(), ParcelUuid.class.getClassLoader(), android.os.ParcelUuid.class);
+        return in.readParcelableList(new ArrayList<>(), ParcelUuid.class.getClassLoader());
     }
 
     /** @hide */
diff --git a/core/java/android/companion/BluetoothLeDeviceFilter.java b/core/java/android/companion/BluetoothLeDeviceFilter.java
index e6091f0..58898cc 100644
--- a/core/java/android/companion/BluetoothLeDeviceFilter.java
+++ b/core/java/android/companion/BluetoothLeDeviceFilter.java
@@ -252,7 +252,7 @@
         public BluetoothLeDeviceFilter createFromParcel(Parcel in) {
             Builder builder = new Builder()
                     .setNamePattern(patternFromString(in.readString()))
-                    .setScanFilter(in.readParcelable(null, android.bluetooth.le.ScanFilter.class));
+                    .setScanFilter(in.readParcelable(null));
             byte[] rawDataFilter = in.createByteArray();
             byte[] rawDataFilterMask = in.createByteArray();
             if (rawDataFilter != null) {
diff --git a/core/java/android/companion/SystemDataTransferRequest.aidl b/core/java/android/companion/SystemDataTransferRequest.aidl
new file mode 100644
index 0000000..19ae60e
--- /dev/null
+++ b/core/java/android/companion/SystemDataTransferRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.companion;
+
+parcelable SystemDataTransferRequest;
diff --git a/core/java/android/companion/SystemDataTransferRequest.java b/core/java/android/companion/SystemDataTransferRequest.java
new file mode 100644
index 0000000..e3b0369
--- /dev/null
+++ b/core/java/android/companion/SystemDataTransferRequest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.companion;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.OneTimeUseBuilder;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A request for users to allow the companion app to transfer system data to the companion devices.
+ *
+ * @hide
+ */
+public final class SystemDataTransferRequest implements Parcelable {
+
+    private final int mAssociationId;
+    private final boolean mPermissionSyncAllPackages;
+    private final List<String> mPermissionSyncPackages;
+
+    /**
+     * @hide
+     */
+    public SystemDataTransferRequest(int associationId, boolean syncAllPackages,
+            @Nullable List<String> permissionSyncPackages) {
+        mAssociationId = associationId;
+        mPermissionSyncAllPackages = syncAllPackages;
+        mPermissionSyncPackages = permissionSyncPackages;
+    }
+
+    public int getAssociationId() {
+        return mAssociationId;
+    }
+
+    @NonNull
+    public boolean isPermissionSyncAllPackages() {
+        return mPermissionSyncAllPackages;
+    }
+
+    @NonNull
+    public List<String> getPermissionSyncPackages() {
+        return mPermissionSyncPackages;
+    }
+
+    /**
+     * A builder for {@link SystemDataTransferRequest}.
+     *
+     * <p>You have to call one of the below methods to create a valid request</p>
+     * <br>1. {@link #setPermissionSyncAllPackages()}
+     * <br>2. {@link #setPermissionSyncPackages(List)}
+     */
+    public static final class Builder extends OneTimeUseBuilder<SystemDataTransferRequest> {
+
+        private final int mAssociationId;
+        private boolean mPermissionSyncAllPackages;
+        private List<String> mPermissionSyncPackages = new ArrayList<>();
+
+        public Builder(int associationId) {
+            mAssociationId = associationId;
+        }
+
+        /**
+         * Call to sync permissions for all the packages. You can optionally call
+         * {@link #setPermissionSyncPackages(List)} to specify the packages to sync permissions.
+         *
+         * <p>The system will only sync permissions that are explicitly granted by the user.</p>
+         *
+         * <p>If a permission is granted or revoked by the system or a policy, even if the user has
+         * explicitly granted or revoked the permission earlier, the permission will be ignored.</p>
+         *
+         * <p>If a system or policy granted or revoked permission is granted or revoked by the user
+         * later, the permission will be ignored.</p>
+         *
+         * @see #setPermissionSyncPackages(List)
+         *
+         * @return the builder
+         */
+        @NonNull
+        public Builder setPermissionSyncAllPackages() {
+            mPermissionSyncAllPackages = true;
+            return this;
+        }
+
+        /**
+         * Set a list of packages to sync permissions. You can optionally call
+         * {@link #setPermissionSyncAllPackages()} to sync permissions for all the packages.
+         *
+         * @see #setPermissionSyncAllPackages()
+         *
+         * @param permissionSyncPackages packages to sync permissions
+         * @return builder
+         */
+        @NonNull
+        public Builder setPermissionSyncPackages(@NonNull List<String> permissionSyncPackages) {
+            mPermissionSyncPackages = permissionSyncPackages;
+            return this;
+        }
+
+        @Override
+        @NonNull
+        public SystemDataTransferRequest build() {
+            return new SystemDataTransferRequest(mAssociationId, mPermissionSyncAllPackages,
+                    mPermissionSyncPackages);
+        }
+    }
+
+    SystemDataTransferRequest(Parcel in) {
+        mAssociationId = in.readInt();
+        mPermissionSyncAllPackages = in.readBoolean();
+        mPermissionSyncPackages = Arrays.asList(in.createString8Array());
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mAssociationId);
+        dest.writeBoolean(mPermissionSyncAllPackages);
+        dest.writeString8Array(mPermissionSyncPackages.toArray(new String[0]));
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @NonNull
+    public static final Creator<SystemDataTransferRequest> CREATOR =
+            new Creator<SystemDataTransferRequest>() {
+                @Override
+                public SystemDataTransferRequest createFromParcel(Parcel in) {
+                    return new SystemDataTransferRequest(in);
+                }
+
+                @Override
+                public SystemDataTransferRequest[] newArray(int size) {
+                    return new SystemDataTransferRequest[size];
+                }
+            };
+}
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 0c065d9b..30775b1 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -108,7 +108,7 @@
             mExtras = null;
         }
         mSelection = source.readInt() != 0 ? source.readString8() : null;
-        mSelectionArgs = source.readSparseArray(null, java.lang.Object.class);
+        mSelectionArgs = source.readSparseArray(null);
         mExpectedCount = source.readInt() != 0 ? source.readInt() : null;
         mYieldAllowed = source.readInt() != 0;
         mExceptionAllowed = source.readInt() != 0;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index bccfacf..2df6f9a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -94,8 +94,11 @@
 import java.io.InputStream;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * Interface to global information about an application environment.  This is
@@ -6407,6 +6410,43 @@
             @Nullable String writePermission, int pid, int uid, @Intent.AccessUriMode int modeFlags,
             @Nullable String message);
 
+
+    /**
+     * Triggers the asynchronous revocation of a permission.
+     *
+     * @param permName The name of the permission to be revoked.
+     * @see #selfRevokePermissions(Collection)
+     */
+    public void selfRevokePermission(@NonNull String permName) {
+        selfRevokePermissions(Collections.singletonList(permName));
+    }
+
+    /**
+     * Triggers the revocation of one or more permissions for the calling package. A package is only
+     * able to revoke a permission under the following conditions:
+     * <ul>
+     * <li>Each permission in {@code permissions} must be granted to the calling package.
+     * <li>Each permission in {@code permissions} must be a runtime permission.
+     * </ul>
+     * <p>
+     * For every permission in {@code permissions}, the entire permission group it belongs to will
+     * be revoked. The revocation happens asynchronously and kills all processes running in the
+     * calling UID. It will be triggered once it is safe to do so. In particular, it will not be
+     * triggered as long as the package remains in the foreground, or has any active manifest
+     * components (e.g. when another app is accessing a content provider in the package).
+     * <p>
+     * If you want to revoke the permissions right away, you could call {@code System.exit()}, but
+     * this could affect other apps that are accessing your app at the moment. For example, apps
+     * accessing a content provider in your app will all crash.
+     *
+     * @param permissions Collection of permissions to be revoked.
+     * @see PackageManager#getGroupOfPlatformPermission(String, Executor, Consumer)
+     * @see PackageManager#getPlatformPermissionsForGroup(String, Executor, Consumer)
+     */
+    public void selfRevokePermissions(@NonNull Collection<String> permissions) {
+        throw new AbstractMethodError("Must be overridden in implementing class");
+    }
+
     /** @hide */
     @IntDef(flag = true, prefix = { "CONTEXT_" }, value = {
             CONTEXT_INCLUDE_CODE,
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 3a02004..805e499 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -53,6 +53,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.Executor;
 
@@ -1015,6 +1016,11 @@
     }
 
     @Override
+    public void selfRevokePermissions(@NonNull Collection<String> permissions) {
+        mBase.selfRevokePermissions(permissions);
+    }
+
+    @Override
     public Context createPackageContext(String packageName, int flags)
         throws PackageManager.NameNotFoundException {
         return mBase.createPackageContext(packageName, flags);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index af84392..74c326d 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4391,9 +4391,9 @@
      * restored from (corresponds to {@link android.os.Build.VERSION#SDK_INT}). The first three
      * values are represented as strings, the fourth one as int.
      *
-     * <p>This broadcast is sent only for settings provider entries known to require special handling
-     * around restore time.  These entries are found in the BROADCAST_ON_RESTORE table within
-     * the provider's backup agent implementation.
+     * <p>This broadcast is sent only for settings provider entries known to require special
+     * handling around restore time to specific receivers. These entries are found in the
+     * BROADCAST_ON_RESTORE table within the provider's backup agent implementation.
      *
      * @see #EXTRA_SETTING_NAME
      * @see #EXTRA_SETTING_PREVIOUS_VALUE
@@ -4401,15 +4401,46 @@
      * @see #EXTRA_SETTING_RESTORED_FROM_SDK_INT
      * {@hide}
      */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @SuppressLint("ActionValue")
     public static final String ACTION_SETTING_RESTORED = "android.os.action.SETTING_RESTORED";
 
-    /** {@hide} */
+    /**
+     * String intent extra to be used with {@link ACTION_SETTING_RESTORED}.
+     * Contain the name of the restored setting.
+     * {@hide}
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @SuppressLint("ActionValue")
     public static final String EXTRA_SETTING_NAME = "setting_name";
-    /** {@hide} */
+
+    /**
+     * String intent extra to be used with {@link ACTION_SETTING_RESTORED}.
+     * Contain the value of the {@link EXTRA_SETTING_NAME} settings entry prior to the restore
+     * operation.
+     * {@hide}
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @SuppressLint("ActionValue")
     public static final String EXTRA_SETTING_PREVIOUS_VALUE = "previous_value";
-    /** {@hide} */
+
+    /**
+     * String intent extra to be used with {@link ACTION_SETTING_RESTORED}.
+     * Contain the value of the {@link EXTRA_SETTING_NAME} settings entry being restored.
+     * {@hide}
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @SuppressLint("ActionValue")
     public static final String EXTRA_SETTING_NEW_VALUE = "new_value";
-    /** {@hide} */
+
+    /**
+     * Int intent extra to be used with {@link ACTION_SETTING_RESTORED}.
+     * Contain the version of the SDK that the setting has been restored from (corresponds to
+     * {@link android.os.Build.VERSION#SDK_INT}).
+     * {@hide}
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @SuppressLint("ActionValue")
     public static final String EXTRA_SETTING_RESTORED_FROM_SDK_INT = "restored_from_sdk_int";
 
     /**
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 32827ae..b3435b1 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -1182,7 +1182,7 @@
         public int match(Uri data, boolean wildcardSupported) {
             String host = data.getHost();
             if (host == null) {
-                if (wildcardSupported && mWild) {
+                if (wildcardSupported && mWild && mHost.isEmpty()) {
                     // special case, if no host is provided, but the Authority is wildcard, match
                     return MATCH_CATEGORY_HOST;
                 } else {
diff --git a/core/java/android/content/PeriodicSync.java b/core/java/android/content/PeriodicSync.java
index 6830f5f..432e81b 100644
--- a/core/java/android/content/PeriodicSync.java
+++ b/core/java/android/content/PeriodicSync.java
@@ -84,7 +84,7 @@
     }
 
     private PeriodicSync(Parcel in) {
-        this.account = in.readParcelable(null, android.accounts.Account.class);
+        this.account = in.readParcelable(null);
         this.authority = in.readString();
         this.extras = in.readBundle();
         this.period = in.readLong();
diff --git a/core/java/android/content/SyncInfo.java b/core/java/android/content/SyncInfo.java
index 57101be..017a92b 100644
--- a/core/java/android/content/SyncInfo.java
+++ b/core/java/android/content/SyncInfo.java
@@ -99,7 +99,7 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     SyncInfo(Parcel parcel) {
         authorityId = parcel.readInt();
-        account = parcel.readParcelable(Account.class.getClassLoader(), android.accounts.Account.class);
+        account = parcel.readParcelable(Account.class.getClassLoader());
         authority = parcel.readString();
         startTime = parcel.readLong();
     }
diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java
index 83ce84e..e1e6f75 100644
--- a/core/java/android/content/SyncRequest.java
+++ b/core/java/android/content/SyncRequest.java
@@ -174,7 +174,7 @@
         mIsAuthority = (in.readInt() != 0);
         mIsExpedited = (in.readInt() != 0);
         mIsScheduledAsExpeditedJob = (in.readInt() != 0);
-        mAccountToSync = in.readParcelable(null, android.accounts.Account.class);
+        mAccountToSync = in.readParcelable(null);
         mAuthority = in.readString();
     }
 
diff --git a/core/java/android/content/UndoManager.java b/core/java/android/content/UndoManager.java
index b2979f3..87afbf8 100644
--- a/core/java/android/content/UndoManager.java
+++ b/core/java/android/content/UndoManager.java
@@ -777,7 +777,7 @@
             final int N = p.readInt();
             for (int i=0; i<N; i++) {
                 UndoOwner owner = mManager.restoreOwner(p);
-                UndoOperation op = (UndoOperation)p.readParcelable(loader, android.content.UndoOperation.class);
+                UndoOperation op = (UndoOperation)p.readParcelable(loader);
                 op.mOwner = owner;
                 mOperations.add(op);
             }
diff --git a/core/java/android/content/UriPermission.java b/core/java/android/content/UriPermission.java
index 7347761..d3a9cb8 100644
--- a/core/java/android/content/UriPermission.java
+++ b/core/java/android/content/UriPermission.java
@@ -47,7 +47,7 @@
 
     /** {@hide} */
     public UriPermission(Parcel in) {
-        mUri = in.readParcelable(null, android.net.Uri.class);
+        mUri = in.readParcelable(null);
         mModeFlags = in.readInt();
         mPersistedTime = in.readLong();
     }
diff --git a/core/java/android/content/om/OverlayManagerTransaction.java b/core/java/android/content/om/OverlayManagerTransaction.java
index 868dab2..73be0ff 100644
--- a/core/java/android/content/om/OverlayManagerTransaction.java
+++ b/core/java/android/content/om/OverlayManagerTransaction.java
@@ -67,7 +67,7 @@
         mRequests = new ArrayList<>(size);
         for (int i = 0; i < size; i++) {
             final int request = source.readInt();
-            final OverlayIdentifier overlay = source.readParcelable(null, android.content.om.OverlayIdentifier.class);
+            final OverlayIdentifier overlay = source.readParcelable(null);
             final int userId = source.readInt();
             final Bundle extras = source.readBundle(null);
             mRequests.add(new Request(request, overlay, userId, extras));
diff --git a/core/java/android/content/pm/BaseParceledListSlice.java b/core/java/android/content/pm/BaseParceledListSlice.java
index 7bade74..1e0deff 100644
--- a/core/java/android/content/pm/BaseParceledListSlice.java
+++ b/core/java/android/content/pm/BaseParceledListSlice.java
@@ -50,10 +50,12 @@
      */
     private static final int MAX_IPC_SIZE = IBinder.getSuggestedMaxIpcSizeBytes();
 
-    private final List<T> mList;
+    private List<T> mList;
 
     private int mInlineCountLimit = Integer.MAX_VALUE;
 
+    private boolean mHasBeenParceled = false;
+
     public BaseParceledListSlice(List<T> list) {
         mList = list;
     }
@@ -151,9 +153,17 @@
      * Write this to another Parcel. Note that this discards the internal Parcel
      * and should not be used anymore. This is so we can pass this to a Binder
      * where we won't have a chance to call recycle on this.
+     *
+     * This method can only be called once per BaseParceledListSlice to ensure that
+     * the referenced list can be cleaned up before the recipient cleans up the
+     * Binder reference.
      */
     @Override
     public void writeToParcel(Parcel dest, int flags) {
+        if (mHasBeenParceled) {
+            throw new IllegalStateException("Can't Parcel a ParceledListSlice more than once");
+        }
+        mHasBeenParceled = true;
         final int N = mList.size();
         final int callFlags = flags;
         dest.writeInt(N);
@@ -180,9 +190,17 @@
                             throws RemoteException {
                         if (code != FIRST_CALL_TRANSACTION) {
                             return super.onTransact(code, data, reply, flags);
+                        } else if (mList == null) {
+                            throw new IllegalArgumentException("Attempt to transfer null list, "
+                                    + "did transfer finish?");
                         }
                         int i = data.readInt();
-                        if (DEBUG) Log.d(TAG, "Writing more @" + i + " of " + N);
+
+                        if (DEBUG) {
+                            Log.d(TAG, "Writing more @" + i + " of " + N + " to "
+                                    + Binder.getCallingPid() + ", sender=" + this);
+                        }
+
                         while (i < N && reply.dataSize() < MAX_IPC_SIZE) {
                             reply.writeInt(1);
 
@@ -196,6 +214,9 @@
                         if (i < N) {
                             if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N);
                             reply.writeInt(0);
+                        } else {
+                            if (DEBUG) Log.d(TAG, "Transfer complete, clearing mList reference");
+                            mList = null;
                         }
                         return true;
                     }
diff --git a/core/java/android/content/pm/InstallSourceInfo.java b/core/java/android/content/pm/InstallSourceInfo.java
index 84d2ca3..a45bf79 100644
--- a/core/java/android/content/pm/InstallSourceInfo.java
+++ b/core/java/android/content/pm/InstallSourceInfo.java
@@ -61,7 +61,7 @@
 
     private InstallSourceInfo(Parcel source) {
         mInitiatingPackageName = source.readString();
-        mInitiatingPackageSigningInfo = source.readParcelable(SigningInfo.class.getClassLoader(), android.content.pm.SigningInfo.class);
+        mInitiatingPackageSigningInfo = source.readParcelable(SigningInfo.class.getClassLoader());
         mOriginatingPackageName = source.readString();
         mInstallingPackageName = source.readString();
     }
diff --git a/core/java/android/content/pm/InstantAppInfo.java b/core/java/android/content/pm/InstantAppInfo.java
index d6cfb0e..24d6a07 100644
--- a/core/java/android/content/pm/InstantAppInfo.java
+++ b/core/java/android/content/pm/InstantAppInfo.java
@@ -65,7 +65,7 @@
         mLabelText = parcel.readCharSequence();
         mRequestedPermissions = parcel.readStringArray();
         mGrantedPermissions = parcel.createStringArray();
-        mApplicationInfo = parcel.readParcelable(null, android.content.pm.ApplicationInfo.class);
+        mApplicationInfo = parcel.readParcelable(null);
     }
 
     /**
diff --git a/core/java/android/content/pm/InstantAppIntentFilter.java b/core/java/android/content/pm/InstantAppIntentFilter.java
index 721b261..123d2ba 100644
--- a/core/java/android/content/pm/InstantAppIntentFilter.java
+++ b/core/java/android/content/pm/InstantAppIntentFilter.java
@@ -46,7 +46,7 @@
 
     InstantAppIntentFilter(Parcel in) {
         mSplitName = in.readString();
-        in.readList(mFilters, getClass().getClassLoader(), android.content.IntentFilter.class);
+        in.readList(mFilters, getClass().getClassLoader());
     }
 
     public String getSplitName() {
diff --git a/core/java/android/content/pm/InstantAppResolveInfo.java b/core/java/android/content/pm/InstantAppResolveInfo.java
index 6124638..9881564 100644
--- a/core/java/android/content/pm/InstantAppResolveInfo.java
+++ b/core/java/android/content/pm/InstantAppResolveInfo.java
@@ -140,7 +140,7 @@
             mFilters = Collections.emptyList();
             mVersionCode = -1;
         } else {
-            mDigest = in.readParcelable(null /*loader*/, android.content.pm.InstantAppResolveInfo.InstantAppDigest.class);
+            mDigest = in.readParcelable(null /*loader*/);
             mPackageName = in.readString();
             mFilters = new ArrayList<>();
             in.readTypedList(mFilters, InstantAppIntentFilter.CREATOR);
diff --git a/core/java/android/content/pm/LauncherActivityInfoInternal.java b/core/java/android/content/pm/LauncherActivityInfoInternal.java
index 46c415d..417f168 100644
--- a/core/java/android/content/pm/LauncherActivityInfoInternal.java
+++ b/core/java/android/content/pm/LauncherActivityInfoInternal.java
@@ -43,10 +43,10 @@
     }
 
     public LauncherActivityInfoInternal(Parcel source) {
-        mActivityInfo = source.readParcelable(ActivityInfo.class.getClassLoader(), android.content.pm.ActivityInfo.class);
+        mActivityInfo = source.readParcelable(ActivityInfo.class.getClassLoader());
         mComponentName = new ComponentName(mActivityInfo.packageName, mActivityInfo.name);
         mIncrementalStatesInfo = source.readParcelable(
-                IncrementalStatesInfo.class.getClassLoader(), android.content.pm.IncrementalStatesInfo.class);
+                IncrementalStatesInfo.class.getClassLoader());
     }
 
     public ComponentName getComponentName() {
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 495100b..d76dc78 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1754,11 +1754,11 @@
             installScenario = source.readInt();
             sizeBytes = source.readLong();
             appPackageName = source.readString();
-            appIcon = source.readParcelable(null, android.graphics.Bitmap.class);
+            appIcon = source.readParcelable(null);
             appLabel = source.readString();
-            originatingUri = source.readParcelable(null, android.net.Uri.class);
+            originatingUri = source.readParcelable(null);
             originatingUid = source.readInt();
-            referrerUri = source.readParcelable(null, android.net.Uri.class);
+            referrerUri = source.readParcelable(null);
             abiOverride = source.readString();
             volumeUuid = source.readString();
             grantedRuntimePermissions = source.readStringArray();
@@ -1770,7 +1770,7 @@
             forceQueryableOverride = source.readBoolean();
             requiredInstalledVersionCode = source.readLong();
             DataLoaderParamsParcel dataLoaderParamsParcel = source.readParcelable(
-                    DataLoaderParamsParcel.class.getClassLoader(), android.content.pm.DataLoaderParamsParcel.class);
+                    DataLoaderParamsParcel.class.getClassLoader());
             if (dataLoaderParamsParcel != null) {
                 dataLoaderParams = new DataLoaderParams(dataLoaderParamsParcel);
             }
@@ -2367,42 +2367,72 @@
         private static final int[] NO_SESSIONS = {};
 
         /** @hide */
-        @IntDef(prefix = { "STAGED_SESSION_" }, value = {
-                STAGED_SESSION_NO_ERROR,
-                STAGED_SESSION_VERIFICATION_FAILED,
-                STAGED_SESSION_ACTIVATION_FAILED,
-                STAGED_SESSION_UNKNOWN,
-                STAGED_SESSION_CONFLICT})
+        @IntDef(prefix = { "SESSION_" }, value = {
+                SESSION_NO_ERROR,
+                SESSION_VERIFICATION_FAILED,
+                SESSION_ACTIVATION_FAILED,
+                SESSION_UNKNOWN_ERROR,
+                SESSION_CONFLICT})
         @Retention(RetentionPolicy.SOURCE)
         public @interface SessionErrorCode {}
         /**
-         * Constant indicating that no error occurred during the preparation or the activation of
-         * this staged session.
+         * @deprecated use {@link #SESSION_NO_ERROR}.
          */
+        @Deprecated
         public static final int STAGED_SESSION_NO_ERROR = 0;
 
         /**
-         * Constant indicating that an error occurred during the verification phase (pre-reboot) of
-         * this staged session.
+         * @deprecated use {@link #SESSION_VERIFICATION_FAILED}.
          */
+        @Deprecated
         public static final int STAGED_SESSION_VERIFICATION_FAILED = 1;
 
         /**
-         * Constant indicating that an error occurred during the activation phase (post-reboot) of
-         * this staged session.
+         * @deprecated use {@link #SESSION_ACTIVATION_FAILED}.
          */
+        @Deprecated
         public static final int STAGED_SESSION_ACTIVATION_FAILED = 2;
 
         /**
-         * Constant indicating that an unknown error occurred while processing this staged session.
+         * @deprecated use {@link #SESSION_UNKNOWN_ERROR}.
          */
+        @Deprecated
         public static final int STAGED_SESSION_UNKNOWN = 3;
 
         /**
-         * Constant indicating that the session was in conflict with another staged session and had
+         * @deprecated use {@link #SESSION_CONFLICT}.
+         */
+        @Deprecated
+        public static final int STAGED_SESSION_CONFLICT = 4;
+
+        /**
+         * Constant indicating that no error occurred during the preparation or the activation of
+         * this session.
+         */
+        public static final int SESSION_NO_ERROR = 0;
+
+        /**
+         * Constant indicating that an error occurred during the verification phase of
+         * this session.
+         */
+        public static final int SESSION_VERIFICATION_FAILED = 1;
+
+        /**
+         * Constant indicating that an error occurred during the activation phase of
+         * this session.
+         */
+        public static final int SESSION_ACTIVATION_FAILED = 2;
+
+        /**
+         * Constant indicating that an unknown error occurred while processing this session.
+         */
+        public static final int SESSION_UNKNOWN_ERROR = 3;
+
+        /**
+         * Constant indicating that the session was in conflict with another session and had
          * to be sacrificed for resolution.
          */
-        public static final int STAGED_SESSION_CONFLICT = 4;
+        public static final int SESSION_CONFLICT = 4;
 
         private static String userActionToString(int requireUserAction) {
             switch(requireUserAction) {
@@ -2533,13 +2563,13 @@
             installScenario = source.readInt();
             sizeBytes = source.readLong();
             appPackageName = source.readString();
-            appIcon = source.readParcelable(null, android.graphics.Bitmap.class);
+            appIcon = source.readParcelable(null);
             appLabel = source.readString();
 
             installLocation = source.readInt();
-            originatingUri = source.readParcelable(null, android.net.Uri.class);
+            originatingUri = source.readParcelable(null);
             originatingUid = source.readInt();
-            referrerUri = source.readParcelable(null, android.net.Uri.class);
+            referrerUri = source.readParcelable(null);
             grantedRuntimePermissions = source.readStringArray();
             whitelistedRestrictedPermissions = source.createStringArrayList();
             autoRevokePermissionsMode = source.readInt();
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index f31f78f..e2c91a4b 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -7297,7 +7297,7 @@
             splitFlags = dest.createIntArray();
             splitPrivateFlags = dest.createIntArray();
             baseHardwareAccelerated = (dest.readInt() == 1);
-            applicationInfo = dest.readParcelable(boot, android.content.pm.ApplicationInfo.class);
+            applicationInfo = dest.readParcelable(boot);
             if (applicationInfo.permission != null) {
                 applicationInfo.permission = applicationInfo.permission.intern();
             }
@@ -7305,19 +7305,19 @@
             // We don't serialize the "owner" package and the application info object for each of
             // these components, in order to save space and to avoid circular dependencies while
             // serialization. We need to fix them all up here.
-            dest.readParcelableList(permissions, boot, android.content.pm.PackageParser.Permission.class);
+            dest.readParcelableList(permissions, boot);
             fixupOwner(permissions);
-            dest.readParcelableList(permissionGroups, boot, android.content.pm.PackageParser.PermissionGroup.class);
+            dest.readParcelableList(permissionGroups, boot);
             fixupOwner(permissionGroups);
-            dest.readParcelableList(activities, boot, android.content.pm.PackageParser.Activity.class);
+            dest.readParcelableList(activities, boot);
             fixupOwner(activities);
-            dest.readParcelableList(receivers, boot, android.content.pm.PackageParser.Activity.class);
+            dest.readParcelableList(receivers, boot);
             fixupOwner(receivers);
-            dest.readParcelableList(providers, boot, android.content.pm.PackageParser.Provider.class);
+            dest.readParcelableList(providers, boot);
             fixupOwner(providers);
-            dest.readParcelableList(services, boot, android.content.pm.PackageParser.Service.class);
+            dest.readParcelableList(services, boot);
             fixupOwner(services);
-            dest.readParcelableList(instrumentation, boot, android.content.pm.PackageParser.Instrumentation.class);
+            dest.readParcelableList(instrumentation, boot);
             fixupOwner(instrumentation);
 
             dest.readStringList(requestedPermissions);
@@ -7327,10 +7327,10 @@
             protectedBroadcasts = dest.createStringArrayList();
             internStringArrayList(protectedBroadcasts);
 
-            parentPackage = dest.readParcelable(boot, android.content.pm.PackageParser.Package.class);
+            parentPackage = dest.readParcelable(boot);
 
             childPackages = new ArrayList<>();
-            dest.readParcelableList(childPackages, boot, android.content.pm.PackageParser.Package.class);
+            dest.readParcelableList(childPackages, boot);
             if (childPackages.size() == 0) {
                 childPackages = null;
             }
@@ -7364,7 +7364,7 @@
             }
 
             preferredActivityFilters = new ArrayList<>();
-            dest.readParcelableList(preferredActivityFilters, boot, android.content.pm.PackageParser.ActivityIntentInfo.class);
+            dest.readParcelableList(preferredActivityFilters, boot);
             if (preferredActivityFilters.size() == 0) {
                 preferredActivityFilters = null;
             }
@@ -7385,7 +7385,7 @@
             }
             mSharedUserLabel = dest.readInt();
 
-            mSigningDetails = dest.readParcelable(boot, android.content.pm.PackageParser.SigningDetails.class);
+            mSigningDetails = dest.readParcelable(boot);
 
             mPreferredOrder = dest.readInt();
 
@@ -7397,19 +7397,19 @@
 
 
             configPreferences = new ArrayList<>();
-            dest.readParcelableList(configPreferences, boot, android.content.pm.ConfigurationInfo.class);
+            dest.readParcelableList(configPreferences, boot);
             if (configPreferences.size() == 0) {
                 configPreferences = null;
             }
 
             reqFeatures = new ArrayList<>();
-            dest.readParcelableList(reqFeatures, boot, android.content.pm.FeatureInfo.class);
+            dest.readParcelableList(reqFeatures, boot);
             if (reqFeatures.size() == 0) {
                 reqFeatures = null;
             }
 
             featureGroups = new ArrayList<>();
-            dest.readParcelableList(featureGroups, boot, android.content.pm.FeatureGroupInfo.class);
+            dest.readParcelableList(featureGroups, boot);
             if (featureGroups.size() == 0) {
                 featureGroups = null;
             }
@@ -7806,13 +7806,13 @@
         private Permission(Parcel in) {
             super(in);
             final ClassLoader boot = Object.class.getClassLoader();
-            info = in.readParcelable(boot, android.content.pm.PermissionInfo.class);
+            info = in.readParcelable(boot);
             if (info.group != null) {
                 info.group = info.group.intern();
             }
 
             tree = (in.readInt() == 1);
-            group = in.readParcelable(boot, android.content.pm.PackageParser.PermissionGroup.class);
+            group = in.readParcelable(boot);
         }
 
         public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Permission>() {
@@ -7867,7 +7867,7 @@
 
         private PermissionGroup(Parcel in) {
             super(in);
-            info = in.readParcelable(Object.class.getClassLoader(), android.content.pm.PermissionGroupInfo.class);
+            info = in.readParcelable(Object.class.getClassLoader());
         }
 
         public static final Parcelable.Creator CREATOR = new Parcelable.Creator<PermissionGroup>() {
@@ -8160,7 +8160,7 @@
 
         private Activity(Parcel in) {
             super(in);
-            info = in.readParcelable(Object.class.getClassLoader(), android.content.pm.ActivityInfo.class);
+            info = in.readParcelable(Object.class.getClassLoader());
             mHasMaxAspectRatio = in.readBoolean();
             mHasMinAspectRatio = in.readBoolean();
 
@@ -8254,7 +8254,7 @@
 
         private Service(Parcel in) {
             super(in);
-            info = in.readParcelable(Object.class.getClassLoader(), android.content.pm.ServiceInfo.class);
+            info = in.readParcelable(Object.class.getClassLoader());
 
             for (ServiceIntentInfo aii : intents) {
                 aii.service = this;
@@ -8344,7 +8344,7 @@
 
         private Provider(Parcel in) {
             super(in);
-            info = in.readParcelable(Object.class.getClassLoader(), android.content.pm.ProviderInfo.class);
+            info = in.readParcelable(Object.class.getClassLoader());
             syncable = (in.readInt() == 1);
 
             for (ProviderIntentInfo aii : intents) {
@@ -8436,7 +8436,7 @@
 
         private Instrumentation(Parcel in) {
             super(in);
-            info = in.readParcelable(Object.class.getClassLoader(), android.content.pm.InstrumentationInfo.class);
+            info = in.readParcelable(Object.class.getClassLoader());
 
             if (info.targetPackage != null) {
                 info.targetPackage = info.targetPackage.intern();
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 7696cbe..78984bd 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -174,7 +174,7 @@
 
         // Register for user-related events
         IntentFilter userFilter = new IntentFilter();
-        sdFilter.addAction(Intent.ACTION_USER_REMOVED);
+        userFilter.addAction(Intent.ACTION_USER_REMOVED);
         mContext.registerReceiver(mUserRemovedReceiver, userFilter, null, handler);
     }
 
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 43a4b17..f153566 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -136,8 +136,8 @@
         mName = parcel.readString8();
         mVersion = parcel.readLong();
         mType = parcel.readInt();
-        mDeclaringPackage = parcel.readParcelable(null, android.content.pm.VersionedPackage.class);
-        mDependentPackages = parcel.readArrayList(null, android.content.pm.VersionedPackage.class);
+        mDeclaringPackage = parcel.readParcelable(null);
+        mDependentPackages = parcel.readArrayList(null);
         mDependencies = parcel.createTypedArrayList(SharedLibraryInfo.CREATOR);
         mIsNative = parcel.readBoolean();
     }
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 7d4f7ec..613fb84 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -2182,7 +2182,7 @@
         mUserId = source.readInt();
         mId = source.readString8();
         mPackageName = source.readString8();
-        mActivity = source.readParcelable(cl, android.content.ComponentName.class);
+        mActivity = source.readParcelable(cl);
         mFlags = source.readInt();
         mIconResId = source.readInt();
         mLastChangedTimestamp = source.readLong();
@@ -2192,7 +2192,7 @@
             return; // key information only.
         }
 
-        mIcon = source.readParcelable(cl, android.graphics.drawable.Icon.class);
+        mIcon = source.readParcelable(cl);
         mTitle = source.readCharSequence();
         mTitleResId = source.readInt();
         mText = source.readCharSequence();
@@ -2202,7 +2202,7 @@
         mIntents = source.readParcelableArray(cl, Intent.class);
         mIntentPersistableExtrases = source.readParcelableArray(cl, PersistableBundle.class);
         mRank = source.readInt();
-        mExtras = source.readParcelable(cl, android.os.PersistableBundle.class);
+        mExtras = source.readParcelable(cl);
         mBitmapPath = source.readString8();
 
         mIconResName = source.readString8();
@@ -2221,7 +2221,7 @@
         }
 
         mPersons = source.readParcelableArray(cl, Person.class);
-        mLocusId = source.readParcelable(cl, android.content.LocusId.class);
+        mLocusId = source.readParcelable(cl);
         mIconUri = source.readString8();
         mStartingThemeResName = source.readString8();
         mExcludedSurfaces = source.readInt();
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 7dbfd08..be0d934 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -704,8 +704,8 @@
         }
 
         private ShareShortcutInfo(@NonNull Parcel in) {
-            mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader(), android.content.pm.ShortcutInfo.class);
-            mTargetComponent = in.readParcelable(ComponentName.class.getClassLoader(), android.content.ComponentName.class);
+            mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader());
+            mTargetComponent = in.readParcelable(ComponentName.class.getClassLoader());
         }
 
         @NonNull
diff --git a/core/java/android/content/pm/ShortcutQueryWrapper.java b/core/java/android/content/pm/ShortcutQueryWrapper.java
index 64337d8..c613441 100644
--- a/core/java/android/content/pm/ShortcutQueryWrapper.java
+++ b/core/java/android/content/pm/ShortcutQueryWrapper.java
@@ -143,7 +143,7 @@
         List<LocusId> locusIds = null;
         if ((flg & 0x8) != 0) {
             locusIds = new ArrayList<>();
-            in.readParcelableList(locusIds, LocusId.class.getClassLoader(), android.content.LocusId.class);
+            in.readParcelableList(locusIds, LocusId.class.getClassLoader());
         }
         ComponentName activity = (flg & 0x10) == 0 ? null
                 : (ComponentName) in.readTypedObject(ComponentName.CREATOR);
diff --git a/core/java/android/content/pm/VerifierInfo.java b/core/java/android/content/pm/VerifierInfo.java
index 868bb9c..3e69ff5 100644
--- a/core/java/android/content/pm/VerifierInfo.java
+++ b/core/java/android/content/pm/VerifierInfo.java
@@ -59,7 +59,7 @@
 
     private VerifierInfo(Parcel source) {
         packageName = source.readString();
-        publicKey = (PublicKey) source.readSerializable(java.security.PublicKey.class.getClassLoader(), java.security.PublicKey.class);
+        publicKey = (PublicKey) source.readSerializable();
     }
 
     @Override
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index 23cae4c..ddab207 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -1408,7 +1408,7 @@
         this.processes = in.readHashMap(boot);
         this.metaData = in.readBundle(boot);
         this.volumeUuid = sForInternedString.unparcel(in);
-        this.signingDetails = in.readParcelable(boot, android.content.pm.SigningDetails.class);
+        this.signingDetails = in.readParcelable(boot);
         this.mPath = in.readString();
         this.queriesIntents = in.createTypedArrayList(Intent.CREATOR);
         this.queriesPackages = sForInternedStringList.unparcel(in);
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index f336672..e02eb7c 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -3519,7 +3519,7 @@
 
             ArraySet<PublicKey> keys = new ArraySet<>(M);
             for (int j = 0; j < M; ++j) {
-                PublicKey pk = (PublicKey) in.readSerializable(java.security.PublicKey.class.getClassLoader(), java.security.PublicKey.class);
+                PublicKey pk = (PublicKey) in.readSerializable();
                 keys.add(pk);
             }
 
diff --git a/core/java/android/content/pm/parsing/ParsingUtils.java b/core/java/android/content/pm/parsing/ParsingUtils.java
index 6dfb268..cce984e 100644
--- a/core/java/android/content/pm/parsing/ParsingUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingUtils.java
@@ -138,7 +138,7 @@
             final List<Pair<String, ParsedIntentInfo>> list = new ArrayList<>(size);
             for (int i = 0; i < size; ++i) {
                 list.add(Pair.create(source.readString(), source.readParcelable(
-                        ParsedIntentInfoImpl.class.getClassLoader(), android.content.pm.parsing.component.ParsedIntentInfo.class)));
+                        ParsedIntentInfoImpl.class.getClassLoader())));
             }
 
             return list;
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionImpl.java b/core/java/android/content/pm/parsing/component/ParsedPermissionImpl.java
index 45038cf..2145e44 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermissionImpl.java
+++ b/core/java/android/content/pm/parsing/component/ParsedPermissionImpl.java
@@ -116,7 +116,7 @@
         this.requestRes = in.readInt();
         this.protectionLevel = in.readInt();
         this.tree = in.readBoolean();
-        this.parsedPermissionGroup = in.readParcelable(boot, android.content.pm.parsing.component.ParsedPermissionGroup.class);
+        this.parsedPermissionGroup = in.readParcelable(boot);
         this.knownCerts = sForStringSet.unparcel(in);
     }
 
diff --git a/core/java/android/graphics/fonts/FontUpdateRequest.java b/core/java/android/graphics/fonts/FontUpdateRequest.java
index dae09f0..cda1638 100644
--- a/core/java/android/graphics/fonts/FontUpdateRequest.java
+++ b/core/java/android/graphics/fonts/FontUpdateRequest.java
@@ -235,7 +235,7 @@
             public Family createFromParcel(Parcel source) {
                 String familyName = source.readString8();
                 List<Font> fonts = source.readParcelableList(
-                        new ArrayList<>(), Font.class.getClassLoader(), android.graphics.fonts.FontUpdateRequest.Font.class);
+                        new ArrayList<>(), Font.class.getClassLoader());
                 return new Family(familyName, fonts);
             }
 
@@ -379,9 +379,9 @@
 
     protected FontUpdateRequest(Parcel in) {
         mType = in.readInt();
-        mFd = in.readParcelable(ParcelFileDescriptor.class.getClassLoader(), android.os.ParcelFileDescriptor.class);
+        mFd = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
         mSignature = in.readBlob();
-        mFontFamily = in.readParcelable(FontConfig.FontFamily.class.getClassLoader(), android.graphics.fonts.FontUpdateRequest.Family.class);
+        mFontFamily = in.readParcelable(FontConfig.FontFamily.class.getClassLoader());
     }
 
     public @Type int getType() {
diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java
index 0c03948..e6b762a 100644
--- a/core/java/android/hardware/biometrics/PromptInfo.java
+++ b/core/java/android/hardware/biometrics/PromptInfo.java
@@ -65,7 +65,7 @@
         mAuthenticators = in.readInt();
         mDisallowBiometricsIfPolicyExists = in.readBoolean();
         mReceiveSystemEvents = in.readBoolean();
-        mAllowedSensorIds = in.readArrayList(Integer.class.getClassLoader(), java.lang.Integer.class);
+        mAllowedSensorIds = in.readArrayList(Integer.class.getClassLoader());
         mAllowBackgroundAuthentication = in.readBoolean();
         mIgnoreEnrollmentState = in.readBoolean();
     }
diff --git a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
index 1490ea1..f365ee6 100644
--- a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
+++ b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
@@ -60,7 +60,7 @@
         sensorStrength = in.readInt();
         maxEnrollmentsPerUser = in.readInt();
         componentInfo = new ArrayList<>();
-        in.readList(componentInfo, ComponentInfoInternal.class.getClassLoader(), android.hardware.biometrics.ComponentInfoInternal.class);
+        in.readList(componentInfo, ComponentInfoInternal.class.getClassLoader());
         resetLockoutRequiresHardwareAuthToken = in.readBoolean();
         resetLockoutRequiresChallenge = in.readBoolean();
     }
diff --git a/core/java/android/hardware/face/FaceAuthenticationFrame.java b/core/java/android/hardware/face/FaceAuthenticationFrame.java
index a53aad7..f39d634 100644
--- a/core/java/android/hardware/face/FaceAuthenticationFrame.java
+++ b/core/java/android/hardware/face/FaceAuthenticationFrame.java
@@ -46,7 +46,7 @@
     }
 
     private FaceAuthenticationFrame(@NonNull Parcel source) {
-        mData = source.readParcelable(FaceDataFrame.class.getClassLoader(), android.hardware.face.FaceDataFrame.class);
+        mData = source.readParcelable(FaceDataFrame.class.getClassLoader());
     }
 
     @Override
diff --git a/core/java/android/hardware/face/FaceEnrollFrame.java b/core/java/android/hardware/face/FaceEnrollFrame.java
index bbccee2..822a579 100644
--- a/core/java/android/hardware/face/FaceEnrollFrame.java
+++ b/core/java/android/hardware/face/FaceEnrollFrame.java
@@ -73,9 +73,9 @@
     }
 
     private FaceEnrollFrame(@NonNull Parcel source) {
-        mCell = source.readParcelable(FaceEnrollCell.class.getClassLoader(), android.hardware.face.FaceEnrollCell.class);
+        mCell = source.readParcelable(FaceEnrollCell.class.getClassLoader());
         mStage = source.readInt();
-        mData = source.readParcelable(FaceDataFrame.class.getClassLoader(), android.hardware.face.FaceDataFrame.class);
+        mData = source.readParcelable(FaceDataFrame.class.getClassLoader());
     }
 
     @Override
diff --git a/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.java b/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.java
index 310ebe9..78cca96 100644
--- a/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.java
+++ b/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.java
@@ -81,7 +81,7 @@
                     int monitoringType = source.readInt();
                     int monitoringStatus = source.readInt();
                     int sourceTechnologies = source.readInt();
-                    Location location = source.readParcelable(classLoader, android.location.Location.class);
+                    Location location = source.readParcelable(classLoader);
 
                     return new GeofenceHardwareMonitorEvent(
                             monitoringType,
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 93573d1..afcb6fc 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -54,6 +54,7 @@
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
+import android.annotation.AnyThread;
 import android.annotation.CallSuper;
 import android.annotation.DrawableRes;
 import android.annotation.IntDef;
@@ -83,6 +84,7 @@
 import android.os.IBinder;
 import android.os.ResultReceiver;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.os.Trace;
 import android.provider.Settings;
 import android.text.InputType;
@@ -302,6 +304,44 @@
     static final boolean DEBUG = false;
 
     /**
+     * Key for a boolean value that tells whether {@link InputMethodService} is responsible for
+     * rendering the back button and the IME switcher button or not when the gestural navigation is
+     * enabled.
+     *
+     * <p>This sysprop is just ignored when the gestural navigation mode is not enabled.</p>
+     *
+     * <p>
+     * To avoid complexity that is not necessary for production, you always need to reboot the
+     * device after modifying this flag as follows:
+     * <pre>
+     * $ adb root
+     * $ adb shell setprop persist.sys.ime.can_render_gestural_nav_buttons true
+     * $ adb reboot
+     * </pre>
+     * </p>
+     */
+    private static final String PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS =
+            "persist.sys.ime.can_render_gestural_nav_buttons";
+
+    /**
+     * Returns whether {@link InputMethodService} is responsible for rendering the back button and
+     * the IME switcher button or not when the gestural navigation is enabled.
+     *
+     * <p>This method is supposed to be used with an assumption that the same value is returned in
+     * other processes. It is developers' responsibility for rebooting the device when the sysprop
+     * is modified.</p>
+     *
+     * @return {@code true} if {@link InputMethodService} is responsible for rendering the back
+     * button and the IME switcher button when the gestural navigation is enabled.
+     *
+     * @hide
+     */
+    @AnyThread
+    public static boolean canImeRenderGesturalNavButtons() {
+        return SystemProperties.getBoolean(PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS, false);
+    }
+
+    /**
      * Allows the system to optimize the back button affordance based on the presence of software
      * keyboard.
      *
diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java
index 1c4089c..37425ff 100644
--- a/core/java/android/net/InterfaceConfiguration.java
+++ b/core/java/android/net/InterfaceConfiguration.java
@@ -160,7 +160,6 @@
         }
     }
 
-    @SuppressWarnings("UnsafeParcelApi")
     public static final @android.annotation.NonNull Creator<InterfaceConfiguration> CREATOR = new Creator<
             InterfaceConfiguration>() {
         public InterfaceConfiguration createFromParcel(Parcel in) {
diff --git a/core/java/android/net/InternalNetworkUpdateRequest.java b/core/java/android/net/InternalNetworkUpdateRequest.java
index 6f09383..f42c4b7 100644
--- a/core/java/android/net/InternalNetworkUpdateRequest.java
+++ b/core/java/android/net/InternalNetworkUpdateRequest.java
@@ -17,7 +17,6 @@
 package android.net;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -27,7 +26,7 @@
 public final class InternalNetworkUpdateRequest implements Parcelable {
     @NonNull
     private final StaticIpConfiguration mIpConfig;
-    @Nullable
+    @NonNull
     private final NetworkCapabilities mNetworkCapabilities;
 
     @NonNull
@@ -37,20 +36,16 @@
 
     @NonNull
     public NetworkCapabilities getNetworkCapabilities() {
-        return mNetworkCapabilities == null
-                ? null : new NetworkCapabilities(mNetworkCapabilities);
+        return new NetworkCapabilities(mNetworkCapabilities);
     }
 
     /** @hide */
     public InternalNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig,
-            @Nullable final NetworkCapabilities networkCapabilities) {
+            @NonNull final NetworkCapabilities networkCapabilities) {
         Objects.requireNonNull(ipConfig);
+        Objects.requireNonNull(networkCapabilities);
         mIpConfig = new StaticIpConfiguration(ipConfig);
-        if (null == networkCapabilities) {
-            mNetworkCapabilities = null;
-        } else {
-            mNetworkCapabilities = new NetworkCapabilities(networkCapabilities);
-        }
+        mNetworkCapabilities = new NetworkCapabilities(networkCapabilities);
     }
 
     private InternalNetworkUpdateRequest(@NonNull final Parcel source) {
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index 596f431..ab1f542 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -142,8 +142,8 @@
     }
 
     private NetworkPolicy(Parcel source) {
-        template = source.readParcelable(null, android.net.NetworkTemplate.class);
-        cycleRule = source.readParcelable(null, android.util.RecurrenceRule.class);
+        template = source.readParcelable(null);
+        cycleRule = source.readParcelable(null);
         warningBytes = source.readLong();
         limitBytes = source.readLong();
         lastWarningSnooze = source.readLong();
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 2ced056..1ae1b05 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -41,6 +41,7 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.net.NetworkUtilsInternal;
 import com.android.internal.net.VpnConfig;
 
@@ -50,6 +51,7 @@
 import java.net.InetAddress;
 import java.net.Socket;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -471,6 +473,13 @@
         }
     }
 
+    private static void checkNonPrefixBytes(@NonNull InetAddress address, int prefixLength) {
+        final IpPrefix prefix = new IpPrefix(address, prefixLength);
+        if (!prefix.getAddress().equals(address)) {
+            throw new IllegalArgumentException("Bad address");
+        }
+    }
+
     /**
      * Helper class to create a VPN interface. This class should be always
      * used within the scope of the outer {@link VpnService}.
@@ -481,9 +490,9 @@
 
         private final VpnConfig mConfig = new VpnConfig();
         @UnsupportedAppUsage
-        private final List<LinkAddress> mAddresses = new ArrayList<LinkAddress>();
+        private final List<LinkAddress> mAddresses = new ArrayList<>();
         @UnsupportedAppUsage
-        private final List<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
+        private final List<RouteInfo> mRoutes = new ArrayList<>();
 
         public Builder() {
             mConfig.user = VpnService.this.getClass().getName();
@@ -555,7 +564,6 @@
                 throw new IllegalArgumentException("Bad address");
             }
             mAddresses.add(new LinkAddress(address, prefixLength));
-            mConfig.updateAllowedFamilies(address);
             return this;
         }
 
@@ -579,28 +587,68 @@
          * Add a network route to the VPN interface. Both IPv4 and IPv6
          * routes are supported.
          *
+         * If a route with the same destination is already present, its type will be updated.
+         *
+         * @throws IllegalArgumentException if the route is invalid.
+         */
+        @NonNull
+        private Builder addRoute(@NonNull IpPrefix prefix, int type) {
+            check(prefix.getAddress(), prefix.getPrefixLength());
+
+            final RouteInfo newRoute = new RouteInfo(prefix, /* gateway */
+                    null, /* interface */ null, type);
+
+            final int index = findRouteIndexByDestination(newRoute);
+
+            if (index == -1) {
+                mRoutes.add(newRoute);
+            } else {
+                mRoutes.set(index, newRoute);
+            }
+
+            return this;
+        }
+
+        /**
+         * Add a network route to the VPN interface. Both IPv4 and IPv6
+         * routes are supported.
+         *
          * Adding a route implicitly allows traffic from that address family
          * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
          *
+         * Calling this method overrides previous calls to {@link #excludeRoute} for the same
+         * destination.
+         *
+         * If multiple routes match the packet destination, route with the longest prefix takes
+         * precedence.
+         *
          * @throws IllegalArgumentException if the route is invalid.
          */
         @NonNull
         public Builder addRoute(@NonNull InetAddress address, int prefixLength) {
-            check(address, prefixLength);
+            checkNonPrefixBytes(address, prefixLength);
 
-            int offset = prefixLength / 8;
-            byte[] bytes = address.getAddress();
-            if (offset < bytes.length) {
-                for (bytes[offset] <<= prefixLength % 8; offset < bytes.length; ++offset) {
-                    if (bytes[offset] != 0) {
-                        throw new IllegalArgumentException("Bad address");
-                    }
-                }
-            }
-            mRoutes.add(new RouteInfo(new IpPrefix(address, prefixLength), null, null,
-                RouteInfo.RTN_UNICAST));
-            mConfig.updateAllowedFamilies(address);
-            return this;
+            return addRoute(new IpPrefix(address, prefixLength), RouteInfo.RTN_UNICAST);
+        }
+
+        /**
+         * Add a network route to the VPN interface. Both IPv4 and IPv6
+         * routes are supported.
+         *
+         * Adding a route implicitly allows traffic from that address family
+         * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
+         *
+         * Calling this method overrides previous calls to {@link #excludeRoute} for the same
+         * destination.
+         *
+         * If multiple routes match the packet destination, route with the longest prefix takes
+         * precedence.
+         *
+         * @throws IllegalArgumentException if the route is invalid.
+         */
+        @NonNull
+        public Builder addRoute(@NonNull IpPrefix prefix) {
+            return addRoute(prefix, RouteInfo.RTN_UNICAST);
         }
 
         /**
@@ -611,6 +659,12 @@
          * Adding a route implicitly allows traffic from that address family
          * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
          *
+         * Calling this method overrides previous calls to {@link #excludeRoute} for the same
+         * destination.
+         *
+         * If multiple routes match the packet destination, route with the longest prefix takes
+         * precedence.
+         *
          * @throws IllegalArgumentException if the route is invalid.
          * @see #addRoute(InetAddress, int)
          */
@@ -620,6 +674,23 @@
         }
 
         /**
+         * Exclude a network route from the VPN interface. Both IPv4 and IPv6
+         * routes are supported.
+         *
+         * Calling this method overrides previous calls to {@link #addRoute} for the same
+         * destination.
+         *
+         * If multiple routes match the packet destination, route with the longest prefix takes
+         * precedence.
+         *
+         * @throws IllegalArgumentException if the route is invalid.
+         */
+        @NonNull
+        public Builder excludeRoute(@NonNull IpPrefix prefix) {
+            return addRoute(prefix, RouteInfo.RTN_THROW);
+        }
+
+        /**
          * Add a DNS server to the VPN connection. Both IPv4 and IPv6
          * addresses are supported. If none is set, the DNS servers of
          * the default network will be used.
@@ -900,5 +971,23 @@
                 throw new IllegalStateException(e);
             }
         }
+
+        private int findRouteIndexByDestination(RouteInfo route) {
+            for (int i = 0; i < mRoutes.size(); i++) {
+                if (mRoutes.get(i).getDestination().equals(route.getDestination())) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        /**
+         * Method for testing, to observe mRoutes while builder is being used.
+         * @hide
+         */
+        @VisibleForTesting
+        public List<RouteInfo> routes() {
+            return Collections.unmodifiableList(mRoutes);
+        }
     }
 }
diff --git a/core/java/android/net/vcn/VcnConfig.java b/core/java/android/net/vcn/VcnConfig.java
index fd3fe37..caab152 100644
--- a/core/java/android/net/vcn/VcnConfig.java
+++ b/core/java/android/net/vcn/VcnConfig.java
@@ -173,7 +173,7 @@
             new Parcelable.Creator<VcnConfig>() {
                 @NonNull
                 public VcnConfig createFromParcel(Parcel in) {
-                    return new VcnConfig((PersistableBundle) in.readParcelable(null, android.os.PersistableBundle.class));
+                    return new VcnConfig((PersistableBundle) in.readParcelable(null));
                 }
 
                 @NonNull
diff --git a/core/java/android/net/vcn/VcnNetworkPolicyResult.java b/core/java/android/net/vcn/VcnNetworkPolicyResult.java
index fca084a..14e70cf 100644
--- a/core/java/android/net/vcn/VcnNetworkPolicyResult.java
+++ b/core/java/android/net/vcn/VcnNetworkPolicyResult.java
@@ -114,7 +114,7 @@
     public static final @NonNull Creator<VcnNetworkPolicyResult> CREATOR =
             new Creator<VcnNetworkPolicyResult>() {
                 public VcnNetworkPolicyResult createFromParcel(Parcel in) {
-                    return new VcnNetworkPolicyResult(in.readBoolean(), in.readParcelable(null, android.net.NetworkCapabilities.class));
+                    return new VcnNetworkPolicyResult(in.readBoolean(), in.readParcelable(null));
                 }
 
                 public VcnNetworkPolicyResult[] newArray(int size) {
diff --git a/core/java/android/net/vcn/VcnTransportInfo.java b/core/java/android/net/vcn/VcnTransportInfo.java
index 5c47b28..25a2574 100644
--- a/core/java/android/net/vcn/VcnTransportInfo.java
+++ b/core/java/android/net/vcn/VcnTransportInfo.java
@@ -146,7 +146,7 @@
             new Creator<VcnTransportInfo>() {
                 public VcnTransportInfo createFromParcel(Parcel in) {
                     final int subId = in.readInt();
-                    final WifiInfo wifiInfo = in.readParcelable(null, android.net.wifi.WifiInfo.class);
+                    final WifiInfo wifiInfo = in.readParcelable(null);
 
                     // If all fields are their null values, return null TransportInfo to avoid
                     // leaking information about this being a VCN Network (instead of macro
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
index 2b5305d..b0d4f3b 100644
--- a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
@@ -106,7 +106,7 @@
     public static final @NonNull Creator<VcnUnderlyingNetworkPolicy> CREATOR =
             new Creator<VcnUnderlyingNetworkPolicy>() {
                 public VcnUnderlyingNetworkPolicy createFromParcel(Parcel in) {
-                    return new VcnUnderlyingNetworkPolicy(in.readParcelable(null, android.net.vcn.VcnNetworkPolicyResult.class));
+                    return new VcnUnderlyingNetworkPolicy(in.readParcelable(null));
                 }
 
                 public VcnUnderlyingNetworkPolicy[] newArray(int size) {
diff --git a/core/java/android/nfc/BeamShareData.java b/core/java/android/nfc/BeamShareData.java
index 6a40f98..ed3b74a 100644
--- a/core/java/android/nfc/BeamShareData.java
+++ b/core/java/android/nfc/BeamShareData.java
@@ -47,13 +47,13 @@
         @Override
         public BeamShareData createFromParcel(Parcel source) {
             Uri[] uris = null;
-            NdefMessage msg = source.readParcelable(NdefMessage.class.getClassLoader(), android.nfc.NdefMessage.class);
+            NdefMessage msg = source.readParcelable(NdefMessage.class.getClassLoader());
             int numUris = source.readInt();
             if (numUris > 0) {
                 uris = new Uri[numUris];
                 source.readTypedArray(uris, Uri.CREATOR);
             }
-            UserHandle userHandle = source.readParcelable(UserHandle.class.getClassLoader(), android.os.UserHandle.class);
+            UserHandle userHandle = source.readParcelable(UserHandle.class.getClassLoader());
             int flags = source.readInt();
 
             return new BeamShareData(msg, uris, userHandle, flags);
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 72fb4ae..c62df40 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -654,7 +654,7 @@
         arg1 = source.readInt();
         arg2 = source.readInt();
         if (source.readInt() != 0) {
-            obj = source.readParcelable(getClass().getClassLoader(), java.lang.Object.class);
+            obj = source.readParcelable(getClass().getClassLoader());
         }
         when = source.readLong();
         data = source.readBundle();
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 70aaa5e..ebbfe47 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -2993,7 +2993,7 @@
          *     should be removed.
          */
         public ViolationInfo(Parcel in, boolean unsetGatheringBit) {
-            mViolation = (Violation) in.readSerializable(android.os.strictmode.Violation.class.getClassLoader(), android.os.strictmode.Violation.class);
+            mViolation = (Violation) in.readSerializable();
             int binderStackSize = in.readInt();
             for (int i = 0; i < binderStackSize; i++) {
                 StackTraceElement[] traceElements = new StackTraceElement[in.readInt()];
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index ae37a71..5de4556 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -576,7 +576,7 @@
         private final int mRepeatIndex;
 
         Composed(@NonNull Parcel in) {
-            this(in.readArrayList(VibrationEffectSegment.class.getClassLoader(), android.os.vibrator.VibrationEffectSegment.class), in.readInt());
+            this(in.readArrayList(VibrationEffectSegment.class.getClassLoader()), in.readInt());
         }
 
         Composed(@NonNull VibrationEffectSegment segment) {
diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java
index 5271c4d..189e454 100644
--- a/core/java/android/os/VibratorInfo.java
+++ b/core/java/android/os/VibratorInfo.java
@@ -69,7 +69,7 @@
         mPwlePrimitiveDurationMax = in.readInt();
         mPwleSizeMax = in.readInt();
         mQFactor = in.readFloat();
-        mFrequencyMapping = in.readParcelable(VibratorInfo.class.getClassLoader(), android.os.VibratorInfo.FrequencyMapping.class);
+        mFrequencyMapping = in.readParcelable(VibratorInfo.class.getClassLoader());
     }
 
     /**
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index e899f77..6588b57 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -130,7 +130,7 @@
         int numChains = in.readInt();
         if (numChains > 0) {
             mChains = new ArrayList<>(numChains);
-            in.readParcelableList(mChains, WorkChain.class.getClassLoader(), android.os.WorkSource.WorkChain.class);
+            in.readParcelableList(mChains, WorkChain.class.getClassLoader());
         } else {
             mChains = null;
         }
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 8ee52c2..b78bb25 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -168,7 +168,7 @@
         mExternallyManaged = in.readInt() != 0;
         mAllowMassStorage = in.readInt() != 0;
         mMaxFileSize = in.readLong();
-        mOwner = in.readParcelable(null, android.os.UserHandle.class);
+        mOwner = in.readParcelable(null);
         if (in.readInt() != 0) {
             mUuid = StorageManager.convert(in.readString8());
         } else {
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index 0e32a78..5814bac 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -56,4 +56,6 @@
             in AndroidFuture<String> callback);
     void getUnusedAppCount(
             in AndroidFuture callback);
+    void selfRevokePermissions(in String packageName, in List<String> permissions,
+            in AndroidFuture callback);
 }
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 90b5e51..8e5581b 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -76,6 +76,8 @@
 
     List<SplitPermissionInfoParcelable> getSplitPermissions();
 
+    void selfRevokePermissions(String packageName, in List<String> permissions);
+
     void startOneTimePermissionSession(String packageName, int userId, long timeout,
             int importanceToResetTimer, int importanceToKeepSessionAlive);
 
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index a0788e7..47cd107 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -817,4 +817,40 @@
             }
         });
     }
+
+    /**
+     * Triggers the revocation of one or more permissions for a package, under the following
+     * conditions:
+     * <ul>
+     * <li>The package {@code packageName} must be under the same UID as the calling process
+     * (typically, the target package is the calling package).
+     * <li>Each permission in {@code permissions} must be granted to the package
+     * {@code packageName}.
+     * <li>Each permission in {@code permissions} must be a runtime permission.
+     * </ul>
+     * <p>
+     * For every permission in {@code permissions}, the entire permission group it belongs to will
+     * be revoked. This revocation happens asynchronously and kills all processes running in the
+     * same UID as {@code packageName}. It will be triggered once it is safe to do so.
+     *
+     * @param packageName The name of the package for which the permissions will be revoked.
+     * @param permissions List of permissions to be revoked.
+     *
+     * @see Context#selfRevokePermissions(Collection)
+     *
+     * @hide
+     */
+    public void selfRevokePermissions(@NonNull String packageName,
+            @NonNull List<String> permissions) {
+        mRemoteService.postAsync(service -> {
+            AndroidFuture<Void> future = new AndroidFuture<>();
+            service.selfRevokePermissions(packageName, permissions, future);
+            return future;
+        }).whenComplete((result, err) -> {
+            if (err != null) {
+                Log.e(TAG, "Failed to self revoke " + String.join(",", permissions)
+                        + " for package " + packageName, err);
+            }
+        });
+    }
 }
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index c979303..dcbab62 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -324,6 +324,27 @@
             @NonNull Consumer<String> callback) {
         throw new AbstractMethodError("Must be overridden in implementing class");
     }
+
+    /**
+     * Triggers the revocation of one or more permissions for a package. This should only be called
+     * at the request of {@code packageName}.
+     * <p>
+     * For every permission in {@code permissions}, the entire permission group it belongs to will
+     * be revoked. This revocation happens asynchronously and kills all processes running in the
+     * same UID as {@code packageName}. It will be triggered once it is safe to do so.
+     *
+     * @param packageName The name of the package for which the permissions will be revoked.
+     * @param permissions List of permissions to be revoked.
+     * @param callback Callback waiting for operation to be complete.
+     *
+     * @see PermissionManager#selfRevokePermissions(java.util.Collection)
+     */
+    @BinderThread
+    public void onSelfRevokePermissions(@NonNull String packageName,
+            @NonNull List<String> permissions, @NonNull Runnable callback) {
+        throw new AbstractMethodError("Must be overridden in implementing class");
+    }
+
     /**
      * Get a user-readable sentence, describing the set of privileges that are to be granted to a
      * companion app managing a device of the given profile.
@@ -646,6 +667,20 @@
                     callback.completeExceptionally(t);
                 }
             }
+
+            @Override
+            public void selfRevokePermissions(@NonNull String packageName,
+                    @NonNull List<String> permissions, @NonNull AndroidFuture callback) {
+                try {
+                    enforceSomePermissionsGrantedToCaller(
+                            Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
+                    Objects.requireNonNull(callback);
+                    onSelfRevokePermissions(packageName, permissions,
+                            () -> callback.complete(null));
+                } catch (Throwable t) {
+                    callback.completeExceptionally(t);
+                }
+            }
         };
     }
 }
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 4f22876..13941dc 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -68,6 +68,7 @@
 import com.android.internal.util.CollectionUtils;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
@@ -561,6 +562,19 @@
     }
 
     /**
+     * @see Context#selfRevokePermissions(Collection)
+     * @hide
+     */
+    public void selfRevokePermissions(@NonNull Collection<String> permissions) {
+        try {
+            mPermissionManager.selfRevokePermissions(mContext.getPackageName(),
+                    new ArrayList<String>(permissions));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Gets the state flags associated with a permission.
      *
      * @param packageName the package name for which to get the flags
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index 9d0c8d8..67249be 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -231,9 +231,9 @@
     }
 
     private PrintJobInfo(@NonNull Parcel parcel) {
-        mId = parcel.readParcelable(null, android.print.PrintJobId.class);
+        mId = parcel.readParcelable(null);
         mLabel = parcel.readString();
-        mPrinterId = parcel.readParcelable(null, android.print.PrinterId.class);
+        mPrinterId = parcel.readParcelable(null);
         mPrinterName = parcel.readString();
         mState = parcel.readInt();
         mAppId = parcel.readInt();
@@ -247,8 +247,8 @@
                 mPageRanges[i] = (PageRange) parcelables[i];
             }
         }
-        mAttributes = (PrintAttributes) parcel.readParcelable(null, android.print.PrintAttributes.class);
-        mDocumentInfo = (PrintDocumentInfo) parcel.readParcelable(null, android.print.PrintDocumentInfo.class);
+        mAttributes = (PrintAttributes) parcel.readParcelable(null);
+        mDocumentInfo = (PrintDocumentInfo) parcel.readParcelable(null);
         mProgress = parcel.readFloat();
         mStatus = parcel.readCharSequence();
         mStatusRes = parcel.readInt();
diff --git a/core/java/android/print/PrinterId.java b/core/java/android/print/PrinterId.java
index 284e122..25260c4 100644
--- a/core/java/android/print/PrinterId.java
+++ b/core/java/android/print/PrinterId.java
@@ -48,7 +48,7 @@
     }
 
     private PrinterId(@NonNull Parcel parcel) {
-        mServiceName = Preconditions.checkNotNull((ComponentName) parcel.readParcelable(null, android.content.ComponentName.class));
+        mServiceName = Preconditions.checkNotNull((ComponentName) parcel.readParcelable(null));
         mLocalId = Preconditions.checkNotNull(parcel.readString());
     }
 
diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java
index 2f93e40..8e03e3e 100644
--- a/core/java/android/print/PrinterInfo.java
+++ b/core/java/android/print/PrinterInfo.java
@@ -270,15 +270,15 @@
     private PrinterInfo(Parcel parcel) {
         // mName can be null due to unchecked set in Builder.setName and status can be invalid
         // due to unchecked set in Builder.setStatus, hence we can only check mId for a valid state
-        mId = checkPrinterId((PrinterId) parcel.readParcelable(null, android.print.PrinterId.class));
+        mId = checkPrinterId((PrinterId) parcel.readParcelable(null));
         mName = checkName(parcel.readString());
         mStatus = checkStatus(parcel.readInt());
         mDescription = parcel.readString();
-        mCapabilities = parcel.readParcelable(null, android.print.PrinterCapabilitiesInfo.class);
+        mCapabilities = parcel.readParcelable(null);
         mIconResourceId = parcel.readInt();
         mHasCustomPrinterIcon = parcel.readByte() != 0;
         mCustomPrinterIconGen = parcel.readInt();
-        mInfoIntent = parcel.readParcelable(null, android.app.PendingIntent.class);
+        mInfoIntent = parcel.readParcelable(null);
     }
 
     @Override
diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java
index 3479557..0c1b61d 100644
--- a/core/java/android/printservice/PrintServiceInfo.java
+++ b/core/java/android/printservice/PrintServiceInfo.java
@@ -76,7 +76,7 @@
     public PrintServiceInfo(Parcel parcel) {
         mId = parcel.readString();
         mIsEnabled = parcel.readByte() != 0;
-        mResolveInfo = parcel.readParcelable(null, android.content.pm.ResolveInfo.class);
+        mResolveInfo = parcel.readParcelable(null);
         mSettingsActivityName = parcel.readString();
         mAddPrintersActivityName = parcel.readString();
         mAdvancedPrintOptionsActivityName = parcel.readString();
diff --git a/core/java/android/service/autofill/BatchUpdates.java b/core/java/android/service/autofill/BatchUpdates.java
index c996cc0..8eeecc2 100644
--- a/core/java/android/service/autofill/BatchUpdates.java
+++ b/core/java/android/service/autofill/BatchUpdates.java
@@ -205,7 +205,7 @@
                     builder.transformChild(ids[i], values[i]);
                 }
             }
-            final RemoteViews updates = parcel.readParcelable(null, android.widget.RemoteViews.class);
+            final RemoteViews updates = parcel.readParcelable(null);
             if (updates != null) {
                 builder.updateTemplate(updates);
             }
diff --git a/core/java/android/service/autofill/CompositeUserData.java b/core/java/android/service/autofill/CompositeUserData.java
index 55ac5a5..92952cb 100644
--- a/core/java/android/service/autofill/CompositeUserData.java
+++ b/core/java/android/service/autofill/CompositeUserData.java
@@ -197,8 +197,8 @@
                     // Always go through the builder to ensure the data ingested by
                     // the system obeys the contract of the builder to avoid attacks
                     // using specially crafted parcels.
-                    final UserData genericUserData = parcel.readParcelable(null, android.service.autofill.UserData.class);
-                    final UserData packageUserData = parcel.readParcelable(null, android.service.autofill.UserData.class);
+                    final UserData genericUserData = parcel.readParcelable(null);
+                    final UserData packageUserData = parcel.readParcelable(null);
                     return new CompositeUserData(genericUserData, packageUserData);
                 }
 
diff --git a/core/java/android/service/autofill/CustomDescription.java b/core/java/android/service/autofill/CustomDescription.java
index 690cd06..f3f912b 100644
--- a/core/java/android/service/autofill/CustomDescription.java
+++ b/core/java/android/service/autofill/CustomDescription.java
@@ -437,7 +437,7 @@
             // Always go through the builder to ensure the data ingested by
             // the system obeys the contract of the builder to avoid attacks
             // using specially crafted parcels.
-            final RemoteViews parentPresentation = parcel.readParcelable(null, android.widget.RemoteViews.class);
+            final RemoteViews parentPresentation = parcel.readParcelable(null);
             if (parentPresentation == null) return null;
 
             final Builder builder = new Builder(parentPresentation);
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index 86341a9..8539bf5 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -913,10 +913,10 @@
     public static final @NonNull Creator<Dataset> CREATOR = new Creator<Dataset>() {
         @Override
         public Dataset createFromParcel(Parcel parcel) {
-            final RemoteViews presentation = parcel.readParcelable(null, android.widget.RemoteViews.class);
-            final InlinePresentation inlinePresentation = parcel.readParcelable(null, android.service.autofill.InlinePresentation.class);
+            final RemoteViews presentation = parcel.readParcelable(null);
+            final InlinePresentation inlinePresentation = parcel.readParcelable(null);
             final InlinePresentation inlineTooltipPresentation =
-                    parcel.readParcelable(null, android.service.autofill.InlinePresentation.class);
+                    parcel.readParcelable(null);
             final ArrayList<AutofillId> ids =
                     parcel.createTypedArrayList(AutofillId.CREATOR);
             final ArrayList<AutofillValue> values =
@@ -929,8 +929,8 @@
                     parcel.createTypedArrayList(InlinePresentation.CREATOR);
             final ArrayList<DatasetFieldFilter> filters =
                     parcel.createTypedArrayList(DatasetFieldFilter.CREATOR);
-            final ClipData fieldContent = parcel.readParcelable(null, android.content.ClipData.class);
-            final IntentSender authentication = parcel.readParcelable(null, android.content.IntentSender.class);
+            final ClipData fieldContent = parcel.readParcelable(null);
+            final IntentSender authentication = parcel.readParcelable(null);
             final String datasetId = parcel.readString();
 
             // Always go through the builder to ensure the data ingested by
@@ -1014,7 +1014,7 @@
 
             @Override
             public DatasetFieldFilter createFromParcel(Parcel parcel) {
-                return new DatasetFieldFilter((Pattern) parcel.readSerializable(java.util.regex.Pattern.class.getClassLoader(), java.util.regex.Pattern.class));
+                return new DatasetFieldFilter((Pattern) parcel.readSerializable());
             }
 
             @Override
diff --git a/core/java/android/service/autofill/DateTransformation.java b/core/java/android/service/autofill/DateTransformation.java
index df5ed4da..7340857 100644
--- a/core/java/android/service/autofill/DateTransformation.java
+++ b/core/java/android/service/autofill/DateTransformation.java
@@ -114,8 +114,8 @@
             new Parcelable.Creator<DateTransformation>() {
         @Override
         public DateTransformation createFromParcel(Parcel parcel) {
-            return new DateTransformation(parcel.readParcelable(null, android.view.autofill.AutofillId.class),
-                    (DateFormat) parcel.readSerializable(android.icu.text.DateFormat.class.getClassLoader(), android.icu.text.DateFormat.class));
+            return new DateTransformation(parcel.readParcelable(null),
+                    (DateFormat) parcel.readSerializable());
         }
 
         @Override
diff --git a/core/java/android/service/autofill/DateValueSanitizer.java b/core/java/android/service/autofill/DateValueSanitizer.java
index c7d5b79..6f7808e 100644
--- a/core/java/android/service/autofill/DateValueSanitizer.java
+++ b/core/java/android/service/autofill/DateValueSanitizer.java
@@ -111,7 +111,7 @@
             new Parcelable.Creator<DateValueSanitizer>() {
         @Override
         public DateValueSanitizer createFromParcel(Parcel parcel) {
-            return new DateValueSanitizer((DateFormat) parcel.readSerializable(android.icu.text.DateFormat.class.getClassLoader(), android.icu.text.DateFormat.class));
+            return new DateValueSanitizer((DateFormat) parcel.readSerializable());
         }
 
         @Override
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index 43bd410..af846b6 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -384,7 +384,7 @@
         byte flg = in.readByte();
         int id = in.readInt();
         List<FillContext> fillContexts = new ArrayList<>();
-        in.readParcelableList(fillContexts, FillContext.class.getClassLoader(), android.service.autofill.FillContext.class);
+        in.readParcelableList(fillContexts, FillContext.class.getClassLoader());
         Bundle clientState = (flg & 0x4) == 0 ? null : in.readBundle();
         int flags = in.readInt();
         InlineSuggestionsRequest inlineSuggestionsRequest = (flg & 0x10) == 0 ? null : (InlineSuggestionsRequest) in.readTypedObject(InlineSuggestionsRequest.CREATOR);
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index d94988e..970cb18 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -834,35 +834,35 @@
             // the system obeys the contract of the builder to avoid attacks
             // using specially crafted parcels.
             final Builder builder = new Builder();
-            final ParceledListSlice<Dataset> datasetSlice = parcel.readParcelable(null, android.content.pm.ParceledListSlice.class);
+            final ParceledListSlice<Dataset> datasetSlice = parcel.readParcelable(null);
             final List<Dataset> datasets = (datasetSlice != null) ? datasetSlice.getList() : null;
             final int datasetCount = (datasets != null) ? datasets.size() : 0;
             for (int i = 0; i < datasetCount; i++) {
                 builder.addDataset(datasets.get(i));
             }
-            builder.setSaveInfo(parcel.readParcelable(null, android.service.autofill.SaveInfo.class));
-            builder.setClientState(parcel.readParcelable(null, android.os.Bundle.class));
+            builder.setSaveInfo(parcel.readParcelable(null));
+            builder.setClientState(parcel.readParcelable(null));
 
             // Sets authentication state.
             final AutofillId[] authenticationIds = parcel.readParcelableArray(null,
                     AutofillId.class);
-            final IntentSender authentication = parcel.readParcelable(null, android.content.IntentSender.class);
-            final RemoteViews presentation = parcel.readParcelable(null, android.widget.RemoteViews.class);
-            final InlinePresentation inlinePresentation = parcel.readParcelable(null, android.service.autofill.InlinePresentation.class);
-            final InlinePresentation inlineTooltipPresentation = parcel.readParcelable(null, android.service.autofill.InlinePresentation.class);
+            final IntentSender authentication = parcel.readParcelable(null);
+            final RemoteViews presentation = parcel.readParcelable(null);
+            final InlinePresentation inlinePresentation = parcel.readParcelable(null);
+            final InlinePresentation inlineTooltipPresentation = parcel.readParcelable(null);
             if (authenticationIds != null) {
                 builder.setAuthentication(authenticationIds, authentication, presentation,
                         inlinePresentation, inlineTooltipPresentation);
             }
-            final RemoteViews header = parcel.readParcelable(null, android.widget.RemoteViews.class);
+            final RemoteViews header = parcel.readParcelable(null);
             if (header != null) {
                 builder.setHeader(header);
             }
-            final RemoteViews footer = parcel.readParcelable(null, android.widget.RemoteViews.class);
+            final RemoteViews footer = parcel.readParcelable(null);
             if (footer != null) {
                 builder.setFooter(footer);
             }
-            final UserData userData = parcel.readParcelable(null, android.service.autofill.UserData.class);
+            final UserData userData = parcel.readParcelable(null);
             if (userData != null) {
                 builder.setUserData(userData);
             }
diff --git a/core/java/android/service/autofill/ImageTransformation.java b/core/java/android/service/autofill/ImageTransformation.java
index af82205..e317159 100644
--- a/core/java/android/service/autofill/ImageTransformation.java
+++ b/core/java/android/service/autofill/ImageTransformation.java
@@ -247,7 +247,7 @@
             new Parcelable.Creator<ImageTransformation>() {
         @Override
         public ImageTransformation createFromParcel(Parcel parcel) {
-            final AutofillId id = parcel.readParcelable(null, android.view.autofill.AutofillId.class);
+            final AutofillId id = parcel.readParcelable(null);
 
             final Pattern[] regexs = (Pattern[]) parcel.readSerializable();
             final int[] resIds = parcel.createIntArray();
diff --git a/core/java/android/service/autofill/NegationValidator.java b/core/java/android/service/autofill/NegationValidator.java
index 85cd981..d626845 100644
--- a/core/java/android/service/autofill/NegationValidator.java
+++ b/core/java/android/service/autofill/NegationValidator.java
@@ -68,7 +68,7 @@
             new Parcelable.Creator<NegationValidator>() {
         @Override
         public NegationValidator createFromParcel(Parcel parcel) {
-            return new NegationValidator(parcel.readParcelable(null, android.service.autofill.InternalValidator.class));
+            return new NegationValidator(parcel.readParcelable(null));
         }
 
         @Override
diff --git a/core/java/android/service/autofill/RegexValidator.java b/core/java/android/service/autofill/RegexValidator.java
index 4c58590..00c4347 100644
--- a/core/java/android/service/autofill/RegexValidator.java
+++ b/core/java/android/service/autofill/RegexValidator.java
@@ -96,8 +96,8 @@
             new Parcelable.Creator<RegexValidator>() {
         @Override
         public RegexValidator createFromParcel(Parcel parcel) {
-            return new RegexValidator(parcel.readParcelable(null, android.view.autofill.AutofillId.class),
-                    (Pattern) parcel.readSerializable(java.util.regex.Pattern.class.getClassLoader(), java.util.regex.Pattern.class));
+            return new RegexValidator(parcel.readParcelable(null),
+                    (Pattern) parcel.readSerializable());
         }
 
         @Override
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 5fe1d4f..8edfde8 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -888,14 +888,14 @@
                 builder.setOptionalIds(optionalIds);
             }
 
-            builder.setNegativeAction(parcel.readInt(), parcel.readParcelable(null, android.content.IntentSender.class));
+            builder.setNegativeAction(parcel.readInt(), parcel.readParcelable(null));
             builder.setPositiveAction(parcel.readInt());
             builder.setDescription(parcel.readCharSequence());
-            final CustomDescription customDescripton = parcel.readParcelable(null, android.service.autofill.CustomDescription.class);
+            final CustomDescription customDescripton = parcel.readParcelable(null);
             if (customDescripton != null) {
                 builder.setCustomDescription(customDescripton);
             }
-            final InternalValidator validator = parcel.readParcelable(null, android.service.autofill.InternalValidator.class);
+            final InternalValidator validator = parcel.readParcelable(null);
             if (validator != null) {
                 builder.setValidator(validator);
             }
@@ -909,7 +909,7 @@
                     builder.addSanitizer(sanitizers[i], autofillIds);
                 }
             }
-            final AutofillId triggerId = parcel.readParcelable(null, android.view.autofill.AutofillId.class);
+            final AutofillId triggerId = parcel.readParcelable(null);
             if (triggerId != null) {
                 builder.setTriggerId(triggerId);
             }
diff --git a/core/java/android/service/autofill/TextValueSanitizer.java b/core/java/android/service/autofill/TextValueSanitizer.java
index 46c18b2..5bafa7a 100644
--- a/core/java/android/service/autofill/TextValueSanitizer.java
+++ b/core/java/android/service/autofill/TextValueSanitizer.java
@@ -119,7 +119,7 @@
             new Parcelable.Creator<TextValueSanitizer>() {
         @Override
         public TextValueSanitizer createFromParcel(Parcel parcel) {
-            return new TextValueSanitizer((Pattern) parcel.readSerializable(java.util.regex.Pattern.class.getClassLoader(), java.util.regex.Pattern.class), parcel.readString());
+            return new TextValueSanitizer((Pattern) parcel.readSerializable(), parcel.readString());
         }
 
         @Override
diff --git a/core/java/android/service/contentcapture/ActivityEvent.java b/core/java/android/service/contentcapture/ActivityEvent.java
index d286942..74a7355 100644
--- a/core/java/android/service/contentcapture/ActivityEvent.java
+++ b/core/java/android/service/contentcapture/ActivityEvent.java
@@ -149,7 +149,7 @@
         @Override
         @NonNull
         public ActivityEvent createFromParcel(@NonNull Parcel parcel) {
-            final ComponentName componentName = parcel.readParcelable(null, android.content.ComponentName.class);
+            final ComponentName componentName = parcel.readParcelable(null);
             final int eventType = parcel.readInt();
             return new ActivityEvent(componentName, eventType);
         }
diff --git a/core/java/android/service/contentcapture/SnapshotData.java b/core/java/android/service/contentcapture/SnapshotData.java
index f72624d..bf469b4 100644
--- a/core/java/android/service/contentcapture/SnapshotData.java
+++ b/core/java/android/service/contentcapture/SnapshotData.java
@@ -51,8 +51,8 @@
 
     SnapshotData(@NonNull Parcel parcel) {
         mAssistData = parcel.readBundle();
-        mAssistStructure = parcel.readParcelable(null, android.app.assist.AssistStructure.class);
-        mAssistContent = parcel.readParcelable(null, android.app.assist.AssistContent.class);
+        mAssistStructure = parcel.readParcelable(null);
+        mAssistContent = parcel.readParcelable(null);
     }
 
     /**
diff --git a/core/java/android/service/games/GameService.java b/core/java/android/service/games/GameService.java
index b79c055..105c2aa 100644
--- a/core/java/android/service/games/GameService.java
+++ b/core/java/android/service/games/GameService.java
@@ -38,10 +38,23 @@
  * when a game session should begin. It is always kept running by the system.
  * Because of this it should be kept as lightweight as possible.
  *
- * Heavy weight operations (such as showing UI) should be implemented in the
+ * <p>Heavyweight operations (such as showing UI) should be implemented in the
  * associated {@link GameSessionService} when a game session is taking place. Its
  * implementation should run in a separate process from the {@link GameService}.
  *
+ * <p>To extend this class, you must declare the service in your manifest file with
+ * the {@link android.Manifest.permission#BIND_GAME_SERVICE} permission
+ * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:
+ * <pre>
+ * &lt;service android:name=".GameService"
+ *          android:label="&#64;string/service_name"
+ *          android:permission="android.permission.BIND_GAME_SERVICE">
+ *     &lt;intent-filter>
+ *         &lt;action android:name="android.service.games.GameService" />
+ *     &lt;/intent-filter>
+ * &lt;/service>
+ * </pre>
+ *
  * @hide
  */
 @SystemApi
@@ -90,7 +103,7 @@
 
     @Override
     @Nullable
-    public IBinder onBind(@Nullable Intent intent) {
+    public final IBinder onBind(@Nullable Intent intent) {
         if (ACTION_GAME_SERVICE.equals(intent.getAction())) {
             return mInterface.asBinder();
         }
diff --git a/core/java/android/service/games/GameSessionService.java b/core/java/android/service/games/GameSessionService.java
index a2c8870..c1a3eb5 100644
--- a/core/java/android/service/games/GameSessionService.java
+++ b/core/java/android/service/games/GameSessionService.java
@@ -73,7 +73,7 @@
 
     @Override
     @Nullable
-    public IBinder onBind(@Nullable Intent intent) {
+    public final IBinder onBind(@Nullable Intent intent) {
         if (intent == null) {
             return null;
         }
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index 267b2ff..4f324f9 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -114,7 +114,7 @@
     }
 
     public Condition(Parcel source) {
-        this((Uri)source.readParcelable(Condition.class.getClassLoader(), android.net.Uri.class),
+        this((Uri)source.readParcelable(Condition.class.getClassLoader()),
                 source.readString(),
                 source.readString(),
                 source.readString(),
diff --git a/core/java/android/service/notification/ConversationChannelWrapper.java b/core/java/android/service/notification/ConversationChannelWrapper.java
index 35b6bad..3d0984c 100644
--- a/core/java/android/service/notification/ConversationChannelWrapper.java
+++ b/core/java/android/service/notification/ConversationChannelWrapper.java
@@ -40,10 +40,10 @@
     public ConversationChannelWrapper() {}
 
     protected ConversationChannelWrapper(Parcel in) {
-        mNotificationChannel = in.readParcelable(NotificationChannel.class.getClassLoader(), android.app.NotificationChannel.class);
+        mNotificationChannel = in.readParcelable(NotificationChannel.class.getClassLoader());
         mGroupLabel = in.readCharSequence();
         mParentChannelLabel = in.readCharSequence();
-        mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader(), android.content.pm.ShortcutInfo.class);
+        mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader());
         mPkg = in.readStringNoHelper();
         mUid = in.readInt();
     }
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index ae39d3d..c945954 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1763,7 +1763,7 @@
             mImportanceExplanation = in.readCharSequence(); // may be null
             mRankingScore = in.readFloat();
             mOverrideGroupKey = in.readString(); // may be null
-            mChannel = in.readParcelable(cl, android.app.NotificationChannel.class); // may be null
+            mChannel = in.readParcelable(cl); // may be null
             mOverridePeople = in.createStringArrayList();
             mSnoozeCriteria = in.createTypedArrayList(SnoozeCriterion.CREATOR);
             mShowBadge = in.readBoolean();
@@ -1776,7 +1776,7 @@
             mCanBubble = in.readBoolean();
             mIsTextChanged = in.readBoolean();
             mIsConversation = in.readBoolean();
-            mShortcutInfo = in.readParcelable(cl, android.content.pm.ShortcutInfo.class);
+            mShortcutInfo = in.readParcelable(cl);
             mRankingAdjustment = in.readInt();
             mIsBubble = in.readBoolean();
         }
diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java
index a853714..c64f4c46 100644
--- a/core/java/android/service/notification/NotificationRankingUpdate.java
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -30,7 +30,7 @@
     }
 
     public NotificationRankingUpdate(Parcel in) {
-        mRankingMap = in.readParcelable(getClass().getClassLoader(), android.service.notification.NotificationListenerService.RankingMap.class);
+        mRankingMap = in.readParcelable(getClass().getClassLoader());
     }
 
     public NotificationListenerService.RankingMap getRankingMap() {
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 8834cee..c1d5a28 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -211,7 +211,7 @@
         allowCallsFrom = source.readInt();
         allowMessagesFrom = source.readInt();
         user = source.readInt();
-        manualRule = source.readParcelable(null, android.service.notification.ZenModeConfig.ZenRule.class);
+        manualRule = source.readParcelable(null);
         final int len = source.readInt();
         if (len > 0) {
             final String[] ids = new String[len];
@@ -1800,10 +1800,10 @@
                 name = source.readString();
             }
             zenMode = source.readInt();
-            conditionId = source.readParcelable(null, android.net.Uri.class);
-            condition = source.readParcelable(null, android.service.notification.Condition.class);
-            component = source.readParcelable(null, android.content.ComponentName.class);
-            configurationActivity = source.readParcelable(null, android.content.ComponentName.class);
+            conditionId = source.readParcelable(null);
+            condition = source.readParcelable(null);
+            component = source.readParcelable(null);
+            configurationActivity = source.readParcelable(null);
             if (source.readInt() == 1) {
                 id = source.readString();
             }
@@ -1811,7 +1811,7 @@
             if (source.readInt() == 1) {
                 enabler = source.readString();
             }
-            zenPolicy = source.readParcelable(null, android.service.notification.ZenPolicy.class);
+            zenPolicy = source.readParcelable(null);
             modified = source.readInt() == 1;
             pkg = source.readString();
         }
diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java
index a04f073..ed3a9ac 100644
--- a/core/java/android/service/notification/ZenPolicy.java
+++ b/core/java/android/service/notification/ZenPolicy.java
@@ -804,8 +804,8 @@
         @Override
         public ZenPolicy createFromParcel(Parcel source) {
             ZenPolicy policy = new ZenPolicy();
-            policy.mPriorityCategories = source.readArrayList(Integer.class.getClassLoader(), java.lang.Integer.class);
-            policy.mVisualEffects = source.readArrayList(Integer.class.getClassLoader(), java.lang.Integer.class);
+            policy.mPriorityCategories = source.readArrayList(Integer.class.getClassLoader());
+            policy.mVisualEffects = source.readArrayList(Integer.class.getClassLoader());
             policy.mPriorityCalls = source.readInt();
             policy.mPriorityMessages = source.readInt();
             policy.mConversationSenders = source.readInt();
diff --git a/core/java/android/service/quickaccesswallet/GetWalletCardsResponse.java b/core/java/android/service/quickaccesswallet/GetWalletCardsResponse.java
index 7471a4f..0551e27 100644
--- a/core/java/android/service/quickaccesswallet/GetWalletCardsResponse.java
+++ b/core/java/android/service/quickaccesswallet/GetWalletCardsResponse.java
@@ -63,7 +63,7 @@
     private static GetWalletCardsResponse readFromParcel(Parcel source) {
         int size = source.readInt();
         List<WalletCard> walletCards =
-                source.readParcelableList(new ArrayList<>(size), WalletCard.class.getClassLoader(), android.service.quickaccesswallet.WalletCard.class);
+                source.readParcelableList(new ArrayList<>(size), WalletCard.class.getClassLoader());
         int selectedIndex = source.readInt();
         return new GetWalletCardsResponse(walletCards, selectedIndex);
     }
diff --git a/core/java/android/service/settings/suggestions/Suggestion.java b/core/java/android/service/settings/suggestions/Suggestion.java
index 16622d7..3e63efb 100644
--- a/core/java/android/service/settings/suggestions/Suggestion.java
+++ b/core/java/android/service/settings/suggestions/Suggestion.java
@@ -120,9 +120,9 @@
         mId = in.readString();
         mTitle = in.readCharSequence();
         mSummary = in.readCharSequence();
-        mIcon = in.readParcelable(Icon.class.getClassLoader(), android.graphics.drawable.Icon.class);
+        mIcon = in.readParcelable(Icon.class.getClassLoader());
         mFlags = in.readInt();
-        mPendingIntent = in.readParcelable(PendingIntent.class.getClassLoader(), android.app.PendingIntent.class);
+        mPendingIntent = in.readParcelable(PendingIntent.class.getClassLoader());
     }
 
     public static final @android.annotation.NonNull Creator<Suggestion> CREATOR = new Creator<Suggestion>() {
diff --git a/core/java/android/service/timezone/TimeZoneProviderEvent.java b/core/java/android/service/timezone/TimeZoneProviderEvent.java
index f6433b7..7005281 100644
--- a/core/java/android/service/timezone/TimeZoneProviderEvent.java
+++ b/core/java/android/service/timezone/TimeZoneProviderEvent.java
@@ -141,7 +141,7 @@
                     int type = in.readInt();
                     long creationElapsedMillis = in.readLong();
                     TimeZoneProviderSuggestion suggestion =
-                            in.readParcelable(getClass().getClassLoader(), android.service.timezone.TimeZoneProviderSuggestion.class);
+                            in.readParcelable(getClass().getClassLoader());
                     String failureCause = in.readString8();
                     return new TimeZoneProviderEvent(
                             type, creationElapsedMillis, suggestion, failureCause);
diff --git a/core/java/android/service/timezone/TimeZoneProviderSuggestion.java b/core/java/android/service/timezone/TimeZoneProviderSuggestion.java
index 4841ac1..229fa26 100644
--- a/core/java/android/service/timezone/TimeZoneProviderSuggestion.java
+++ b/core/java/android/service/timezone/TimeZoneProviderSuggestion.java
@@ -100,7 +100,7 @@
                 public TimeZoneProviderSuggestion createFromParcel(Parcel in) {
                     @SuppressWarnings("unchecked")
                     ArrayList<String> timeZoneIds =
-                            (ArrayList<String>) in.readArrayList(null /* classLoader */, java.lang.String.class);
+                            (ArrayList<String>) in.readArrayList(null /* classLoader */);
                     long elapsedRealtimeMillis = in.readLong();
                     return new TimeZoneProviderSuggestion(timeZoneIds, elapsedRealtimeMillis);
                 }
diff --git a/core/java/android/speech/tts/Voice.java b/core/java/android/speech/tts/Voice.java
index 0d98a6c..7ffe5eb 100644
--- a/core/java/android/speech/tts/Voice.java
+++ b/core/java/android/speech/tts/Voice.java
@@ -84,7 +84,7 @@
 
     private Voice(Parcel in) {
         this.mName = in.readString();
-        this.mLocale = (Locale)in.readSerializable(java.util.Locale.class.getClassLoader(), java.util.Locale.class);
+        this.mLocale = (Locale)in.readSerializable();
         this.mQuality = in.readInt();
         this.mLatency = in.readInt();
         this.mRequiresNetworkConnection = (in.readByte() == 1);
diff --git a/core/java/android/telephony/SubscriptionPlan.java b/core/java/android/telephony/SubscriptionPlan.java
index fb2d771..d5ac436 100644
--- a/core/java/android/telephony/SubscriptionPlan.java
+++ b/core/java/android/telephony/SubscriptionPlan.java
@@ -99,7 +99,7 @@
     }
 
     private SubscriptionPlan(Parcel source) {
-        cycleRule = source.readParcelable(null, android.util.RecurrenceRule.class);
+        cycleRule = source.readParcelable(null);
         title = source.readCharSequence();
         summary = source.readCharSequence();
         dataLimitBytes = source.readLong();
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 9eaaa91..542de3f 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -131,6 +131,7 @@
                     mContext.getAttributionTag(), callback);
         } catch (RemoteException ex) {
             // system server crash
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -152,6 +153,7 @@
             mSubscriptionChangedListenerMap.remove(listener);
         } catch (RemoteException ex) {
             // system server crash
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -194,6 +196,7 @@
                     mContext.getAttributionTag(), callback);
         } catch (RemoteException ex) {
             // system server crash
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -216,6 +219,7 @@
             mOpportunisticSubscriptionChangedListenerMap.remove(listener);
         } catch (RemoteException ex) {
             // system server crash
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -304,6 +308,7 @@
             sRegistry.notifyCarrierNetworkChange(active);
         } catch (RemoteException ex) {
             // system server crash
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -329,6 +334,7 @@
             sRegistry.notifyCarrierNetworkChangeWithSubId(subscriptionId, active);
         } catch (RemoteException ex) {
             // system server crash
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -347,6 +353,7 @@
             sRegistry.notifyCallState(slotIndex, subId, state, incomingNumber);
         } catch (RemoteException ex) {
             // system server crash
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -364,6 +371,7 @@
             sRegistry.notifyCallStateForAllSubs(state, incomingNumber);
         } catch (RemoteException ex) {
             // system server crash
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -376,6 +384,7 @@
             sRegistry.notifySubscriptionInfoChanged();
         } catch (RemoteException ex) {
             // system server crash
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -388,6 +397,7 @@
             sRegistry.notifyOpportunisticSubscriptionInfoChanged();
         } catch (RemoteException ex) {
             // system server crash
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -404,6 +414,7 @@
             sRegistry.notifyServiceStateForPhoneId(slotIndex, subId, state);
         } catch (RemoteException ex) {
             // system server crash
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -421,6 +432,7 @@
             sRegistry.notifySignalStrengthForPhoneId(slotIndex, subId, signalStrength);
         } catch (RemoteException ex) {
             // system server crash
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -439,6 +451,7 @@
             sRegistry.notifyMessageWaitingChangedForPhoneId(slotIndex, subId, msgWaitingInd);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -454,6 +467,7 @@
             sRegistry.notifyCallForwardingChangedForSubscriber(subId, callForwardInd);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -469,6 +483,7 @@
             sRegistry.notifyDataActivityForSubscriber(subId, dataActivityType);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -490,6 +505,7 @@
                     slotIndex, subId, preciseState);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -508,6 +524,7 @@
             sRegistry.notifyCallQualityChanged(callQuality, slotIndex, subId, networkType);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -523,6 +540,7 @@
             sRegistry.notifyEmergencyNumberList(slotIndex, subId);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -538,6 +556,7 @@
             sRegistry.notifyOutgoingEmergencyCall(phoneId, subId, emergencyNumber);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -553,6 +572,7 @@
             sRegistry.notifyOutgoingEmergencySms(phoneId, subId, emergencyNumber);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -570,6 +590,7 @@
             sRegistry.notifyRadioPowerStateChanged(slotIndex, subId, radioPowerState);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -583,6 +604,7 @@
             sRegistry.notifyPhoneCapabilityChanged(phoneCapability);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -615,6 +637,7 @@
                     SIM_ACTIVATION_TYPE_DATA, activationState);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -634,6 +657,7 @@
                     SIM_ACTIVATION_TYPE_VOICE, activationState);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -651,6 +675,7 @@
             sRegistry.notifyUserMobileDataStateChangedForPhoneId(slotIndex, subId, state);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -669,6 +694,7 @@
             sRegistry.notifyDisplayInfoChanged(slotIndex, subscriptionId, telephonyDisplayInfo);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -683,6 +709,7 @@
             sRegistry.notifyImsDisconnectCause(subId, imsReasonInfo);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -698,6 +725,7 @@
             sRegistry.notifySrvccStateChanged(subId, state);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -721,6 +749,7 @@
                 foregroundCallPreciseState, backgroundCallPreciseState);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -741,6 +770,7 @@
             sRegistry.notifyDisconnectCause(slotIndex, subId, cause, preciseCause);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -755,6 +785,7 @@
             sRegistry.notifyCellLocationForSubscriber(subId, cellLocation);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -769,7 +800,7 @@
         try {
             sRegistry.notifyCellInfoForSubscriber(subId, cellInfo);
         } catch (RemoteException ex) {
-
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -781,7 +812,7 @@
         try {
             sRegistry.notifyActiveDataSubIdChanged(activeDataSubId);
         } catch (RemoteException ex) {
-
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -814,6 +845,7 @@
             sRegistry.notifyRegistrationFailed(slotIndex, subId, cellIdentity,
                     chosenPlmn, domain, causeCode, additionalCauseCode);
         } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -830,6 +862,7 @@
             sRegistry.notifyBarringInfoChanged(slotIndex, subId, barringInfo);
         } catch (RemoteException ex) {
             // system server crash
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -846,6 +879,7 @@
             sRegistry.notifyPhysicalChannelConfigForSubscriber(slotIndex, subId, configs);
         } catch (RemoteException ex) {
             // system server crash
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -862,6 +896,7 @@
             sRegistry.notifyDataEnabled(slotIndex, subId, enabled, reason);
         } catch (RemoteException ex) {
             // system server crash
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -880,6 +915,7 @@
                     allowedNetworkType);
         } catch (RemoteException ex) {
             // system process is dead
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -895,6 +931,7 @@
             sRegistry.notifyLinkCapacityEstimateChanged(slotIndex, subId, linkCapacityEstimateList);
         } catch (RemoteException ex) {
             // system server crash
+            throw ex.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index 3ee1a90..fee23f4 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -16,6 +16,9 @@
 
 package android.text;
 
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Canvas;
 import android.graphics.Paint;
@@ -85,6 +88,41 @@
     }
 
     /**
+     * Utility function to construct a BoringLayout instance.
+     *
+     * The spacing multiplier and additional amount spacing are not used by BoringLayout.
+     * {@link Layout#getSpacingMultiplier()} will return 1.0 and {@link Layout#getSpacingAdd()} will
+     * return 0.0.
+     *
+     * @param source the text to render
+     * @param paint the default paint for the layout
+     * @param outerWidth the wrapping width for the text
+     * @param align whether to left, right, or center the text
+     * @param metrics {@code #Metrics} instance that contains information about FontMetrics and
+     *                line width
+     * @param includePad set whether to include extra space beyond font ascent and descent which is
+     *                   needed to avoid clipping in some scripts
+     * @param ellipsize whether to ellipsize the text if width of the text is longer than the
+     *                  requested width
+     * @param ellipsizedWidth the width to which this Layout is ellipsizing. If {@code ellipsize} is
+     *                        {@code null}, or is {@link TextUtils.TruncateAt#MARQUEE} this value is
+     *                        not used, {@code outerWidth} is used instead
+     * @param useFallbackLineSpacing True for adjusting the line spacing based on fallback fonts.
+     *                              False for keeping the first font's line height. If some glyphs
+     *                              requires larger vertical spaces, by passing true to this
+     *                              argument, the layout increase the line height to fit all glyphs.
+     */
+    public static @NonNull BoringLayout make(
+            @NonNull CharSequence source, @NonNull TextPaint paint,
+            @IntRange(from = 0) int outerWidth,
+            @NonNull Alignment align, @NonNull BoringLayout.Metrics metrics,
+            boolean includePad, @NonNull TextUtils.TruncateAt ellipsize,
+            @IntRange(from = 0) int ellipsizedWidth, boolean useFallbackLineSpacing) {
+        return new BoringLayout(source, paint, outerWidth, align, 1f, 0f, metrics, includePad,
+                ellipsize, ellipsizedWidth, useFallbackLineSpacing);
+    }
+
+    /**
      * Returns a BoringLayout for the specified text, potentially reusing
      * this one if it is already suitable.  The caller must make sure that
      * no one is still using this Layout.
@@ -109,7 +147,61 @@
         mEllipsizedStart = 0;
         mEllipsizedCount = 0;
 
-        init(source, paint, align, metrics, includePad, true);
+        init(source, paint, align, metrics, includePad, true, false /* useFallbackLineSpacing */);
+        return this;
+    }
+
+    /**
+     * Returns a BoringLayout for the specified text, potentially reusing
+     * this one if it is already suitable.  The caller must make sure that
+     * no one is still using this Layout.
+     *
+     * The spacing multiplier and additional amount spacing are not used by BoringLayout.
+     * {@link Layout#getSpacingMultiplier()} will return 1.0 and {@link Layout#getSpacingAdd()} will
+     * return 0.0.
+     *
+     * @param source the text to render
+     * @param paint the default paint for the layout
+     * @param outerWidth the wrapping width for the text
+     * @param align whether to left, right, or center the text
+     * @param metrics {@code #Metrics} instance that contains information about FontMetrics and
+     *                line width
+     * @param includePad set whether to include extra space beyond font ascent and descent which is
+     *                   needed to avoid clipping in some scripts
+     * @param ellipsize whether to ellipsize the text if width of the text is longer than the
+     *                  requested width
+     * @param ellipsizedWidth the width to which this Layout is ellipsizing. If {@code ellipsize} is
+     *                        {@code null}, or is {@link TextUtils.TruncateAt#MARQUEE} this value is
+     *                        not used, {@code outerWidth} is used instead
+     * @param useFallbackLineSpacing True for adjusting the line spacing based on fallback fonts.
+     *                              False for keeping the first font's line height. If some glyphs
+     *                              requires larger vertical spaces, by passing true to this
+     *                              argument, the layout increase the line height to fit all glyphs.
+     */
+    public @NonNull BoringLayout replaceOrMake(@NonNull CharSequence source,
+            @NonNull TextPaint paint, @IntRange(from = 0) int outerWidth,
+            @NonNull Alignment align, @NonNull BoringLayout.Metrics metrics, boolean includePad,
+            @NonNull TextUtils.TruncateAt ellipsize, @IntRange(from = 0) int ellipsizedWidth,
+            boolean useFallbackLineSpacing) {
+        boolean trust;
+
+        if (ellipsize == null || ellipsize == TextUtils.TruncateAt.MARQUEE) {
+            replaceWith(source, paint, outerWidth, align, 1f, 0f);
+
+            mEllipsizedWidth = outerWidth;
+            mEllipsizedStart = 0;
+            mEllipsizedCount = 0;
+            trust = true;
+        } else {
+            replaceWith(TextUtils.ellipsize(source, paint, ellipsizedWidth, ellipsize, true, this),
+                    paint, outerWidth, align, 1f, 0f);
+
+            mEllipsizedWidth = ellipsizedWidth;
+            trust = false;
+        }
+
+        init(getText(), paint, align, metrics, includePad, trust,
+                useFallbackLineSpacing);
         return this;
     }
 
@@ -132,30 +224,13 @@
      *                  requested width
      * @param ellipsizedWidth the width to which this Layout is ellipsizing. If {@code ellipsize} is
      *                        {@code null}, or is {@link TextUtils.TruncateAt#MARQUEE} this value is
-     *                        not used, {@code outerwidth} is used instead
+     *                        not used, {@code outerWidth} is used instead
      */
     public BoringLayout replaceOrMake(CharSequence source, TextPaint paint, int outerWidth,
             Alignment align, float spacingMult, float spacingAdd, BoringLayout.Metrics metrics,
             boolean includePad, TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
-        boolean trust;
-
-        if (ellipsize == null || ellipsize == TextUtils.TruncateAt.MARQUEE) {
-            replaceWith(source, paint, outerWidth, align, spacingMult, spacingAdd);
-
-            mEllipsizedWidth = outerWidth;
-            mEllipsizedStart = 0;
-            mEllipsizedCount = 0;
-            trust = true;
-        } else {
-            replaceWith(TextUtils.ellipsize(source, paint, ellipsizedWidth, ellipsize, true, this),
-                    paint, outerWidth, align, spacingMult, spacingAdd);
-
-            mEllipsizedWidth = ellipsizedWidth;
-            trust = false;
-        }
-
-        init(getText(), paint, align, metrics, includePad, trust);
-        return this;
+        return replaceOrMake(source, paint, outerWidth, align, metrics,
+                includePad, ellipsize, ellipsizedWidth, false /* useFallbackLineSpacing */);
     }
 
     /**
@@ -178,7 +253,7 @@
         mEllipsizedStart = 0;
         mEllipsizedCount = 0;
 
-        init(source, paint, align, metrics, includePad, true);
+        init(source, paint, align, metrics, includePad, true, false /* useFallbackLineSpacing */);
     }
 
     /**
@@ -194,14 +269,46 @@
      * @param includePad set whether to include extra space beyond font ascent and descent which is
      *                   needed to avoid clipping in some scripts
      * @param ellipsize whether to ellipsize the text if width of the text is longer than the
-     *                  requested {@code outerwidth}
+     *                  requested {@code outerWidth}
      * @param ellipsizedWidth the width to which this Layout is ellipsizing. If {@code ellipsize} is
      *                        {@code null}, or is {@link TextUtils.TruncateAt#MARQUEE} this value is
-     *                        not used, {@code outerwidth} is used instead
+     *                        not used, {@code outerWidth} is used instead
      */
     public BoringLayout(CharSequence source, TextPaint paint, int outerWidth, Alignment align,
             float spacingMult, float spacingAdd, BoringLayout.Metrics metrics, boolean includePad,
             TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
+        this(source, paint, outerWidth, align, spacingMult, spacingAdd, metrics, includePad,
+                ellipsize, ellipsizedWidth, false /* fallbackLineSpacing */);
+    }
+
+    /**
+     *
+     * @param source the text to render
+     * @param paint the default paint for the layout
+     * @param outerWidth the wrapping width for the text
+     * @param align whether to left, right, or center the text
+     * @param spacingMult this value is no longer used by BoringLayout
+     * @param spacingAdd this value is no longer used by BoringLayout
+     * @param metrics {@code #Metrics} instance that contains information about FontMetrics and
+     *                line width
+     * @param includePad set whether to include extra space beyond font ascent and descent which is
+     *                   needed to avoid clipping in some scripts
+     * @param ellipsize whether to ellipsize the text if width of the text is longer than the
+     *                  requested {@code outerWidth}
+     * @param ellipsizedWidth the width to which this Layout is ellipsizing. If {@code ellipsize} is
+     *                        {@code null}, or is {@link TextUtils.TruncateAt#MARQUEE} this value is
+     *                        not used, {@code outerWidth} is used instead
+     * @param useFallbackLineSpacing True for adjusting the line spacing based on fallback fonts.
+     *                              False for keeping the first font's line height. If some glyphs
+     *                              requires larger vertical spaces, by passing true to this
+     *                              argument, the layout increase the line height to fit all glyphs.
+     */
+    public BoringLayout(
+            @NonNull CharSequence source, @NonNull TextPaint paint,
+            @IntRange(from = 0) int outerWidth, @NonNull Alignment align, float spacingMult,
+            float spacingAdd, @NonNull BoringLayout.Metrics metrics, boolean includePad,
+            @NonNull TextUtils.TruncateAt ellipsize, @IntRange(from = 0) int ellipsizedWidth,
+            boolean useFallbackLineSpacing) {
         /*
          * It is silly to have to call super() and then replaceWith(),
          * but we can't use "this" for the callback until the call to
@@ -224,11 +331,12 @@
             trust = false;
         }
 
-        init(getText(), paint, align, metrics, includePad, trust);
+        init(getText(), paint, align, metrics, includePad, trust, useFallbackLineSpacing);
     }
 
     /* package */ void init(CharSequence source, TextPaint paint, Alignment align,
-            BoringLayout.Metrics metrics, boolean includePad, boolean trustWidth) {
+            BoringLayout.Metrics metrics, boolean includePad, boolean trustWidth,
+            boolean useFallbackLineSpacing) {
         int spacing;
 
         if (source instanceof String && align == Layout.Alignment.ALIGN_NORMAL) {
@@ -260,7 +368,7 @@
             TextLine line = TextLine.obtain();
             line.set(paint, source, 0, source.length(), Layout.DIR_LEFT_TO_RIGHT,
                     Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null,
-                    mEllipsizedStart, mEllipsizedStart + mEllipsizedCount);
+                    mEllipsizedStart, mEllipsizedStart + mEllipsizedCount, useFallbackLineSpacing);
             mMax = (int) Math.ceil(line.metrics(null));
             TextLine.recycle(line);
         }
@@ -336,6 +444,27 @@
     @UnsupportedAppUsage
     public static Metrics isBoring(CharSequence text, TextPaint paint,
             TextDirectionHeuristic textDir, Metrics metrics) {
+        return isBoring(text, paint, textDir, false /* useFallbackLineSpacing */, metrics);
+    }
+
+    /**
+     * Returns null if not boring; the width, ascent, and descent in the
+     * provided Metrics object (or a new one if the provided one was null)
+     * if boring.
+     *
+     * @param text a text to be calculated text layout.
+     * @param paint a paint object used for styling.
+     * @param textDir a text direction.
+     * @param useFallbackLineSpacing True for adjusting the line spacing based on fallback fonts.
+     *                              False for keeping the first font's line height. If some glyphs
+     *                              requires larger vertical spaces, by passing true to this
+     *                              argument, the layout increase the line height to fit all glyphs.
+     * @param metrics the out metrics.
+     * @return metrics on success. null if text cannot be rendered by BoringLayout.
+     */
+    public static @Nullable Metrics isBoring(@NonNull CharSequence text, @NonNull TextPaint paint,
+            @NonNull TextDirectionHeuristic textDir, boolean useFallbackLineSpacing,
+            @Nullable Metrics metrics) {
         final int textLength = text.length();
         if (hasAnyInterestingChars(text, textLength)) {
            return null;  // There are some interesting characters. Not boring.
@@ -362,7 +491,8 @@
         line.set(paint, text, 0, textLength, Layout.DIR_LEFT_TO_RIGHT,
                 Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null,
                 0 /* ellipsisStart, 0 since text has not been ellipsized at this point */,
-                0 /* ellipsisEnd, 0 since text has not been ellipsized at this point */);
+                0 /* ellipsisEnd, 0 since text has not been ellipsized at this point */,
+                useFallbackLineSpacing);
         fm.width = (int) Math.ceil(line.metrics(fm));
         TextLine.recycle(line);
 
@@ -450,6 +580,11 @@
         return mEllipsizedWidth;
     }
 
+    @Override
+    public boolean isFallbackLineSpacingEnabled() {
+        return mUseFallbackLineSpacing;
+    }
+
     // Override draw so it will be faster.
     @Override
     public void draw(Canvas c, Path highlight, Paint highlightpaint,
@@ -471,6 +606,7 @@
 
     private String mDirect;
     private Paint mPaint;
+    private boolean mUseFallbackLineSpacing;
 
     /* package */ int mBottom, mDesc;   // for Direct
     private int mTopPadding, mBottomPadding;
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index 32b3bc6..2f7fb2f 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -143,9 +143,9 @@
         @Override
         public FontConfig createFromParcel(Parcel source) {
             List<FontFamily> families = source.readParcelableList(new ArrayList<>(),
-                    FontFamily.class.getClassLoader(), android.text.FontConfig.FontFamily.class);
+                    FontFamily.class.getClassLoader());
             List<Alias> aliases = source.readParcelableList(new ArrayList<>(),
-                    Alias.class.getClassLoader(), android.text.FontConfig.Alias.class);
+                    Alias.class.getClassLoader());
             long lastModifiedDate = source.readLong();
             int configVersion = source.readInt();
             return new FontConfig(families, aliases, lastModifiedDate, configVersion);
@@ -617,7 +617,7 @@
             @Override
             public FontFamily createFromParcel(Parcel source) {
                 List<Font> fonts = source.readParcelableList(
-                        new ArrayList<>(), Font.class.getClassLoader(), android.text.FontConfig.Font.class);
+                        new ArrayList<>(), Font.class.getClassLoader());
                 String name = source.readString8();
                 String langTags = source.readString8();
                 int variant = source.readInt();
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index da3e9b6..95adb77 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -591,7 +591,8 @@
             } else {
                 tl.set(paint, buf, start, end, dir, directions, hasTab, tabStops,
                         getEllipsisStart(lineNum),
-                        getEllipsisStart(lineNum) + getEllipsisCount(lineNum));
+                        getEllipsisStart(lineNum) + getEllipsisCount(lineNum),
+                        isFallbackLineSpacingEnabled());
                 if (justify) {
                     tl.justify(right - left - indentWidth);
                 }
@@ -960,6 +961,15 @@
     }
 
     /**
+     * Return true if the fallback line space is enabled in this Layout.
+     *
+     * @return true if the fallback line space is enabled. Otherwise returns false.
+     */
+    public boolean isFallbackLineSpacingEnabled() {
+        return false;
+    }
+
+    /**
      * Returns true if the character at offset and the preceding character
      * are at different run levels (and thus there's a split caret).
      * @param offset the offset
@@ -1231,7 +1241,8 @@
 
         TextLine tl = TextLine.obtain();
         tl.set(mPaint, mText, start, end, dir, directions, hasTab, tabStops,
-                getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line));
+                getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line),
+                isFallbackLineSpacingEnabled());
         float wid = tl.measure(offset - start, trailing, null);
         TextLine.recycle(tl);
 
@@ -1271,7 +1282,8 @@
 
         TextLine tl = TextLine.obtain();
         tl.set(mPaint, mText, start, end, dir, directions, hasTab, tabStops,
-                getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line));
+                getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line),
+                isFallbackLineSpacingEnabled());
         boolean[] trailings = primaryIsTrailingPreviousAllLineOffsets(line);
         if (!primary) {
             for (int offset = 0; offset < trailings.length; ++offset) {
@@ -1456,7 +1468,8 @@
         paint.setStartHyphenEdit(getStartHyphenEdit(line));
         paint.setEndHyphenEdit(getEndHyphenEdit(line));
         tl.set(paint, mText, start, end, dir, directions, hasTabs, tabStops,
-                getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line));
+                getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line),
+                isFallbackLineSpacingEnabled());
         if (isJustificationRequired(line)) {
             tl.justify(getJustifyWidth(line));
         }
@@ -1486,7 +1499,8 @@
         paint.setStartHyphenEdit(getStartHyphenEdit(line));
         paint.setEndHyphenEdit(getEndHyphenEdit(line));
         tl.set(paint, mText, start, end, dir, directions, hasTabs, tabStops,
-                getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line));
+                getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line),
+                isFallbackLineSpacingEnabled());
         if (isJustificationRequired(line)) {
             tl.justify(getJustifyWidth(line));
         }
@@ -1572,7 +1586,8 @@
         // XXX: we don't care about tabs as we just use TextLine#getOffsetToLeftRightOf here.
         tl.set(mPaint, mText, lineStartOffset, lineEndOffset, getParagraphDirection(line), dirs,
                 false, null,
-                getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line));
+                getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line),
+                isFallbackLineSpacingEnabled());
         final HorizontalMeasurementProvider horizontal =
                 new HorizontalMeasurementProvider(line, primary);
 
@@ -1828,7 +1843,8 @@
         TextLine tl = TextLine.obtain();
         // XXX: we don't care about tabs
         tl.set(mPaint, mText, lineStart, lineEnd, lineDir, directions, false, null,
-                getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line));
+                getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line),
+                isFallbackLineSpacingEnabled());
         caret = lineStart + tl.getOffsetToLeftRightOf(caret - lineStart, toLeft);
         TextLine.recycle(tl);
         return caret;
@@ -2202,7 +2218,8 @@
                 }
             }
             tl.set(paint, text, start, end, dir, directions, hasTabs, tabStops,
-                    0 /* ellipsisStart */, 0 /* ellipsisEnd */);
+                    0 /* ellipsisStart */, 0 /* ellipsisEnd */,
+                    false /* use fallback line spacing. unused */);
             return margin + Math.abs(tl.metrics(null));
         } finally {
             TextLine.recycle(tl);
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 4789231..b1bc766 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -612,7 +612,6 @@
         TextPaint paint = b.mPaint;
         int outerWidth = b.mWidth;
         TextDirectionHeuristic textDir = b.mTextDir;
-        final boolean fallbackLineSpacing = b.mFallbackLineSpacing;
         float spacingmult = b.mSpacingMult;
         float spacingadd = b.mSpacingAdd;
         float ellipsizedWidth = b.mEllipsizedWidth;
@@ -630,6 +629,7 @@
         mLineCount = 0;
         mEllipsized = false;
         mMaxLineHeight = mMaximumVisibleLineCount < 1 ? 0 : DEFAULT_MAX_LINE_HEIGHT;
+        mFallbackLineSpacing = b.mFallbackLineSpacing;
 
         int v = 0;
         boolean needMultiply = (spacingmult != 1 || spacingadd != 0);
@@ -867,17 +867,17 @@
 
                     boolean moreChars = (endPos < bufEnd);
 
-                    final int ascent = fallbackLineSpacing
+                    final int ascent = mFallbackLineSpacing
                             ? Math.min(fmAscent, Math.round(ascents[breakIndex]))
                             : fmAscent;
-                    final int descent = fallbackLineSpacing
+                    final int descent = mFallbackLineSpacing
                             ? Math.max(fmDescent, Math.round(descents[breakIndex]))
                             : fmDescent;
 
                     // The fallback ascent/descent may be larger than top/bottom of the default font
                     // metrics. Adjust top/bottom with ascent/descent for avoiding unexpected
                     // clipping.
-                    if (fallbackLineSpacing) {
+                    if (mFallbackLineSpacing) {
                         if (ascent < fmTop) {
                             fmTop = ascent;
                         }
@@ -1381,6 +1381,11 @@
         return mEllipsizedWidth;
     }
 
+    @Override
+    public boolean isFallbackLineSpacingEnabled() {
+        return mFallbackLineSpacing;
+    }
+
     /**
      * Return the total height of this layout.
      *
@@ -1407,6 +1412,7 @@
     @UnsupportedAppUsage
     private int mColumns;
     private int mEllipsizedWidth;
+    private boolean mFallbackLineSpacing;
 
     /**
      * Keeps track if ellipsize is applied to the text.
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 1a7ec7f..49e2111 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -71,6 +71,8 @@
     private Spanned mSpanned;
     private PrecomputedText mComputed;
 
+    private boolean mUseFallbackExtent = false;
+
     // The start and end of a potentially existing ellipsis on this text line.
     // We use them to filter out replacement and metric affecting spans on ellipsized away chars.
     private int mEllipsisStart;
@@ -141,6 +143,7 @@
         tl.mTabs = null;
         tl.mChars = null;
         tl.mComputed = null;
+        tl.mUseFallbackExtent = false;
 
         tl.mMetricAffectingSpanSpanSet.recycle();
         tl.mCharacterStyleSpanSet.recycle();
@@ -171,17 +174,20 @@
      * @param ellipsisStart the start of the ellipsis relative to the line
      * @param ellipsisEnd the end of the ellipsis relative to the line. When there
      *                    is no ellipsis, this should be equal to ellipsisStart.
+     * @param useFallbackLineSpacing true for enabling fallback line spacing. false for disabling
+     *                              fallback line spacing.
      */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     public void set(TextPaint paint, CharSequence text, int start, int limit, int dir,
             Directions directions, boolean hasTabs, TabStops tabStops,
-            int ellipsisStart, int ellipsisEnd) {
+            int ellipsisStart, int ellipsisEnd, boolean useFallbackLineSpacing) {
         mPaint = paint;
         mText = text;
         mStart = start;
         mLen = limit - start;
         mDir = dir;
         mDirections = directions;
+        mUseFallbackExtent = useFallbackLineSpacing;
         if (mDirections == null) {
             throw new IllegalArgumentException("Directions cannot be null");
         }
@@ -845,6 +851,30 @@
                 previousLeading);
     }
 
+    private void expandMetricsFromPaint(TextPaint wp, int start, int end,
+            int contextStart, int contextEnd, boolean runIsRtl, FontMetricsInt fmi) {
+
+        final int previousTop     = fmi.top;
+        final int previousAscent  = fmi.ascent;
+        final int previousDescent = fmi.descent;
+        final int previousBottom  = fmi.bottom;
+        final int previousLeading = fmi.leading;
+
+        int count = end - start;
+        int contextCount = contextEnd - contextStart;
+        if (mCharsValid) {
+            wp.getFontMetricsInt(mChars, start, count, contextStart, contextCount, runIsRtl,
+                    fmi);
+        } else {
+            wp.getFontMetricsInt(mText, mStart + start, count, mStart + contextStart, contextCount,
+                    runIsRtl, fmi);
+        }
+
+        updateMetrics(fmi, previousTop, previousAscent, previousDescent, previousBottom,
+                previousLeading);
+    }
+
+
     static void updateMetrics(FontMetricsInt fmi, int previousTop, int previousAscent,
             int previousDescent, int previousBottom, int previousLeading) {
         fmi.top     = Math.min(fmi.top,     previousTop);
@@ -949,6 +979,10 @@
             shapeTextRun(consumer, wp, start, end, contextStart, contextEnd, runIsRtl, leftX);
         }
 
+        if (mUseFallbackExtent && fmi != null) {
+            expandMetricsFromPaint(wp, start, end, contextStart, contextEnd, runIsRtl, fmi);
+        }
+
         if (c != null) {
             if (wp.bgColor != 0) {
                 int previousColor = wp.getColor();
diff --git a/core/java/android/text/TextShaper.java b/core/java/android/text/TextShaper.java
index 02fd7b4..a1d6cc8 100644
--- a/core/java/android/text/TextShaper.java
+++ b/core/java/android/text/TextShaper.java
@@ -222,7 +222,8 @@
                     mp.getDirections(0, count),
                     false /* tabstop is not supported */,
                     null,
-                    -1, -1 // ellipsis is not supported.
+                    -1, -1, // ellipsis is not supported.
+                    false /* fallback line spacing is not used */
             );
             tl.shape(consumer);
         } finally {
diff --git a/core/java/android/text/style/EasyEditSpan.java b/core/java/android/text/style/EasyEditSpan.java
index 3da8333..ccccdcf 100644
--- a/core/java/android/text/style/EasyEditSpan.java
+++ b/core/java/android/text/style/EasyEditSpan.java
@@ -82,7 +82,7 @@
      * Constructor called from {@link TextUtils} to restore the span.
      */
     public EasyEditSpan(@NonNull Parcel source) {
-        mPendingIntent = source.readParcelable(null, android.app.PendingIntent.class);
+        mPendingIntent = source.readParcelable(null);
         mDeleteEnabled = (source.readByte() == 1);
     }
 
diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java
index adb379a..2355769 100644
--- a/core/java/android/text/style/TextAppearanceSpan.java
+++ b/core/java/android/text/style/TextAppearanceSpan.java
@@ -249,7 +249,7 @@
         mTypeface = LeakyTypefaceStorage.readTypefaceFromParcel(src);
 
         mTextFontWeight = src.readInt();
-        mTextLocales = src.readParcelable(LocaleList.class.getClassLoader(), android.os.LocaleList.class);
+        mTextLocales = src.readParcelable(LocaleList.class.getClassLoader());
 
         mShadowRadius = src.readFloat();
         mShadowDx = src.readFloat();
diff --git a/core/java/android/util/MemoryIntArray.java b/core/java/android/util/MemoryIntArray.java
index 5cbbbef..42181c3 100644
--- a/core/java/android/util/MemoryIntArray.java
+++ b/core/java/android/util/MemoryIntArray.java
@@ -80,7 +80,7 @@
 
     private MemoryIntArray(Parcel parcel) throws IOException {
         mIsOwner = false;
-        ParcelFileDescriptor pfd = parcel.readParcelable(null, android.os.ParcelFileDescriptor.class);
+        ParcelFileDescriptor pfd = parcel.readParcelable(null);
         if (pfd == null) {
             throw new IOException("No backing file descriptor");
         }
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 678c80a..b8614cc 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -449,8 +449,8 @@
         type = source.readInt();
         displayId = source.readInt();
         displayGroupId = source.readInt();
-        address = source.readParcelable(null, android.view.DisplayAddress.class);
-        deviceProductInfo = source.readParcelable(null, android.hardware.display.DeviceProductInfo.class);
+        address = source.readParcelable(null);
+        deviceProductInfo = source.readParcelable(null);
         name = source.readString8();
         appWidth = source.readInt();
         appHeight = source.readInt();
@@ -475,7 +475,7 @@
         for (int i = 0; i < nColorModes; i++) {
             supportedColorModes[i] = source.readInt();
         }
-        hdrCapabilities = source.readParcelable(null, android.view.Display.HdrCapabilities.class);
+        hdrCapabilities = source.readParcelable(null);
         minimalPostProcessingSupported = source.readBoolean();
         logicalDensityDpi = source.readInt();
         physicalXDpi = source.readFloat();
diff --git a/core/java/android/view/KeyboardShortcutInfo.java b/core/java/android/view/KeyboardShortcutInfo.java
index 118b03c..2660e74 100644
--- a/core/java/android/view/KeyboardShortcutInfo.java
+++ b/core/java/android/view/KeyboardShortcutInfo.java
@@ -91,7 +91,7 @@
 
     private KeyboardShortcutInfo(Parcel source) {
         mLabel = source.readCharSequence();
-        mIcon = source.readParcelable(null, android.graphics.drawable.Icon.class);
+        mIcon = source.readParcelable(null);
         mBaseCharacter = (char) source.readInt();
         mKeycode = source.readInt();
         mModifiers = source.readInt();
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 07d5fc5..25e0eca 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -1896,7 +1896,7 @@
 
         private Canvas mCanvas;
         private Bitmap mBitmap;
-        private boolean mEnabledHwBitmapsInSwMode;
+        private boolean mEnabledHwFeaturesInSwMode;
 
         @Override
         public Canvas getCanvas(View view, int width, int height) {
@@ -1913,7 +1913,7 @@
             if (mCanvas == null) {
                 mCanvas = new Canvas();
             }
-            mEnabledHwBitmapsInSwMode = mCanvas.isHwBitmapsInSwModeEnabled();
+            mEnabledHwFeaturesInSwMode = mCanvas.isHwFeaturesInSwModeEnabled();
             mCanvas.setBitmap(mBitmap);
             return mCanvas;
         }
@@ -1921,7 +1921,7 @@
         @Override
         public Bitmap createBitmap() {
             mCanvas.setBitmap(null);
-            mCanvas.setHwBitmapsInSwModeEnabled(mEnabledHwBitmapsInSwMode);
+            mCanvas.setHwFeaturesInSwModeEnabled(mEnabledHwFeaturesInSwMode);
             return mBitmap;
         }
     }
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index a427ab8..6ad2d9a 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -1315,7 +1315,7 @@
         record.mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
         record.mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
         record.mParcelableData = parcel.readParcelable(null);
-        parcel.readList(record.mText, null, java.lang.CharSequence.class);
+        parcel.readList(record.mText, null);
         record.mSourceWindowId = parcel.readInt();
         record.mSourceNodeId = parcel.readLong();
         record.mSourceDisplayId = parcel.readInt();
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index 540f5dc..67e6d3f 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -917,7 +917,7 @@
                 final int count = source.readInt();
                 for (int i = 0; i < count; i++) {
                     List<AccessibilityWindowInfo> windows = new ArrayList<>();
-                    source.readParcelableList(windows, loader, android.view.accessibility.AccessibilityWindowInfo.class);
+                    source.readParcelableList(windows, loader);
                     array.put(source.readInt(), windows);
                 }
                 return array;
diff --git a/core/java/android/view/autofill/ParcelableMap.java b/core/java/android/view/autofill/ParcelableMap.java
index 3fa7734..d8459aa 100644
--- a/core/java/android/view/autofill/ParcelableMap.java
+++ b/core/java/android/view/autofill/ParcelableMap.java
@@ -56,8 +56,8 @@
                     ParcelableMap map = new ParcelableMap(size);
 
                     for (int i = 0; i < size; i++) {
-                        AutofillId key = source.readParcelable(null, android.view.autofill.AutofillId.class);
-                        AutofillValue value = source.readParcelable(null, android.view.autofill.AutofillValue.class);
+                        AutofillId key = source.readParcelable(null);
+                        AutofillValue value = source.readParcelable(null);
 
                         map.put(key, value);
                     }
diff --git a/core/java/android/view/contentcapture/ContentCaptureCondition.java b/core/java/android/view/contentcapture/ContentCaptureCondition.java
index 685ea1a..027c8d2 100644
--- a/core/java/android/view/contentcapture/ContentCaptureCondition.java
+++ b/core/java/android/view/contentcapture/ContentCaptureCondition.java
@@ -133,7 +133,7 @@
 
                 @Override
                 public ContentCaptureCondition createFromParcel(@NonNull Parcel parcel) {
-                    return new ContentCaptureCondition(parcel.readParcelable(null, android.content.LocusId.class),
+                    return new ContentCaptureCondition(parcel.readParcelable(null),
                             parcel.readInt());
                 }
 
diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index 59b5286..3bc9a96 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -419,7 +419,7 @@
             final ContentCaptureContext clientContext;
             if (hasClientContext) {
                 // Must reconstruct the client context using the Builder API
-                final LocusId id = parcel.readParcelable(null, android.content.LocusId.class);
+                final LocusId id = parcel.readParcelable(null);
                 final Bundle extras = parcel.readBundle();
                 final Builder builder = new Builder(id);
                 if (extras != null) builder.setExtras(extras);
@@ -427,7 +427,7 @@
             } else {
                 clientContext = null;
             }
-            final ComponentName componentName = parcel.readParcelable(null, android.content.ComponentName.class);
+            final ComponentName componentName = parcel.readParcelable(null);
             if (componentName == null) {
                 // Client-state only
                 return clientContext;
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index ba4176f..0f4bc19 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -620,7 +620,7 @@
             final int type = parcel.readInt();
             final long eventTime  = parcel.readLong();
             final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, type, eventTime);
-            final AutofillId id = parcel.readParcelable(null, android.view.autofill.AutofillId.class);
+            final AutofillId id = parcel.readParcelable(null);
             if (id != null) {
                 event.setAutofillId(id);
             }
@@ -637,13 +637,13 @@
                 event.setParentSessionId(parcel.readInt());
             }
             if (type == TYPE_SESSION_STARTED || type == TYPE_CONTEXT_UPDATED) {
-                event.setClientContext(parcel.readParcelable(null, android.view.contentcapture.ContentCaptureContext.class));
+                event.setClientContext(parcel.readParcelable(null));
             }
             if (type == TYPE_VIEW_INSETS_CHANGED) {
-                event.setInsets(parcel.readParcelable(null, android.graphics.Insets.class));
+                event.setInsets(parcel.readParcelable(null));
             }
             if (type == TYPE_WINDOW_BOUNDS_CHANGED) {
-                event.setBounds(parcel.readParcelable(null, android.graphics.Rect.class));
+                event.setBounds(parcel.readParcelable(null));
             }
             if (type == TYPE_VIEW_TEXT_CHANGED) {
                 event.setComposingIndex(parcel.readInt(), parcel.readInt());
diff --git a/core/java/android/view/contentcapture/ViewNode.java b/core/java/android/view/contentcapture/ViewNode.java
index 1762a58..1b4a00f 100644
--- a/core/java/android/view/contentcapture/ViewNode.java
+++ b/core/java/android/view/contentcapture/ViewNode.java
@@ -124,10 +124,10 @@
         mFlags = nodeFlags;
 
         if ((nodeFlags & FLAGS_HAS_AUTOFILL_ID) != 0) {
-            mAutofillId = parcel.readParcelable(null, android.view.autofill.AutofillId.class);
+            mAutofillId = parcel.readParcelable(null);
         }
         if ((nodeFlags & FLAGS_HAS_AUTOFILL_PARENT_ID) != 0) {
-            mParentAutofillId = parcel.readParcelable(null, android.view.autofill.AutofillId.class);
+            mParentAutofillId = parcel.readParcelable(null);
         }
         if ((nodeFlags & FLAGS_HAS_TEXT) != 0) {
             mText = new ViewNodeText(parcel, (nodeFlags & FLAGS_HAS_COMPLEX_TEXT) == 0);
@@ -169,7 +169,7 @@
             mExtras = parcel.readBundle();
         }
         if ((nodeFlags & FLAGS_HAS_LOCALE_LIST) != 0) {
-            mLocaleList = parcel.readParcelable(null, android.os.LocaleList.class);
+            mLocaleList = parcel.readParcelable(null);
         }
         if ((nodeFlags & FLAGS_HAS_MIME_TYPES) != 0) {
             mReceiveContentMimeTypes = parcel.readStringArray();
@@ -196,7 +196,7 @@
             mAutofillHints = parcel.readStringArray();
         }
         if ((nodeFlags & FLAGS_HAS_AUTOFILL_VALUE) != 0) {
-            mAutofillValue = parcel.readParcelable(null, android.view.autofill.AutofillValue.class);
+            mAutofillValue = parcel.readParcelable(null);
         }
         if ((nodeFlags & FLAGS_HAS_AUTOFILL_OPTIONS) != 0) {
             mAutofillOptions = parcel.readCharSequenceArray();
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java
index 437e54f..fbc9470 100644
--- a/core/java/android/view/inputmethod/CursorAnchorInfo.java
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -140,7 +140,7 @@
         mInsertionMarkerTop = source.readFloat();
         mInsertionMarkerBaseline = source.readFloat();
         mInsertionMarkerBottom = source.readFloat();
-        mCharacterBoundsArray = source.readParcelable(SparseRectFArray.class.getClassLoader(), android.view.inputmethod.SparseRectFArray.class);
+        mCharacterBoundsArray = source.readParcelable(SparseRectFArray.class.getClassLoader());
         mMatrixValues = source.createFloatArray();
     }
 
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 09a1448..4cbd477 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -1067,7 +1067,7 @@
                     res.hintText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
                     res.label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
                     res.packageName = source.readString();
-                    res.autofillId = source.readParcelable(AutofillId.class.getClassLoader(), android.view.autofill.AutofillId.class);
+                    res.autofillId = source.readParcelable(AutofillId.class.getClassLoader());
                     res.fieldId = source.readInt();
                     res.fieldName = source.readString();
                     res.extras = source.readBundle();
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
index 70279cc..e1e1755 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
@@ -490,7 +490,7 @@
         boolean clientSupported = (flg & 0x200) != 0;
         int maxSuggestionCount = in.readInt();
         List<InlinePresentationSpec> inlinePresentationSpecs = new ArrayList<>();
-        in.readParcelableList(inlinePresentationSpecs, InlinePresentationSpec.class.getClassLoader(), android.widget.inline.InlinePresentationSpec.class);
+        in.readParcelableList(inlinePresentationSpecs, InlinePresentationSpec.class.getClassLoader());
         String hostPackageName = in.readString();
         LocaleList supportedLocales = (LocaleList) in.readTypedObject(LocaleList.CREATOR);
         Bundle extras = in.readBundle();
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsResponse.java b/core/java/android/view/inputmethod/InlineSuggestionsResponse.java
index 532fc85..b393c67 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsResponse.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsResponse.java
@@ -170,7 +170,7 @@
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
         List<InlineSuggestion> inlineSuggestions = new ArrayList<>();
-        in.readParcelableList(inlineSuggestions, InlineSuggestion.class.getClassLoader(), android.view.inputmethod.InlineSuggestion.class);
+        in.readParcelableList(inlineSuggestions, InlineSuggestion.class.getClassLoader());
 
         this.mInlineSuggestions = inlineSuggestions;
         com.android.internal.util.AnnotationValidations.validate(
diff --git a/core/java/android/view/textclassifier/ConversationAction.java b/core/java/android/view/textclassifier/ConversationAction.java
index a4a5a1e..bf0409d 100644
--- a/core/java/android/view/textclassifier/ConversationAction.java
+++ b/core/java/android/view/textclassifier/ConversationAction.java
@@ -141,7 +141,7 @@
 
     private ConversationAction(Parcel in) {
         mType = in.readString();
-        mAction = in.readParcelable(null, android.app.RemoteAction.class);
+        mAction = in.readParcelable(null);
         mTextReply = in.readCharSequence();
         mScore = in.readFloat();
         mExtras = in.readBundle();
diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java
index 7a6a3cd..6ad5cb9 100644
--- a/core/java/android/view/textclassifier/ConversationActions.java
+++ b/core/java/android/view/textclassifier/ConversationActions.java
@@ -149,7 +149,7 @@
         }
 
         private Message(Parcel in) {
-            mAuthor = in.readParcelable(null, android.app.Person.class);
+            mAuthor = in.readParcelable(null);
             mReferenceTime =
                     in.readInt() == 0
                             ? null
@@ -331,13 +331,13 @@
 
         private static Request readFromParcel(Parcel in) {
             List<Message> conversation = new ArrayList<>();
-            in.readParcelableList(conversation, null, android.view.textclassifier.ConversationActions.Message.class);
-            TextClassifier.EntityConfig typeConfig = in.readParcelable(null, android.view.textclassifier.TextClassifier.EntityConfig.class);
+            in.readParcelableList(conversation, null);
+            TextClassifier.EntityConfig typeConfig = in.readParcelable(null);
             int maxSuggestions = in.readInt();
             List<String> hints = new ArrayList<>();
             in.readStringList(hints);
             Bundle extras = in.readBundle();
-            SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null, android.view.textclassifier.SystemTextClassifierMetadata.class);
+            SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
 
             Request request = new Request(
                     conversation,
diff --git a/core/java/android/view/textclassifier/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java
index b347010..858825b 100644
--- a/core/java/android/view/textclassifier/SelectionEvent.java
+++ b/core/java/android/view/textclassifier/SelectionEvent.java
@@ -172,7 +172,7 @@
         mEnd = in.readInt();
         mSmartStart = in.readInt();
         mSmartEnd = in.readInt();
-        mSystemTcMetadata = in.readParcelable(null, android.view.textclassifier.SystemTextClassifierMetadata.class);
+        mSystemTcMetadata = in.readParcelable(null);
     }
 
     @Override
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 8b04d35..7db35d4 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -713,12 +713,12 @@
             final CharSequence text = in.readCharSequence();
             final int startIndex = in.readInt();
             final int endIndex = in.readInt();
-            final LocaleList defaultLocales = in.readParcelable(null, android.os.LocaleList.class);
+            final LocaleList defaultLocales = in.readParcelable(null);
             final String referenceTimeString = in.readString();
             final ZonedDateTime referenceTime = referenceTimeString == null
                     ? null : ZonedDateTime.parse(referenceTimeString);
             final Bundle extras = in.readBundle();
-            final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null, android.view.textclassifier.SystemTextClassifierMetadata.class);
+            final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
 
             final Request request = new Request(text, startIndex, endIndex,
                     defaultLocales, referenceTime, extras);
diff --git a/core/java/android/view/textclassifier/TextClassificationContext.java b/core/java/android/view/textclassifier/TextClassificationContext.java
index 3a50809..5d5683f 100644
--- a/core/java/android/view/textclassifier/TextClassificationContext.java
+++ b/core/java/android/view/textclassifier/TextClassificationContext.java
@@ -159,7 +159,7 @@
         mPackageName = in.readString();
         mWidgetType = in.readString();
         mWidgetVersion = in.readString();
-        mSystemTcMetadata = in.readParcelable(null, android.view.textclassifier.SystemTextClassifierMetadata.class);
+        mSystemTcMetadata = in.readParcelable(null);
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<TextClassificationContext> CREATOR =
diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java
index 195565c..90667cf 100644
--- a/core/java/android/view/textclassifier/TextClassifierEvent.java
+++ b/core/java/android/view/textclassifier/TextClassifierEvent.java
@@ -189,7 +189,7 @@
         mEventCategory = in.readInt();
         mEventType = in.readInt();
         mEntityTypes = in.readStringArray();
-        mEventContext = in.readParcelable(null, android.view.textclassifier.TextClassificationContext.class);
+        mEventContext = in.readParcelable(null);
         mResultId = in.readString();
         mEventIndex = in.readInt();
         int scoresLength = in.readInt();
diff --git a/core/java/android/view/textclassifier/TextLanguage.java b/core/java/android/view/textclassifier/TextLanguage.java
index 67167c6..604979b 100644
--- a/core/java/android/view/textclassifier/TextLanguage.java
+++ b/core/java/android/view/textclassifier/TextLanguage.java
@@ -295,7 +295,7 @@
         private static Request readFromParcel(Parcel in) {
             final CharSequence text = in.readCharSequence();
             final Bundle extra = in.readBundle();
-            final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null, android.view.textclassifier.SystemTextClassifierMetadata.class);
+            final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
 
             final Request request = new Request(text, extra);
             request.setSystemTextClassifierMetadata(systemTcMetadata);
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index 445e9ec..dea3a90 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -558,13 +558,13 @@
 
         private static Request readFromParcel(Parcel in) {
             final String text = in.readString();
-            final LocaleList defaultLocales = in.readParcelable(null, android.os.LocaleList.class);
-            final EntityConfig entityConfig = in.readParcelable(null, android.view.textclassifier.TextClassifier.EntityConfig.class);
+            final LocaleList defaultLocales = in.readParcelable(null);
+            final EntityConfig entityConfig = in.readParcelable(null);
             final Bundle extras = in.readBundle();
             final String referenceTimeString = in.readString();
             final ZonedDateTime referenceTime = referenceTimeString == null
                     ? null : ZonedDateTime.parse(referenceTimeString);
-            final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null, android.view.textclassifier.SystemTextClassifierMetadata.class);
+            final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
 
             final Request request = new Request(text, defaultLocales, entityConfig,
                     /* legacyFallback= */ true, referenceTime, extras);
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index dda0fcdd..c1913f6 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -489,9 +489,9 @@
             final CharSequence text = in.readCharSequence();
             final int startIndex = in.readInt();
             final int endIndex = in.readInt();
-            final LocaleList defaultLocales = in.readParcelable(null, android.os.LocaleList.class);
+            final LocaleList defaultLocales = in.readParcelable(null);
             final Bundle extras = in.readBundle();
-            final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null, android.view.textclassifier.SystemTextClassifierMetadata.class);
+            final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
             final boolean includeTextClassification = in.readBoolean();
 
             final Request request = new Request(text, startIndex, endIndex, defaultLocales,
@@ -548,6 +548,6 @@
         mEntityConfidence = EntityConfidence.CREATOR.createFromParcel(in);
         mId = in.readString();
         mExtras = in.readBundle();
-        mTextClassification = in.readParcelable(TextClassification.class.getClassLoader(), android.view.textclassifier.TextClassification.class);
+        mTextClassification = in.readParcelable(TextClassification.class.getClassLoader());
     }
 }
diff --git a/core/java/android/view/translation/TranslationRequest.java b/core/java/android/view/translation/TranslationRequest.java
index 027edc2..0d41851 100644
--- a/core/java/android/view/translation/TranslationRequest.java
+++ b/core/java/android/view/translation/TranslationRequest.java
@@ -255,9 +255,9 @@
 
         int flags = in.readInt();
         List<TranslationRequestValue> translationRequestValues = new ArrayList<>();
-        in.readParcelableList(translationRequestValues, TranslationRequestValue.class.getClassLoader(), android.view.translation.TranslationRequestValue.class);
+        in.readParcelableList(translationRequestValues, TranslationRequestValue.class.getClassLoader());
         List<ViewTranslationRequest> viewTranslationRequests = new ArrayList<>();
-        in.readParcelableList(viewTranslationRequests, ViewTranslationRequest.class.getClassLoader(), android.view.translation.ViewTranslationRequest.class);
+        in.readParcelableList(viewTranslationRequests, ViewTranslationRequest.class.getClassLoader());
 
         this.mFlags = flags;
 
diff --git a/core/java/android/view/translation/TranslationSpec.java b/core/java/android/view/translation/TranslationSpec.java
index 76dda5f..efc3d8b 100644
--- a/core/java/android/view/translation/TranslationSpec.java
+++ b/core/java/android/view/translation/TranslationSpec.java
@@ -64,7 +64,7 @@
     }
 
     static ULocale unparcelLocale(Parcel in) {
-        return (ULocale) in.readSerializable(android.icu.util.ULocale.class.getClassLoader(), android.icu.util.ULocale.class);
+        return (ULocale) in.readSerializable();
     }
 
     /**
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 60ce651..6284bc2 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1073,7 +1073,7 @@
                 com.android.internal.R.dimen.textview_error_popup_default_width);
         final StaticLayout l = StaticLayout.Builder.obtain(text, 0, text.length(), tv.getPaint(),
                 defaultWidthInPixels)
-                .setUseLineSpacingFromFallbacks(tv.mUseFallbackLineSpacing)
+                .setUseLineSpacingFromFallbacks(tv.isFallbackLineSpacingForStaticLayout())
                 .build();
 
         float max = 0;
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index e243aae..51869d4 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -1309,7 +1309,7 @@
         private SavedState(Parcel in) {
             super(in);
             expandedGroupMetadataList = new ArrayList<ExpandableListConnector.GroupMetadata>();
-            in.readList(expandedGroupMetadataList, ExpandableListConnector.class.getClassLoader(), android.widget.ExpandableListConnector.GroupMetadata.class);
+            in.readList(expandedGroupMetadataList, ExpandableListConnector.class.getClassLoader());
         }
 
         @Override
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index b21d08c..e60f9a6 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1489,7 +1489,7 @@
 
         SetRippleDrawableColor(Parcel parcel) {
             viewId = parcel.readInt();
-            mColorStateList = parcel.readParcelable(null, android.content.res.ColorStateList.class);
+            mColorStateList = parcel.readParcelable(null);
         }
 
         public void writeToParcel(Parcel dest, int flags) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 67a2715..1a808b2 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -48,6 +48,9 @@
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.app.assist.AssistStructure;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ClipData;
 import android.content.ClipDescription;
@@ -453,6 +456,22 @@
 
     private static final int FLOATING_TOOLBAR_SELECT_ALL_REFRESH_DELAY = 500;
 
+    /**
+     * This change ID enables the fallback text line spacing (line height) for BoringLayout.
+     * @hide
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+    public static final long BORINGLAYOUT_FALLBACK_LINESPACING = 210923482L; // buganizer id
+
+    /**
+     * This change ID enables the fallback text line spacing (line height) for StaticLayout.
+     * @hide
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.P)
+    public static final long STATICLAYOUT_FALLBACK_LINESPACING = 37756858; // buganizer id
+
     // System wide time for last cut, copy or text changed action.
     static long sLastCutCopyOrTextChangedTime;
 
@@ -766,8 +785,13 @@
     private boolean mListenerChanged = false;
     // True if internationalized input should be used for numbers and date and time.
     private final boolean mUseInternationalizedInput;
-    // True if fallback fonts that end up getting used should be allowed to affect line spacing.
-    /* package */ boolean mUseFallbackLineSpacing;
+
+    // Fallback fonts that end up getting used should be allowed to affect line spacing.
+    private static final int FALLBACK_LINE_SPACING_NONE = 0;
+    private static final int FALLBACK_LINE_SPACING_STATIC_LAYOUT_ONLY = 1;
+    private static final int FALLBACK_LINE_SPACING_ALL = 2;
+
+    private int mUseFallbackLineSpacing;
     // True if the view text can be padded for compat reasons, when the view is translated.
     private final boolean mUseTextPaddingForUiTranslation;
 
@@ -1479,7 +1503,13 @@
 
         final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
         mUseInternationalizedInput = targetSdkVersion >= VERSION_CODES.O;
-        mUseFallbackLineSpacing = targetSdkVersion >= VERSION_CODES.P;
+        if (CompatChanges.isChangeEnabled(BORINGLAYOUT_FALLBACK_LINESPACING)) {
+            mUseFallbackLineSpacing = FALLBACK_LINE_SPACING_ALL;
+        } else if (CompatChanges.isChangeEnabled(STATICLAYOUT_FALLBACK_LINESPACING)) {
+            mUseFallbackLineSpacing = FALLBACK_LINE_SPACING_STATIC_LAYOUT_ONLY;
+        } else {
+            mUseFallbackLineSpacing = FALLBACK_LINE_SPACING_NONE;
+        }
         // TODO(b/179693024): Use a ChangeId instead.
         mUseTextPaddingForUiTranslation = targetSdkVersion <= Build.VERSION_CODES.R;
 
@@ -4541,8 +4571,18 @@
      * @attr ref android.R.styleable#TextView_fallbackLineSpacing
      */
     public void setFallbackLineSpacing(boolean enabled) {
-        if (mUseFallbackLineSpacing != enabled) {
-            mUseFallbackLineSpacing = enabled;
+        int fallbackStrategy;
+        if (enabled) {
+            if (CompatChanges.isChangeEnabled(BORINGLAYOUT_FALLBACK_LINESPACING)) {
+                fallbackStrategy = FALLBACK_LINE_SPACING_ALL;
+            } else {
+                fallbackStrategy = FALLBACK_LINE_SPACING_STATIC_LAYOUT_ONLY;
+            }
+        } else {
+            fallbackStrategy = FALLBACK_LINE_SPACING_NONE;
+        }
+        if (mUseFallbackLineSpacing != fallbackStrategy) {
+            mUseFallbackLineSpacing = fallbackStrategy;
             if (mLayout != null) {
                 nullLayouts();
                 requestLayout();
@@ -4560,7 +4600,17 @@
      */
     @InspectableProperty
     public boolean isFallbackLineSpacing() {
-        return mUseFallbackLineSpacing;
+        return mUseFallbackLineSpacing != FALLBACK_LINE_SPACING_NONE;
+    }
+
+    private boolean isFallbackLineSpacingForBoringLayout() {
+        return mUseFallbackLineSpacing == FALLBACK_LINE_SPACING_ALL;
+    }
+
+    // Package privte for accessing from Editor.java
+    /* package */ boolean isFallbackLineSpacingForStaticLayout() {
+        return mUseFallbackLineSpacing == FALLBACK_LINE_SPACING_ALL
+                || mUseFallbackLineSpacing == FALLBACK_LINE_SPACING_STATIC_LAYOUT_ONLY;
     }
 
     /**
@@ -9148,7 +9198,7 @@
 
             if (hintBoring == UNKNOWN_BORING) {
                 hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir,
-                                                   mHintBoring);
+                        isFallbackLineSpacingForBoringLayout(), mHintBoring);
                 if (hintBoring != null) {
                     mHintBoring = hintBoring;
                 }
@@ -9190,7 +9240,7 @@
                         .setTextDirection(mTextDir)
                         .setLineSpacing(mSpacingAdd, mSpacingMult)
                         .setIncludePad(mIncludePad)
-                        .setUseLineSpacingFromFallbacks(mUseFallbackLineSpacing)
+                        .setUseLineSpacingFromFallbacks(isFallbackLineSpacingForStaticLayout())
                         .setBreakStrategy(mBreakStrategy)
                         .setHyphenationFrequency(mHyphenationFrequency)
                         .setJustificationMode(mJustificationMode)
@@ -9250,7 +9300,7 @@
                     .setTextDirection(mTextDir)
                     .setLineSpacing(mSpacingAdd, mSpacingMult)
                     .setIncludePad(mIncludePad)
-                    .setUseLineSpacingFromFallbacks(mUseFallbackLineSpacing)
+                    .setUseLineSpacingFromFallbacks(isFallbackLineSpacingForStaticLayout())
                     .setBreakStrategy(mBreakStrategy)
                     .setHyphenationFrequency(mHyphenationFrequency)
                     .setJustificationMode(mJustificationMode)
@@ -9259,7 +9309,8 @@
             result = builder.build();
         } else {
             if (boring == UNKNOWN_BORING) {
-                boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
+                boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir,
+                        isFallbackLineSpacingForBoringLayout(), mBoring);
                 if (boring != null) {
                     mBoring = boring;
                 }
@@ -9303,7 +9354,7 @@
                     .setTextDirection(mTextDir)
                     .setLineSpacing(mSpacingAdd, mSpacingMult)
                     .setIncludePad(mIncludePad)
-                    .setUseLineSpacingFromFallbacks(mUseFallbackLineSpacing)
+                    .setUseLineSpacingFromFallbacks(isFallbackLineSpacingForStaticLayout())
                     .setBreakStrategy(mBreakStrategy)
                     .setHyphenationFrequency(mHyphenationFrequency)
                     .setJustificationMode(mJustificationMode)
@@ -9430,7 +9481,8 @@
             }
 
             if (des < 0) {
-                boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
+                boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir,
+                        isFallbackLineSpacingForBoringLayout(), mBoring);
                 if (boring != null) {
                     mBoring = boring;
                 }
@@ -9463,7 +9515,8 @@
                 }
 
                 if (hintDes < 0) {
-                    hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir, mHintBoring);
+                    hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir,
+                            isFallbackLineSpacingForBoringLayout(), mHintBoring);
                     if (hintBoring != null) {
                         mHintBoring = hintBoring;
                     }
@@ -9667,7 +9720,7 @@
         layoutBuilder.setAlignment(getLayoutAlignment())
                 .setLineSpacing(getLineSpacingExtra(), getLineSpacingMultiplier())
                 .setIncludePad(getIncludeFontPadding())
-                .setUseLineSpacingFromFallbacks(mUseFallbackLineSpacing)
+                .setUseLineSpacingFromFallbacks(isFallbackLineSpacingForStaticLayout())
                 .setBreakStrategy(getBreakStrategy())
                 .setHyphenationFrequency(getHyphenationFrequency())
                 .setJustificationMode(getJustificationMode())
diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java
index 974a1dd..88ece5c 100644
--- a/core/java/android/window/DisplayAreaOrganizer.java
+++ b/core/java/android/window/DisplayAreaOrganizer.java
@@ -101,14 +101,6 @@
     public static final int FEATURE_IME_PLACEHOLDER = FEATURE_SYSTEM_FIRST + 7;
 
     /**
-     * Display area for one handed background layer, which preventing when user
-     * turning the Dark theme on, they can not clearly identify the screen has entered
-     * one handed mode.
-     * @hide
-     */
-    public static final int FEATURE_ONE_HANDED_BACKGROUND_PANEL = FEATURE_SYSTEM_FIRST + 8;
-
-    /**
      * Display area hosting IME window tokens (@see ImeContainer). By default, IMEs are parented
      * to FEATURE_IME_PLACEHOLDER but can be reparented under other RootDisplayArea.
      *
@@ -118,7 +110,7 @@
      * app on another screen).
      * @hide
      */
-    public static final int FEATURE_IME = FEATURE_SYSTEM_FIRST + 9;
+    public static final int FEATURE_IME = FEATURE_SYSTEM_FIRST + 8;
 
     /**
      * The last boundary of display area for system features
diff --git a/core/java/com/android/ims/internal/uce/options/OptionsCapInfo.java b/core/java/com/android/ims/internal/uce/options/OptionsCapInfo.java
index d709acf..6f83bf3 100644
--- a/core/java/com/android/ims/internal/uce/options/OptionsCapInfo.java
+++ b/core/java/com/android/ims/internal/uce/options/OptionsCapInfo.java
@@ -89,6 +89,6 @@
 
     public void readFromParcel(Parcel source) {
         mSdp = source.readString();
-        mCapInfo = source.readParcelable(CapInfo.class.getClassLoader(), com.android.ims.internal.uce.common.CapInfo.class);
+        mCapInfo = source.readParcelable(CapInfo.class.getClassLoader());
     }
 }
\ No newline at end of file
diff --git a/core/java/com/android/ims/internal/uce/options/OptionsCmdStatus.java b/core/java/com/android/ims/internal/uce/options/OptionsCmdStatus.java
index 559d61b..461f8bf 100644
--- a/core/java/com/android/ims/internal/uce/options/OptionsCmdStatus.java
+++ b/core/java/com/android/ims/internal/uce/options/OptionsCmdStatus.java
@@ -147,8 +147,8 @@
     /** @hide */
     public void readFromParcel(Parcel source) {
         mUserData = source.readInt();
-        mCmdId = source.readParcelable(OptionsCmdId.class.getClassLoader(), com.android.ims.internal.uce.options.OptionsCmdId.class);
-        mStatus = source.readParcelable(StatusCode.class.getClassLoader(), com.android.ims.internal.uce.common.StatusCode.class);
-        mCapInfo = source.readParcelable(CapInfo.class.getClassLoader(), com.android.ims.internal.uce.common.CapInfo.class);
+        mCmdId = source.readParcelable(OptionsCmdId.class.getClassLoader());
+        mStatus = source.readParcelable(StatusCode.class.getClassLoader());
+        mCapInfo = source.readParcelable(CapInfo.class.getClassLoader());
     }
 }
\ No newline at end of file
diff --git a/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java b/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java
index 160f9eb..3242081 100644
--- a/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java
+++ b/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java
@@ -180,7 +180,7 @@
         mRequestId = source.readInt();
         mSipResponseCode = source.readInt();
         mReasonPhrase = source.readString();
-        mCmdId = source.readParcelable(OptionsCmdId.class.getClassLoader(), com.android.ims.internal.uce.options.OptionsCmdId.class);
+        mCmdId = source.readParcelable(OptionsCmdId.class.getClassLoader());
         mRetryAfter = source.readInt();
         mReasonHeader = source.readString();
     }
diff --git a/core/java/com/android/ims/internal/uce/presence/PresCapInfo.java b/core/java/com/android/ims/internal/uce/presence/PresCapInfo.java
index f0ee5f3..ec8b6bf 100644
--- a/core/java/com/android/ims/internal/uce/presence/PresCapInfo.java
+++ b/core/java/com/android/ims/internal/uce/presence/PresCapInfo.java
@@ -105,6 +105,6 @@
     /** @hide */
     public void readFromParcel(Parcel source) {
         mContactUri = source.readString();
-        mCapInfo = source.readParcelable(CapInfo.class.getClassLoader(), com.android.ims.internal.uce.common.CapInfo.class);
+        mCapInfo = source.readParcelable(CapInfo.class.getClassLoader());
     }
 }
diff --git a/core/java/com/android/ims/internal/uce/presence/PresCmdStatus.java b/core/java/com/android/ims/internal/uce/presence/PresCmdStatus.java
index 8fbb000c..7e22106 100644
--- a/core/java/com/android/ims/internal/uce/presence/PresCmdStatus.java
+++ b/core/java/com/android/ims/internal/uce/presence/PresCmdStatus.java
@@ -146,8 +146,8 @@
     public void readFromParcel(Parcel source) {
         mUserData = source.readInt();
         mRequestId = source.readInt();
-        mCmdId = source.readParcelable(PresCmdId.class.getClassLoader(), com.android.ims.internal.uce.presence.PresCmdId.class);
-        mStatus = source.readParcelable(StatusCode.class.getClassLoader(), com.android.ims.internal.uce.common.StatusCode.class);
+        mCmdId = source.readParcelable(PresCmdId.class.getClassLoader());
+        mStatus = source.readParcelable(StatusCode.class.getClassLoader());
     }
 
 }
\ No newline at end of file
diff --git a/core/java/com/android/ims/internal/uce/presence/PresResInfo.java b/core/java/com/android/ims/internal/uce/presence/PresResInfo.java
index 954c2b6..2f797b4 100644
--- a/core/java/com/android/ims/internal/uce/presence/PresResInfo.java
+++ b/core/java/com/android/ims/internal/uce/presence/PresResInfo.java
@@ -122,6 +122,6 @@
     public void readFromParcel(Parcel source) {
         mResUri = source.readString();
         mDisplayName = source.readString();
-        mInstanceInfo = source.readParcelable(PresResInstanceInfo.class.getClassLoader(), com.android.ims.internal.uce.presence.PresResInstanceInfo.class);
+        mInstanceInfo = source.readParcelable(PresResInstanceInfo.class.getClassLoader());
     }
 }
\ No newline at end of file
diff --git a/core/java/com/android/ims/internal/uce/presence/PresRlmiInfo.java b/core/java/com/android/ims/internal/uce/presence/PresRlmiInfo.java
index 63247db..e33aa13 100644
--- a/core/java/com/android/ims/internal/uce/presence/PresRlmiInfo.java
+++ b/core/java/com/android/ims/internal/uce/presence/PresRlmiInfo.java
@@ -236,7 +236,7 @@
         mListName = source.readString();
         mRequestId = source.readInt();
         mPresSubscriptionState = source.readParcelable(
-                                  PresSubscriptionState.class.getClassLoader(), com.android.ims.internal.uce.presence.PresSubscriptionState.class);
+                                  PresSubscriptionState.class.getClassLoader());
         mSubscriptionExpireTime = source.readInt();
         mSubscriptionTerminatedReason = source.readString();
     }
diff --git a/core/java/com/android/ims/internal/uce/presence/PresSipResponse.java b/core/java/com/android/ims/internal/uce/presence/PresSipResponse.java
index 8097a37..5e394ef 100644
--- a/core/java/com/android/ims/internal/uce/presence/PresSipResponse.java
+++ b/core/java/com/android/ims/internal/uce/presence/PresSipResponse.java
@@ -185,7 +185,7 @@
         mRequestId = source.readInt();
         mSipResponseCode = source.readInt();
         mReasonPhrase = source.readString();
-        mCmdId = source.readParcelable(PresCmdId.class.getClassLoader(), com.android.ims.internal.uce.presence.PresCmdId.class);
+        mCmdId = source.readParcelable(PresCmdId.class.getClassLoader());
         mRetryAfter = source.readInt();
         mReasonHeader = source.readString();
     }
diff --git a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
index 301de2d..9c3c224 100644
--- a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
+++ b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
@@ -237,12 +237,12 @@
     private DisplayResolveInfo(Parcel in) {
         mDisplayLabel = in.readCharSequence();
         mExtendedInfo = in.readCharSequence();
-        mResolvedIntent = in.readParcelable(null /* ClassLoader */, android.content.Intent.class);
+        mResolvedIntent = in.readParcelable(null /* ClassLoader */);
         mSourceIntents.addAll(
                 Arrays.asList((Intent[]) in.readParcelableArray(null /* ClassLoader */,
                         Intent.class)));
         mIsSuspended = in.readBoolean();
         mPinned = in.readBoolean();
-        mResolveInfo = in.readParcelable(null /* ClassLoader */, android.content.pm.ResolveInfo.class);
+        mResolveInfo = in.readParcelable(null /* ClassLoader */);
     }
 }
diff --git a/core/java/com/android/internal/net/LegacyVpnInfo.java b/core/java/com/android/internal/net/LegacyVpnInfo.java
index b3bc93a..43984b5 100644
--- a/core/java/com/android/internal/net/LegacyVpnInfo.java
+++ b/core/java/com/android/internal/net/LegacyVpnInfo.java
@@ -69,7 +69,7 @@
             LegacyVpnInfo info = new LegacyVpnInfo();
             info.key = in.readString();
             info.state = in.readInt();
-            info.intent = in.readParcelable(null, android.app.PendingIntent.class);
+            info.intent = in.readParcelable(null);
             return info;
         }
 
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index 2a203ac..2ae56f8 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -34,8 +34,6 @@
 import android.os.Parcelable;
 import android.os.UserHandle;
 
-import java.net.Inet4Address;
-import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -93,8 +91,8 @@
     public String interfaze;
     public String session;
     public int mtu = -1;
-    public List<LinkAddress> addresses = new ArrayList<LinkAddress>();
-    public List<RouteInfo> routes = new ArrayList<RouteInfo>();
+    public List<LinkAddress> addresses = new ArrayList<>();
+    public List<RouteInfo> routes = new ArrayList<>();
     public List<String> dnsServers;
     public List<String> searchDomains;
     public List<String> allowedApplications;
@@ -114,12 +112,32 @@
     public VpnConfig() {
     }
 
-    public void updateAllowedFamilies(InetAddress address) {
-        if (address instanceof Inet4Address) {
-            allowIPv4 = true;
-        } else {
-            allowIPv6 = true;
-        }
+    public VpnConfig(VpnConfig other) {
+        user = other.user;
+        interfaze = other.interfaze;
+        session = other.session;
+        mtu = other.mtu;
+        addresses = copyOf(other.addresses);
+        routes = copyOf(other.routes);
+        dnsServers = copyOf(other.dnsServers);
+        searchDomains = copyOf(other.searchDomains);
+        allowedApplications = copyOf(other.allowedApplications);
+        disallowedApplications = copyOf(other.disallowedApplications);
+        configureIntent = other.configureIntent;
+        startTime = other.startTime;
+        legacy = other.legacy;
+        blocking = other.blocking;
+        allowBypass = other.allowBypass;
+        allowIPv4 = other.allowIPv4;
+        allowIPv6 = other.allowIPv6;
+        isMetered = other.isMetered;
+        underlyingNetworks = other.underlyingNetworks != null ? Arrays.copyOf(
+                other.underlyingNetworks, other.underlyingNetworks.length) : null;
+        proxyInfo = other.proxyInfo;
+    }
+
+    private static <T> List<T> copyOf(List<T> list) {
+        return list != null ? new ArrayList<>(list) : null;
     }
 
     public void addLegacyRoutes(String routesStr) {
@@ -131,7 +149,6 @@
             //each route is ip/prefix
             RouteInfo info = new RouteInfo(new IpPrefix(route), null, null, RouteInfo.RTN_UNICAST);
             this.routes.add(info);
-            updateAllowedFamilies(info.getDestination().getAddress());
         }
     }
 
@@ -144,7 +161,6 @@
             //each address is ip/prefix
             LinkAddress addr = new LinkAddress(address);
             this.addresses.add(addr);
-            updateAllowedFamilies(addr.getAddress());
         }
     }
 
@@ -192,7 +208,7 @@
             config.searchDomains = in.createStringArrayList();
             config.allowedApplications = in.createStringArrayList();
             config.disallowedApplications = in.createStringArrayList();
-            config.configureIntent = in.readParcelable(null, android.app.PendingIntent.class);
+            config.configureIntent = in.readParcelable(null);
             config.startTime = in.readLong();
             config.legacy = in.readInt() != 0;
             config.blocking = in.readInt() != 0;
@@ -201,7 +217,7 @@
             config.allowIPv6 = in.readInt() != 0;
             config.isMetered = in.readInt() != 0;
             config.underlyingNetworks = in.createTypedArray(Network.CREATOR);
-            config.proxyInfo = in.readParcelable(null, android.net.ProxyInfo.class);
+            config.proxyInfo = in.readParcelable(null);
             return config;
         }
 
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index 519faa8..d8dc143 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -182,9 +182,9 @@
         ipsecCaCert = in.readString();
         ipsecServerCert = in.readString();
         saveLogin = in.readInt() != 0;
-        proxy = in.readParcelable(null, android.net.ProxyInfo.class);
+        proxy = in.readParcelable(null);
         mAllowedAlgorithms = new ArrayList<>();
-        in.readList(mAllowedAlgorithms, null, java.lang.String.class);
+        in.readList(mAllowedAlgorithms, null);
         isBypassable = in.readBoolean();
         isMetered = in.readBoolean();
         maxMtu = in.readInt();
diff --git a/core/java/com/android/internal/os/AppFuseMount.java b/core/java/com/android/internal/os/AppFuseMount.java
index 5404fea..04d7211 100644
--- a/core/java/com/android/internal/os/AppFuseMount.java
+++ b/core/java/com/android/internal/os/AppFuseMount.java
@@ -57,7 +57,7 @@
             new Parcelable.Creator<AppFuseMount>() {
         @Override
         public AppFuseMount createFromParcel(Parcel in) {
-            return new AppFuseMount(in.readInt(), in.readParcelable(null, android.os.ParcelFileDescriptor.class));
+            return new AppFuseMount(in.readInt(), in.readParcelable(null));
         }
 
         @Override
diff --git a/core/java/com/android/internal/statusbar/StatusBarIcon.java b/core/java/com/android/internal/statusbar/StatusBarIcon.java
index 4f80afa..1d62623 100644
--- a/core/java/com/android/internal/statusbar/StatusBarIcon.java
+++ b/core/java/com/android/internal/statusbar/StatusBarIcon.java
@@ -81,9 +81,9 @@
     }
 
     public void readFromParcel(Parcel in) {
-        this.icon = (Icon) in.readParcelable(null, android.graphics.drawable.Icon.class);
+        this.icon = (Icon) in.readParcelable(null);
         this.pkg = in.readString();
-        this.user = (UserHandle) in.readParcelable(null, android.os.UserHandle.class);
+        this.user = (UserHandle) in.readParcelable(null);
         this.iconLevel = in.readInt();
         this.visible = in.readInt() != 0;
         this.number = in.readInt();
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index d3c3917..f46223a 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -71,11 +71,11 @@
 
             if (in.readInt() == 1) {
                 mBitmapBundle = in.readBundle(getClass().getClassLoader());
-                mBoundsInScreen = in.readParcelable(Rect.class.getClassLoader(), android.graphics.Rect.class);
-                mInsets = in.readParcelable(Insets.class.getClassLoader(), android.graphics.Insets.class);
+                mBoundsInScreen = in.readParcelable(Rect.class.getClassLoader());
+                mInsets = in.readParcelable(Insets.class.getClassLoader());
                 mTaskId = in.readInt();
                 mUserId = in.readInt();
-                mTopComponent = in.readParcelable(ComponentName.class.getClassLoader(), android.content.ComponentName.class);
+                mTopComponent = in.readParcelable(ComponentName.class.getClassLoader());
             }
         }
 
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 627381c..09ff4e0 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -37,6 +37,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerCoords;
+import android.view.RoundedCorner;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -229,13 +230,29 @@
 
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        if (insets.getDisplayCutout() != null) {
-            mHeaderPaddingTop = insets.getDisplayCutout().getSafeInsetTop();
-            mWaterfallInsets = insets.getDisplayCutout().getWaterfallInsets();
-        } else {
-            mHeaderPaddingTop = 0;
-            mWaterfallInsets = Insets.NONE;
+        int headerPaddingTop = 0;
+        Insets waterfallInsets = Insets.NONE;
+
+        final RoundedCorner topLeftRounded =
+                insets.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT);
+        if (topLeftRounded != null) {
+            headerPaddingTop = topLeftRounded.getRadius();
         }
+
+        final RoundedCorner topRightRounded =
+                insets.getRoundedCorner(RoundedCorner.POSITION_TOP_RIGHT);
+        if (topRightRounded != null) {
+            headerPaddingTop = Math.max(headerPaddingTop, topRightRounded.getRadius());
+        }
+
+        if (insets.getDisplayCutout() != null) {
+            headerPaddingTop =
+                    Math.max(headerPaddingTop, insets.getDisplayCutout().getSafeInsetTop());
+            waterfallInsets = insets.getDisplayCutout().getWaterfallInsets();
+        }
+
+        mHeaderPaddingTop = headerPaddingTop;
+        mWaterfallInsets = waterfallInsets;
         return super.onApplyWindowInsets(insets);
     }
 
diff --git a/core/tests/coretests/src/android/text/TextLineTest.java b/core/tests/coretests/src/android/text/TextLineTest.java
index 90ce305..412d6ec 100644
--- a/core/tests/coretests/src/android/text/TextLineTest.java
+++ b/core/tests/coretests/src/android/text/TextLineTest.java
@@ -48,7 +48,7 @@
         final TextLine tl = TextLine.obtain();
         tl.set(paint, line, 0, line.length(), Layout.DIR_LEFT_TO_RIGHT,
                 Layout.DIRS_ALL_LEFT_TO_RIGHT, false /* hasTabs */, null /* tabStops */,
-                0, 0 /* no ellipsis */);
+                0, 0 /* no ellipsis */, false /* useFallbackLinespace */);
         final float originalWidth = tl.metrics(null);
         final float expandedWidth = 2 * originalWidth;
 
@@ -105,7 +105,7 @@
         tl.set(paint, str, 0, str.length(),
                 TextDirectionHeuristics.FIRSTSTRONG_LTR.isRtl(str, 0, str.length()) ? -1 : 1,
                 layout.getLineDirections(0), tabStops != null, tabStops,
-                0, 0 /* no ellipsis */);
+                0, 0 /* no ellipsis */, false /* useFallbackLineSpacing */);
         return tl;
     }
 
@@ -276,7 +276,8 @@
 
         final TextLine tl = TextLine.obtain();
         tl.set(new TextPaint(), text, 0, text.length(), 1, Layout.DIRS_ALL_LEFT_TO_RIGHT,
-                false /* hasTabs */, null /* tabStops */, 9, 12);
+                false /* hasTabs */, null /* tabStops */, 9, 12,
+                false /* useFallbackLineSpacing */);
         tl.measure(text.length(), false /* trailing */, null /* fmi */);
 
         assertFalse(span.mIsUsed);
@@ -292,7 +293,8 @@
 
         final TextLine tl = TextLine.obtain();
         tl.set(new TextPaint(), text, 0, text.length(), 1, Layout.DIRS_ALL_LEFT_TO_RIGHT,
-                false /* hasTabs */, null /* tabStops */, 9, 12);
+                false /* hasTabs */, null /* tabStops */, 9, 12,
+                false /* useFallbackLineSpacing */);
         tl.measure(text.length(), false /* trailing */, null /* fmi */);
 
         assertTrue(span.mIsUsed);
@@ -308,7 +310,8 @@
 
         final TextLine tl = TextLine.obtain();
         tl.set(new TextPaint(), text, 0, text.length(), 1, Layout.DIRS_ALL_LEFT_TO_RIGHT,
-                false /* hasTabs */, null /* tabStops */, 9, 12);
+                false /* hasTabs */, null /* tabStops */, 9, 12,
+                false /* useFallbackLineSpacing */);
         tl.measure(text.length(), false /* trailing */, null /* fmi */);
         assertTrue(span.mIsUsed);
     }
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 878d302..ee0fb44 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -275,6 +275,7 @@
     <privapp-permissions package="com.android.server.telecom">
         <permission name="android.permission.BIND_CONNECTION_SERVICE"/>
         <permission name="android.permission.BIND_INCALL_SERVICE"/>
+        <permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
         <permission name="android.permission.CALL_PRIVILEGED"/>
         <permission name="android.permission.HANDLE_CAR_MODE_CHANGES"/>
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index a612265..425a378 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -67,7 +67,7 @@
      * @hide
      */
     protected int mDensity = Bitmap.DENSITY_NONE;
-    private boolean mAllowHwBitmapsInSwMode = false;
+    private boolean mAllowHwFeaturesInSwMode = false;
 
     protected void throwIfCannotDraw(Bitmap bitmap) {
         if (bitmap.isRecycled()) {
@@ -101,14 +101,14 @@
 
     public void drawArc(float left, float top, float right, float bottom, float startAngle,
             float sweepAngle, boolean useCenter, @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawArc(mNativeCanvasWrapper, left, top, right, bottom, startAngle, sweepAngle,
                 useCenter, paint.getNativeInstance());
     }
 
     public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,
             @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         drawArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, useCenter,
                 paint);
     }
@@ -119,14 +119,14 @@
 
     public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
         throwIfCannotDraw(bitmap);
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawBitmap(mNativeCanvasWrapper, bitmap.getNativeInstance(), left, top,
                 paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity,
                 bitmap.mDensity);
     }
 
     public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawBitmapMatrix(mNativeCanvasWrapper, bitmap.getNativeInstance(), matrix.ni(),
                 paint != null ? paint.getNativeInstance() : 0);
     }
@@ -137,7 +137,7 @@
             throw new NullPointerException();
         }
         throwIfCannotDraw(bitmap);
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
 
         int left, top, right, bottom;
@@ -163,7 +163,7 @@
             throw new NullPointerException();
         }
         throwIfCannotDraw(bitmap);
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
 
         float left, top, right, bottom;
@@ -202,7 +202,7 @@
                 || (lastScanline + width > length)) {
             throw new ArrayIndexOutOfBoundsException();
         }
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         // quick escape if there's nothing to draw
         if (width == 0 || height == 0) {
             return;
@@ -226,7 +226,7 @@
         if ((meshWidth | meshHeight | vertOffset | colorOffset) < 0) {
             throw new ArrayIndexOutOfBoundsException();
         }
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         if (meshWidth == 0 || meshHeight == 0) {
             return;
         }
@@ -243,7 +243,7 @@
     }
 
     public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawCircle(mNativeCanvasWrapper, cx, cy, radius, paint.getNativeInstance());
     }
 
@@ -275,23 +275,23 @@
 
     public void drawLine(float startX, float startY, float stopX, float stopY,
             @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.getNativeInstance());
     }
 
     public void drawLines(@Size(multiple = 4) @NonNull float[] pts, int offset, int count,
             @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawLines(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance());
     }
 
     public void drawLines(@Size(multiple = 4) @NonNull float[] pts, @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         drawLines(pts, 0, pts.length, paint);
     }
 
     public void drawOval(float left, float top, float right, float bottom, @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawOval(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance());
     }
 
@@ -299,18 +299,19 @@
         if (oval == null) {
             throw new NullPointerException();
         }
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         drawOval(oval.left, oval.top, oval.right, oval.bottom, paint);
     }
 
     public void drawPaint(@NonNull Paint paint) {
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawPaint(mNativeCanvasWrapper, paint.getNativeInstance());
     }
 
     public void drawPatch(@NonNull NinePatch patch, @NonNull Rect dst, @Nullable Paint paint) {
         Bitmap bitmap = patch.getBitmap();
         throwIfCannotDraw(bitmap);
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
         nDrawNinePatch(mNativeCanvasWrapper, bitmap.getNativeInstance(), patch.mNativeChunk,
                 dst.left, dst.top, dst.right, dst.bottom, nativePaint,
@@ -320,7 +321,7 @@
     public void drawPatch(@NonNull NinePatch patch, @NonNull RectF dst, @Nullable Paint paint) {
         Bitmap bitmap = patch.getBitmap();
         throwIfCannotDraw(bitmap);
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
         nDrawNinePatch(mNativeCanvasWrapper, bitmap.getNativeInstance(), patch.mNativeChunk,
                 dst.left, dst.top, dst.right, dst.bottom, nativePaint,
@@ -328,7 +329,7 @@
     }
 
     public void drawPath(@NonNull Path path, @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         if (path.isSimplePath && path.rects != null) {
             nDrawRegion(mNativeCanvasWrapper, path.rects.mNativeRegion, paint.getNativeInstance());
         } else {
@@ -337,18 +338,18 @@
     }
 
     public void drawPoint(float x, float y, @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawPoint(mNativeCanvasWrapper, x, y, paint.getNativeInstance());
     }
 
     public void drawPoints(@Size(multiple = 2) float[] pts, int offset, int count,
             @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawPoints(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance());
     }
 
     public void drawPoints(@Size(multiple = 2) @NonNull float[] pts, @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         drawPoints(pts, 0, pts.length, paint);
     }
 
@@ -359,7 +360,7 @@
         if (index < 0 || index + count > text.length || count * 2 > pos.length) {
             throw new IndexOutOfBoundsException();
         }
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         for (int i = 0; i < count; i++) {
             drawText(text, index + i, 1, pos[i * 2], pos[i * 2 + 1], paint);
         }
@@ -368,22 +369,22 @@
     @Deprecated
     public void drawPosText(@NonNull String text, @NonNull @Size(multiple = 2) float[] pos,
             @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         drawPosText(text.toCharArray(), 0, text.length(), pos, paint);
     }
 
     public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance());
     }
 
     public void drawRect(@NonNull Rect r, @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         drawRect(r.left, r.top, r.right, r.bottom, paint);
     }
 
     public void drawRect(@NonNull RectF rect, @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawRect(mNativeCanvasWrapper,
                 rect.left, rect.top, rect.right, rect.bottom, paint.getNativeInstance());
     }
@@ -394,13 +395,13 @@
 
     public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
             @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawRoundRect(mNativeCanvasWrapper, left, top, right, bottom, rx, ry,
                 paint.getNativeInstance());
     }
 
     public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         drawRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, paint);
     }
 
@@ -410,7 +411,7 @@
      */
     public void drawDoubleRoundRect(@NonNull RectF outer, float outerRx, float outerRy,
             @NonNull RectF inner, float innerRx, float innerRy, @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         float outerLeft = outer.left;
         float outerTop = outer.top;
         float outerRight = outer.right;
@@ -431,7 +432,7 @@
      */
     public void drawDoubleRoundRect(@NonNull RectF outer, @NonNull float[] outerRadii,
             @NonNull RectF inner, @NonNull float[] innerRadii, @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         if (innerRadii == null || outerRadii == null
                 || innerRadii.length != 8 || outerRadii.length != 8) {
             throw new IllegalArgumentException("Both inner and outer radii arrays must contain "
@@ -509,7 +510,7 @@
                 (text.length - index - count)) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawText(mNativeCanvasWrapper, text, index, count, x, y, paint.mBidiFlags,
                 paint.getNativeInstance());
     }
@@ -519,7 +520,7 @@
         if ((start | end | (end - start) | (text.length() - end)) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             nDrawText(mNativeCanvasWrapper, text.toString(), start, end, x, y,
@@ -537,7 +538,7 @@
     }
 
     public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) {
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags,
                 paint.getNativeInstance());
     }
@@ -547,7 +548,7 @@
         if ((start | end | (end - start) | (text.length() - end)) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawText(mNativeCanvasWrapper, text, start, end, x, y, paint.mBidiFlags,
                 paint.getNativeInstance());
     }
@@ -557,7 +558,7 @@
         if (index < 0 || index + count > text.length) {
             throw new ArrayIndexOutOfBoundsException();
         }
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawTextOnPath(mNativeCanvasWrapper, text, index, count,
                 path.readOnlyNI(), hOffset, vOffset,
                 paint.mBidiFlags, paint.getNativeInstance());
@@ -566,7 +567,7 @@
     public void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset,
             float vOffset, @NonNull Paint paint) {
         if (text.length() > 0) {
-            throwIfHasHwBitmapInSwMode(paint);
+            throwIfHasHwFeaturesInSwMode(paint);
             nDrawTextOnPath(mNativeCanvasWrapper, text, path.readOnlyNI(), hOffset, vOffset,
                     paint.mBidiFlags, paint.getNativeInstance());
         }
@@ -587,7 +588,7 @@
             throw new IndexOutOfBoundsException();
         }
 
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawTextRun(mNativeCanvasWrapper, text, index, count, contextIndex, contextCount,
                 x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */);
     }
@@ -606,7 +607,7 @@
             throw new IndexOutOfBoundsException();
         }
 
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             nDrawTextRun(mNativeCanvasWrapper, text.toString(), start, end, contextStart,
@@ -664,7 +665,7 @@
         if (indices != null) {
             checkRange(indices.length, indexOffset, indexCount);
         }
-        throwIfHasHwBitmapInSwMode(paint);
+        throwIfHasHwFeaturesInSwMode(paint);
         nDrawVertices(mNativeCanvasWrapper, mode.nativeInt, vertexCount, verts,
                 vertOffset, texs, texOffset, colors, colorOffset,
                 indices, indexOffset, indexCount, paint.getNativeInstance());
@@ -680,50 +681,52 @@
     /**
      * @hide
      */
-    public void setHwBitmapsInSwModeEnabled(boolean enabled) {
-        mAllowHwBitmapsInSwMode = enabled;
+    public void setHwFeaturesInSwModeEnabled(boolean enabled) {
+        mAllowHwFeaturesInSwMode = enabled;
     }
 
     /**
      * @hide
      */
-    public boolean isHwBitmapsInSwModeEnabled() {
-        return mAllowHwBitmapsInSwMode;
+    public boolean isHwFeaturesInSwModeEnabled() {
+        return mAllowHwFeaturesInSwMode;
     }
 
     /**
+     * If true throw an exception
      * @hide
      */
-    protected void onHwBitmapInSwMode() {
-        if (!mAllowHwBitmapsInSwMode) {
+    protected boolean onHwFeatureInSwMode() {
+        return !mAllowHwFeaturesInSwMode;
+    }
+
+    private void throwIfHwBitmapInSwMode(Bitmap bitmap) {
+        if (!isHardwareAccelerated() && bitmap.getConfig() == Bitmap.Config.HARDWARE
+                && onHwFeatureInSwMode()) {
             throw new IllegalArgumentException(
                     "Software rendering doesn't support hardware bitmaps");
         }
     }
 
-    private void throwIfHwBitmapInSwMode(Bitmap bitmap) {
-        if (!isHardwareAccelerated() && bitmap.getConfig() == Bitmap.Config.HARDWARE) {
-            onHwBitmapInSwMode();
-        }
-    }
-
-    private void throwIfHasHwBitmapInSwMode(Paint p) {
+    private void throwIfHasHwFeaturesInSwMode(Paint p) {
         if (isHardwareAccelerated() || p == null) {
             return;
         }
-        throwIfHasHwBitmapInSwMode(p.getShader());
+        throwIfHasHwFeaturesInSwMode(p.getShader());
     }
 
-    private void throwIfHasHwBitmapInSwMode(Shader shader) {
+    private void throwIfHasHwFeaturesInSwMode(Shader shader) {
         if (shader == null) {
             return;
         }
         if (shader instanceof BitmapShader) {
             throwIfHwBitmapInSwMode(((BitmapShader) shader).mBitmap);
-        }
-        if (shader instanceof ComposeShader) {
-            throwIfHasHwBitmapInSwMode(((ComposeShader) shader).mShaderA);
-            throwIfHasHwBitmapInSwMode(((ComposeShader) shader).mShaderB);
+        } else if (shader instanceof RuntimeShader && onHwFeatureInSwMode()) {
+            throw new IllegalArgumentException(
+                    "Software rendering doesn't support RuntimeShader");
+        } else if (shader instanceof ComposeShader) {
+            throwIfHasHwFeaturesInSwMode(((ComposeShader) shader).mShaderA);
+            throwIfHasHwFeaturesInSwMode(((ComposeShader) shader).mShaderB);
         }
     }
 
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 42e470b..eefad8d 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -46,6 +46,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Locale;
+import java.util.Objects;
 
 /**
  * The Paint class holds the style and color information about how to draw
@@ -2131,6 +2132,116 @@
     }
 
     /**
+     * Returns the font metrics value for the given text.
+     *
+     * If the text is rendered with multiple font files, this function returns the large ascent and
+     * descent that are enough for drawing all font files.
+     *
+     * The context range is used for shaping context. Some script, e.g. Arabic or Devanagari,
+     * changes letter shape based on its location or surrounding characters.
+     *
+     * @param text a text to be measured.
+     * @param start a starting offset in the text.
+     * @param count a length of the text to be measured.
+     * @param contextStart a context starting offset in the text.
+     * @param contextCount a length of the context to be used.
+     * @param isRtl true if measuring on RTL context, otherwise false.
+     * @param outMetrics the output font metrics.
+     */
+    public void getFontMetricsInt(
+            @NonNull CharSequence text,
+            @IntRange(from = 0) int start, @IntRange(from = 0) int count,
+            @IntRange(from = 0) int contextStart, @IntRange(from = 0) int contextCount,
+            boolean isRtl,
+            @NonNull FontMetricsInt outMetrics) {
+
+        if (text == null) {
+            throw new IllegalArgumentException("text must not be null");
+        }
+        if (start < 0 || start >= text.length()) {
+            throw new IllegalArgumentException("start argument is out of bounds.");
+        }
+        if (count < 0 || start + count > text.length()) {
+            throw new IllegalArgumentException("count argument is out of bounds.");
+        }
+        if (contextStart < 0 || contextStart >= text.length()) {
+            throw new IllegalArgumentException("ctxStart argument is out of bounds.");
+        }
+        if (contextCount < 0 || contextStart + contextCount > text.length()) {
+            throw new IllegalArgumentException("ctxCount argument is out of bounds.");
+        }
+        if (outMetrics == null) {
+            throw new IllegalArgumentException("outMetrics must not be null.");
+        }
+
+        if (count == 0) {
+            getFontMetricsInt(outMetrics);
+            return;
+        }
+
+        if (text instanceof String) {
+            nGetFontMetricsIntForText(mNativePaint, (String) text, start, count, contextStart,
+                    contextCount, isRtl, outMetrics);
+        } else {
+            char[] buf = TemporaryBuffer.obtain(contextCount);
+            TextUtils.getChars(text, contextStart, contextStart + contextCount, buf, 0);
+            nGetFontMetricsIntForText(mNativePaint, buf, start - contextStart, count, 0,
+                    contextCount, isRtl, outMetrics);
+        }
+
+    }
+
+    /**
+     * Returns the font metrics value for the given text.
+     *
+     * If the text is rendered with multiple font files, this function returns the large ascent and
+     * descent that are enough for drawing all font files.
+     *
+     * The context range is used for shaping context. Some script, e.g. Arabic or Devanagari,
+     * changes letter shape based on its location or surrounding characters.
+     *
+     * @param text a text to be measured.
+     * @param start a starting offset in the text.
+     * @param count a length of the text to be measured.
+     * @param contextStart a context starting offset in the text.
+     * @param contextCount a length of the context to be used.
+     * @param isRtl true if measuring on RTL context, otherwise false.
+     * @param outMetrics the output font metrics.
+     */
+    public void getFontMetricsInt(@NonNull char[] text,
+            @IntRange(from = 0) int start, @IntRange(from = 0) int count,
+            @IntRange(from = 0) int contextStart, @IntRange(from = 0) int contextCount,
+            boolean isRtl,
+            @NonNull FontMetricsInt outMetrics) {
+        if (text == null) {
+            throw new IllegalArgumentException("text must not be null");
+        }
+        if (start < 0 || start >= text.length) {
+            throw new IllegalArgumentException("start argument is out of bounds.");
+        }
+        if (count < 0 || start + count > text.length) {
+            throw new IllegalArgumentException("count argument is out of bounds.");
+        }
+        if (contextStart < 0 || contextStart >= text.length) {
+            throw new IllegalArgumentException("ctxStart argument is out of bounds.");
+        }
+        if (contextCount < 0 || contextStart + contextCount > text.length) {
+            throw new IllegalArgumentException("ctxCount argument is out of bounds.");
+        }
+        if (outMetrics == null) {
+            throw new IllegalArgumentException("outMetrics must not be null.");
+        }
+
+        if (count == 0) {
+            getFontMetricsInt(outMetrics);
+            return;
+        }
+
+        nGetFontMetricsIntForText(mNativePaint, text, start, count, contextStart, contextCount,
+                isRtl, outMetrics);
+    }
+
+    /**
      * Convenience method for callers that want to have FontMetrics values as
      * integers.
      */
@@ -2163,6 +2274,23 @@
                     " descent=" + descent + " bottom=" + bottom +
                     " leading=" + leading;
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof FontMetricsInt)) return false;
+            FontMetricsInt that = (FontMetricsInt) o;
+            return top == that.top
+                    && ascent == that.ascent
+                    && descent == that.descent
+                    && bottom == that.bottom
+                    && leading == that.leading;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(top, ascent, descent, bottom, leading);
+        }
     }
 
     /**
@@ -3117,6 +3245,13 @@
             int contextStart, int contextEnd, boolean isRtl, int offset);
     private static native int nGetOffsetForAdvance(long paintPtr, char[] text, int start, int end,
             int contextStart, int contextEnd, boolean isRtl, float advance);
+    private static native void nGetFontMetricsIntForText(long paintPtr, char[] text,
+            int start, int count, int ctxStart, int ctxCount, boolean isRtl,
+            FontMetricsInt outMetrics);
+    private static native void nGetFontMetricsIntForText(long paintPtr, String text,
+            int start, int count, int ctxStart, int ctxCount, boolean isRtl,
+            FontMetricsInt outMetrics);
+
 
 
     // ---------------- @FastNative ------------------------
@@ -3130,7 +3265,6 @@
     @FastNative
     private static native int nGetFontMetricsInt(long paintPtr, FontMetricsInt fmi);
 
-
     // ---------------- @CriticalNative ------------------------
 
     @CriticalNative
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index 390d3d4..ee4165b 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -124,7 +124,7 @@
     public void endRecording() {
         verifyValid();
         if (mRecordingCanvas != null) {
-            mRequiresHwAcceleration = mRecordingCanvas.mHoldsHwBitmap;
+            mRequiresHwAcceleration = mRecordingCanvas.mUsesHwFeature;
             mRecordingCanvas = null;
             nativeEndRecording(mNativePicture);
         }
@@ -182,8 +182,10 @@
         if (mRecordingCanvas != null) {
             endRecording();
         }
-        if (mRequiresHwAcceleration && !canvas.isHardwareAccelerated()) {
-            canvas.onHwBitmapInSwMode();
+        if (mRequiresHwAcceleration && !canvas.isHardwareAccelerated()
+                && canvas.onHwFeatureInSwMode()) {
+            throw new IllegalArgumentException("Software rendering not supported for Pictures that"
+                    + " require hardware acceleration");
         }
         nativeDraw(canvas.getNativeCanvasWrapper(), mNativePicture);
     }
@@ -242,7 +244,7 @@
 
     private static class PictureCanvas extends Canvas {
         private final Picture mPicture;
-        boolean mHoldsHwBitmap;
+        boolean mUsesHwFeature;
 
         public PictureCanvas(Picture pict, long nativeCanvas) {
             super(nativeCanvas);
@@ -265,8 +267,9 @@
         }
 
         @Override
-        protected void onHwBitmapInSwMode() {
-            mHoldsHwBitmap = true;
+        protected boolean onHwFeatureInSwMode() {
+            mUsesHwFeature = true;
+            return false;
         }
     }
 }
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index b843589..ffaa4ea 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -868,7 +868,7 @@
     private void drawPatterned(@NonNull Canvas canvas) {
         final Rect bounds = mHotspotBounds;
         final int saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
-        boolean useCanvasProps = shouldUseCanvasProps(canvas);
+        boolean useCanvasProps = !mForceSoftware;
         if (isBounded()) {
             canvas.clipRect(getDirtyBounds());
         }
@@ -914,7 +914,11 @@
         }
         for (int i = 0; i < mRunningAnimations.size(); i++) {
             RippleAnimationSession s = mRunningAnimations.get(i);
-            if (useCanvasProps) {
+            if (!canvas.isHardwareAccelerated()) {
+                Log.e(TAG, "The RippleDrawable.STYLE_PATTERNED animation is not supported for a "
+                        + "non-hardware accelerated Canvas. Skipping animation.");
+                break;
+            } else if (useCanvasProps) {
                 RippleAnimationSession.AnimationProperties<CanvasProperty<Float>,
                         CanvasProperty<Paint>>
                         p = s.getCanvasProperties();
@@ -1002,10 +1006,6 @@
         return color;
     }
 
-    private boolean shouldUseCanvasProps(Canvas c) {
-        return !mForceSoftware && c.isHardwareAccelerated();
-    }
-
     @Override
     public void invalidateSelf() {
         invalidateSelf(true);
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 df751fc..180c772 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
@@ -79,22 +79,23 @@
     }
 
     @Override
-    public void registerOrganizer() {
-        if (mAnimationController != null) {
-            throw new IllegalStateException("Must unregister the organizer before re-register.");
+    public void unregisterOrganizer() {
+        stopOverrideSplitAnimation();
+        mAnimationController = null;
+        super.unregisterOrganizer();
+    }
+
+    void startOverrideSplitAnimation() {
+        if (mAnimationController == null) {
+            mAnimationController = new TaskFragmentAnimationController(this);
         }
-        super.registerOrganizer();
-        mAnimationController = new TaskFragmentAnimationController(this);
         mAnimationController.registerRemoteAnimations();
     }
 
-    @Override
-    public void unregisterOrganizer() {
+    void stopOverrideSplitAnimation() {
         if (mAnimationController != null) {
             mAnimationController.unregisterRemoteAnimations();
-            mAnimationController = null;
         }
-        super.unregisterOrganizer();
     }
 
     /**
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index b8e8b01..8f368c2 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -33,6 +33,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -63,6 +64,9 @@
     private @NonNull Consumer<List<SplitInfo>> mEmbeddingCallback;
     private final List<SplitInfo> mLastReportedSplitStates = new ArrayList<>();
 
+    // We currently only support split activity embedding within the one root Task.
+    private final Rect mParentBounds = new Rect();
+
     public SplitController() {
         mPresenter = new SplitPresenter(new MainThreadExecutor(), this);
         ActivityThread activityThread = ActivityThread.currentActivityThread();
@@ -79,6 +83,7 @@
     public void setEmbeddingRules(@NonNull Set<EmbeddingRule> rules) {
         mSplitRules.clear();
         mSplitRules.addAll(rules);
+        updateAnimationOverride();
     }
 
     @NonNull
@@ -158,6 +163,7 @@
     @Override
     public void onTaskFragmentParentInfoChanged(@NonNull IBinder fragmentToken,
             @NonNull Configuration parentConfig) {
+        onParentBoundsMayChange(parentConfig.windowConfiguration.getBounds());
         TaskFragmentContainer container = getContainer(fragmentToken);
         if (container != null) {
             mPresenter.updateContainer(container);
@@ -165,6 +171,51 @@
         }
     }
 
+    private void onParentBoundsMayChange(Activity activity) {
+        if (activity.isFinishing()) {
+            return;
+        }
+
+        onParentBoundsMayChange(mPresenter.getParentContainerBounds(activity));
+    }
+
+    private void onParentBoundsMayChange(Rect parentBounds) {
+        if (!parentBounds.isEmpty() && !mParentBounds.equals(parentBounds)) {
+            mParentBounds.set(parentBounds);
+            updateAnimationOverride();
+        }
+    }
+
+    /**
+     * Updates if we should override transition animation. We only want to override if the Task
+     * bounds is large enough for at least one split rule.
+     */
+    private void updateAnimationOverride() {
+        if (mParentBounds.isEmpty()) {
+            // We don't know about the parent bounds yet.
+            return;
+        }
+
+        // Check if the parent container bounds can support any split rule.
+        boolean supportSplit = false;
+        for (EmbeddingRule rule : mSplitRules) {
+            if (!(rule instanceof SplitRule)) {
+                continue;
+            }
+            if (mPresenter.shouldShowSideBySide(mParentBounds, (SplitRule) rule)) {
+                supportSplit = true;
+                break;
+            }
+        }
+
+        // We only want to override if it supports split.
+        if (supportSplit) {
+            mPresenter.startOverrideSplitAnimation();
+        } else {
+            mPresenter.stopOverrideSplitAnimation();
+        }
+    }
+
     void onActivityCreated(@NonNull Activity launchedActivity) {
         handleActivityCreated(launchedActivity);
         updateCallbackIfNecessary();
@@ -180,6 +231,11 @@
         final TaskFragmentContainer currentContainer = getContainerWithActivity(
                 launchedActivity.getActivityToken());
 
+        if (currentContainer == null) {
+            // Initial check before any TaskFragment is created.
+            onParentBoundsMayChange(launchedActivity);
+        }
+
         // Check if the activity is configured to always be expanded.
         if (shouldExpand(launchedActivity, null, splitRules)) {
             if (shouldContainerBeExpanded(currentContainer)) {
@@ -257,6 +313,8 @@
             // onTaskFragmentParentInfoChanged
             return;
         }
+        // The bounds of the container may have been changed.
+        onParentBoundsMayChange(activity);
 
         // Check if activity requires a placeholder
         launchPlaceholderIfNecessary(activity);
@@ -346,7 +404,7 @@
     TaskFragmentContainer getTopActiveContainer() {
         for (int i = mContainers.size() - 1; i >= 0; i--) {
             TaskFragmentContainer container = mContainers.get(i);
-            if (!container.isFinished()) {
+            if (!container.isFinished() && container.getTopNonFinishingActivity() != null) {
                 return container;
             }
         }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
index 3c7d2de..a801dc8 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
@@ -37,32 +37,42 @@
 
     private final TaskFragmentOrganizer mOrganizer;
     private final TaskFragmentAnimationRunner mRemoteRunner = new TaskFragmentAnimationRunner();
+    private final RemoteAnimationDefinition mDefinition;
+    private boolean mIsRegister;
 
     TaskFragmentAnimationController(TaskFragmentOrganizer organizer) {
         mOrganizer = organizer;
+        mDefinition = new RemoteAnimationDefinition();
+        final RemoteAnimationAdapter animationAdapter =
+                new RemoteAnimationAdapter(mRemoteRunner, 0, 0, true /* changeNeedsSnapshot */);
+        mDefinition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, animationAdapter);
+        mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, animationAdapter);
+        mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_OPEN, animationAdapter);
+        mDefinition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, animationAdapter);
+        mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, animationAdapter);
+        mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_CLOSE, animationAdapter);
+        mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, animationAdapter);
     }
 
     void registerRemoteAnimations() {
         if (DEBUG) {
             Log.v(TAG, "registerRemoteAnimations");
         }
-        final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
-        final RemoteAnimationAdapter animationAdapter =
-                new RemoteAnimationAdapter(mRemoteRunner, 0, 0, true /* changeNeedsSnapshot */);
-        definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, animationAdapter);
-        definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, animationAdapter);
-        definition.addRemoteAnimation(TRANSIT_OLD_TASK_OPEN, animationAdapter);
-        definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, animationAdapter);
-        definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, animationAdapter);
-        definition.addRemoteAnimation(TRANSIT_OLD_TASK_CLOSE, animationAdapter);
-        definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, animationAdapter);
-        mOrganizer.registerRemoteAnimations(definition);
+        if (mIsRegister) {
+            return;
+        }
+        mOrganizer.registerRemoteAnimations(mDefinition);
+        mIsRegister = true;
     }
 
     void unregisterRemoteAnimations() {
         if (DEBUG) {
             Log.v(TAG, "unregisterRemoteAnimations");
         }
+        if (!mIsRegister) {
+            return;
+        }
         mOrganizer.unregisterRemoteAnimations();
+        mIsRegister = false;
     }
 }
diff --git a/libs/WindowManager/Shell/res/layout/background_panel.xml b/libs/WindowManager/Shell/res/layout/background_panel.xml
new file mode 100644
index 0000000..c3569d8
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/background_panel.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/background_panel_layout"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:gravity="center_horizontal | center_vertical"
+    android:background="@android:color/transparent">
+</LinearLayout>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/BackgroundWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/BackgroundWindowManager.java
new file mode 100644
index 0000000..c20b7d9
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/BackgroundWindowManager.java
@@ -0,0 +1,246 @@
+/*
+ * 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.onehanded;
+
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+
+import static com.android.wm.shell.onehanded.OneHandedState.STATE_ACTIVE;
+import static com.android.wm.shell.onehanded.OneHandedState.STATE_ENTERING;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.util.Slog;
+import android.view.ContextThemeWrapper;
+import android.view.IWindow;
+import android.view.LayoutInflater;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.SurfaceSession;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowlessWindowManager;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.common.DisplayLayout;
+
+import java.io.PrintWriter;
+
+/**
+ * Holds view hierarchy of a root surface and helps inflate a themeable view for background.
+ */
+public final class BackgroundWindowManager extends WindowlessWindowManager {
+    private static final String TAG = BackgroundWindowManager.class.getSimpleName();
+    private static final int THEME_COLOR_OFFSET = 10;
+
+    private final OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
+            mTransactionFactory;
+
+    private Context mContext;
+    private Rect mDisplayBounds;
+    private SurfaceControlViewHost mViewHost;
+    private SurfaceControl mLeash;
+    private View mBackgroundView;
+    private @OneHandedState.State int mCurrentState;
+
+    public BackgroundWindowManager(Context context) {
+        super(context.getResources().getConfiguration(), null /* rootSurface */,
+                null /* hostInputToken */);
+        mContext = context;
+        mTransactionFactory = SurfaceControl.Transaction::new;
+    }
+
+    @Override
+    public SurfaceControl getSurfaceControl(IWindow window) {
+        return super.getSurfaceControl(window);
+    }
+
+    @Override
+    public void setConfiguration(Configuration configuration) {
+        super.setConfiguration(configuration);
+        mContext = mContext.createConfigurationContext(configuration);
+    }
+
+    /**
+     * onConfigurationChanged events for updating background theme color.
+     */
+    public void onConfigurationChanged() {
+        if (mCurrentState == STATE_ENTERING || mCurrentState == STATE_ACTIVE) {
+            updateThemeOnly();
+        }
+    }
+
+    /**
+     * One-handed mode state changed callback
+     * @param newState of One-handed mode representing by {@link OneHandedState}
+     */
+    public void onStateChanged(int newState) {
+        mCurrentState = newState;
+    }
+
+    @Override
+    protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
+        final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
+                .setColorLayer()
+                .setBufferSize(mDisplayBounds.width(), mDisplayBounds.height())
+                .setFormat(PixelFormat.RGB_888)
+                .setOpaque(true)
+                .setName(TAG)
+                .setCallsite("BackgroundWindowManager#attachToParentSurface");
+        mLeash = builder.build();
+        b.setParent(mLeash);
+    }
+
+    /** Inflates background view on to the root surface. */
+    boolean initView() {
+        if (mBackgroundView != null || mViewHost != null) {
+            return false;
+        }
+
+        mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
+        mBackgroundView = (View) LayoutInflater.from(mContext)
+                .inflate(R.layout.background_panel, null /* root */);
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                mDisplayBounds.width(), mDisplayBounds.height(), 0 /* TYPE NONE */,
+                FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL | FLAG_WATCH_OUTSIDE_TOUCH
+                        | FLAG_SLIPPERY, PixelFormat.TRANSLUCENT);
+        lp.token = new Binder();
+        lp.setTitle("background-panel");
+        lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
+        mBackgroundView.setBackgroundColor(getThemeColorForBackground());
+        mViewHost.setView(mBackgroundView, lp);
+        return true;
+    }
+
+    /**
+     * Called when onDisplayAdded() or onDisplayRemoved() callback.
+     * @param displayLayout The latest {@link DisplayLayout} for display bounds.
+     */
+    public void onDisplayChanged(DisplayLayout displayLayout) {
+        // One-handed mode is only available on portrait.
+        if (displayLayout.height() > displayLayout.width()) {
+            mDisplayBounds = new Rect(0, 0, displayLayout.width(), displayLayout.height());
+        } else {
+            mDisplayBounds = new Rect(0, 0, displayLayout.height(), displayLayout.width());
+        }
+    }
+
+    private void updateThemeOnly() {
+        if (mBackgroundView == null || mViewHost == null || mLeash == null) {
+            Slog.w(TAG, "Background view or SurfaceControl does not exist when trying to "
+                    + "update theme only!");
+            return;
+        }
+
+        WindowManager.LayoutParams lp = (WindowManager.LayoutParams)
+                mBackgroundView.getLayoutParams();
+        mBackgroundView.setBackgroundColor(getThemeColorForBackground());
+        mViewHost.setView(mBackgroundView, lp);
+    }
+
+    /**
+     * Shows the background layer when One-handed mode triggered.
+     */
+    public void showBackgroundLayer() {
+        if (!initView()) {
+            updateThemeOnly();
+            return;
+        }
+        if (mLeash == null) {
+            Slog.w(TAG, "SurfaceControl mLeash is null, can't show One-handed mode "
+                    + "background panel!");
+            return;
+        }
+
+        mTransactionFactory.getTransaction()
+                .setAlpha(mLeash, 1.0f)
+                .setLayer(mLeash, -1 /* at bottom-most layer */)
+                .show(mLeash)
+                .apply();
+    }
+
+    /**
+     * Remove the leash of background layer after stop One-handed mode.
+     */
+    public void removeBackgroundLayer() {
+        if (mBackgroundView != null) {
+            mBackgroundView = null;
+        }
+
+        if (mViewHost != null) {
+            mViewHost.release();
+            mViewHost = null;
+        }
+
+        if (mLeash != null) {
+            mTransactionFactory.getTransaction().remove(mLeash).apply();
+            mLeash = null;
+        }
+    }
+
+    /**
+     * Gets {@link SurfaceControl} of the background layer.
+     * @return {@code null} if not exist.
+     */
+    @Nullable
+    SurfaceControl getSurfaceControl() {
+        return mLeash;
+    }
+
+    private int getThemeColor() {
+        final Context themedContext = new ContextThemeWrapper(mContext,
+                com.android.internal.R.style.Theme_DeviceDefault_DayNight);
+        return themedContext.getColor(R.color.one_handed_tutorial_background_color);
+    }
+
+    int getThemeColorForBackground() {
+        final int origThemeColor = getThemeColor();
+        return android.graphics.Color.argb(Color.alpha(origThemeColor),
+                Color.red(origThemeColor) - THEME_COLOR_OFFSET,
+                Color.green(origThemeColor) - THEME_COLOR_OFFSET,
+                Color.blue(origThemeColor) - THEME_COLOR_OFFSET);
+    }
+
+    private float adjustColor(int origColor) {
+        return Math.max(origColor - THEME_COLOR_OFFSET, 0) / 255.0f;
+    }
+
+    void dump(@NonNull PrintWriter pw) {
+        final String innerPrefix = "  ";
+        pw.println(TAG);
+        pw.print(innerPrefix + "mDisplayBounds=");
+        pw.println(mDisplayBounds);
+        pw.print(innerPrefix + "mViewHost=");
+        pw.println(mViewHost);
+        pw.print(innerPrefix + "mLeash=");
+        pw.println(mLeash);
+        pw.print(innerPrefix + "mBackgroundView=");
+        pw.println(mBackgroundView);
+    }
+
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
deleted file mode 100644
index 9e1c61a..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2020 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.onehanded;
-
-import static com.android.wm.shell.onehanded.OneHandedState.STATE_ACTIVE;
-
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.view.ContextThemeWrapper;
-import android.view.SurfaceControl;
-import android.view.SurfaceSession;
-import android.view.animation.LinearInterpolator;
-import android.window.DisplayAreaAppearedInfo;
-import android.window.DisplayAreaInfo;
-import android.window.DisplayAreaOrganizer;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-
-import com.android.wm.shell.R;
-import com.android.wm.shell.common.DisplayLayout;
-
-import java.io.PrintWriter;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-/**
- * Manages OneHanded color background layer areas.
- * To avoid when turning the Dark theme on, users can not clearly identify
- * the screen has entered one handed mode.
- */
-public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer
-        implements OneHandedAnimationCallback, OneHandedState.OnStateChangedListener {
-    private static final String TAG = "OneHandedBackgroundPanelOrganizer";
-    private static final int THEME_COLOR_OFFSET = 10;
-    private static final int ALPHA_ANIMATION_DURATION = 200;
-
-    private final Context mContext;
-    private final SurfaceSession mSurfaceSession = new SurfaceSession();
-    private final OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
-            mTransactionFactory;
-
-    private @OneHandedState.State int mCurrentState;
-    private ValueAnimator mAlphaAnimator;
-
-    private float mTranslationFraction;
-    private float[] mThemeColor;
-
-    /**
-     * The background to distinguish the boundary of translated windows and empty region when
-     * one handed mode triggered.
-     */
-    private Rect mBkgBounds;
-    private Rect mStableInsets;
-
-    @Nullable
-    @VisibleForTesting
-    SurfaceControl mBackgroundSurface;
-    @Nullable
-    private SurfaceControl mParentLeash;
-
-    public OneHandedBackgroundPanelOrganizer(Context context, DisplayLayout displayLayout,
-            OneHandedSettingsUtil settingsUtil, Executor executor) {
-        super(executor);
-        mContext = context;
-        mTranslationFraction = settingsUtil.getTranslationFraction(context);
-        mTransactionFactory = SurfaceControl.Transaction::new;
-        updateThemeColors();
-    }
-
-    @Override
-    public void onDisplayAreaAppeared(@NonNull DisplayAreaInfo displayAreaInfo,
-            @NonNull SurfaceControl leash) {
-        mParentLeash = leash;
-    }
-
-    @Override
-    public List<DisplayAreaAppearedInfo> registerOrganizer(int displayAreaFeature) {
-        final List<DisplayAreaAppearedInfo> displayAreaInfos;
-        displayAreaInfos = super.registerOrganizer(displayAreaFeature);
-        for (int i = 0; i < displayAreaInfos.size(); i++) {
-            final DisplayAreaAppearedInfo info = displayAreaInfos.get(i);
-            onDisplayAreaAppeared(info.getDisplayAreaInfo(), info.getLeash());
-        }
-        return displayAreaInfos;
-    }
-
-    @Override
-    public void unregisterOrganizer() {
-        super.unregisterOrganizer();
-        removeBackgroundPanelLayer();
-        mParentLeash = null;
-    }
-
-    @Override
-    public void onAnimationUpdate(SurfaceControl.Transaction tx, float xPos, float yPos) {
-        final int yTopPos = (mStableInsets.top - mBkgBounds.height()) + Math.round(yPos);
-        tx.setPosition(mBackgroundSurface, 0, yTopPos);
-    }
-
-    @Nullable
-    @VisibleForTesting
-    boolean isRegistered() {
-        return mParentLeash != null;
-    }
-
-    void createBackgroundSurface() {
-        mBackgroundSurface = new SurfaceControl.Builder(mSurfaceSession)
-                .setBufferSize(mBkgBounds.width(), mBkgBounds.height())
-                .setColorLayer()
-                .setFormat(PixelFormat.RGB_888)
-                .setOpaque(true)
-                .setName("one-handed-background-panel")
-                .setCallsite("OneHandedBackgroundPanelOrganizer")
-                .build();
-
-        // TODO(185890335) Avoid Dimming for mid-range luminance wallpapers flash.
-        mAlphaAnimator = ValueAnimator.ofFloat(1.0f, 0.0f);
-        mAlphaAnimator.setInterpolator(new LinearInterpolator());
-        mAlphaAnimator.setDuration(ALPHA_ANIMATION_DURATION);
-        mAlphaAnimator.addUpdateListener(
-                animator -> detachBackgroundFromParent(animator));
-    }
-
-    void detachBackgroundFromParent(ValueAnimator animator) {
-        if (mBackgroundSurface == null || mParentLeash == null) {
-            return;
-        }
-        // TODO(185890335) Avoid Dimming for mid-range luminance wallpapers flash.
-        final float currentValue = (float) animator.getAnimatedValue();
-        final SurfaceControl.Transaction tx = mTransactionFactory.getTransaction();
-        if (currentValue == 0.0f) {
-            tx.reparent(mBackgroundSurface, null).apply();
-        } else {
-            tx.setAlpha(mBackgroundSurface, (float) animator.getAnimatedValue()).apply();
-        }
-    }
-
-    /**
-     * Called when onDisplayAdded() or onDisplayRemoved() callback.
-     *
-     * @param displayLayout The latest {@link DisplayLayout} representing current displayId
-     */
-    public void onDisplayChanged(DisplayLayout displayLayout) {
-        mStableInsets = displayLayout.stableInsets();
-        // Ensure the mBkgBounds is portrait, due to OHM only support on portrait
-        if (displayLayout.height() > displayLayout.width()) {
-            mBkgBounds = new Rect(0, 0, displayLayout.width(),
-                    Math.round(displayLayout.height() * mTranslationFraction) + mStableInsets.top);
-        } else {
-            mBkgBounds = new Rect(0, 0, displayLayout.height(),
-                    Math.round(displayLayout.width() * mTranslationFraction) + mStableInsets.top);
-        }
-    }
-
-    @VisibleForTesting
-    void onStart() {
-        if (mBackgroundSurface == null) {
-            createBackgroundSurface();
-        }
-        showBackgroundPanelLayer();
-    }
-
-    /**
-     * Called when transition finished.
-     */
-    public void onStopFinished() {
-        if (mAlphaAnimator == null) {
-            return;
-        }
-        mAlphaAnimator.start();
-    }
-
-    @VisibleForTesting
-    void showBackgroundPanelLayer() {
-        if (mParentLeash == null) {
-            return;
-        }
-
-        if (mBackgroundSurface == null) {
-            createBackgroundSurface();
-        }
-
-        // TODO(185890335) Avoid Dimming for mid-range luminance wallpapers flash.
-        if (mAlphaAnimator.isRunning()) {
-            mAlphaAnimator.end();
-        }
-
-        mTransactionFactory.getTransaction()
-                .reparent(mBackgroundSurface, mParentLeash)
-                .setAlpha(mBackgroundSurface, 1.0f)
-                .setLayer(mBackgroundSurface, -1 /* at bottom-most layer */)
-                .setColor(mBackgroundSurface, mThemeColor)
-                .show(mBackgroundSurface)
-                .apply();
-    }
-
-    @VisibleForTesting
-    void removeBackgroundPanelLayer() {
-        if (mBackgroundSurface == null) {
-            return;
-        }
-
-        mTransactionFactory.getTransaction()
-                .remove(mBackgroundSurface)
-                .apply();
-        mBackgroundSurface = null;
-    }
-
-    /**
-     * onConfigurationChanged events for updating tutorial text.
-     */
-    public void onConfigurationChanged() {
-        updateThemeColors();
-
-        if (mCurrentState != STATE_ACTIVE) {
-            return;
-        }
-        showBackgroundPanelLayer();
-    }
-
-    private void updateThemeColors() {
-        final Context themedContext = new ContextThemeWrapper(mContext,
-                com.android.internal.R.style.Theme_DeviceDefault_DayNight);
-        final int themeColor = themedContext.getColor(
-                R.color.one_handed_tutorial_background_color);
-        mThemeColor = new float[]{
-                adjustColor(Color.red(themeColor)),
-                adjustColor(Color.green(themeColor)),
-                adjustColor(Color.blue(themeColor))};
-    }
-
-    private float adjustColor(int origColor) {
-        return Math.max(origColor - THEME_COLOR_OFFSET, 0) / 255.0f;
-    }
-
-    @Override
-    public void onStateChanged(int newState) {
-        mCurrentState = newState;
-    }
-
-    void dump(@NonNull PrintWriter pw) {
-        final String innerPrefix = "  ";
-        pw.println(TAG);
-        pw.print(innerPrefix + "mBackgroundSurface=");
-        pw.println(mBackgroundSurface);
-        pw.print(innerPrefix + "mBkgBounds=");
-        pw.println(mBkgBounds);
-        pw.print(innerPrefix + "mThemeColor=");
-        pw.println(mThemeColor);
-        pw.print(innerPrefix + "mTranslationFraction=");
-        pw.println(mTranslationFraction);
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index 96f82fa..48acfc1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -99,7 +99,6 @@
 
     private OneHandedEventCallback mEventCallback;
     private OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer;
-    private OneHandedBackgroundPanelOrganizer mBackgroundPanelOrganizer;
     private OneHandedUiEventLogger mOneHandedUiEventLogger;
 
     private final DisplayController.OnDisplaysChangedListener mDisplaysChangedListener =
@@ -163,7 +162,6 @@
                 public void onStopFinished(Rect bounds) {
                     mState.setState(STATE_NONE);
                     notifyShortcutStateChanged(STATE_NONE);
-                    mBackgroundPanelOrganizer.onStopFinished();
                 }
             };
 
@@ -201,32 +199,28 @@
         OneHandedAccessibilityUtil accessibilityUtil = new OneHandedAccessibilityUtil(context);
         OneHandedTimeoutHandler timeoutHandler = new OneHandedTimeoutHandler(mainExecutor);
         OneHandedState oneHandedState = new OneHandedState();
+        BackgroundWindowManager backgroundWindowManager = new BackgroundWindowManager(context);
         OneHandedTutorialHandler tutorialHandler = new OneHandedTutorialHandler(context,
-                settingsUtil, windowManager);
+                settingsUtil, windowManager, backgroundWindowManager);
         OneHandedAnimationController animationController =
                 new OneHandedAnimationController(context);
         OneHandedTouchHandler touchHandler = new OneHandedTouchHandler(timeoutHandler,
                 mainExecutor);
-        OneHandedBackgroundPanelOrganizer oneHandedBackgroundPanelOrganizer =
-                new OneHandedBackgroundPanelOrganizer(context, displayLayout, settingsUtil,
-                        mainExecutor);
         OneHandedDisplayAreaOrganizer organizer = new OneHandedDisplayAreaOrganizer(
                 context, displayLayout, settingsUtil, animationController, tutorialHandler,
-                oneHandedBackgroundPanelOrganizer, jankMonitor, mainExecutor);
+                jankMonitor, mainExecutor);
         OneHandedUiEventLogger oneHandedUiEventsLogger = new OneHandedUiEventLogger(uiEventLogger);
         IOverlayManager overlayManager = IOverlayManager.Stub.asInterface(
                 ServiceManager.getService(Context.OVERLAY_SERVICE));
-        return new OneHandedController(context, displayController,
-                oneHandedBackgroundPanelOrganizer, organizer, touchHandler, tutorialHandler,
-                settingsUtil, accessibilityUtil, timeoutHandler, oneHandedState, jankMonitor,
-                oneHandedUiEventsLogger, overlayManager, taskStackListener, mainExecutor,
-                mainHandler);
+        return new OneHandedController(context, displayController, organizer, touchHandler,
+                tutorialHandler, settingsUtil, accessibilityUtil, timeoutHandler, oneHandedState,
+                jankMonitor, oneHandedUiEventsLogger, overlayManager, taskStackListener,
+                mainExecutor, mainHandler);
     }
 
     @VisibleForTesting
     OneHandedController(Context context,
             DisplayController displayController,
-            OneHandedBackgroundPanelOrganizer backgroundPanelOrganizer,
             OneHandedDisplayAreaOrganizer displayAreaOrganizer,
             OneHandedTouchHandler touchHandler,
             OneHandedTutorialHandler tutorialHandler,
@@ -243,7 +237,6 @@
         mContext = context;
         mOneHandedSettingsUtil = settingsUtil;
         mOneHandedAccessibilityUtil = oneHandedAccessibilityUtil;
-        mBackgroundPanelOrganizer = backgroundPanelOrganizer;
         mDisplayAreaOrganizer = displayAreaOrganizer;
         mDisplayController = displayController;
         mTouchHandler = touchHandler;
@@ -286,7 +279,6 @@
         mAccessibilityManager.addAccessibilityStateChangeListener(
                 mAccessibilityStateChangeListener);
 
-        mState.addSListeners(mBackgroundPanelOrganizer);
         mState.addSListeners(mTutorialHandler);
     }
 
@@ -368,7 +360,6 @@
                 mDisplayAreaOrganizer.getDisplayLayout().height() * mOffSetFraction);
         mOneHandedAccessibilityUtil.announcementForScreenReader(
                 mOneHandedAccessibilityUtil.getOneHandedStartDescription());
-        mBackgroundPanelOrganizer.onStart();
         mDisplayAreaOrganizer.scheduleOffset(0, yOffSet);
         mTimeoutHandler.resetTimer();
         mOneHandedUiEventLogger.writeEvent(
@@ -461,7 +452,6 @@
         }
         mDisplayAreaOrganizer.setDisplayLayout(newDisplayLayout);
         mTutorialHandler.onDisplayChanged(newDisplayLayout);
-        mBackgroundPanelOrganizer.onDisplayChanged(newDisplayLayout);
     }
 
     private ContentObserver getObserver(Runnable onChangeRunnable) {
@@ -585,7 +575,6 @@
 
         if (!mIsOneHandedEnabled) {
             mDisplayAreaOrganizer.unregisterOrganizer();
-            mBackgroundPanelOrganizer.unregisterOrganizer();
             // Do NOT register + unRegister DA in the same call
             return;
         }
@@ -594,11 +583,6 @@
             mDisplayAreaOrganizer.registerOrganizer(
                     OneHandedDisplayAreaOrganizer.FEATURE_ONE_HANDED);
         }
-
-        if (!mBackgroundPanelOrganizer.isRegistered()) {
-            mBackgroundPanelOrganizer.registerOrganizer(
-                    OneHandedBackgroundPanelOrganizer.FEATURE_ONE_HANDED_BACKGROUND_PANEL);
-        }
     }
 
     @VisibleForTesting
@@ -613,13 +597,12 @@
     }
 
     private void onConfigChanged(Configuration newConfig) {
-        if (mTutorialHandler == null || mBackgroundPanelOrganizer == null) {
+        if (mTutorialHandler == null) {
             return;
         }
         if (!mIsOneHandedEnabled || newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
             return;
         }
-        mBackgroundPanelOrganizer.onConfigurationChanged();
         mTutorialHandler.onConfigurationChanged();
     }
 
@@ -650,10 +633,6 @@
         pw.print(innerPrefix + "mIsSwipeToNotificationEnabled=");
         pw.println(mIsSwipeToNotificationEnabled);
 
-        if (mBackgroundPanelOrganizer != null) {
-            mBackgroundPanelOrganizer.dump(pw);
-        }
-
         if (mDisplayAreaOrganizer != null) {
             mDisplayAreaOrganizer.dump(pw);
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index 87eb40c..f61d1b9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -80,7 +80,6 @@
             mSurfaceControlTransactionFactory;
     private OneHandedTutorialHandler mTutorialHandler;
     private List<OneHandedTransitionCallback> mTransitionCallbacks = new ArrayList<>();
-    private OneHandedBackgroundPanelOrganizer mBackgroundPanelOrganizer;
 
     @VisibleForTesting
     OneHandedAnimationCallback mOneHandedAnimationCallback =
@@ -135,7 +134,6 @@
             OneHandedSettingsUtil oneHandedSettingsUtil,
             OneHandedAnimationController animationController,
             OneHandedTutorialHandler tutorialHandler,
-            OneHandedBackgroundPanelOrganizer oneHandedBackgroundGradientOrganizer,
             InteractionJankMonitor jankMonitor,
             ShellExecutor mainExecutor) {
         super(mainExecutor);
@@ -150,7 +148,6 @@
                 SystemProperties.getInt(ONE_HANDED_MODE_TRANSLATE_ANIMATION_DURATION,
                         animationDurationConfig);
         mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
-        mBackgroundPanelOrganizer = oneHandedBackgroundGradientOrganizer;
         mTutorialHandler = tutorialHandler;
     }
 
@@ -258,7 +255,6 @@
             animator.setTransitionDirection(direction)
                     .addOneHandedAnimationCallback(mOneHandedAnimationCallback)
                     .addOneHandedAnimationCallback(mTutorialHandler)
-                    .addOneHandedAnimationCallback(mBackgroundPanelOrganizer)
                     .setDuration(durationMs)
                     .start();
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
index 88f3375..04e8cf9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
@@ -32,7 +32,6 @@
 import android.content.res.TypedArray;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
-import android.os.SystemProperties;
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -65,6 +64,7 @@
 
     private final float mTutorialHeightRatio;
     private final WindowManager mWindowManager;
+    private final BackgroundWindowManager mBackgroundWindowManager;
 
     private @OneHandedState.State int mCurrentState;
     private int mTutorialAreaHeight;
@@ -79,9 +79,10 @@
     private int mAlphaAnimationDurationMs;
 
     public OneHandedTutorialHandler(Context context, OneHandedSettingsUtil settingsUtil,
-            WindowManager windowManager) {
+            WindowManager windowManager, BackgroundWindowManager backgroundWindowManager) {
         mContext = context;
         mWindowManager = windowManager;
+        mBackgroundWindowManager = backgroundWindowManager;
         mTutorialHeightRatio = settingsUtil.getTranslationFraction(context);
         mAlphaAnimationDurationMs = settingsUtil.getTransitionDuration(context);
     }
@@ -110,8 +111,19 @@
     }
 
     @Override
+    public void onStartFinished(Rect bounds) {
+        fillBackgroundColor();
+    }
+
+    @Override
+    public void onStopFinished(Rect bounds) {
+        removeBackgroundSurface();
+    }
+
+    @Override
     public void onStateChanged(int newState) {
         mCurrentState = newState;
+        mBackgroundWindowManager.onStateChanged(newState);
         switch (newState) {
             case STATE_ENTERING:
                 createViewAndAttachToWindow(mContext);
@@ -126,7 +138,6 @@
             case STATE_NONE:
                 checkTransitionEnd();
                 removeTutorialFromWindowManager();
-                break;
             default:
                 break;
         }
@@ -146,6 +157,7 @@
         }
         mTutorialAreaHeight = Math.round(mDisplayBounds.height() * mTutorialHeightRatio);
         mAlphaTransitionStart = mTutorialAreaHeight * START_TRANSITION_FRACTION;
+        mBackgroundWindowManager.onDisplayChanged(displayLayout);
     }
 
     @VisibleForTesting
@@ -169,6 +181,7 @@
     private void attachTargetToWindow() {
         try {
             mWindowManager.addView(mTargetViewContainer, getTutorialTargetLayoutParams());
+            mBackgroundWindowManager.showBackgroundLayer();
         } catch (IllegalStateException e) {
             // This shouldn't happen, but if the target is already added, just update its
             // layout params.
@@ -186,6 +199,11 @@
         mTargetViewContainer = null;
     }
 
+    @VisibleForTesting
+    void removeBackgroundSurface() {
+        mBackgroundWindowManager.removeBackgroundLayer();
+    }
+
     /**
      * Returns layout params for the dismiss target, using the latest display metrics.
      */
@@ -213,9 +231,12 @@
      * onConfigurationChanged events for updating tutorial text.
      */
     public void onConfigurationChanged() {
+        mBackgroundWindowManager.onConfigurationChanged();
+
         removeTutorialFromWindowManager();
         if (mCurrentState == STATE_ENTERING || mCurrentState == STATE_ACTIVE) {
             createViewAndAttachToWindow(mContext);
+            fillBackgroundColor();
             updateThemeColor();
             checkTransitionEnd();
         }
@@ -247,6 +268,14 @@
         tutorialDesc.setTextColor(themedTextColorSecondary);
     }
 
+    private void fillBackgroundColor() {
+        if (mTargetViewContainer == null || mBackgroundWindowManager == null) {
+            return;
+        }
+        mTargetViewContainer.setBackgroundColor(
+                mBackgroundWindowManager.getThemeColorForBackground());
+    }
+
     private void setupAlphaTransition(boolean isEntering) {
         final float start = isEntering ? 0.0f : 1.0f;
         final float end = isEntering ? 1.0f : 0.0f;
@@ -282,5 +311,9 @@
         pw.println(mAlphaTransitionStart);
         pw.print(innerPrefix + "mAlphaAnimationDurationMs=");
         pw.println(mAlphaAnimationDurationMs);
+
+        if (mBackgroundWindowManager != null) {
+            mBackgroundWindowManager.dump(pw);
+        }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 7decb54..338c944 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -292,7 +292,6 @@
          * Invalidates this instance, preventing future calls from updating the controller.
          */
         void invalidate() {
-            Slog.d("b/206648922", "invalidating controller: " + mController);
             mController = null;
         }
 
@@ -313,13 +312,16 @@
         @Override
         public GroupedRecentTaskInfo[] getRecentTasks(int maxNum, int flags, int userId)
                 throws RemoteException {
+            if (mController == null) {
+                // The controller is already invalidated -- just return an empty task list for now
+                return new GroupedRecentTaskInfo[0];
+            }
+
             final GroupedRecentTaskInfo[][] out = new GroupedRecentTaskInfo[][]{null};
             executeRemoteCallWithTaskPermission(mController, "getRecentTasks",
                     (controller) -> out[0] = controller.getRecentTasks(maxNum, flags, userId)
                             .toArray(new GroupedRecentTaskInfo[0]),
                     true /* blocking */);
-            Slog.d("b/206648922", "getRecentTasks(" + maxNum + "): " + out[0]
-                    + " mController=" + mController);
             return out[0];
         }
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/BackgroundWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/BackgroundWindowManagerTest.java
new file mode 100644
index 0000000..f3f7067
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/BackgroundWindowManagerTest.java
@@ -0,0 +1,61 @@
+/**
+ * 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.onehanded;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.testing.TestableLooper;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.DisplayLayout;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link BackgroundWindowManager} */
+@SmallTest
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@RunWith(AndroidJUnit4.class)
+public class BackgroundWindowManagerTest extends ShellTestCase {
+    private BackgroundWindowManager mBackgroundWindowManager;
+    @Mock
+    private DisplayLayout  mMockDisplayLayout;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mBackgroundWindowManager = new BackgroundWindowManager(mContext);
+        mBackgroundWindowManager.onDisplayChanged(mMockDisplayLayout);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testInitRelease() {
+        mBackgroundWindowManager.initView();
+        assertThat(mBackgroundWindowManager.getSurfaceControl()).isNotNull();
+
+        mBackgroundWindowManager.removeBackgroundLayer();
+        assertThat(mBackgroundWindowManager.getSurfaceControl()).isNull();
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java
deleted file mode 100644
index 7b9553c..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2020 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.onehanded;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.window.DisplayAreaOrganizer.FEATURE_ONE_HANDED_BACKGROUND_PANEL;
-
-import static com.android.wm.shell.onehanded.OneHandedState.STATE_ACTIVE;
-import static com.android.wm.shell.onehanded.OneHandedState.STATE_NONE;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.Display;
-import android.view.SurfaceControl;
-import android.window.DisplayAreaInfo;
-import android.window.IWindowContainerToken;
-import android.window.WindowContainerToken;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayLayout;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class OneHandedBackgroundPanelOrganizerTest extends OneHandedTestCase {
-    private DisplayAreaInfo mDisplayAreaInfo;
-    private Display mDisplay;
-    private DisplayLayout mDisplayLayout;
-    private OneHandedBackgroundPanelOrganizer mSpiedBackgroundPanelOrganizer;
-    private WindowContainerToken mToken;
-    private SurfaceControl mLeash;
-
-    @Mock
-    IWindowContainerToken mMockRealToken;
-    @Mock
-    DisplayController mMockDisplayController;
-    @Mock
-    OneHandedSettingsUtil mMockSettingsUtil;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mToken = new WindowContainerToken(mMockRealToken);
-        mLeash = new SurfaceControl();
-        mDisplay = mContext.getDisplay();
-        mDisplayLayout = new DisplayLayout(mContext, mDisplay);
-        when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay);
-        mDisplayAreaInfo = new DisplayAreaInfo(mToken, DEFAULT_DISPLAY,
-                FEATURE_ONE_HANDED_BACKGROUND_PANEL);
-
-        mSpiedBackgroundPanelOrganizer = spy(
-                new OneHandedBackgroundPanelOrganizer(mContext, mDisplayLayout, mMockSettingsUtil,
-                        Runnable::run));
-        mSpiedBackgroundPanelOrganizer.onDisplayChanged(mDisplayLayout);
-    }
-
-    @Test
-    public void testOnDisplayAreaAppeared() {
-        mSpiedBackgroundPanelOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash);
-
-        assertThat(mSpiedBackgroundPanelOrganizer.isRegistered()).isTrue();
-        verify(mSpiedBackgroundPanelOrganizer, never()).showBackgroundPanelLayer();
-    }
-
-    @Test
-    public void testShowBackgroundLayer() {
-        mSpiedBackgroundPanelOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, null);
-        mSpiedBackgroundPanelOrganizer.onStart();
-
-        verify(mSpiedBackgroundPanelOrganizer).showBackgroundPanelLayer();
-    }
-
-    @Test
-    public void testRemoveBackgroundLayer() {
-        mSpiedBackgroundPanelOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash);
-
-        assertThat(mSpiedBackgroundPanelOrganizer.isRegistered()).isNotNull();
-
-        reset(mSpiedBackgroundPanelOrganizer);
-        mSpiedBackgroundPanelOrganizer.removeBackgroundPanelLayer();
-
-        assertThat(mSpiedBackgroundPanelOrganizer.mBackgroundSurface).isNull();
-    }
-
-    @Test
-    public void testStateNone_onConfigurationChanged() {
-        mSpiedBackgroundPanelOrganizer.onStateChanged(STATE_NONE);
-        mSpiedBackgroundPanelOrganizer.onConfigurationChanged();
-
-        verify(mSpiedBackgroundPanelOrganizer, never()).showBackgroundPanelLayer();
-    }
-
-    @Test
-    public void testStateActivate_onConfigurationChanged() {
-        mSpiedBackgroundPanelOrganizer.onStateChanged(STATE_ACTIVE);
-        mSpiedBackgroundPanelOrganizer.onConfigurationChanged();
-
-        verify(mSpiedBackgroundPanelOrganizer).showBackgroundPanelLayer();
-    }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index 636e875..2886b97 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -73,8 +73,6 @@
     @Mock
     DisplayController mMockDisplayController;
     @Mock
-    OneHandedBackgroundPanelOrganizer mMockBackgroundOrganizer;
-    @Mock
     OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer;
     @Mock
     OneHandedEventCallback mMockEventCallback;
@@ -115,7 +113,6 @@
         when(mMockDisplayController.getDisplayLayout(anyInt())).thenReturn(null);
         when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>());
         when(mMockDisplayAreaOrganizer.isReady()).thenReturn(true);
-        when(mMockBackgroundOrganizer.isRegistered()).thenReturn(true);
         when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn(
                 mDefaultEnabled);
         when(mMockSettingsUitl.getSettingsOneHandedModeTimeout(any(), anyInt())).thenReturn(
@@ -134,7 +131,6 @@
         mSpiedOneHandedController = spy(new OneHandedController(
                 mContext,
                 mMockDisplayController,
-                mMockBackgroundOrganizer,
                 mMockDisplayAreaOrganizer,
                 mMockTouchHandler,
                 mMockTutorialHandler,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
index df21163..9c7f723 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
@@ -95,8 +95,6 @@
     @Mock
     WindowContainerTransaction mMockWindowContainerTransaction;
     @Mock
-    OneHandedBackgroundPanelOrganizer mMockBackgroundOrganizer;
-    @Mock
     ShellExecutor mMockShellMainExecutor;
     @Mock
     OneHandedSettingsUtil mMockSettingsUitl;
@@ -143,7 +141,6 @@
                 mMockSettingsUitl,
                 mMockAnimationController,
                 mTutorialHandler,
-                mMockBackgroundOrganizer,
                 mJankMonitor,
                 mMockShellMainExecutor));
 
@@ -431,7 +428,6 @@
                         mMockSettingsUitl,
                         mMockAnimationController,
                         mTutorialHandler,
-                        mMockBackgroundOrganizer,
                         mJankMonitor,
                         mMockShellMainExecutor));
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java
index 58399b6..dba1b8b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java
@@ -67,8 +67,6 @@
     @Mock
     DisplayController mMockDisplayController;
     @Mock
-    OneHandedBackgroundPanelOrganizer mMockBackgroundOrganizer;
-    @Mock
     OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer;
     @Mock
     OneHandedTouchHandler mMockTouchHandler;
@@ -105,7 +103,6 @@
 
         when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay);
         when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>());
-        when(mMockBackgroundOrganizer.isRegistered()).thenReturn(true);
         when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn(
                 mDefaultEnabled);
         when(mMockSettingsUitl.getSettingsOneHandedModeTimeout(any(), anyInt())).thenReturn(
@@ -123,7 +120,6 @@
         mSpiedOneHandedController = spy(new OneHandedController(
                 mContext,
                 mMockDisplayController,
-                mMockBackgroundOrganizer,
                 mMockDisplayAreaOrganizer,
                 mMockTouchHandler,
                 mMockTutorialHandler,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
index b1434ca..63d8bfd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
@@ -56,6 +56,8 @@
     OneHandedSettingsUtil mMockSettingsUtil;
     @Mock
     WindowManager mMockWindowManager;
+    @Mock
+    BackgroundWindowManager mMockBackgroundWindowManager;
 
     @Before
     public void setUp() {
@@ -63,10 +65,11 @@
         when(mMockSettingsUtil.getTutorialShownCounts(any(), anyInt())).thenReturn(0);
 
         mDisplay = mContext.getDisplay();
-        mDisplayLayout = new DisplayLayout(mContext, mDisplay);
+        mDisplayLayout = new DisplayLayout(getTestContext().getApplicationContext(), mDisplay);
         mSpiedTransitionState = spy(new OneHandedState());
         mSpiedTutorialHandler = spy(
-                new OneHandedTutorialHandler(mContext, mMockSettingsUtil, mMockWindowManager));
+                new OneHandedTutorialHandler(mContext, mMockSettingsUtil, mMockWindowManager,
+                        mMockBackgroundWindowManager));
         mTimeoutHandler = new OneHandedTimeoutHandler(mMockShellMainExecutor);
     }
 
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index b802908..e359145 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -95,6 +95,16 @@
                                         endHyphen, advances);
 }
 
+minikin::MinikinExtent MinikinUtils::getFontExtent(const Paint* paint, minikin::Bidi bidiFlags,
+                                                   const Typeface* typeface, const uint16_t* buf,
+                                                   size_t start, size_t count, size_t bufSize) {
+    minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
+    const minikin::U16StringPiece textBuf(buf, bufSize);
+    const minikin::Range range(start, start + count);
+
+    return minikin::getFontExtent(textBuf, range, bidiFlags, minikinPaint);
+}
+
 bool MinikinUtils::hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs) {
     const Typeface* resolvedFace = Typeface::resolveDefault(typeface);
     return resolvedFace->fFontCollection->hasVariationSelector(codepoint, vs);
diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h
index a15803a..009b84b 100644
--- a/libs/hwui/hwui/MinikinUtils.h
+++ b/libs/hwui/hwui/MinikinUtils.h
@@ -56,6 +56,10 @@
                                          size_t start, size_t count, size_t bufSize,
                                          float* advances);
 
+    static minikin::MinikinExtent getFontExtent(const Paint* paint, minikin::Bidi bidiFlags,
+                                                const Typeface* typeface, const uint16_t* buf,
+                                                size_t start, size_t count, size_t bufSize);
+
     static bool hasVariationSelector(const Typeface* typeface, uint32_t codepoint,
                                                  uint32_t vs);
 
diff --git a/libs/hwui/jni/NinePatch.cpp b/libs/hwui/jni/NinePatch.cpp
index b7ddd21..08fc80f 100644
--- a/libs/hwui/jni/NinePatch.cpp
+++ b/libs/hwui/jni/NinePatch.cpp
@@ -67,7 +67,7 @@
         size_t chunkSize = obj != NULL ? env->GetArrayLength(obj) : 0;
         if (chunkSize < (int) (sizeof(Res_png_9patch))) {
             jniThrowRuntimeException(env, "Array too small for chunk.");
-            return NULL;
+            return 0;
         }
 
         int8_t* storage = new int8_t[chunkSize];
diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp
index 22a1e1f..f768632 100644
--- a/libs/hwui/jni/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -541,26 +541,6 @@
         return result;
     }
 
-    // ------------------ @FastNative ---------------------------
-
-    static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        ScopedUtfChars localesChars(env, locales);
-        jint minikinLocaleListId = minikin::registerLocaleList(localesChars.c_str());
-        obj->setMinikinLocaleListId(minikinLocaleListId);
-        return minikinLocaleListId;
-    }
-
-    static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle, jstring settings) {
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        if (!settings) {
-            paint->setFontFeatureSettings(std::string());
-        } else {
-            ScopedUtfChars settingsChars(env, settings);
-            paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size()));
-        }
-    }
-
     static SkScalar getMetricsInternal(jlong paintHandle, SkFontMetrics *metrics) {
         const int kElegantTop = 2500;
         const int kElegantBottom = -1000;
@@ -593,6 +573,67 @@
         return spacing;
     }
 
+    static void doFontExtent(JNIEnv* env, jlong paintHandle, const jchar buf[], jint start,
+                             jint count, jint bufSize, jboolean isRtl, jobject fmi) {
+        const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        const Typeface* typeface = paint->getAndroidTypeface();
+        minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR;
+        minikin::MinikinExtent extent =
+                MinikinUtils::getFontExtent(paint, bidiFlags, typeface, buf, start, count, bufSize);
+
+        SkFontMetrics metrics;
+        getMetricsInternal(paintHandle, &metrics);
+
+        metrics.fAscent = extent.ascent;
+        metrics.fDescent = extent.descent;
+
+        // If top/bottom is narrower than ascent/descent, adjust top/bottom to ascent/descent.
+        metrics.fTop = std::min(metrics.fAscent, metrics.fTop);
+        metrics.fBottom = std::max(metrics.fDescent, metrics.fBottom);
+
+        GraphicsJNI::set_metrics_int(env, fmi, metrics);
+    }
+
+    static void getFontMetricsIntForText___C(JNIEnv* env, jclass, jlong paintHandle,
+                                             jcharArray text, jint start, jint count, jint ctxStart,
+                                             jint ctxCount, jboolean isRtl, jobject fmi) {
+        ScopedCharArrayRO textArray(env, text);
+
+        doFontExtent(env, paintHandle, textArray.get() + ctxStart, start - ctxStart, count,
+                     ctxCount, isRtl, fmi);
+    }
+
+    static void getFontMetricsIntForText___String(JNIEnv* env, jclass, jlong paintHandle,
+                                                  jstring text, jint start, jint count,
+                                                  jint ctxStart, jint ctxCount, jboolean isRtl,
+                                                  jobject fmi) {
+        ScopedStringChars textChars(env, text);
+
+        doFontExtent(env, paintHandle, textChars.get() + ctxStart, start - ctxStart, count,
+                     ctxCount, isRtl, fmi);
+    }
+
+    // ------------------ @FastNative ---------------------------
+
+    static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        ScopedUtfChars localesChars(env, locales);
+        jint minikinLocaleListId = minikin::registerLocaleList(localesChars.c_str());
+        obj->setMinikinLocaleListId(minikinLocaleListId);
+        return minikinLocaleListId;
+    }
+
+    static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle,
+                                       jstring settings) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        if (!settings) {
+            paint->setFontFeatureSettings(std::string());
+        } else {
+            ScopedUtfChars settingsChars(env, settings);
+            paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size()));
+        }
+    }
+
     static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle, jobject metricsObj) {
         SkFontMetrics metrics;
         SkScalar spacing = getMetricsInternal(paintHandle, &metrics);
@@ -1015,6 +1056,11 @@
     {"nGetRunAdvance", "(J[CIIIIZI)F", (void*) PaintGlue::getRunAdvance___CIIIIZI_F},
     {"nGetOffsetForAdvance", "(J[CIIIIZF)I",
             (void*) PaintGlue::getOffsetForAdvance___CIIIIZF_I},
+    {"nGetFontMetricsIntForText", "(J[CIIIIZLandroid/graphics/Paint$FontMetricsInt;)V",
+      (void*)PaintGlue::getFontMetricsIntForText___C},
+    {"nGetFontMetricsIntForText",
+      "(JLjava/lang/String;IIIIZLandroid/graphics/Paint$FontMetricsInt;)V",
+      (void*)PaintGlue::getFontMetricsIntForText___String},
 
     // --------------- @FastNative ----------------------
 
@@ -1093,6 +1139,7 @@
     {"nEqualsForTextMeasurement", "(JJ)Z", (void*)PaintGlue::equalsForTextMeasurement},
 };
 
+
 int register_android_graphics_Paint(JNIEnv* env) {
     return RegisterMethodsOrDie(env, "android/graphics/Paint", methods, NELEM(methods));
 }
diff --git a/libs/hwui/jni/android_util_PathParser.cpp b/libs/hwui/jni/android_util_PathParser.cpp
index 72995ef..8cbb70e 100644
--- a/libs/hwui/jni/android_util_PathParser.cpp
+++ b/libs/hwui/jni/android_util_PathParser.cpp
@@ -61,7 +61,7 @@
     } else {
         delete pathData;
         doThrowIAE(env, result.failureMessage.c_str());
-        return NULL;
+        return 0;
     }
 }
 
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index 2c94820d..ecdd4b6 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -1860,7 +1860,7 @@
             gnssMeasurement.mSatelliteInterSignalBiasUncertaintyNanos = parcel.readDouble();
             if (gnssMeasurement.hasSatellitePvt()) {
                 ClassLoader classLoader = getClass().getClassLoader();
-                gnssMeasurement.mSatellitePvt = parcel.readParcelable(classLoader, android.location.SatellitePvt.class);
+                gnssMeasurement.mSatellitePvt = parcel.readParcelable(classLoader);
             }
             if (gnssMeasurement.hasCorrelationVectors()) {
                 CorrelationVector[] correlationVectorsArray =
diff --git a/location/java/android/location/GnssMeasurementsEvent.java b/location/java/android/location/GnssMeasurementsEvent.java
index b744017..a07a64a 100644
--- a/location/java/android/location/GnssMeasurementsEvent.java
+++ b/location/java/android/location/GnssMeasurementsEvent.java
@@ -156,7 +156,7 @@
         public GnssMeasurementsEvent createFromParcel(Parcel in) {
             ClassLoader classLoader = getClass().getClassLoader();
 
-            GnssClock clock = in.readParcelable(classLoader, android.location.GnssClock.class);
+            GnssClock clock = in.readParcelable(classLoader);
 
             int measurementsLength = in.readInt();
             GnssMeasurement[] measurementsArray = new GnssMeasurement[measurementsLength];
diff --git a/location/java/android/location/GpsMeasurementsEvent.java b/location/java/android/location/GpsMeasurementsEvent.java
index 6b834f3..f3feb7a 100644
--- a/location/java/android/location/GpsMeasurementsEvent.java
+++ b/location/java/android/location/GpsMeasurementsEvent.java
@@ -112,7 +112,7 @@
         public GpsMeasurementsEvent createFromParcel(Parcel in) {
             ClassLoader classLoader = getClass().getClassLoader();
 
-            GpsClock clock = in.readParcelable(classLoader, android.location.GpsClock.class);
+            GpsClock clock = in.readParcelable(classLoader);
 
             int measurementsLength = in.readInt();
             GpsMeasurement[] measurementsArray = new GpsMeasurement[measurementsLength];
diff --git a/location/java/android/location/GpsNavigationMessageEvent.java b/location/java/android/location/GpsNavigationMessageEvent.java
index b37fe3d..2d5d6eb 100644
--- a/location/java/android/location/GpsNavigationMessageEvent.java
+++ b/location/java/android/location/GpsNavigationMessageEvent.java
@@ -92,7 +92,7 @@
                 @Override
                 public GpsNavigationMessageEvent createFromParcel(Parcel in) {
                     ClassLoader classLoader = getClass().getClassLoader();
-                    GpsNavigationMessage navigationMessage = in.readParcelable(classLoader, android.location.GpsNavigationMessage.class);
+                    GpsNavigationMessage navigationMessage = in.readParcelable(classLoader);
                     return new GpsNavigationMessageEvent(navigationMessage);
                 }
 
diff --git a/location/java/android/location/SatellitePvt.java b/location/java/android/location/SatellitePvt.java
index aa43cfd..794a8d0 100644
--- a/location/java/android/location/SatellitePvt.java
+++ b/location/java/android/location/SatellitePvt.java
@@ -465,9 +465,9 @@
                 public SatellitePvt createFromParcel(Parcel in) {
                     int flags = in.readInt();
                     ClassLoader classLoader = getClass().getClassLoader();
-                    PositionEcef positionEcef = in.readParcelable(classLoader, android.location.SatellitePvt.PositionEcef.class);
-                    VelocityEcef velocityEcef = in.readParcelable(classLoader, android.location.SatellitePvt.VelocityEcef.class);
-                    ClockInfo clockInfo = in.readParcelable(classLoader, android.location.SatellitePvt.ClockInfo.class);
+                    PositionEcef positionEcef = in.readParcelable(classLoader);
+                    VelocityEcef velocityEcef = in.readParcelable(classLoader);
+                    ClockInfo clockInfo = in.readParcelable(classLoader);
                     double ionoDelayMeters = in.readDouble();
                     double tropoDelayMeters = in.readDouble();
 
diff --git a/media/OWNERS b/media/OWNERS
index 0aff43e..5f50137 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -3,7 +3,6 @@
 essick@google.com
 etalvala@google.com
 hdmoon@google.com
-hkuang@google.com
 hunga@google.com
 insun@google.com
 jaewan@google.com
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index bd0f32e..69ce8d2 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -18,10 +18,13 @@
 
 import android.annotation.IntRange;
 import android.annotation.NonNull;
+import android.annotation.SuppressLint;
 import android.graphics.GraphicBuffer;
 import android.graphics.ImageFormat;
 import android.graphics.ImageFormat.Format;
 import android.graphics.Rect;
+import android.hardware.DataSpace;
+import android.hardware.DataSpace.NamedDataSpace;
 import android.hardware.HardwareBuffer;
 import android.hardware.HardwareBuffer.Usage;
 import android.hardware.camera2.MultiResolutionImageReader;
@@ -136,8 +139,7 @@
         // If the format is private don't default to USAGE_CPU_READ_OFTEN since it may not
         // work, and is inscrutable anyway
         return new ImageReader(width, height, format, maxImages,
-                format == ImageFormat.PRIVATE ? 0 : HardwareBuffer.USAGE_CPU_READ_OFTEN,
-                /*parent*/ null);
+                format == ImageFormat.PRIVATE ? 0 : HardwareBuffer.USAGE_CPU_READ_OFTEN, null);
     }
 
     /**
@@ -268,44 +270,32 @@
         // If the format is private don't default to USAGE_CPU_READ_OFTEN since it may not
         // work, and is inscrutable anyway
         return new ImageReader(width, height, format, maxImages,
-                format == ImageFormat.PRIVATE ? 0 : HardwareBuffer.USAGE_CPU_READ_OFTEN,
-                parent);
+                format == ImageFormat.PRIVATE ? 0 : HardwareBuffer.USAGE_CPU_READ_OFTEN, parent);
     }
 
-
-    /**
-     * @hide
-     */
-    protected ImageReader(int width, int height, int format, int maxImages, long usage,
-            MultiResolutionImageReader parent) {
-        mWidth = width;
-        mHeight = height;
-        mFormat = format;
-        mUsage = usage;
-        mMaxImages = maxImages;
-        mParent = parent;
-
+    private void initializeImageReader(int width, int height, int imageFormat, int maxImages,
+            long usage, int hardwareBufferFormat, long dataSpace, boolean useLegacyImageFormat) {
         if (width < 1 || height < 1) {
             throw new IllegalArgumentException(
                 "The image dimensions must be positive");
         }
-        if (mMaxImages < 1) {
+
+        if (maxImages < 1) {
             throw new IllegalArgumentException(
                 "Maximum outstanding image count must be at least 1");
         }
 
-        if (format == ImageFormat.NV21) {
+        if (imageFormat == ImageFormat.NV21) {
             throw new IllegalArgumentException(
-                    "NV21 format is not supported");
+                "NV21 format is not supported");
         }
 
-        mNumPlanes = ImageUtils.getNumPlanesForFormat(mFormat);
-
-        nativeInit(new WeakReference<>(this), width, height, format, maxImages, usage);
-
-        mSurface = nativeGetSurface();
+        nativeInit(new WeakReference<>(this), width, height, maxImages, usage,
+                hardwareBufferFormat, dataSpace);
 
         mIsReaderValid = true;
+
+        mSurface = nativeGetSurface();
         // Estimate the native buffer allocation size and register it so it gets accounted for
         // during GC. Note that this doesn't include the buffers required by the buffer queue
         // itself and the buffers requested by the producer.
@@ -313,10 +303,46 @@
         // complex, and 1 buffer is enough for the VM to treat the ImageReader as being of some
         // size.
         mEstimatedNativeAllocBytes = ImageUtils.getEstimatedNativeAllocBytes(
-                width, height, format, /*buffer count*/ 1);
+            width, height, useLegacyImageFormat ? imageFormat : hardwareBufferFormat,
+            /*buffer count*/ 1);
         VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes);
     }
 
+    private ImageReader(int width, int height, int imageFormat, int maxImages, long usage,
+            MultiResolutionImageReader parent) {
+        mWidth = width;
+        mHeight = height;
+        mFormat = imageFormat;
+        mUsage = usage;
+        mMaxImages = maxImages;
+        mParent = parent;
+        // retrieve hal Format and hal dataspace from imageFormat
+        mHardwareBufferFormat = PublicFormatUtils.getHalFormat(mFormat);
+        mDataSpace = PublicFormatUtils.getHalDataspace(mFormat);
+        mUseLegacyImageFormat = true;
+        mNumPlanes = ImageUtils.getNumPlanesForFormat(mFormat);
+
+        initializeImageReader(width, height, imageFormat, maxImages, usage, mHardwareBufferFormat,
+                mDataSpace, mUseLegacyImageFormat);
+    }
+
+    private ImageReader(int width, int height, int maxImages, long usage,
+            MultiResolutionImageReader parent, int hardwareBufferFormat, long dataSpace) {
+        mWidth = width;
+        mHeight = height;
+        mFormat = ImageFormat.UNKNOWN; // set default image format value as UNKNOWN
+        mUsage = usage;
+        mMaxImages = maxImages;
+        mParent = parent;
+        mHardwareBufferFormat = hardwareBufferFormat;
+        mDataSpace = dataSpace;
+        mUseLegacyImageFormat = false;
+        mNumPlanes = ImageUtils.getNumPlanesForHardwareBufferFormat(mHardwareBufferFormat);
+
+        initializeImageReader(width, height, mFormat, maxImages, usage, hardwareBufferFormat,
+                dataSpace, mUseLegacyImageFormat);
+    }
+
     /**
      * The default width of {@link Image Images}, in pixels.
      *
@@ -354,6 +380,10 @@
      * As of now, each format is only compatible to itself.
      * The actual format of the images can be found using {@link Image#getFormat}.</p>
      *
+     * <p>Use this function if the ImageReader instance is created by factory method
+     * {@code newInstance} function or by builder pattern {@code ImageReader.Builder} and using
+     * {@link Builder#setImageFormat}.</p>
+     *
      * @return the expected format of an Image
      *
      * @see ImageFormat
@@ -363,6 +393,32 @@
     }
 
     /**
+     * The default {@link HardwareBuffer} format of {@link Image Images}.
+     *
+     * <p>Use this function if the ImageReader instance is created by builder pattern
+     * {@code ImageReader.Builder} and using {@link Builder#setDefaultHardwareBufferFormat} and
+     * {@link Builder#setDefaultDataSpace}.</p>
+     *
+     * @return the expected {@link HardwareBuffer} format of an Image.
+     */
+    public @HardwareBuffer.Format int getHardwareBufferFormat() {
+        return mHardwareBufferFormat;
+    }
+
+    /**
+     * The default dataspace of {@link Image Images}.
+     *
+     * <p>Use this function if the ImageReader instance is created by builder pattern
+     * {@code ImageReader.Builder} and {@link Builder#setDefaultDataSpace}.</p>
+     *
+     * @return the expected dataspace of an Image.
+     */
+    @SuppressLint("MethodNameUnits")
+    public @NamedDataSpace long getDataSpace() {
+        return mDataSpace;
+    }
+
+    /**
      * Maximum number of images that can be acquired from the ImageReader by any time (for example,
      * with {@link #acquireNextImage}).
      *
@@ -384,6 +440,15 @@
     }
 
     /**
+     * The usage flag of images that can be produced by the ImageReader.
+     *
+     * @return The usage flag of the images for this ImageReader.
+     */
+    public @Usage long getUsage() {
+        return mUsage;
+    }
+
+    /**
      * <p>Get a {@link Surface} that can be used to produce {@link Image Images} for this
      * {@code ImageReader}.</p>
      *
@@ -469,7 +534,12 @@
      * @hide
      */
     public Image acquireNextImageNoThrowISE() {
-        SurfaceImage si = new SurfaceImage(mFormat);
+        SurfaceImage si;
+        if (mUseLegacyImageFormat) {
+            si = new SurfaceImage(mFormat);
+        } else {
+            si = new SurfaceImage(mHardwareBufferFormat, mDataSpace);
+        }
         return acquireNextSurfaceImage(si) == ACQUIRE_SUCCESS ? si : null;
     }
 
@@ -492,7 +562,7 @@
             // A null image will eventually be returned if ImageReader is already closed.
             int status = ACQUIRE_NO_BUFS;
             if (mIsReaderValid) {
-                status = nativeImageSetup(si);
+                status = nativeImageSetup(si, mUseLegacyImageFormat);
             }
 
             switch (status) {
@@ -545,7 +615,12 @@
     public Image acquireNextImage() {
         // Initialize with reader format, but can be overwritten by native if the image
         // format is different from the reader format.
-        SurfaceImage si = new SurfaceImage(mFormat);
+        SurfaceImage si;
+        if (mUseLegacyImageFormat) {
+            si = new SurfaceImage(mFormat);
+        } else {
+            si = new SurfaceImage(mHardwareBufferFormat, mDataSpace);
+        }
         int status = acquireNextSurfaceImage(si);
 
         switch (status) {
@@ -838,13 +913,161 @@
         }
     }
 
+    /**
+     * Builder class for {@link ImageReader} objects.
+     */
+    public static final class Builder {
+        private int mWidth;
+        private int mHeight;
+        private int mMaxImages = 1;
+        private int mImageFormat = ImageFormat.UNKNOWN;
+        private int mHardwareBufferFormat = HardwareBuffer.RGBA_8888;
+        private long mDataSpace = DataSpace.DATASPACE_UNKNOWN;
+        private long mUsage = HardwareBuffer.USAGE_CPU_READ_OFTEN;
+        private boolean mUseLegacyImageFormat = false;
+
+        /**
+         * Constructs a new builder for {@link ImageReader}.
+         *
+         * @param width The default width in pixels that will be passed to the producer.
+         *              May be overridden by the producer.
+         * @param height The default height in pixels that will be passed to the producer.
+         *              May be overridden by the producer.
+         * @see Image
+         */
+        public Builder(@IntRange(from = 1) int width, @IntRange(from = 1) int height) {
+            mWidth = width;
+            mHeight = height;
+        }
+
+        /**
+         * Set the maximal number of images.
+         *
+         * @param maxImages The maximum number of images the user will want to
+         *            access simultaneously. This should be as small as possible to
+         *            limit memory use. Default value is 1.
+         * @return the Builder instance with customized usage value.
+         */
+        public @NonNull Builder setMaxImages(int maxImages) {
+            mMaxImages = maxImages;
+            return this;
+        }
+
+        /**
+         * Set the consumer usage flag.
+         *
+         * @param usage The intended usage of the images consumed by this ImageReader.
+         *              See the usages on {@link HardwareBuffer} for a list of valid usage bits.
+         *              Default value is {@link HardwareBuffer#USAGE_CPU_READ_OFTEN}.
+         * @return the Builder instance with customized usage value.
+         *
+         * @see HardwareBuffer
+         */
+        public @NonNull Builder setUsage(long usage) {
+            mUsage = usage;
+            return this;
+        }
+
+        /**
+         * Set the default image format passed by the producer. May be overridden by the producer.
+         *
+         * <p>{@link #setImageFormat} function replaces the combination of
+         * {@link #setDefaultHardwareBufferFormat} and {@link #setDefaultDataSpace} functions.
+         * Either this or these two functions must be called to initialize an {@code ImageReader}
+         * instance.</p>
+         *
+         * @param imageFormat The format of the image that this reader will produce. This
+         *                    must be one of the {@link android.graphics.ImageFormat} or
+         *                   {@link android.graphics.PixelFormat} constants. Note that not
+         *                   all formats are supported, like ImageFormat.NV21. The default value is
+         *                   {@link ImageFormat#UNKNOWN}.
+         * @return the builder instance with customized image format value.
+         *
+         * @see #setDefaultHardwareBufferFormat
+         * @see #setDefaultDataSpace
+         */
+        public @NonNull Builder setImageFormat(@Format int imageFormat) {
+            mImageFormat = imageFormat;
+            mUseLegacyImageFormat = true;
+            mHardwareBufferFormat = HardwareBuffer.RGBA_8888;
+            mDataSpace = DataSpace.DATASPACE_UNKNOWN;
+            return this;
+        }
+
+        /**
+         * Set the default hardwareBuffer format passed by the producer.
+         * May be overridden by the producer.
+         *
+         * <p>This function works together with {@link #setDefaultDataSpace} for an
+         * {@link ImageReader} instance. Setting at least one of these two replaces
+         * {@link #setImageFormat} function.</p>
+         *
+         * <p>The format of the Image can be overridden after {@link #setImageFormat} by calling
+         * this function and then {@link #setDefaultDataSpace} functions.
+         * <i>Warning:</i> Missing one of callings for initializing or overriding the format may
+         * involve undefined behaviors.</p>
+         *
+         * @param hardwareBufferFormat The HardwareBuffer format of the image that this reader
+         *                             will produce. The default value is
+         *                             {@link HardwareBuffer#RGBA_8888 HardwareBuffer.RGBA_8888}.
+         * @return the builder instance with customized hardwareBuffer value.
+         *
+         * @see #setDefaultDataSpace
+         * @see #setImageFormat
+         */
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public @NonNull Builder setDefaultHardwareBufferFormat(
+                @HardwareBuffer.Format int hardwareBufferFormat) {
+            mHardwareBufferFormat = hardwareBufferFormat;
+            mUseLegacyImageFormat = false;
+            mImageFormat = ImageFormat.UNKNOWN;
+            return this;
+        }
+
+        /**
+         * Set the default dataspace passed by the producer.
+         * May be overridden by the producer.
+         *
+         * <p>This function works together with {@link #setDefaultHardwareBufferFormat} for an
+         * {@link ImageReader} instance. Setting at least one of these two replaces
+         * {@link #setImageFormat} function.</p>
+         *
+         * @param dataSpace The dataspace of the image that this reader will produce.
+         *                  The default value is {@link DataSpace#DATASPACE_UNKNOWN}.
+         * @return the builder instance with customized dataspace value.
+         *
+         * @see #setDefaultHardwareBufferFormat
+         */
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public @NonNull Builder setDefaultDataSpace(@NamedDataSpace long dataSpace) {
+            mDataSpace = dataSpace;
+            mUseLegacyImageFormat = false;
+            mImageFormat = ImageFormat.UNKNOWN;
+            return this;
+        }
+
+        /**
+         * Builds a new ImageReader object.
+         *
+         * @return The new ImageReader object.
+         */
+        public @NonNull ImageReader build() {
+            if (mUseLegacyImageFormat) {
+                return new ImageReader(mWidth, mHeight, mImageFormat, mMaxImages, mUsage, null);
+            } else {
+                return new ImageReader(mWidth, mHeight, mMaxImages, mUsage, null,
+                    mHardwareBufferFormat, mDataSpace);
+            }
+        }
+    }
+
     private final int mWidth;
     private final int mHeight;
     private final int mFormat;
     private final long mUsage;
     private final int mMaxImages;
     private final int mNumPlanes;
-    private final Surface mSurface;
+    private Surface mSurface;
     private int mEstimatedNativeAllocBytes;
 
     private final Object mListenerLock = new Object();
@@ -861,6 +1084,12 @@
     // MultiResolutionImageReader.
     private final MultiResolutionImageReader mParent;
 
+    private final int mHardwareBufferFormat;
+
+    private final long mDataSpace;
+
+    private final boolean mUseLegacyImageFormat;
+
     /**
      * This field is used by native code, do not access or modify.
      */
@@ -897,6 +1126,12 @@
             mFormat = format;
         }
 
+        SurfaceImage(int hardwareBufferFormat, long dataSpace) {
+            mHardwareBufferFormat = hardwareBufferFormat;
+            mDataSpace = dataSpace;
+            mFormat = PublicFormatUtils.getPublicFormat(mHardwareBufferFormat, mDataSpace);
+        }
+
         @Override
         public void close() {
             ImageReader.this.releaseImage(this);
@@ -909,10 +1144,15 @@
         @Override
         public int getFormat() {
             throwISEIfImageIsInvalid();
-            int readerFormat = ImageReader.this.getImageFormat();
-            // Assume opaque reader always produce opaque images.
-            mFormat = (readerFormat == ImageFormat.PRIVATE) ? readerFormat :
-                nativeGetFormat(readerFormat);
+            // update mFormat only if ImageReader is initialized by factory pattern.
+            // if using builder pattern, mFormat has been updated upon initialization.
+            // no need update here.
+            if (ImageReader.this.mUseLegacyImageFormat) {
+                int readerFormat = ImageReader.this.getImageFormat();
+                // Assume opaque reader always produce opaque images.
+                mFormat = (readerFormat == ImageFormat.PRIVATE) ? readerFormat :
+                    nativeGetFormat(readerFormat);
+            }
             return mFormat;
         }
 
@@ -1125,6 +1365,8 @@
 
         private SurfacePlane[] mPlanes;
         private int mFormat = ImageFormat.UNKNOWN;
+        private int mHardwareBufferFormat = HardwareBuffer.RGBA_8888;
+        private long mDataSpace = DataSpace.DATASPACE_UNKNOWN;
         // If this image is detached from the ImageReader.
         private AtomicBoolean mIsDetached = new AtomicBoolean(false);
 
@@ -1137,8 +1379,8 @@
         private synchronized native HardwareBuffer nativeGetHardwareBuffer();
     }
 
-    private synchronized native void nativeInit(Object weakSelf, int w, int h,
-                                                    int fmt, int maxImgs, long consumerUsage);
+    private synchronized native void nativeInit(Object weakSelf, int w, int h, int maxImgs,
+            long consumerUsage, int hardwareBufferFormat, long dataSpace);
     private synchronized native void nativeClose();
     private synchronized native void nativeReleaseImage(Image i);
     private synchronized native Surface nativeGetSurface();
@@ -1152,7 +1394,7 @@
      * @see #ACQUIRE_NO_BUFS
      * @see #ACQUIRE_MAX_IMAGES
      */
-    private synchronized native int nativeImageSetup(Image i);
+    private synchronized native int nativeImageSetup(Image i, boolean legacyValidateImageFormat);
 
     /**
      * @hide
diff --git a/media/java/android/media/ImageUtils.java b/media/java/android/media/ImageUtils.java
index 7837d7e..2f1a36c 100644
--- a/media/java/android/media/ImageUtils.java
+++ b/media/java/android/media/ImageUtils.java
@@ -18,6 +18,7 @@
 
 import android.graphics.ImageFormat;
 import android.graphics.PixelFormat;
+import android.hardware.HardwareBuffer;
 import android.media.Image.Plane;
 import android.util.Size;
 
@@ -77,6 +78,34 @@
     }
 
     /**
+     * Only a subset of the formats defined in
+     * {@link android.graphics.HardwareBuffer.Format} constants are supported by ImageReader.
+     */
+    public static int getNumPlanesForHardwareBufferFormat(int hardwareBufferFormat) {
+        switch(hardwareBufferFormat) {
+            case HardwareBuffer.YCBCR_420_888:
+                return 3;
+            case HardwareBuffer.RGBA_8888:
+            case HardwareBuffer.RGBX_8888:
+            case HardwareBuffer.RGB_888:
+            case HardwareBuffer.RGB_565:
+            case HardwareBuffer.RGBA_FP16:
+            case HardwareBuffer.RGBA_1010102:
+            case HardwareBuffer.BLOB:
+            case HardwareBuffer.D_16:
+            case HardwareBuffer.D_24:
+            case HardwareBuffer.DS_24UI8:
+            case HardwareBuffer.D_FP32:
+            case HardwareBuffer.DS_FP32UI8:
+            case HardwareBuffer.S_UI8:
+                return 1;
+            default:
+                throw new UnsupportedOperationException(
+                    String.format("Invalid hardwareBuffer format specified %d",
+                            hardwareBufferFormat));
+        }
+    }
+    /**
      * <p>
      * Copy source image data to destination Image.
      * </p>
diff --git a/media/java/android/media/MediaDescription.java b/media/java/android/media/MediaDescription.java
index dece6bd..458562a 100644
--- a/media/java/android/media/MediaDescription.java
+++ b/media/java/android/media/MediaDescription.java
@@ -142,10 +142,10 @@
         mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-        mIcon = in.readParcelable(null, android.graphics.Bitmap.class);
-        mIconUri = in.readParcelable(null, android.net.Uri.class);
+        mIcon = in.readParcelable(null);
+        mIconUri = in.readParcelable(null);
         mExtras = in.readBundle();
-        mMediaUri = in.readParcelable(null, android.net.Uri.class);
+        mMediaUri = in.readParcelable(null);
     }
 
     /**
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 2427fa6..9c9e83b 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -371,7 +371,7 @@
         mFeatures = in.createStringArrayList();
         mType = in.readInt();
         mIsSystem = in.readBoolean();
-        mIconUri = in.readParcelable(null, android.net.Uri.class);
+        mIconUri = in.readParcelable(null);
         mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mConnectionState = in.readInt();
         mClientPackageName = in.readString();
diff --git a/media/java/android/media/PublicFormatUtils.java b/media/java/android/media/PublicFormatUtils.java
new file mode 100644
index 0000000..6268804
--- /dev/null
+++ b/media/java/android/media/PublicFormatUtils.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media;
+
+/**
+ * Package private utility class for PublicFormat related methods.
+ */
+class PublicFormatUtils {
+    public static int getHalFormat(int imageFormat) {
+        return nativeGetHalFormat(imageFormat);
+    }
+    public static long getHalDataspace(int imageFormat) {
+        return nativeGetHalDataspace(imageFormat);
+    }
+    public static int getPublicFormat(int imageFormat, long dataspace) {
+        return nativeGetPublicFormat(imageFormat, dataspace);
+    }
+    private static native int nativeGetHalFormat(int imageFormat);
+    private static native long nativeGetHalDataspace(int imageFormat);
+    private static native int nativeGetPublicFormat(int imageFormat, long dataspace);
+}
diff --git a/media/java/android/media/midi/MidiDeviceStatus.java b/media/java/android/media/midi/MidiDeviceStatus.java
index aa06267..b118279 100644
--- a/media/java/android/media/midi/MidiDeviceStatus.java
+++ b/media/java/android/media/midi/MidiDeviceStatus.java
@@ -115,7 +115,7 @@
         new Parcelable.Creator<MidiDeviceStatus>() {
         public MidiDeviceStatus createFromParcel(Parcel in) {
             ClassLoader classLoader = MidiDeviceInfo.class.getClassLoader();
-            MidiDeviceInfo deviceInfo = in.readParcelable(classLoader, android.media.midi.MidiDeviceInfo.class);
+            MidiDeviceInfo deviceInfo = in.readParcelable(classLoader);
             boolean[] inputPortOpen = in.createBooleanArray();
             int[] outputPortOpenCount = in.createIntArray();
             return new MidiDeviceStatus(deviceInfo, inputPortOpen, outputPortOpenCount);
diff --git a/media/java/android/media/musicrecognition/RecognitionRequest.java b/media/java/android/media/musicrecognition/RecognitionRequest.java
index b8757a3..3298d63 100644
--- a/media/java/android/media/musicrecognition/RecognitionRequest.java
+++ b/media/java/android/media/musicrecognition/RecognitionRequest.java
@@ -152,8 +152,8 @@
     }
 
     private RecognitionRequest(Parcel in) {
-        mAudioFormat = in.readParcelable(AudioFormat.class.getClassLoader(), android.media.AudioFormat.class);
-        mAudioAttributes = in.readParcelable(AudioAttributes.class.getClassLoader(), android.media.AudioAttributes.class);
+        mAudioFormat = in.readParcelable(AudioFormat.class.getClassLoader());
+        mAudioAttributes = in.readParcelable(AudioAttributes.class.getClassLoader());
         mCaptureSession = in.readInt();
         mMaxAudioLengthSeconds = in.readInt();
         mIgnoreBeginningFrames = in.readInt();
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 955ae3c..1da41fb 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -1022,7 +1022,7 @@
             mVolumeControl = in.readInt();
             mMaxVolume = in.readInt();
             mCurrentVolume = in.readInt();
-            mAudioAttrs = in.readParcelable(null, android.media.AudioAttributes.class);
+            mAudioAttrs = in.readParcelable(null);
             mVolumeControlId = in.readString();
         }
 
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index d34e636..770b8aa 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -66,6 +66,7 @@
             int seq, int userId);
     void releaseSession(in IBinder sessionToken, int userId);
     int getClientPid(in String sessionId);
+    int getClientPriority(int useCase, in String sessionId);
 
     void setMainSession(in IBinder sessionToken, int userId);
     void setSurface(in IBinder sessionToken, in Surface surface, int userId);
diff --git a/media/java/android/media/tv/TvContentRatingSystemInfo.java b/media/java/android/media/tv/TvContentRatingSystemInfo.java
index 947b2d6..f44ded3 100644
--- a/media/java/android/media/tv/TvContentRatingSystemInfo.java
+++ b/media/java/android/media/tv/TvContentRatingSystemInfo.java
@@ -94,8 +94,8 @@
     };
 
     private TvContentRatingSystemInfo(Parcel in) {
-        mXmlUri = in.readParcelable(null, android.net.Uri.class);
-        mApplicationInfo = in.readParcelable(null, android.content.pm.ApplicationInfo.class);
+        mXmlUri = in.readParcelable(null);
+        mApplicationInfo = in.readParcelable(null);
     }
 
     @Override
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index e60d537..54cb2bf 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -653,16 +653,16 @@
         mType = in.readInt();
         mIsHardwareInput = in.readByte() == 1;
         mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-        mIconUri = in.readParcelable(null, android.net.Uri.class);
+        mIconUri = in.readParcelable(null);
         mLabelResId = in.readInt();
-        mIcon = in.readParcelable(null, android.graphics.drawable.Icon.class);
-        mIconStandby = in.readParcelable(null, android.graphics.drawable.Icon.class);
-        mIconDisconnected = in.readParcelable(null, android.graphics.drawable.Icon.class);
+        mIcon = in.readParcelable(null);
+        mIconStandby = in.readParcelable(null);
+        mIconDisconnected = in.readParcelable(null);
         mSetupActivity = in.readString();
         mCanRecord = in.readByte() == 1;
         mCanPauseRecording = in.readByte() == 1;
         mTunerCount = in.readInt();
-        mHdmiDeviceInfo = in.readParcelable(null, android.hardware.hdmi.HdmiDeviceInfo.class);
+        mHdmiDeviceInfo = in.readParcelable(null);
         mIsConnectedToHdmiSwitch = in.readByte() == 1;
         mHdmiConnectionRelativePosition = in.readInt();
         mParentId = in.readString();
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index ad86002..52036b0 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -764,6 +764,9 @@
                 @Override
                 public void run() {
                     mSessionCallback.onVideoAvailable(mSession);
+                    if (mSession.mIAppNotificationEnabled && mSession.getIAppSession() != null) {
+                        mSession.getIAppSession().notifyVideoAvailable();
+                    }
                 }
             });
         }
@@ -773,6 +776,9 @@
                 @Override
                 public void run() {
                     mSessionCallback.onVideoUnavailable(mSession, reason);
+                    if (mSession.mIAppNotificationEnabled && mSession.getIAppSession() != null) {
+                        mSession.getIAppSession().notifyVideoUnavailable(reason);
+                    }
                 }
             });
         }
@@ -782,6 +788,9 @@
                 @Override
                 public void run() {
                     mSessionCallback.onContentAllowed(mSession);
+                    if (mSession.mIAppNotificationEnabled && mSession.getIAppSession() != null) {
+                        mSession.getIAppSession().notifyContentAllowed();
+                    }
                 }
             });
         }
@@ -791,6 +800,9 @@
                 @Override
                 public void run() {
                     mSessionCallback.onContentBlocked(mSession, rating);
+                    if (mSession.mIAppNotificationEnabled && mSession.getIAppSession() != null) {
+                        mSession.getIAppSession().notifyContentBlocked(rating);
+                    }
                 }
             });
         }
@@ -1786,6 +1798,29 @@
     };
 
     /**
+     * Returns a priority for the given use case type and the client's foreground or background
+     * status.
+     *
+     * @param useCase the use case type of the client. When the given use case type is invalid,
+     *        the default use case type will be used. {@see TvInputService#PriorityHintUseCaseType}.
+     * @param sessionId the unique id of the session owned by the client. When {@code null},
+     *        the caller will be used as a client. When the session is invalid, background status
+     *        will be used as a client's status. Otherwise, TV app corresponding to the given
+     *        session id will be used as a client.
+     *        {@see TvInputService#onCreateSession(String, String)}.
+     *
+     * @return the use case priority value for the given use case type and the client's foreground
+     *         or background status.
+     *
+     * @hide
+     */
+    @SystemApi
+    public int getClientPriority(@TvInputService.PriorityHintUseCaseType int useCase,
+            @Nullable String sessionId) {
+        return getClientPriorityInternal(useCase, sessionId);
+    };
+
+    /**
      * Creates a recording {@link Session} for a given TV input.
      *
      * <p>The number of sessions that can be created at the same time is limited by the capability
@@ -1829,6 +1864,14 @@
         return clientPid;
     }
 
+    private int getClientPriorityInternal(int useCase, String sessionId) {
+        try {
+            return mService.getClientPriority(useCase, sessionId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /**
      * Returns the TvStreamConfig list of the given TV input.
      *
diff --git a/media/java/android/media/tv/interactive/ITvIAppManager.aidl b/media/java/android/media/tv/interactive/ITvIAppManager.aidl
index 23201fa..2e04359 100644
--- a/media/java/android/media/tv/interactive/ITvIAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvIAppManager.aidl
@@ -51,6 +51,10 @@
     void notifyTuned(in IBinder sessionToken, in Uri channelUri, int userId);
     void notifyTrackSelected(in IBinder sessionToken, int type, in String trackId, int userId);
     void notifyTracksChanged(in IBinder sessionToken, in List<TvTrackInfo> tracks, int userId);
+    void notifyVideoAvailable(in IBinder sessionToken, int userId);
+    void notifyVideoUnavailable(in IBinder sessionToken, int reason, int userId);
+    void notifyContentAllowed(in IBinder sessionToken, int userId);
+    void notifyContentBlocked(in IBinder sessionToken, in String rating, int userId);
     void setSurface(in IBinder sessionToken, in Surface surface, int userId);
     void dispatchSurfaceChanged(in IBinder sessionToken, int format, int width, int height,
             int userId);
diff --git a/media/java/android/media/tv/interactive/ITvIAppSession.aidl b/media/java/android/media/tv/interactive/ITvIAppSession.aidl
index 52f9a87..2788ff6 100644
--- a/media/java/android/media/tv/interactive/ITvIAppSession.aidl
+++ b/media/java/android/media/tv/interactive/ITvIAppSession.aidl
@@ -42,6 +42,10 @@
     void notifyTuned(in Uri channelUri);
     void notifyTrackSelected(int type, in String trackId);
     void notifyTracksChanged(in List<TvTrackInfo> tracks);
+    void notifyVideoAvailable();
+    void notifyVideoUnavailable(int reason);
+    void notifyContentAllowed();
+    void notifyContentBlocked(in String rating);
     void setSurface(in Surface surface);
     void dispatchSurfaceChanged(int format, int width, int height);
     void notifyBroadcastInfoResponse(in BroadcastInfoResponse response);
diff --git a/media/java/android/media/tv/interactive/TvIAppManager.java b/media/java/android/media/tv/interactive/TvIAppManager.java
index d1fd1df..9685e3a 100644
--- a/media/java/android/media/tv/interactive/TvIAppManager.java
+++ b/media/java/android/media/tv/interactive/TvIAppManager.java
@@ -26,6 +26,7 @@
 import android.media.tv.AdResponse;
 import android.media.tv.BroadcastInfoRequest;
 import android.media.tv.BroadcastInfoResponse;
+import android.media.tv.TvContentRating;
 import android.media.tv.TvInputManager;
 import android.media.tv.TvTrackInfo;
 import android.net.Uri;
@@ -1037,6 +1038,66 @@
             }
         }
 
+        /**
+         * Notifies IAPP session when video is available.
+         */
+        public void notifyVideoAvailable() {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.notifyVideoAvailable(mToken, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
+         * Notifies IAPP session when video is unavailable.
+         */
+        public void notifyVideoUnavailable(int reason) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.notifyVideoUnavailable(mToken, reason, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
+         * Notifies IAPP session when content is allowed.
+         */
+        public void notifyContentAllowed() {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.notifyContentAllowed(mToken, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
+         * Notifies IAPP session when content is blocked.
+         */
+        public void notifyContentBlocked(TvContentRating rating) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.notifyContentBlocked(mToken, rating.flattenToString(), mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
         private void flushPendingEventsLocked() {
             mHandler.removeMessages(InputEventHandler.MSG_FLUSH_INPUT_EVENT);
 
diff --git a/media/java/android/media/tv/interactive/TvIAppService.java b/media/java/android/media/tv/interactive/TvIAppService.java
index 0456041..4993bc3 100644
--- a/media/java/android/media/tv/interactive/TvIAppService.java
+++ b/media/java/android/media/tv/interactive/TvIAppService.java
@@ -31,6 +31,7 @@
 import android.media.tv.AdResponse;
 import android.media.tv.BroadcastInfoRequest;
 import android.media.tv.BroadcastInfoResponse;
+import android.media.tv.TvContentRating;
 import android.media.tv.TvTrackInfo;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -442,6 +443,34 @@
         }
 
         /**
+         * Called when video is available.
+         * @hide
+         */
+        public void onVideoAvailable() {
+        }
+
+        /**
+         * Called when video is unavailable.
+         * @hide
+         */
+        public void onVideoUnavailable(int reason) {
+        }
+
+        /**
+         * Called when content is allowed.
+         * @hide
+         */
+        public void onContentAllowed() {
+        }
+
+        /**
+         * Called when content is blocked.
+         * @hide
+         */
+        public void onContentBlocked(TvContentRating rating) {
+        }
+
+        /**
          * Called when a broadcast info response is received.
          * @hide
          */
@@ -816,6 +845,33 @@
             onTracksChanged(tracks);
         }
 
+        void notifyVideoAvailable() {
+            if (DEBUG) {
+                Log.d(TAG, "notifyVideoAvailable");
+            }
+            onVideoAvailable();
+        }
+
+        void notifyVideoUnavailable(int reason) {
+            if (DEBUG) {
+                Log.d(TAG, "notifyVideoAvailable (reason=" + reason + ")");
+            }
+            onVideoUnavailable(reason);
+        }
+
+        void notifyContentAllowed() {
+            if (DEBUG) {
+                Log.d(TAG, "notifyContentAllowed");
+            }
+            notifyContentAllowed();
+        }
+
+        void notifyContentBlocked(TvContentRating rating) {
+            if (DEBUG) {
+                Log.d(TAG, "notifyContentBlocked (rating=" + rating.flattenToString() + ")");
+            }
+            onContentBlocked(rating);
+        }
 
         /**
          * Calls {@link #onBroadcastInfoResponse}.
@@ -1182,6 +1238,26 @@
         }
 
         @Override
+        public void notifyVideoAvailable() {
+            mSessionImpl.notifyVideoAvailable();
+        }
+
+        @Override
+        public void notifyVideoUnavailable(int reason) {
+            mSessionImpl.notifyVideoUnavailable(reason);
+        }
+
+        @Override
+        public void notifyContentAllowed() {
+            mSessionImpl.notifyContentAllowed();
+        }
+
+        @Override
+        public void notifyContentBlocked(String rating) {
+            mSessionImpl.notifyContentBlocked(TvContentRating.unflattenFromString(rating));
+        }
+
+        @Override
         public void setSurface(Surface surface) {
             mSessionImpl.setSurface(surface);
         }
diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java
index 6a6a22c..50a2083 100644
--- a/media/java/android/media/tv/tuner/Lnb.java
+++ b/media/java/android/media/tv/tuner/Lnb.java
@@ -28,6 +28,9 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 
 /**
@@ -145,9 +148,9 @@
 
     private static final String TAG = "Lnb";
 
-    LnbCallback mCallback;
-    Executor mExecutor;
-    Tuner mTuner;
+    Map<LnbCallback, Executor> mCallbackMap =
+            new HashMap<LnbCallback, Executor>();
+    Tuner mOwner;
     private final Object mCallbackLock = new Object();
 
 
@@ -164,38 +167,82 @@
 
     private Lnb() {}
 
-    void setCallback(Executor executor, @Nullable LnbCallback callback, Tuner tuner) {
+    void setCallbackAndOwner(Executor executor, @Nullable LnbCallback callback, Tuner tuner) {
         synchronized (mCallbackLock) {
-            mCallback = callback;
-            mExecutor = executor;
-            mTuner = tuner;
+            if (callback != null && executor != null) {
+                addCallback(callback, executor);
+            }
+        }
+        setOwner(tuner);
+    }
+
+    /**
+     * Adds LnbCallback
+     *
+     * @param callback the callback to receive notifications from LNB.
+     * @param executor the executor on which callback will be invoked. Cannot be null.
+     */
+    public void addCallback(@NonNull  LnbCallback callback, @NonNull Executor executor) {
+        Objects.requireNonNull(callback, "callback must not be null");
+        Objects.requireNonNull(executor, "executor must not be null");
+        synchronized (mCallbackLock) {
+            mCallbackMap.put(callback, executor);
+        }
+    }
+
+    /**
+     * Removes LnbCallback
+     *
+     * @param callback the callback be removed for callback
+     *
+     * @return {@code true} when successful. {@code false} otherwise.
+     */
+    public boolean removeCallback(@NonNull LnbCallback callback) {
+        Objects.requireNonNull(callback, "callback must not be null");
+        synchronized (mCallbackLock) {
+            boolean result = (mCallbackMap.remove(callback) != null);
+            return result;
+        }
+    }
+
+    // allow owner transfer independent of whether callback is registered or not
+    /* package */ void setOwner(@NonNull Tuner newOwner) {
+        Objects.requireNonNull(newOwner, "newOwner must not be null");
+        synchronized (mLock) {
+            mOwner = newOwner;
         }
     }
 
     private void onEvent(int eventType) {
         synchronized (mCallbackLock) {
-            if (mExecutor != null && mCallback != null) {
-                mExecutor.execute(() -> {
-                    synchronized (mCallbackLock) {
-                        if (mCallback != null) {
-                            mCallback.onEvent(eventType);
+            for (LnbCallback callback : mCallbackMap.keySet()) {
+                Executor executor = mCallbackMap.get(callback);
+                if (callback != null && executor != null) {
+                    executor.execute(() -> {
+                        synchronized (mCallbackLock) {
+                            if (callback != null) {
+                                callback.onEvent(eventType);
+                            }
                         }
-                    }
-                });
+                    });
+                }
             }
         }
     }
 
     private void onDiseqcMessage(byte[] diseqcMessage) {
         synchronized (mCallbackLock) {
-            if (mExecutor != null && mCallback != null) {
-                mExecutor.execute(() -> {
-                    synchronized (mCallbackLock) {
-                        if (mCallback != null) {
-                            mCallback.onDiseqcMessage(diseqcMessage);
+            for (LnbCallback callback : mCallbackMap.keySet()) {
+                Executor executor = mCallbackMap.get(callback);
+                if (callback != null && executor != null) {
+                    executor.execute(() -> {
+                        synchronized (mCallbackLock) {
+                            if (callback != null) {
+                                callback.onDiseqcMessage(diseqcMessage);
+                            }
                         }
-                    }
-                });
+                    });
+                }
             }
         }
     }
@@ -279,7 +326,11 @@
                 TunerUtils.throwExceptionForResult(res, "Failed to close LNB");
             } else {
                 mIsClosed = true;
-                mTuner.releaseLnb();
+                if (mOwner != null) {
+                    mOwner.releaseLnb();
+                    mOwner = null;
+                }
+                mCallbackMap.clear();
             }
         }
     }
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 4128abf..9c4a83a 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -241,7 +241,7 @@
 
 
     private static final String TAG = "MediaTvTuner";
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private static final int MSG_RESOURCE_LOST = 1;
     private static final int MSG_ON_FILTER_EVENT = 2;
@@ -250,7 +250,6 @@
 
     private static final int FILTER_CLEANUP_THRESHOLD = 256;
 
-
     /** @hide */
     @IntDef(prefix = "DVR_TYPE_", value = {DVR_TYPE_RECORD, DVR_TYPE_PLAYBACK})
     @Retention(RetentionPolicy.SOURCE)
@@ -455,6 +454,260 @@
     }
 
     /**
+     * Transfers the ownership of shared frontend and its associated resources.
+     *
+     * @param newOwner the Tuner instance to be the new owner.
+     *
+     * @return result status of tune operation.
+     */
+    public int transferOwner(@NonNull Tuner newOwner) {
+        acquireTRMSLock("transferOwner()");
+        mFrontendLock.lock();
+        mFrontendCiCamLock.lock();
+        mLnbLock.lock();
+        try {
+
+            if (!isFrontendOwner() || !isNewOwnerQualifiedForTransfer(newOwner)) {
+                return RESULT_INVALID_STATE;
+            }
+
+            int res = transferFeOwner(newOwner);
+            if (res != RESULT_SUCCESS) {
+                return res;
+            }
+
+            res = transferCiCamOwner(newOwner);
+            if (res != RESULT_SUCCESS) {
+                return res;
+            }
+
+            res = transferLnbOwner(newOwner);
+            if (res != RESULT_SUCCESS) {
+                return res;
+            }
+        } finally {
+            mFrontendLock.unlock();
+            mFrontendCiCamLock.unlock();
+            mLnbLock.unlock();
+            releaseTRMSLock();
+        }
+        return RESULT_SUCCESS;
+    }
+
+    /**
+     * Resets or copies Frontend related settings.
+     */
+    private void replicateFrontendSettings(@Nullable Tuner src) {
+        mFrontendLock.lock();
+        try {
+            if (src == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "resetting Frontend params for " + mClientId);
+                }
+                mFrontend = null;
+                mFrontendHandle = null;
+                mFrontendInfo = null;
+                mFrontendType = FrontendSettings.TYPE_UNDEFINED;
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "copying Frontend params from " + src.mClientId
+                            + " to " + mClientId);
+                }
+                mFrontend = src.mFrontend;
+                mFrontendHandle = src.mFrontendHandle;
+                mFrontendInfo = src.mFrontendInfo;
+                mFrontendType = src.mFrontendType;
+            }
+        } finally {
+            mFrontendLock.unlock();
+        }
+    }
+
+    /**
+     * Sets the frontend owner. mFeOwnerTuner should be null for the owner Tuner instance.
+     */
+    private void setFrontendOwner(Tuner owner) {
+        mFrontendLock.lock();
+        try {
+            mFeOwnerTuner = owner;
+        } finally {
+            mFrontendLock.unlock();
+        }
+    }
+
+    /**
+     * Resets or copies the CiCam related settings.
+     */
+    private void replicateCiCamSettings(@Nullable Tuner src) {
+        mFrontendCiCamLock.lock();
+        try {
+            if (src == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "resetting CiCamParams: " + mClientId);
+                }
+                mFrontendCiCamHandle = null;
+                mFrontendCiCamId = null;
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "copying CiCamParams from " + src.mClientId + " to " + mClientId);
+                    Log.d(TAG, "mFrontendCiCamHandle:" + src.mFrontendCiCamHandle + ", "
+                            + "mFrontendCiCamId:" + src.mFrontendCiCamId);
+                }
+                mFrontendCiCamHandle = src.mFrontendCiCamHandle;
+                mFrontendCiCamId = src.mFrontendCiCamId;
+            }
+        } finally {
+            mFrontendCiCamLock.unlock();
+        }
+    }
+
+    /**
+     * Resets or copies Lnb related settings.
+     */
+    private void replicateLnbSettings(@Nullable Tuner src) {
+        mLnbLock.lock();
+        try {
+            if (src == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "resetting Lnb params");
+                }
+                mLnb = null;
+                mLnbHandle = null;
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "copying Lnb params from " + src.mClientId + " to " + mClientId);
+                }
+                mLnb = src.mLnb;
+                mLnbHandle = src.mLnbHandle;
+            }
+        } finally {
+            mLnbLock.unlock();
+        }
+    }
+
+    /**
+     * Checks if it is a frontend resource owner.
+     * Proper mutex must be held prior to calling this.
+     */
+    private boolean isFrontendOwner() {
+        boolean notAnOwner = (mFeOwnerTuner != null);
+        if (notAnOwner) {
+            Log.e(TAG, "transferOwner() - cannot be called on the non-owner");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Checks if the newOwner is qualified.
+     * Proper mutex must be held prior to calling this.
+     */
+    private boolean isNewOwnerQualifiedForTransfer(@NonNull Tuner newOwner) {
+        // new owner must be the current sharee
+        boolean newOwnerIsTheCurrentSharee = (newOwner.mFeOwnerTuner == this)
+                && (newOwner.mFrontendHandle.equals(mFrontendHandle));
+        if (!newOwnerIsTheCurrentSharee) {
+            Log.e(TAG, "transferOwner() - new owner must be the current sharee");
+            return false;
+        }
+
+        // new owner must not be holding any of the to-be-shared resources
+        boolean newOwnerAlreadyHoldsToBeSharedResource =
+                (newOwner.mFrontendCiCamHandle != null || newOwner.mLnb != null);
+        if (newOwnerAlreadyHoldsToBeSharedResource) {
+            Log.e(TAG, "transferOwner() - new owner cannot be holding CiCam"
+                    + " nor Lnb resource");
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Transfers the ownership of the already held frontend resource.
+     * Proper mutex must be held prior to calling this.
+     */
+    private int transferFeOwner(@NonNull Tuner newOwner) {
+        // handle native resource first
+        newOwner.nativeUpdateFrontend(getNativeContext());
+        nativeUpdateFrontend(0);
+
+        // transfer frontend related settings
+        newOwner.replicateFrontendSettings(this);
+
+        // transfer the frontend owner info
+        setFrontendOwner(newOwner);
+        newOwner.setFrontendOwner(null);
+
+        // handle TRM
+        if (mTunerResourceManager.transferOwner(
+                TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND,
+                mClientId, newOwner.mClientId)) {
+            return RESULT_SUCCESS;
+        } else {
+            return RESULT_UNKNOWN_ERROR;
+        }
+    }
+
+    /**
+     * Transfers the ownership of CiCam resource.
+     * This is a no-op if the CiCam resource is not held.
+     * Proper mutex must be held prior to calling this.
+     */
+    private int transferCiCamOwner(Tuner newOwner) {
+        boolean notAnOwner = (mFrontendCiCamHandle == null);
+        if (notAnOwner) {
+            // There is nothing to do here if there is no CiCam
+            return RESULT_SUCCESS;
+        }
+
+        // no need to handle at native level
+
+        // transfer the CiCam info at Tuner level
+        newOwner.replicateCiCamSettings(this);
+        replicateCiCamSettings(null);
+
+        // handle TRM
+        if (mTunerResourceManager.transferOwner(
+                TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND_CICAM,
+                mClientId, newOwner.mClientId)) {
+            return RESULT_SUCCESS;
+        } else {
+            return RESULT_UNKNOWN_ERROR;
+        }
+    }
+
+    /**
+     * Transfers the ownership of Lnb resource.
+     * This is a no-op if the Lnb resource is not held.
+     * Proper mutex must be held prior to calling this.
+     */
+    private int transferLnbOwner(Tuner newOwner) {
+        boolean notAnOwner = (mLnb == null);
+        if (notAnOwner) {
+            // There is nothing to do here if there is no Lnb
+            return RESULT_SUCCESS;
+        }
+
+        // no need to handle at native level
+
+        // set the new owner
+        mLnb.setOwner(newOwner);
+
+        newOwner.replicateLnbSettings(this);
+        replicateLnbSettings(null);
+
+        // handle TRM
+        if (mTunerResourceManager.transferOwner(
+                TunerResourceManager.TUNER_RESOURCE_TYPE_LNB,
+                mClientId, newOwner.mClientId)) {
+            return RESULT_SUCCESS;
+        } else {
+            return RESULT_UNKNOWN_ERROR;
+        }
+    }
+
+    /**
      * Updates client priority with an arbitrary value along with a nice value.
      *
      * <p>Tuner resource manager (TRM) uses the client priority value to decide whether it is able
@@ -547,59 +800,114 @@
         }
     }
 
+    /**
+     * Either unshares the frontend resource (for sharee) or release Frontend (for owner)
+     */
+    public void closeFrontend() {
+        acquireTRMSLock("closeFrontend()");
+        try {
+            releaseFrontend();
+        } finally {
+            releaseTRMSLock();
+        }
+    }
+
+    /**
+     * Releases frontend resource for the owner. Unshares frontend resource for the sharee.
+     */
     private void releaseFrontend() {
+        if (DEBUG) {
+            Log.d(TAG, "Tuner#releaseFrontend");
+        }
         mFrontendLock.lock();
         try {
             if (mFrontendHandle != null) {
+                if (DEBUG) {
+                    Log.d(TAG, "mFrontendHandle not null");
+                }
                 if (mFeOwnerTuner != null) {
+                    if (DEBUG) {
+                        Log.d(TAG, "mFeOwnerTuner not null - sharee");
+                    }
                     // unregister self from the Frontend callback
                     mFeOwnerTuner.unregisterFrontendCallbackListener(this);
                     mFeOwnerTuner = null;
+                    nativeUnshareFrontend();
                 } else {
+                    if (DEBUG) {
+                        Log.d(TAG, "mFeOwnerTuner null - owner");
+                    }
                     // close resource as owner
                     int res = nativeCloseFrontend(mFrontendHandle);
                     if (res != Tuner.RESULT_SUCCESS) {
                         TunerUtils.throwExceptionForResult(res, "failed to close frontend");
                     }
-                    mTunerResourceManager.releaseFrontend(mFrontendHandle, mClientId);
                 }
+                if (DEBUG) {
+                    Log.d(TAG, "call TRM#releaseFrontend :" + mFrontendHandle + ", " + mClientId);
+                }
+                mTunerResourceManager.releaseFrontend(mFrontendHandle, mClientId);
                 FrameworkStatsLog
                         .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
                         FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__UNKNOWN);
-                mFrontendHandle = null;
-                mFrontend = null;
+                replicateFrontendSettings(null);
             }
         } finally {
             mFrontendLock.unlock();
         }
     }
 
+    /**
+     * Releases CiCam resource if held. No-op otherwise.
+     */
+    private void releaseCiCam() {
+        mFrontendCiCamLock.lock();
+        try {
+            if (mFrontendCiCamHandle != null) {
+                if (DEBUG) {
+                    Log.d(TAG, "unlinking CiCam : " + mFrontendCiCamHandle + " for " +  mClientId);
+                }
+                int result = nativeUnlinkCiCam(mFrontendCiCamId);
+                if (result == RESULT_SUCCESS) {
+                    mTunerResourceManager.releaseCiCam(mFrontendCiCamHandle, mClientId);
+                    replicateCiCamSettings(null);
+                } else {
+                    Log.e(TAG, "nativeUnlinkCiCam(" + mFrontendCiCamHandle + ") for mClientId:"
+                            + mClientId + "failed with result:" + result);
+                }
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "NOT unlinking CiCam : " + mClientId);
+                }
+            }
+        } finally {
+            mFrontendCiCamLock.unlock();
+        }
+    }
+
     private void releaseAll() {
+        // release CiCam before frontend because frontend handle is needed to unlink CiCam
+        releaseCiCam();
+
         releaseFrontend();
 
         mLnbLock.lock();
         try {
             // mLnb will be non-null only for owner tuner
             if (mLnb != null) {
+                if (DEBUG) {
+                    Log.d(TAG, "calling mLnb.close() : " + mClientId);
+                }
                 mLnb.close();
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "NOT calling mLnb.close() : " + mClientId);
+                }
             }
         } finally {
             mLnbLock.unlock();
         }
 
-        mFrontendCiCamLock.lock();
-        try {
-            if (mFrontendCiCamHandle != null) {
-                int result = nativeUnlinkCiCam(mFrontendCiCamId);
-                if (result == RESULT_SUCCESS) {
-                    mTunerResourceManager.releaseCiCam(mFrontendCiCamHandle, mClientId);
-                    mFrontendCiCamId = null;
-                    mFrontendCiCamHandle = null;
-                }
-            }
-        } finally {
-            mFrontendCiCamLock.unlock();
-        }
 
         synchronized (mDescramblers) {
             if (!mDescramblers.isEmpty()) {
@@ -669,8 +977,11 @@
      */
     private native Frontend nativeOpenFrontendByHandle(int handle);
     private native int nativeShareFrontend(int id);
+    private native int nativeUnshareFrontend();
     private native void nativeRegisterFeCbListener(long nativeContext);
     private native void nativeUnregisterFeCbListener(long nativeContext);
+    // nativeUpdateFrontend must be called on the new owner first
+    private native void nativeUpdateFrontend(long nativeContext);
     @Result
     private native int nativeTune(int type, FrontendSettings settings);
     private native int nativeStopTune();
@@ -997,6 +1308,21 @@
             mFrontendHandle = feHandle[0];
             mFrontend = nativeOpenFrontendByHandle(mFrontendHandle);
         }
+
+        // For satellite type, set Lnb if valid handle exists.
+        // This is necessary as now that we support closeFrontend().
+        if (mFrontendType == FrontendSettings.TYPE_DVBS
+                || mFrontendType == FrontendSettings.TYPE_ISDBS
+                || mFrontendType == FrontendSettings.TYPE_ISDBS3) {
+            mLnbLock.lock();
+            try {
+                if (mLnbHandle != null && mLnb != null) {
+                    nativeSetLnb(mLnb);
+                }
+            } finally {
+                mLnbLock.unlock();
+            }
+        }
         return granted;
     }
 
@@ -1756,12 +2082,12 @@
             Objects.requireNonNull(executor, "executor must not be null");
             Objects.requireNonNull(cb, "LnbCallback must not be null");
             if (mLnb != null) {
-                mLnb.setCallback(executor, cb, this);
+                mLnb.setCallbackAndOwner(executor, cb, this);
                 return mLnb;
             }
             if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_LNB, mLnbLock)
                     && mLnb != null) {
-                mLnb.setCallback(executor, cb, this);
+                mLnb.setCallbackAndOwner(executor, cb, this);
                 setLnb(mLnb);
                 return mLnb;
             }
@@ -1795,7 +2121,7 @@
                     mLnbHandle = null;
                 }
                 mLnb = newLnb;
-                mLnb.setCallback(executor, cb, this);
+                mLnb.setCallbackAndOwner(executor, cb, this);
                 setLnb(mLnb);
             }
             return mLnb;
@@ -2081,8 +2407,15 @@
         try {
             if (mLnbHandle != null) {
                 // LNB handle can be null if it's opened by name.
+                if (DEBUG) {
+                    Log.d(TAG, "releasing Lnb");
+                }
                 mTunerResourceManager.releaseLnb(mLnbHandle, mClientId);
                 mLnbHandle = null;
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "NOT releasing Lnb because mLnbHandle is null");
+                }
             }
             mLnb = null;
         } finally {
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
index fe611c7..5ada89e 100644
--- a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
@@ -21,9 +21,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresFeature;
+import android.annotation.SuppressLint;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.media.tv.TvInputService;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.util.Log;
@@ -415,6 +418,25 @@
     }
 
     /**
+     * Transfers the ownership of shared resource.
+     *
+     * <p><strong>Note:</strong> Only the existing frontend sharee can be the new owner.
+     *
+     * @param resourceType the type of the resource to transfer the ownership for.
+     * @param currentOwnerId the id of the current owner client.
+     * @param newOwnerId the id of the new owner client.
+     *
+     * @return true if successful and false otherwise.
+     */
+    public boolean transferOwner(int resourceType, int currentOwnerId, int newOwnerId) {
+        try {
+            return mService.transferOwner(resourceType, currentOwnerId, newOwnerId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Requests a Tuner Demux resource.
      *
      * <p>There are three possible scenarios:
@@ -702,6 +724,49 @@
     }
 
     /**
+     * Returns a priority for the given use case type and the client's foreground or background
+     * status.
+     *
+     * @param useCase the use case type of the client. When the given use case type is invalid,
+     *        the default use case type will be used. {@see TvInputService#PriorityHintUseCaseType}.
+     * @param pid the pid of the client. When the pid is invalid, background status will be used as
+     *        a client's status. Otherwise, client's app corresponding to the given session id will
+     *        be used as a client. {@see TvInputService#onCreateSession(String, String)}.
+     *
+     * @return the client priority..
+     */
+    public int getClientPriority(@TvInputService.PriorityHintUseCaseType int useCase, int pid) {
+        try {
+            return mService.getClientPriority(useCase, pid);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns a config priority for the given use case type and the foreground or background
+     * status.
+     *
+     * @param useCase the use case type of the client. When the given use case type is invalid,
+     *        the default use case type will be used. {@see TvInputService#PriorityHintUseCaseType}.
+     * @param isForeground {@code true} if foreground, {@code false} otherwise.
+     *
+     * @return the config priority.
+     *
+     * @hide
+     */
+    @TestApi
+    @SuppressLint("ShowingMemberInHiddenClass")
+    public int getConfigPriority(@TvInputService.PriorityHintUseCaseType int useCase,
+            boolean isForeground) {
+        try {
+            return mService.getConfigPriority(useCase, isForeground);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Interface used to receive events from TunerResourceManager.
      */
     public abstract static class ResourcesReclaimListener {
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
index 5f35820..d16fc6c 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
+++ b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
@@ -177,6 +177,19 @@
     void shareFrontend(in int selfClientId, in int targetClientId);
 
     /*
+     * Transfers the ownership of the shared resource.
+     *
+     * <p><strong>Note:</strong> Only the existing frontend sharee can be the new owner.
+     *
+     * @param resourceType the type of resource to transfer the ownership for.
+     * @param currentOwnerId the id of the current owner client.
+     * @param newOwnerId the id of the new owner client.
+     *
+     * @return true if successful. false otherwise.
+     */
+    boolean transferOwner(in int resourceType, in int currentOwnerId, in int newOwnerId);
+
+    /*
      * This API is used by the Tuner framework to request an available demux from the TunerHAL.
      *
      * <p>There are three possible scenarios:
@@ -442,4 +455,30 @@
      * guaranteed to work and may be unrecoverrable. (This should not happen.)
      */
     boolean releaseLock(in int clientId);
+
+    /**
+     * Returns a priority for the given use case type and the client's foreground or background
+     * status.
+     *
+     * @param useCase the use case type of the client. When the given use case type is invalid,
+     *        the default use case type will be used. {@see TvInputService#PriorityHintUseCaseType}.
+     * @param pid the pid of the client. When the pid is invalid, background status will be used as
+     *        a client's status. Otherwise, client's app corresponding to the given session id will
+     *        be used as a client. {@see TvInputService#onCreateSession(String, String)}.
+     *
+     * @return the client priority..
+     */
+    int getClientPriority(int useCase, int pid);
+
+    /**
+     * Returns a config priority for the given use case type and the foreground or background
+     * status.
+     *
+     * @param useCase the use case type of the client. When the given use case type is invalid,
+     *        the default use case type will be used. {@see TvInputService#PriorityHintUseCaseType}.
+     * @param isForeground {@code true} if foreground, {@code false} otherwise.
+     *
+     * @return the config priority.
+     */
+    int getConfigPriority(int useCase, boolean isForeground);
 }
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index e817f2d..feae606 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -39,6 +39,7 @@
         "android_media_MediaProfiles.cpp",
         "android_media_MediaRecorder.cpp",
         "android_media_MediaSync.cpp",
+        "android_media_PublicFormatUtils.cpp",
         "android_media_ResampleInputStream.cpp",
         "android_media_Streams.cpp",
         "android_media_SyncParams.cpp",
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 021507c..6002e28 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -375,18 +375,13 @@
 }
 
 static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, jint width, jint height,
-                             jint format, jint maxImages, jlong ndkUsage)
-{
+                             jint maxImages, jlong ndkUsage, jint nativeFormat, jlong dataSpace) {
     status_t res;
-    int nativeFormat;
-    android_dataspace nativeDataspace;
 
-    ALOGV("%s: width:%d, height: %d, format: 0x%x, maxImages:%d",
-          __FUNCTION__, width, height, format, maxImages);
+    ALOGV("%s: width:%d, height: %d, nativeFormat: %d, maxImages:%d",
+          __FUNCTION__, width, height, nativeFormat, maxImages);
 
-    PublicFormat publicFormat = static_cast<PublicFormat>(format);
-    nativeFormat = mapPublicFormatToHalFormat(publicFormat);
-    nativeDataspace = mapPublicFormatToHalDataspace(publicFormat);
+    android_dataspace nativeDataspace = static_cast<android_dataspace>(dataSpace);
 
     jclass clazz = env->GetObjectClass(thiz);
     if (clazz == NULL) {
@@ -400,7 +395,7 @@
     BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
     sp<BufferItemConsumer> bufferConsumer;
     String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
-            width, height, format, maxImages, getpid(),
+            width, height, nativeFormat, maxImages, getpid(),
             createProcessUniqueId());
     uint64_t consumerUsage =
             android_hardware_HardwareBuffer_convertToGrallocUsageBits(ndkUsage);
@@ -527,7 +522,8 @@
     ALOGV("%s: Image (format: 0x%x) has been released", __FUNCTION__, ctx->getBufferFormat());
 }
 
-static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image) {
+static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image,
+                                   jboolean legacyValidateImageFormat) {
     ALOGV("%s:", __FUNCTION__);
     JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
     if (ctx == NULL) {
@@ -590,7 +586,7 @@
             ALOGV("%s: Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
                     __FUNCTION__, outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
         }
-        if (imgReaderFmt != bufferFormat) {
+        if (legacyValidateImageFormat && imgReaderFmt != bufferFormat) {
             if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 &&
                     isPossiblyYUV(bufferFormat)) {
                 // Treat formats that are compatible with flexible YUV
@@ -958,10 +954,10 @@
 
 static const JNINativeMethod gImageReaderMethods[] = {
     {"nativeClassInit",        "()V",                        (void*)ImageReader_classInit },
-    {"nativeInit",             "(Ljava/lang/Object;IIIIJ)V",  (void*)ImageReader_init },
+    {"nativeInit",             "(Ljava/lang/Object;IIIJIJ)V",   (void*)ImageReader_init },
     {"nativeClose",            "()V",                        (void*)ImageReader_close },
     {"nativeReleaseImage",     "(Landroid/media/Image;)V",   (void*)ImageReader_imageRelease },
-    {"nativeImageSetup",       "(Landroid/media/Image;)I",   (void*)ImageReader_imageSetup },
+    {"nativeImageSetup",       "(Landroid/media/Image;Z)I",   (void*)ImageReader_imageSetup },
     {"nativeGetSurface",       "()Landroid/view/Surface;",   (void*)ImageReader_getSurface },
     {"nativeDetachImage",      "(Landroid/media/Image;)I",   (void*)ImageReader_detachImage },
     {"nativeCreateImagePlanes",
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 8dcdc98..a548a47 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1454,6 +1454,7 @@
 extern int register_android_media_MediaMuxer(JNIEnv *env);
 extern int register_android_media_MediaRecorder(JNIEnv *env);
 extern int register_android_media_MediaSync(JNIEnv *env);
+extern int register_android_media_PublicFormatUtils(JNIEnv *env);
 extern int register_android_media_ResampleInputStream(JNIEnv *env);
 extern int register_android_media_MediaProfiles(JNIEnv *env);
 extern int register_android_mtp_MtpDatabase(JNIEnv *env);
@@ -1501,6 +1502,11 @@
         goto bail;
     }
 
+    if (register_android_media_PublicFormatUtils(env) < 0) {
+        ALOGE("ERROR: PublicFormatUtils native registration failed\n");
+        goto bail;
+    }
+
     if (register_android_media_ResampleInputStream(env) < 0) {
         ALOGE("ERROR: ResampleInputStream native registration failed\n");
         goto bail;
diff --git a/media/jni/android_media_PublicFormatUtils.cpp b/media/jni/android_media_PublicFormatUtils.cpp
new file mode 100644
index 0000000..09ebdee
--- /dev/null
+++ b/media/jni/android_media_PublicFormatUtils.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "PublicFormatUtils_JNI"
+
+#include <utils/misc.h>
+#include <ui/PublicFormat.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <jni.h>
+
+using namespace android;
+
+static jint android_media_PublicFormatUtils_getHalFormat(JNIEnv* /*env*/, jobject /*thiz*/,
+                                                         jint imageFormat) {
+    PublicFormat publicFormat = static_cast<PublicFormat>(imageFormat);
+    int nativeFormat = mapPublicFormatToHalFormat(publicFormat);
+    return static_cast<jint>(nativeFormat);
+}
+
+static jlong android_media_PublicFormatUtils_getHalDataspace(JNIEnv* /*env*/, jobject /*thiz*/,
+                                                             jint imageFormat) {
+    PublicFormat publicFormat = static_cast<PublicFormat>(imageFormat);
+    android_dataspace
+        nativeDataspace = mapPublicFormatToHalDataspace(publicFormat);
+    return static_cast<jlong>(nativeDataspace);
+}
+
+static jint android_media_PublicFormatUtils_getPublicFormat(JNIEnv* /*env*/, jobject /*thiz*/,
+                                                            jint hardwareBufferFormat,
+                                                            jlong dataspace) {
+    PublicFormat nativeFormat = mapHalFormatDataspaceToPublicFormat(
+            hardwareBufferFormat, static_cast<android_dataspace>(dataspace));
+    return static_cast<jint>(nativeFormat);
+}
+
+static const JNINativeMethod gMethods[] = {
+    {"nativeGetHalFormat",    "(I)I", (void*)android_media_PublicFormatUtils_getHalFormat},
+    {"nativeGetHalDataspace", "(I)J", (void*)android_media_PublicFormatUtils_getHalDataspace},
+    {"nativeGetPublicFormat", "(IJ)I",(void*)android_media_PublicFormatUtils_getPublicFormat}
+};
+
+int register_android_media_PublicFormatUtils(JNIEnv *env) {
+    return AndroidRuntime::registerNativeMethods(env,
+             "android/media/PublicFormatUtils", gMethods, NELEM(gMethods));
+}
+
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index d9feaf40..1b41494 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -978,7 +978,8 @@
 void FrontendClientCallbackImpl::addCallbackListener(JTuner* jtuner, jweak listener) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jweak listenerRef = env->NewWeakGlobalRef(listener);
-    ALOGV("addCallbackListener() with listener:%p and ref:%p @%p", listener, listenerRef, this);
+    ALOGV("addCallbackListener() with listener:%p and ref:%p @%p",
+              listener, listenerRef, this);
     std::scoped_lock<std::mutex> lock(mMutex);
     mListenersMap[jtuner] = listenerRef;
 }
@@ -1345,18 +1346,43 @@
     return (int)Result::SUCCESS;
 }
 
+int JTuner::unshareFrontend() {
+    if (mFeClient != nullptr) {
+        ALOGE("Cannot unshare frontend because this session is already holding %d"
+              " as an owner instead of as a sharee", mFeClient->getId());
+        return (int)Result::INVALID_STATE;
+    }
+
+    mSharedFeId = (int)Constant::INVALID_FRONTEND_ID;
+    return (int)Result::SUCCESS;
+}
+
 void JTuner::registerFeCbListener(JTuner* jtuner) {
+    ALOGV("registerFeCbListener: %p", jtuner);
     if (mFeClientCb != nullptr && jtuner != nullptr) {
         mFeClientCb->addCallbackListener(jtuner, jtuner->getObject());
     }
 }
 
 void JTuner::unregisterFeCbListener(JTuner* jtuner) {
+    ALOGV("unregisterFeCbListener: %p", jtuner);
     if (mFeClientCb != nullptr && jtuner != nullptr) {
         mFeClientCb->removeCallbackListener(jtuner);
     }
 }
 
+void JTuner::updateFrontend(JTuner* jtuner) {
+    if (jtuner == nullptr) {
+        ALOGV("JTuner::updateFrontend(null) called for previous owner: %p", this);
+        mFeClient = nullptr;
+        mFeClientCb = nullptr;
+    } else {
+        ALOGV("JTuner::updateFrontend(%p) called for new owner: %p", jtuner, this);
+        mFeClient = jtuner->mFeClient;
+        mFeClientCb = jtuner->mFeClientCb;
+    }
+}
+
 jobject JTuner::getAnalogFrontendCaps(JNIEnv *env, FrontendCapabilities &caps) {
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AnalogFrontendCapabilities");
     jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(II)V");
@@ -3319,6 +3345,12 @@
     return tuner->shareFrontend(id);
 }
 
+static int android_media_tv_Tuner_unshare_frontend(
+        JNIEnv *env, jobject thiz) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->unshareFrontend();
+}
+
 static void android_media_tv_Tuner_register_fe_cb_listener(
         JNIEnv *env, jobject thiz, jlong shareeJTuner) {
     sp<JTuner> tuner = getTuner(env, thiz);
@@ -3333,6 +3365,17 @@
     tuner->unregisterFeCbListener(jtuner);
 }
 
+static void android_media_tv_Tuner_update_frontend(JNIEnv *env, jobject thiz, jlong jtunerPtr) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    JTuner *jtuner;
+    if (jtunerPtr == 0) {
+        jtuner = nullptr;
+    } else {
+        jtuner = (JTuner *) jtunerPtr;
+    }
+    tuner->updateFrontend(jtuner);
+}
+
 static int android_media_tv_Tuner_tune(JNIEnv *env, jobject thiz, jint type, jobject settings) {
     sp<JTuner> tuner = getTuner(env, thiz);
     FrontendSettings setting = getFrontendSettings(env, type, settings);
@@ -4574,10 +4617,14 @@
             (void *)android_media_tv_Tuner_open_frontend_by_handle },
     { "nativeShareFrontend", "(I)I",
             (void *)android_media_tv_Tuner_share_frontend },
+    { "nativeUnshareFrontend", "()I",
+            (void *)android_media_tv_Tuner_unshare_frontend },
     { "nativeRegisterFeCbListener", "(J)V",
             (void*)android_media_tv_Tuner_register_fe_cb_listener },
     { "nativeUnregisterFeCbListener", "(J)V",
             (void*)android_media_tv_Tuner_unregister_fe_cb_listener },
+    { "nativeUpdateFrontend", "(J)V",
+            (void*)android_media_tv_Tuner_update_frontend },
     { "nativeTune", "(ILandroid/media/tv/tuner/frontend/FrontendSettings;)I",
             (void *)android_media_tv_Tuner_tune },
     { "nativeStopTune", "()I", (void *)android_media_tv_Tuner_stop_tune },
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index f1b31e3..502bd6b 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -178,8 +178,10 @@
     jobject getFrontendIds();
     jobject openFrontendByHandle(int feHandle);
     int shareFrontend(int feId);
+    int unshareFrontend();
     void registerFeCbListener(JTuner* jtuner);
     void unregisterFeCbListener(JTuner* jtuner);
+    void updateFrontend(JTuner* jtuner);
     jint closeFrontendById(int id);
     jobject getFrontendInfo(int id);
     int tune(const FrontendSettings& settings);
diff --git a/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.java b/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.java
index f0ff465..b06d515 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.java
@@ -75,7 +75,7 @@
                 @Override
                 public DataUsageRequest createFromParcel(Parcel in) {
                     int requestId = in.readInt();
-                    NetworkTemplate template = in.readParcelable(null, android.net.NetworkTemplate.class);
+                    NetworkTemplate template = in.readParcelable(null);
                     long thresholdInBytes = in.readLong();
                     DataUsageRequest result = new DataUsageRequest(requestId, template,
                             thresholdInBytes);
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.java
index 03bb187..575c5ed 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.java
@@ -267,14 +267,14 @@
         mMode = in.readInt();
         mSourceAddress = in.readString();
         mDestinationAddress = in.readString();
-        mNetwork = (Network) in.readParcelable(Network.class.getClassLoader(), android.net.Network.class);
+        mNetwork = (Network) in.readParcelable(Network.class.getClassLoader());
         mSpiResourceId = in.readInt();
         mEncryption =
-                (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class);
+                (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
         mAuthentication =
-                (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class);
+                (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
         mAuthenticatedEncryption =
-                (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class);
+                (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
         mEncapType = in.readInt();
         mEncapSocketResourceId = in.readInt();
         mEncapRemotePort = in.readInt();
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.java
index 390af82..732cf19 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.java
@@ -81,7 +81,7 @@
         status = in.readInt();
         resourceId = in.readInt();
         port = in.readInt();
-        fileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader(), android.os.ParcelFileDescriptor.class);
+        fileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
     }
 
     @android.annotation.NonNull
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java
index d577aa8..3915634 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java
@@ -73,9 +73,9 @@
 
     /** @hide */
     public NetworkStateSnapshot(@NonNull Parcel in) {
-        mNetwork = in.readParcelable(null, android.net.Network.class);
-        mNetworkCapabilities = in.readParcelable(null, android.net.NetworkCapabilities.class);
-        mLinkProperties = in.readParcelable(null, android.net.LinkProperties.class);
+        mNetwork = in.readParcelable(null);
+        mNetworkCapabilities = in.readParcelable(null);
+        mLinkProperties = in.readParcelable(null);
         mSubscriberId = in.readString();
         mLegacyType = in.readInt();
     }
diff --git a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.java b/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.java
index 7ab53b1..33f9375 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.java
@@ -60,7 +60,7 @@
         mOwnerUid = in.readInt();
         mIface = in.readString();
         List<String> underlyingIfaces = new ArrayList<>();
-        in.readList(underlyingIfaces, null /*classLoader*/, java.lang.String.class);
+        in.readList(underlyingIfaces, null /*classLoader*/);
         mUnderlyingIfaces = Collections.unmodifiableList(underlyingIfaces);
     }
 
diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
index c206903..3f2b8ac 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
@@ -43,4 +43,8 @@
     <color name="settingslib_accent_primary_variant">@android:color/system_accent1_300</color>
 
     <color name="settingslib_text_color_primary_device_default">@android:color/system_neutral1_50</color>
+
+    <color name="settingslib_text_color_secondary_device_default">@android:color/system_neutral2_200</color>
+
+    <color name="settingslib_text_color_preference_category_title">@android:color/system_accent1_100</color>
 </resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
index 0401098..ec3c336 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
@@ -65,4 +65,8 @@
     <color name="settingslib_background_device_default_light">@android:color/system_neutral1_50</color>
 
     <color name="settingslib_text_color_primary_device_default">@android:color/system_neutral1_900</color>
+
+    <color name="settingslib_text_color_secondary_device_default">@android:color/system_neutral2_700</color>
+
+    <color name="settingslib_text_color_preference_category_title">@android:color/system_accent1_600</color>
 </resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml
index 1c33f1a..11546c8 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml
@@ -20,4 +20,9 @@
     <dimen name="app_icon_min_width">52dp</dimen>
     <dimen name="settingslib_preferred_minimum_touch_target">48dp</dimen>
     <dimen name="settingslib_dialogCornerRadius">28dp</dimen>
+
+    <!-- Left padding of the preference -->
+    <dimen name="settingslib_listPreferredItemPaddingStart">24dp</dimen>
+    <!-- Right padding of the preference -->
+    <dimen name="settingslib_listPreferredItemPaddingEnd">24dp</dimen>
 </resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
index 5800636..8e7226b 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
@@ -17,13 +17,19 @@
 <resources>
     <style name="TextAppearance.PreferenceTitle.SettingsLib"
            parent="@android:style/TextAppearance.Material.Subhead">
+        <item name="android:textColor">@color/settingslib_text_color_primary_device_default</item>
         <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
         <item name="android:textSize">20sp</item>
     </style>
 
+    <style name="TextAppearance.PreferenceSummary.SettingsLib"
+           parent="@android:style/TextAppearance.DeviceDefault.Small">
+        <item name="android:textColor">@color/settingslib_text_color_secondary_device_default</item>
+    </style>
+
     <style name="TextAppearance.CategoryTitle.SettingsLib"
            parent="@android:style/TextAppearance.DeviceDefault.Medium">
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textColor">@color/settingslib_text_color_preference_category_title</item>
         <item name="android:textSize">14sp</item>
     </style>
 
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
index 6bf288b..7bf75bc 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
@@ -19,8 +19,8 @@
     <!-- Only using in Settings application -->
     <style name="Theme.SettingsBase" parent="@android:style/Theme.DeviceDefault.Settings" >
         <item name="android:textAppearanceListItem">@style/TextAppearance.PreferenceTitle.SettingsLib</item>
-        <item name="android:listPreferredItemPaddingStart">24dp</item>
-        <item name="android:listPreferredItemPaddingLeft">24dp</item>
+        <item name="android:listPreferredItemPaddingStart">@dimen/settingslib_listPreferredItemPaddingStart</item>
+        <item name="android:listPreferredItemPaddingLeft">@dimen/settingslib_listPreferredItemPaddingStart</item>
         <item name="android:listPreferredItemPaddingEnd">16dp</item>
         <item name="android:listPreferredItemPaddingRight">16dp</item>
         <item name="preferenceTheme">@style/PreferenceTheme.SettingsLib</item>
diff --git a/packages/SettingsLib/SettingsTheme/res/values/config.xml b/packages/SettingsLib/SettingsTheme/res/values/config.xml
new file mode 100644
index 0000000..e73dcc0
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values/config.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <bool name="settingslib_config_icon_space_reserved">true</bool>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
index 18af1f9..f7e0144 100644
--- a/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
@@ -21,4 +21,11 @@
     <dimen name="app_icon_min_width">56dp</dimen>
     <dimen name="two_target_min_width">72dp</dimen>
     <dimen name="settingslib_dialogCornerRadius">8dp</dimen>
+
+    <!-- Left padding of the preference -->
+    <dimen name="settingslib_listPreferredItemPaddingStart">16dp</dimen>
+    <!-- Right padding of the preference -->
+    <dimen name="settingslib_listPreferredItemPaddingEnd">16dp</dimen>
+    <!-- Icon size of the preference -->
+    <dimen name="settingslib_preferenceIconSize">24dp</dimen>
 </resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values/styles.xml b/packages/SettingsLib/SettingsTheme/res/values/styles.xml
new file mode 100644
index 0000000..aaab0f0
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values/styles.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+<resources>
+    <style name="TextAppearance.PreferenceTitle.SettingsLib"
+           parent="@android:style/TextAppearance.Material.Subhead">
+    </style>
+
+    <style name="TextAppearance.PreferenceSummary.SettingsLib"
+           parent="@style/PreferenceSummaryTextStyle">
+    </style>
+
+    <style name="TextAppearance.CategoryTitle.SettingsLib"
+           parent="@android:style/TextAppearance.DeviceDefault.Medium">
+    </style>
+</resources>
diff --git a/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java b/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java
index de45ea5..d3fe4a7 100644
--- a/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java
+++ b/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java
@@ -47,7 +47,7 @@
  * Annotation processor for {@link SearchIndexable} that generates {@link SearchIndexableResources}
  * subclasses.
  */
-@SupportedSourceVersion(SourceVersion.RELEASE_8)
+@SupportedSourceVersion(SourceVersion.RELEASE_9)
 @SupportedAnnotationTypes({"com.android.settingslib.search.SearchIndexable"})
 public class IndexableProcessor extends AbstractProcessor {
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index 9dd329e..b11bbde 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -138,13 +138,6 @@
         return mService.getActiveDevice();
     }
 
-    public boolean isAudioOn() {
-        if (mService == null) {
-            return false;
-        }
-        return mService.isAudioOn();
-    }
-
     public int getAudioState(BluetoothDevice device) {
         if (mService == null) {
             return BluetoothHeadset.STATE_AUDIO_DISCONNECTED;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java
index 30182c4..f5ce664 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java
@@ -55,15 +55,6 @@
     }
 
     @Test
-    public void bluetoothProfile_shouldReturnTheAudioStatusFromBlueToothHeadsetService() {
-        when(mService.isAudioOn()).thenReturn(true);
-        assertThat(mProfile.isAudioOn()).isTrue();
-
-        when(mService.isAudioOn()).thenReturn(false);
-        assertThat(mProfile.isAudioOn()).isFalse();
-    }
-
-    @Test
     public void testHeadsetProfile_shouldReturnAudioState() {
         when(mService.getAudioState(mBluetoothDevice)).
                 thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
diff --git a/packages/SystemUI/res-keyguard/values/bools.xml b/packages/SystemUI/res-keyguard/values/bools.xml
index 2b83787..c5bf4ce 100644
--- a/packages/SystemUI/res-keyguard/values/bools.xml
+++ b/packages/SystemUI/res-keyguard/values/bools.xml
@@ -17,4 +17,5 @@
 <resources>
     <bool name="kg_show_ime_at_screen_on">true</bool>
     <bool name="kg_use_all_caps">true</bool>
+    <bool name="flag_active_unlock">false</bool>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 7b8f349..56517cc 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -294,6 +294,7 @@
     <string-array name="config_systemUIServiceComponents" translatable="false">
         <item>com.android.systemui.util.NotificationChannels</item>
         <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
+        <item>com.android.keyguard.KeyguardBiometricLockoutLogger</item>
         <item>com.android.systemui.recents.Recents</item>
         <item>com.android.systemui.volume.VolumeUI</item>
         <item>com.android.systemui.statusbar.phone.StatusBar</item>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 2916c1c..7600eb1 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1165,7 +1165,7 @@
     <string name="wallet_lockscreen_settings_label">Lock screen settings</string>
 
     <!-- QR Code Scanner label, title [CHAR LIMIT=32] -->
-    <string name="qr_code_scanner_title">QR Code</string>
+    <string name="qr_code_scanner_title">QR code</string>
 
     <!-- QR Code Scanner description [CHAR LIMIT=NONE] -->
     <string name="qr_code_scanner_description">Tap to scan</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
index 9808374..1d2caf9 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
@@ -28,6 +28,8 @@
 import android.view.ViewRootImpl;
 import android.view.ViewTreeObserver;
 
+import androidx.annotation.VisibleForTesting;
+
 import java.io.PrintWriter;
 import java.util.concurrent.Executor;
 
@@ -60,6 +62,7 @@
     private final Rect mRegisteredSamplingBounds = new Rect();
     private final SamplingCallback mCallback;
     private final Executor mBackgroundExecutor;
+    private final SysuiCompositionSamplingListener mCompositionSamplingListener;
     private boolean mSamplingEnabled = false;
     private boolean mSamplingListenerRegistered = false;
 
@@ -91,9 +94,17 @@
 
     public RegionSamplingHelper(View sampledView, SamplingCallback samplingCallback,
             Executor backgroundExecutor) {
+        this(sampledView, samplingCallback, sampledView.getContext().getMainExecutor(),
+                backgroundExecutor, new SysuiCompositionSamplingListener());
+    }
+
+    @VisibleForTesting
+    RegionSamplingHelper(View sampledView, SamplingCallback samplingCallback,
+            Executor mainExecutor, Executor backgroundExecutor,
+            SysuiCompositionSamplingListener compositionSamplingListener) {
         mBackgroundExecutor = backgroundExecutor;
-        mSamplingListener = new CompositionSamplingListener(
-                sampledView.getContext().getMainExecutor()) {
+        mCompositionSamplingListener = compositionSamplingListener;
+        mSamplingListener = new CompositionSamplingListener(mainExecutor) {
             @Override
             public void onSampleCollected(float medianLuma) {
                 if (mSamplingEnabled) {
@@ -136,7 +147,7 @@
 
     public void stopAndDestroy() {
         stop();
-        mSamplingListener.destroy();
+        mBackgroundExecutor.execute(mSamplingListener::destroy);
         mIsDestroyed = true;
     }
 
@@ -189,13 +200,12 @@
                 // We only want to re-register if something actually changed
                 unregisterSamplingListener();
                 mSamplingListenerRegistered = true;
-                SurfaceControl wrappedStopLayer = stopLayerControl == null
-                        ? null : new SurfaceControl(stopLayerControl, "regionSampling");
+                SurfaceControl wrappedStopLayer = wrap(stopLayerControl);
                 mBackgroundExecutor.execute(() -> {
                     if (wrappedStopLayer != null && !wrappedStopLayer.isValid()) {
                         return;
                     }
-                    CompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
+                    mCompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
                             wrappedStopLayer, mSamplingRequestBounds);
                 });
                 mRegisteredSamplingBounds.set(mSamplingRequestBounds);
@@ -208,14 +218,21 @@
         }
     }
 
+    @VisibleForTesting
+    protected SurfaceControl wrap(SurfaceControl stopLayerControl) {
+        return stopLayerControl == null ? null : new SurfaceControl(stopLayerControl,
+                "regionSampling");
+    }
+
     private void unregisterSamplingListener() {
         if (mSamplingListenerRegistered) {
             mSamplingListenerRegistered = false;
             SurfaceControl wrappedStopLayer = mWrappedStopLayer;
             mRegisteredStopLayer = null;
+            mWrappedStopLayer = null;
             mRegisteredSamplingBounds.setEmpty();
             mBackgroundExecutor.execute(() -> {
-                CompositionSamplingListener.unregister(mSamplingListener);
+                mCompositionSamplingListener.unregister(mSamplingListener);
                 if (wrappedStopLayer != null && wrappedStopLayer.isValid()) {
                     wrappedStopLayer.release();
                 }
@@ -299,4 +316,19 @@
             return true;
         }
     }
+
+    @VisibleForTesting
+    public static class SysuiCompositionSamplingListener {
+        public void register(CompositionSamplingListener listener,
+                int displayId, SurfaceControl stopLayer, Rect samplingArea) {
+            CompositionSamplingListener.register(listener, displayId, stopLayer, samplingArea);
+        }
+
+        /**
+         * Unregisters a sampling listener.
+         */
+        public void unregister(CompositionSamplingListener listener) {
+            CompositionSamplingListener.unregister(listener);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardBiometricLockoutLogger.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardBiometricLockoutLogger.kt
new file mode 100644
index 0000000..214b284
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardBiometricLockoutLogger.kt
@@ -0,0 +1,176 @@
+/*
+ * 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.keyguard
+
+import android.content.Context
+import android.hardware.biometrics.BiometricSourceType
+import com.android.internal.annotations.VisibleForTesting
+import com.android.internal.logging.UiEvent
+import com.android.internal.logging.UiEventLogger
+import com.android.internal.widget.LockPatternUtils
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE
+import com.android.keyguard.KeyguardBiometricLockoutLogger.PrimaryAuthRequiredEvent
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import javax.inject.Inject
+
+/**
+ * Logs events when primary authentication requirements change. Primary authentication is considered
+ * authentication using pin/pattern/password input.
+ *
+ * See [PrimaryAuthRequiredEvent] for all the events and their descriptions.
+ */
+@SysUISingleton
+class KeyguardBiometricLockoutLogger @Inject constructor(
+    context: Context?,
+    private val uiEventLogger: UiEventLogger,
+    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+    private val dumpManager: DumpManager
+) : CoreStartable(context) {
+    private var fingerprintLockedOut = false
+    private var faceLockedOut = false
+    private var encryptedOrLockdown = false
+    private var unattendedUpdate = false
+    private var timeout = false
+
+    override fun start() {
+        dumpManager.registerDumpable(this)
+        mKeyguardUpdateMonitorCallback.onStrongAuthStateChanged(
+                KeyguardUpdateMonitor.getCurrentUser())
+        keyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback)
+    }
+
+    private val mKeyguardUpdateMonitorCallback: KeyguardUpdateMonitorCallback =
+            object : KeyguardUpdateMonitorCallback() {
+        override fun onLockedOutStateChanged(biometricSourceType: BiometricSourceType) {
+            if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
+                val lockedOut = keyguardUpdateMonitor.isFingerprintLockedOut
+                if (lockedOut && !fingerprintLockedOut) {
+                    uiEventLogger.log(
+                            PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT)
+                } else if (!lockedOut && fingerprintLockedOut) {
+                    uiEventLogger.log(
+                            PrimaryAuthRequiredEvent
+                                    .PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT_RESET)
+                }
+                fingerprintLockedOut = lockedOut
+            } else if (biometricSourceType == BiometricSourceType.FACE) {
+                val lockedOut = keyguardUpdateMonitor.isFaceLockedOut
+                if (lockedOut && !faceLockedOut) {
+                    uiEventLogger.log(
+                            PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT)
+                } else if (!lockedOut && faceLockedOut) {
+                    uiEventLogger.log(
+                            PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT_RESET)
+                }
+                faceLockedOut = lockedOut
+            }
+        }
+
+        override fun onStrongAuthStateChanged(userId: Int) {
+            if (userId != KeyguardUpdateMonitor.getCurrentUser()) {
+                return
+            }
+            val strongAuthFlags = keyguardUpdateMonitor.strongAuthTracker
+                    .getStrongAuthForUser(userId)
+
+            val newEncryptedOrLockdown = keyguardUpdateMonitor.isEncryptedOrLockdown(userId)
+            if (newEncryptedOrLockdown && !encryptedOrLockdown) {
+                uiEventLogger.log(
+                        PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_ENCRYPTED_OR_LOCKDOWN)
+            }
+            encryptedOrLockdown = newEncryptedOrLockdown
+
+            val newUnattendedUpdate = isUnattendedUpdate(strongAuthFlags)
+            if (newUnattendedUpdate && !unattendedUpdate) {
+                uiEventLogger.log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_UNATTENDED_UPDATE)
+            }
+            unattendedUpdate = newUnattendedUpdate
+
+            val newTimeout = isStrongAuthTimeout(strongAuthFlags)
+            if (newTimeout && !timeout) {
+                uiEventLogger.log(PrimaryAuthRequiredEvent.PRIMARY_AUTH_REQUIRED_TIMEOUT)
+            }
+            timeout = newTimeout
+        }
+    }
+
+    private fun isUnattendedUpdate(
+        @LockPatternUtils.StrongAuthTracker.StrongAuthFlags flags: Int
+    ) = containsFlag(flags, STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE)
+
+    private fun isStrongAuthTimeout(
+        @LockPatternUtils.StrongAuthTracker.StrongAuthFlags flags: Int
+    ) = containsFlag(flags, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) ||
+            containsFlag(flags, STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT)
+
+    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
+        pw.println("  mFingerprintLockedOut=$fingerprintLockedOut")
+        pw.println("  mFaceLockedOut=$faceLockedOut")
+        pw.println("  mIsEncryptedOrLockdown=$encryptedOrLockdown")
+        pw.println("  mIsUnattendedUpdate=$unattendedUpdate")
+        pw.println("  mIsTimeout=$timeout")
+    }
+
+    /**
+     * Events pertaining to whether primary authentication (pin/pattern/password input) is required
+     * for device entry.
+     */
+    @VisibleForTesting
+    enum class PrimaryAuthRequiredEvent(private val mId: Int) : UiEventLogger.UiEventEnum {
+        @UiEvent(doc = "Fingerprint cannot be used to authenticate for device entry. This" +
+                "can persist until the next primary auth or may timeout.")
+        PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT(924),
+
+        @UiEvent(doc = "Fingerprint can be used to authenticate for device entry.")
+        PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT_RESET(925),
+
+        @UiEvent(doc = "Face cannot be used to authenticate for device entry.")
+        PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT(926),
+
+        @UiEvent(doc = "Face can be used to authenticate for device entry.")
+        PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT_RESET(927),
+
+        @UiEvent(doc = "Device is encrypted (ie: after reboot) or device is locked down by DPM " +
+                "or a manual user lockdown.")
+        PRIMARY_AUTH_REQUIRED_ENCRYPTED_OR_LOCKDOWN(928),
+
+        @UiEvent(doc = "Primary authentication is required because it hasn't been used for a " +
+                "time required by a device admin or because primary auth hasn't been used for a " +
+                "time after a non-strong biometric (weak or convenience) is used to unlock the " +
+                "device.")
+        PRIMARY_AUTH_REQUIRED_TIMEOUT(929),
+
+        @UiEvent(doc = "Strong authentication is required to prepare for unattended upgrade.")
+        PRIMARY_AUTH_REQUIRED_UNATTENDED_UPDATE(931);
+
+        override fun getId(): Int {
+            return mId
+        }
+    }
+
+    companion object {
+        private fun containsFlag(strongAuthFlags: Int, flagCheck: Int): Boolean {
+            return strongAuthFlags and flagCheck != 0
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
index 03f04d3..36fe5ba 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
@@ -64,3 +64,19 @@
     val secureCameraLaunched: Boolean,
     val switchingUser: Boolean
 ) : KeyguardListenModel()
+/**
+ * Verbose debug information associated with [KeyguardUpdateMonitor.shouldTriggerActiveUnlock].
+ */
+data class KeyguardActiveUnlockModel(
+    @CurrentTimeMillisLong override val timeMillis: Long,
+    override val userId: Int,
+    override val listening: Boolean,
+    // keep sorted
+    val authInterruptActive: Boolean,
+    val encryptedOrTimedOut: Boolean,
+    val fpLockout: Boolean,
+    val lockDown: Boolean,
+    val switchingUser: Boolean,
+    val triggerActiveUnlockForAssistant: Boolean,
+    val userCanDismissLockScreen: Boolean
+) : KeyguardListenModel()
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardListenQueue.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardListenQueue.kt
index f13a59a..210f5e7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardListenQueue.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardListenQueue.kt
@@ -32,15 +32,17 @@
 ) {
     private val faceQueue = ArrayDeque<KeyguardFaceListenModel>()
     private val fingerprintQueue = ArrayDeque<KeyguardFingerprintListenModel>()
+    private val activeUnlockQueue = ArrayDeque<KeyguardActiveUnlockModel>()
 
     @get:VisibleForTesting val models: List<KeyguardListenModel>
-        get() = faceQueue + fingerprintQueue
+        get() = faceQueue + fingerprintQueue + activeUnlockQueue
 
     /** Push a [model] to the queue (will be logged until the queue exceeds [sizePerModality]). */
     fun add(model: KeyguardListenModel) {
         val queue = when (model) {
             is KeyguardFaceListenModel -> faceQueue.apply { add(model) }
             is KeyguardFingerprintListenModel -> fingerprintQueue.apply { add(model) }
+            is KeyguardActiveUnlockModel -> activeUnlockQueue.apply { add(model) }
         }
 
         if (queue.size > sizePerModality) {
@@ -63,5 +65,9 @@
         for (model in fingerprintQueue) {
             writer.println(stringify(model))
         }
+        writer.println("  Active unlock triggers (last ${activeUnlockQueue.size} calls):")
+        for (model in activeUnlockQueue) {
+            writer.println(stringify(model))
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 98721fd..5276679 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -37,6 +37,8 @@
 import android.app.ActivityTaskManager;
 import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.AlarmManager;
+import android.app.Notification;
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.UserSwitchObserver;
 import android.app.admin.DevicePolicyManager;
@@ -102,6 +104,8 @@
 import com.android.systemui.dagger.qualifiers.Background;
 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.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -109,6 +113,7 @@
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.telephony.TelephonyListenerManager;
 import com.android.systemui.util.Assert;
+import com.android.systemui.util.NotificationChannels;
 import com.android.systemui.util.RingerModeTracker;
 
 import com.google.android.collect.Lists;
@@ -143,8 +148,10 @@
     private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
     private static final boolean DEBUG_FACE = Build.IS_DEBUGGABLE;
     private static final boolean DEBUG_FINGERPRINT = Build.IS_DEBUGGABLE;
+    private static final boolean DEBUG_ACTIVE_UNLOCK = Build.IS_DEBUGGABLE;
     private static final boolean DEBUG_SPEW = false;
     private static final int BIOMETRIC_LOCKOUT_RESET_DELAY_MS = 600;
+    private int mNumActiveUnlockTriggers = 0;
 
     private static final String ACTION_FACE_UNLOCK_STARTED
             = "com.android.facelock.FACE_UNLOCK_STARTED";
@@ -183,7 +190,6 @@
     private static final int MSG_USER_STOPPED = 340;
     private static final int MSG_USER_REMOVED = 341;
     private static final int MSG_KEYGUARD_GOING_AWAY = 342;
-    private static final int MSG_LOCK_SCREEN_MODE = 343;
     private static final int MSG_TIME_FORMAT_UPDATE = 344;
     private static final int MSG_REQUIRE_NFC_UNLOCK = 345;
 
@@ -221,7 +227,6 @@
     private static final int BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED = -1;
     public static final int BIOMETRIC_HELP_FACE_NOT_RECOGNIZED = -2;
 
-    private static final int DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT = 5000000;
     /**
      * If no cancel signal has been received after this amount of time, set the biometric running
      * state to stopped to allow Keyguard to retry authentication.
@@ -231,7 +236,6 @@
     private static final ComponentName FALLBACK_HOME_COMPONENT = new ComponentName(
             "com.android.settings", "com.android.settings.FallbackHome");
 
-
     /**
      * If true, the system is in the half-boot-to-decryption-screen state.
      * Prudently disable lockscreen.
@@ -334,6 +338,7 @@
     private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
     private final Executor mBackgroundExecutor;
     private SensorPrivacyManager mSensorPrivacyManager;
+    private FeatureFlags mFeatureFlags;
     private int mFaceAuthUserId;
 
     /**
@@ -1250,7 +1255,11 @@
                 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
     }
 
-    private boolean isEncryptedOrLockdown(int userId) {
+    /**
+     * Returns true if primary authentication is required for the given user due to lockdown
+     * or encryption after reboot.
+     */
+    public boolean isEncryptedOrLockdown(int userId) {
         final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(userId);
         final boolean isLockDown =
                 containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
@@ -1311,6 +1320,9 @@
     void setAssistantVisible(boolean assistantVisible) {
         mAssistantVisible = assistantVisible;
         updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+        if (mAssistantVisible) {
+            requestActiveUnlock();
+        }
     }
 
     static class DisplayClientState {
@@ -1650,6 +1662,7 @@
         Trace.beginSection("KeyguardUpdateMonitor#handleStartedWakingUp");
         Assert.isMainThread();
         updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+        requestActiveUnlock();
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -1777,7 +1790,8 @@
             AuthController authController,
             TelephonyListenerManager telephonyListenerManager,
             InteractionJankMonitor interactionJankMonitor,
-            LatencyTracker latencyTracker) {
+            LatencyTracker latencyTracker,
+            FeatureFlags featureFlags) {
         mContext = context;
         mSubscriptionManager = SubscriptionManager.from(context);
         mTelephonyListenerManager = telephonyListenerManager;
@@ -1795,6 +1809,7 @@
         mAuthController = authController;
         dumpManager.registerDumpable(getClass().getName(), this);
         mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
+        mFeatureFlags = featureFlags;
 
         mHandler = new Handler(mainLooper) {
             @Override
@@ -2180,6 +2195,7 @@
         }
         mAuthInterruptActive = active;
         updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
+        requestActiveUnlock();
     }
 
     /**
@@ -2228,6 +2244,97 @@
         }
     }
 
+    /**
+     * Attempts to trigger active unlock.
+     */
+    public void requestActiveUnlock() {
+        // If this message exists, FP has already authenticated, so wait until that is handled
+        if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
+            return;
+        }
+
+        if (shouldTriggerActiveUnlock() && mFeatureFlags.isEnabled(Flags.ACTIVE_UNLOCK)) {
+            // TODO (b/192405661): call new TrustManager API
+            mNumActiveUnlockTriggers++;
+            Log.d("ActiveUnlock", "would have triggered times=" + mNumActiveUnlockTriggers);
+            showActiveUnlockNotification(mNumActiveUnlockTriggers);
+        }
+    }
+
+    /**
+     * TODO (b/192405661): Only for testing. Remove before release.
+     */
+    private void showActiveUnlockNotification(int times) {
+        final String message = "Active unlock triggered "  + times + " times.";
+        final Notification.Builder nb =
+                new Notification.Builder(mContext, NotificationChannels.GENERAL)
+                        .setSmallIcon(R.drawable.ic_volume_ringer)
+                        .setContentTitle(message)
+                        .setStyle(new Notification.BigTextStyle().bigText(message));
+        mContext.getSystemService(NotificationManager.class).notifyAsUser(
+                "active_unlock",
+                0,
+                nb.build(),
+                UserHandle.ALL);
+    }
+
+    private boolean shouldTriggerActiveUnlock() {
+        // TODO: check if active unlock is ENABLED / AVAILABLE
+
+        // Triggers:
+        final boolean triggerActiveUnlockForAssistant = shouldTriggerActiveUnlockForAssistant();
+        final boolean awakeKeyguard = mKeyguardIsVisible && mDeviceInteractive && !mGoingToSleep
+                && mStatusBarState != StatusBarState.SHADE_LOCKED;
+
+        // Gates:
+        final int user = getCurrentUser();
+
+        // No need to trigger active unlock if we're already unlocked or don't have
+        // pin/pattern/password setup
+        final boolean userCanDismissLockScreen = getUserCanSkipBouncer(user)
+                || !mLockPatternUtils.isSecure(user);
+
+        // Don't trigger active unlock if fp is locked out TODO: confirm this one
+        final boolean fpLockedout = mFingerprintLockedOut || mFingerprintLockedOutPermanent;
+
+        // Don't trigger active unlock if primary auth is required
+        final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(user);
+        final boolean isLockDown =
+                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
+                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+        final boolean isEncryptedOrTimedOut =
+                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT)
+                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT);
+
+        final boolean shouldTriggerActiveUnlock =
+                (mAuthInterruptActive || triggerActiveUnlockForAssistant || awakeKeyguard)
+                        && !mSwitchingUser
+                        && !userCanDismissLockScreen
+                        && !fpLockedout
+                        && !isLockDown
+                        && !isEncryptedOrTimedOut
+                        && !mKeyguardGoingAway
+                        && !mSecureCameraLaunched;
+
+        // Aggregate relevant fields for debug logging.
+        if (DEBUG_ACTIVE_UNLOCK || DEBUG_SPEW) {
+            maybeLogListenerModelData(
+                    new KeyguardActiveUnlockModel(
+                            System.currentTimeMillis(),
+                            user,
+                            shouldTriggerActiveUnlock,
+                            mAuthInterruptActive,
+                            isEncryptedOrTimedOut,
+                            fpLockedout,
+                            isLockDown,
+                            mSwitchingUser,
+                            triggerActiveUnlockForAssistant,
+                            userCanDismissLockScreen));
+        }
+
+        return shouldTriggerActiveUnlock;
+    }
+
     private boolean shouldListenForFingerprintAssistant() {
         BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(getCurrentUser());
         return mAssistantVisible && mKeyguardOccluded
@@ -2242,6 +2349,11 @@
                 && !mUserHasTrust.get(getCurrentUser(), false);
     }
 
+    private boolean shouldTriggerActiveUnlockForAssistant() {
+        return mAssistantVisible && mKeyguardOccluded
+                && !mUserHasTrust.get(getCurrentUser(), false);
+    }
+
     @VisibleForTesting
     protected boolean shouldListenForFingerprint(boolean isUdfps) {
         final int user = getCurrentUser();
@@ -2406,6 +2518,13 @@
             Log.v(TAG, model.toString());
         }
 
+        if (DEBUG_ACTIVE_UNLOCK
+                && model instanceof KeyguardActiveUnlockModel
+                && model.getListening()) {
+            mListenModels.add(model);
+            return;
+        }
+
         // Add model data to the historical buffer.
         final boolean notYetRunning =
                 (DEBUG_FACE
@@ -2514,6 +2633,10 @@
         return mFingerprintLockedOut || mFingerprintLockedOutPermanent;
     }
 
+    public boolean isFaceLockedOut() {
+        return mFaceLockedOutPermanent;
+    }
+
     /**
      * If biometrics hardware is available, not disabled, and user has enrolled templates.
      * This does NOT check if the device is encrypted or in lockdown.
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 33538ec..a100cb8 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -342,7 +342,7 @@
             mDisplayManager.getDisplay(DEFAULT_DISPLAY).getMetrics(metrics);
             mDensity = metrics.density;
 
-            mExecutor.execute(() -> mTunerService.addTunable(this, SIZE));
+            mMainExecutor.execute(() -> mTunerService.addTunable(this, SIZE));
 
             // Watch color inversion and invert the overlay as needed.
             if (mColorInversionSetting == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
index 977e46a..d2ded71 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
@@ -131,6 +131,12 @@
             wrapper = null
             bindService(false)
         }
+
+        override fun onNullBinding(name: ComponentName?) {
+            if (DEBUG) Log.d(TAG, "onNullBinding $name")
+            wrapper = null
+            context.unbindService(this)
+        }
     }
 
     private fun handlePendingServiceMethods() {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index cffb2f7..b235692 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -28,6 +28,8 @@
 import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender;
 import com.android.systemui.people.PeopleProvider;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.unfold.FoldStateLogger;
+import com.android.systemui.unfold.FoldStateLoggingProvider;
 import com.android.systemui.unfold.SysUIUnfoldComponent;
 import com.android.systemui.unfold.UnfoldLatencyTracker;
 import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider;
@@ -139,6 +141,8 @@
         getMediaTttChipControllerReceiver();
         getMediaTttCommandLineHelper();
         getUnfoldLatencyTracker().init();
+        getFoldStateLoggingProvider().ifPresent(FoldStateLoggingProvider::init);
+        getFoldStateLogger().ifPresent(FoldStateLogger::init);
     }
 
     /**
@@ -166,6 +170,18 @@
     UnfoldLatencyTracker getUnfoldLatencyTracker();
 
     /**
+     * Creates a FoldStateLoggingProvider.
+     */
+    @SysUISingleton
+    Optional<FoldStateLoggingProvider> getFoldStateLoggingProvider();
+
+    /**
+     * Creates a FoldStateLogger.
+     */
+    @SysUISingleton
+    Optional<FoldStateLogger> getFoldStateLogger();
+
+    /**
      * Main dependency providing module.
      */
     @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 9dddbb1..c0da57f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.dagger;
 
+import com.android.keyguard.KeyguardBiometricLockoutLogger;
 import com.android.systemui.CoreStartable;
 import com.android.systemui.LatencyTester;
 import com.android.systemui.ScreenDecorations;
@@ -90,6 +91,13 @@
     @ClassKey(KeyguardViewMediator.class)
     public abstract CoreStartable bindKeyguardViewMediator(KeyguardViewMediator sysui);
 
+    /** Inject into KeyguardBiometricLockoutLogger. */
+    @Binds
+    @IntoMap
+    @ClassKey(KeyguardBiometricLockoutLogger.class)
+    public abstract CoreStartable bindKeyguardBiometricLockoutLogger(
+            KeyguardBiometricLockoutLogger sysui);
+
     /** Inject into LatencyTests. */
     @Binds
     @IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 4be819a..5d6c2a2 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -74,6 +74,9 @@
     public static final ResourceBooleanFlag BOUNCER_USER_SWITCHER =
             new ResourceBooleanFlag(204, R.bool.config_enableBouncerUserSwitcher);
 
+    public static final ResourceBooleanFlag ACTIVE_UNLOCK =
+            new ResourceBooleanFlag(205, R.bool.flag_active_unlock);
+
     /***************************************/
     // 300 - power menu
     public static final BooleanFlag POWER_MENU_LITE =
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 5fbdd88..ac816ba 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.navigationbar;
 
+import static android.inputmethodservice.InputMethodService.canImeRenderGesturalNavButtons;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
 
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
@@ -185,6 +186,17 @@
     @Nullable
     private Rect mOrientedHandleSamplingRegion;
 
+    /**
+     * {@code true} if the IME can render the back button and the IME switcher button.
+     *
+     * <p>The value must be used when and only when
+     * {@link com.android.systemui.shared.system.QuickStepContract#isGesturalMode(int)} returns
+     * {@code true}</p>
+     *
+     * <p>Cache the value here for better performance.</p>
+     */
+    private final boolean mImeCanRenderGesturalNavButtons = canImeRenderGesturalNavButtons();
+
     private class NavTransitionListener implements TransitionListener {
         private boolean mBackTransitioning;
         private boolean mHomeAppearing;
@@ -760,9 +772,14 @@
 
         updateRecentsIcon();
 
+        boolean isImeRenderingNavButtons = isGesturalMode(mNavBarMode)
+                && mImeCanRenderGesturalNavButtons;
+
         // Update IME button visibility, a11y and rotate button always overrides the appearance
-        mContextualButtonGroup.setButtonVisibility(R.id.ime_switcher,
-                (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
+        boolean disableImeSwitcher =
+                (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0
+                || isImeRenderingNavButtons;
+        mContextualButtonGroup.setButtonVisibility(R.id.ime_switcher, !disableImeSwitcher);
 
         mBarTransitions.reapplyDarkIntensity();
 
@@ -777,7 +794,8 @@
                 && ((mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
 
         boolean disableBack = !useAltBack && (mEdgeBackGestureHandler.isHandlingGestures()
-                || ((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0));
+                || ((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0))
+                || isImeRenderingNavButtons;
 
         // When screen pinning, don't hide back and home when connected service or back and
         // recents buttons when disconnected from launcher service in screen pinning mode,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index bfa4a24..dee1b33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -11,7 +11,7 @@
  * 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
+ * limitations under the License.
  */
 
 package com.android.systemui.statusbar.phone;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
index ec2d036..571c10b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
@@ -54,6 +54,7 @@
             isListening = false
             updateListeningState()
             keyguardUpdateMonitor.requestFaceAuth(true)
+            keyguardUpdateMonitor.requestActiveUnlock()
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt
index 4de78f5..868efa0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt
@@ -34,7 +34,7 @@
     private val displayMetrics: DisplayMetrics
 ) {
     fun logUnSuccessfulDragDown(startingChild: View?) {
-        val entry = (startingChild as ExpandableNotificationRow?)?.entry
+        val entry = (startingChild as? ExpandableNotificationRow)?.entry
         buffer.log(TAG, LogLevel.INFO, {
             str1 = entry?.key ?: "no entry"
         }, {
@@ -49,7 +49,7 @@
     }
 
     fun logDragDownStarted(startingChild: ExpandableView?) {
-        val entry = (startingChild as ExpandableNotificationRow?)?.entry
+        val entry = (startingChild as? ExpandableNotificationRow)?.entry
         buffer.log(TAG, LogLevel.INFO, {
             str1 = entry?.key ?: "no entry"
         }, {
@@ -58,7 +58,7 @@
     }
 
     fun logDraggedDownLockDownShade(startingChild: View?) {
-        val entry = (startingChild as ExpandableNotificationRow?)?.entry
+        val entry = (startingChild as? ExpandableNotificationRow)?.entry
         buffer.log(TAG, LogLevel.INFO, {
             str1 = entry?.key ?: "no entry"
         }, {
@@ -67,7 +67,7 @@
     }
 
     fun logDraggedDown(startingChild: View?, dragLengthY: Int) {
-        val entry = (startingChild as ExpandableNotificationRow?)?.entry
+        val entry = (startingChild as? ExpandableNotificationRow)?.entry
         buffer.log(TAG, LogLevel.INFO, {
             str1 = entry?.key ?: "no entry"
         }, {
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldStateLogger.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldStateLogger.kt
new file mode 100644
index 0000000..1451c03
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldStateLogger.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.unfold
+
+import com.android.internal.util.FrameworkStatsLog
+
+/** Logs fold state changes. */
+class FoldStateLogger(private val foldStateLoggingProvider: FoldStateLoggingProvider) :
+    FoldStateLoggingProvider.FoldStateLoggingListener {
+
+    fun init() {
+        foldStateLoggingProvider.addCallback(this)
+    }
+
+    override fun onFoldUpdate(foldStateUpdate: FoldStateChange) {
+        FrameworkStatsLog.write(
+            FrameworkStatsLog.FOLD_STATE_DURATION_REPORTED,
+            foldStateUpdate.previous,
+            foldStateUpdate.current,
+            foldStateUpdate.dtMillis)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
index f2c1561..c2fd34c 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
@@ -102,6 +102,15 @@
 
     @Provides
     @Singleton
+    fun providesFoldStateLogger(
+        optionalFoldStateLoggingProvider: Optional<FoldStateLoggingProvider>
+    ): Optional<FoldStateLogger> =
+        optionalFoldStateLoggingProvider.map { FoldStateLoggingProvider ->
+            FoldStateLogger(FoldStateLoggingProvider)
+        }
+
+    @Provides
+    @Singleton
     fun provideUnfoldTransitionConfig(context: Context): UnfoldTransitionConfig =
         createConfig(context)
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardBiometricLockoutLoggerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardBiometricLockoutLoggerTest.kt
new file mode 100644
index 0000000..6bc6505
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardBiometricLockoutLoggerTest.kt
@@ -0,0 +1,194 @@
+/*
+ * 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.keyguard
+
+import android.hardware.biometrics.BiometricSourceType
+import org.mockito.Mockito.verify
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.UiEventLogger
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class KeyguardBiometricLockoutLoggerTest : SysuiTestCase() {
+    @Mock
+    lateinit var uiEventLogger: UiEventLogger
+    @Mock
+    lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+    @Mock
+    lateinit var dumpManager: DumpManager
+    @Mock
+    lateinit var strongAuthTracker: KeyguardUpdateMonitor.StrongAuthTracker
+
+    @Captor
+    lateinit var updateMonitorCallbackCaptor: ArgumentCaptor<KeyguardUpdateMonitorCallback>
+    lateinit var updateMonitorCallback: KeyguardUpdateMonitorCallback
+
+    lateinit var keyguardBiometricLockoutLogger: KeyguardBiometricLockoutLogger
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        whenever(keyguardUpdateMonitor.strongAuthTracker).thenReturn(strongAuthTracker)
+        keyguardBiometricLockoutLogger = KeyguardBiometricLockoutLogger(
+                mContext,
+                uiEventLogger,
+                keyguardUpdateMonitor,
+                dumpManager)
+    }
+
+    @Test
+    fun test_logsOnStart() {
+        // GIVEN is encrypted / lockdown before start
+        whenever(keyguardUpdateMonitor.isEncryptedOrLockdown(anyInt()))
+                .thenReturn(true)
+
+        // WHEN start
+        keyguardBiometricLockoutLogger.start()
+
+        // THEN encrypted / lockdown state is logged
+        verify(uiEventLogger).log(KeyguardBiometricLockoutLogger.PrimaryAuthRequiredEvent
+                .PRIMARY_AUTH_REQUIRED_ENCRYPTED_OR_LOCKDOWN)
+    }
+
+    @Test
+    fun test_logTimeoutChange() {
+        keyguardBiometricLockoutLogger.start()
+        captureUpdateMonitorCallback()
+
+        // GIVEN primary auth required b/c timeout
+        whenever(strongAuthTracker.getStrongAuthForUser(anyInt()))
+                .thenReturn(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT)
+
+        // WHEN primary auth requirement changes
+        updateMonitorCallback.onStrongAuthStateChanged(0)
+
+        // THEN primary auth required state is logged
+        verify(uiEventLogger).log(KeyguardBiometricLockoutLogger.PrimaryAuthRequiredEvent
+                .PRIMARY_AUTH_REQUIRED_TIMEOUT)
+    }
+
+    @Test
+    fun test_logUnattendedUpdate() {
+        keyguardBiometricLockoutLogger.start()
+        captureUpdateMonitorCallback()
+
+        // GIVEN primary auth required b/c unattended update
+        whenever(strongAuthTracker.getStrongAuthForUser(anyInt()))
+                .thenReturn(STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE)
+
+        // WHEN primary auth requirement changes
+        updateMonitorCallback.onStrongAuthStateChanged(0)
+
+        // THEN primary auth required state is logged
+        verify(uiEventLogger).log(KeyguardBiometricLockoutLogger.PrimaryAuthRequiredEvent
+                .PRIMARY_AUTH_REQUIRED_UNATTENDED_UPDATE)
+    }
+
+    @Test
+    fun test_logMultipleChanges() {
+        keyguardBiometricLockoutLogger.start()
+        captureUpdateMonitorCallback()
+
+        // GIVEN primary auth required b/c timeout
+        whenever(strongAuthTracker.getStrongAuthForUser(anyInt()))
+                .thenReturn(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT
+                        or STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE)
+
+        // WHEN primary auth requirement changes
+        updateMonitorCallback.onStrongAuthStateChanged(0)
+
+        // THEN primary auth required state is logged with all the reasons
+        verify(uiEventLogger).log(KeyguardBiometricLockoutLogger.PrimaryAuthRequiredEvent
+                .PRIMARY_AUTH_REQUIRED_TIMEOUT)
+        verify(uiEventLogger).log(KeyguardBiometricLockoutLogger.PrimaryAuthRequiredEvent
+                .PRIMARY_AUTH_REQUIRED_UNATTENDED_UPDATE)
+
+        // WHEN onStrongAuthStateChanged is called again
+        updateMonitorCallback.onStrongAuthStateChanged(0)
+
+        // THEN no more events are sent since there haven't been any changes
+        verifyNoMoreInteractions(uiEventLogger)
+    }
+
+    @Test
+    fun test_logFaceLockout() {
+        keyguardBiometricLockoutLogger.start()
+        captureUpdateMonitorCallback()
+
+        // GIVEN primary auth required b/c face lock
+        whenever(keyguardUpdateMonitor.isFaceLockedOut).thenReturn(true)
+
+        // WHEN lockout state changes
+        updateMonitorCallback.onLockedOutStateChanged(BiometricSourceType.FACE)
+
+        // THEN primary auth required state is logged
+        verify(uiEventLogger).log(KeyguardBiometricLockoutLogger.PrimaryAuthRequiredEvent
+                .PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT)
+
+        // WHEN face lockout is reset
+        whenever(keyguardUpdateMonitor.isFaceLockedOut).thenReturn(false)
+        updateMonitorCallback.onLockedOutStateChanged(BiometricSourceType.FACE)
+
+        // THEN primary auth required state is logged
+        verify(uiEventLogger).log(KeyguardBiometricLockoutLogger.PrimaryAuthRequiredEvent
+                .PRIMARY_AUTH_REQUIRED_FACE_LOCKED_OUT_RESET)
+    }
+
+    @Test
+    fun test_logFingerprintLockout() {
+        keyguardBiometricLockoutLogger.start()
+        captureUpdateMonitorCallback()
+
+        // GIVEN primary auth required b/c fingerprint lock
+        whenever(keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(true)
+
+        // WHEN lockout state changes
+        updateMonitorCallback.onLockedOutStateChanged(BiometricSourceType.FINGERPRINT)
+
+        // THEN primary auth required state is logged
+        verify(uiEventLogger).log(KeyguardBiometricLockoutLogger.PrimaryAuthRequiredEvent
+                .PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT)
+
+        // WHEN fingerprint lockout is reset
+        whenever(keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(false)
+        updateMonitorCallback.onLockedOutStateChanged(BiometricSourceType.FINGERPRINT)
+
+        // THEN primary auth required state is logged
+        verify(uiEventLogger).log(KeyguardBiometricLockoutLogger.PrimaryAuthRequiredEvent
+                .PRIMARY_AUTH_REQUIRED_FINGERPRINT_LOCKED_OUT_RESET)
+    }
+
+    fun captureUpdateMonitorCallback() {
+        verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallbackCaptor.capture())
+        updateMonitorCallback = updateMonitorCallbackCaptor.value
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 70792cf..7266e41 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -88,6 +88,7 @@
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -173,6 +174,8 @@
     private InteractionJankMonitor mInteractionJankMonitor;
     @Mock
     private LatencyTracker mLatencyTracker;
+    @Mock
+    private FeatureFlags mFeatureFlags;
     @Captor
     private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
     // Direct executor
@@ -1105,7 +1108,7 @@
                     mRingerModeTracker, mBackgroundExecutor, mMainExecutor,
                     mStatusBarStateController, mLockPatternUtils,
                     mAuthController, mTelephonyListenerManager,
-                    mInteractionJankMonitor, mLatencyTracker);
+                    mInteractionJankMonitor, mLatencyTracker, mFeatureFlags);
             setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker);
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
index 2d3757c..12096bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
@@ -17,6 +17,9 @@
 package com.android.systemui.controls.controller
 
 import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
 import android.os.UserHandle
 import android.service.controls.IControlsActionCallback
 import android.service.controls.IControlsProvider
@@ -43,6 +46,8 @@
 import org.mockito.Captor
 import org.mockito.Mock
 import org.mockito.Mockito.`when`
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
@@ -57,8 +62,6 @@
     private lateinit var subscriberService: IControlsSubscriber.Stub
     @Mock
     private lateinit var service: IControlsProvider.Stub
-    @Mock
-    private lateinit var loadCallback: ControlsBindingController.LoadCallback
 
     @Captor
     private lateinit var wrapperCaptor: ArgumentCaptor<ControlActionWrapper>
@@ -75,7 +78,7 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
-        mContext.addMockService(componentName, service)
+        context.addMockService(componentName, service)
         executor = FakeExecutor(FakeSystemClock())
         `when`(service.asBinder()).thenCallRealMethod()
         `when`(service.queryLocalInterface(ArgumentMatchers.anyString())).thenReturn(service)
@@ -98,7 +101,36 @@
     fun testBindService() {
         manager.bindService()
         executor.runAllReady()
-        assertTrue(mContext.isBound(componentName))
+        assertTrue(context.isBound(componentName))
+    }
+
+    @Test
+    fun testNullBinding() {
+        val mockContext = mock(Context::class.java)
+        lateinit var serviceConnection: ServiceConnection
+        `when`(mockContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer {
+            val component = (it.arguments[0] as Intent).component
+            if (component == componentName) {
+                serviceConnection = it.arguments[1] as ServiceConnection
+                serviceConnection.onNullBinding(component)
+                true
+            } else {
+                false
+            }
+        }
+
+        val nullManager = ControlsProviderLifecycleManager(
+                mockContext,
+                executor,
+                actionCallbackService,
+                UserHandle.of(0),
+                componentName
+        )
+
+        nullManager.bindService()
+        executor.runAllReady()
+
+        verify(mockContext).unbindService(serviceConnection)
     }
 
     @Test
@@ -109,7 +141,7 @@
         manager.unbindService()
         executor.runAllReady()
 
-        assertFalse(mContext.isBound(componentName))
+        assertFalse(context.isBound(componentName))
     }
 
     @Test
@@ -119,7 +151,7 @@
 
         verify(service).load(subscriberService)
 
-        assertTrue(mContext.isBound(componentName))
+        assertTrue(context.isBound(componentName))
     }
 
     @Test
@@ -129,7 +161,7 @@
 
         manager.unbindService()
         executor.runAllReady()
-        assertFalse(mContext.isBound(componentName))
+        assertFalse(context.isBound(componentName))
     }
 
     @Test
@@ -162,7 +194,7 @@
         manager.maybeBindAndSubscribe(list, subscriberService)
         executor.runAllReady()
 
-        assertTrue(mContext.isBound(componentName))
+        assertTrue(context.isBound(componentName))
         verify(service).subscribe(list, subscriberService)
     }
 
@@ -173,7 +205,7 @@
         manager.maybeBindAndSendAction(controlId, action)
         executor.runAllReady()
 
-        assertTrue(mContext.isBound(componentName))
+        assertTrue(context.isBound(componentName))
         verify(service).action(eq(controlId), capture(wrapperCaptor),
                 eq(actionCallbackService))
         assertEquals(action, wrapperCaptor.getValue().getWrappedAction())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt
new file mode 100644
index 0000000..8bc438b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt
@@ -0,0 +1,102 @@
+/*
+ * 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.shared.navigationbar
+import android.graphics.Rect
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.SurfaceControl
+import android.view.View
+import android.view.ViewRootImpl
+import androidx.concurrent.futures.DirectExecutor
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.*
+import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.`when` as whenever
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+@RunWithLooper
+class RegionSamplingHelperTest : SysuiTestCase() {
+
+    @Mock
+    lateinit var sampledView: View
+    @Mock
+    lateinit var samplingCallback: RegionSamplingHelper.SamplingCallback
+    @Mock
+    lateinit var compositionListener: RegionSamplingHelper.SysuiCompositionSamplingListener
+    @Mock
+    lateinit var viewRootImpl: ViewRootImpl
+    @Mock
+    lateinit var surfaceControl: SurfaceControl
+    @Mock
+    lateinit var wrappedSurfaceControl: SurfaceControl
+    @JvmField @Rule
+    var rule = MockitoJUnit.rule()
+    lateinit var regionSamplingHelper: RegionSamplingHelper
+
+    @Before
+    fun setup() {
+        whenever(sampledView.isAttachedToWindow).thenReturn(true)
+        whenever(sampledView.viewRootImpl).thenReturn(viewRootImpl)
+        whenever(viewRootImpl.surfaceControl).thenReturn(surfaceControl)
+        whenever(surfaceControl.isValid).thenReturn(true)
+        whenever(wrappedSurfaceControl.isValid).thenReturn(true)
+        whenever(samplingCallback.isSamplingEnabled).thenReturn(true)
+        regionSamplingHelper = object : RegionSamplingHelper(sampledView, samplingCallback,
+                DirectExecutor.INSTANCE, DirectExecutor.INSTANCE, compositionListener) {
+            override fun wrap(stopLayerControl: SurfaceControl?): SurfaceControl {
+                return wrappedSurfaceControl
+            }
+        }
+        regionSamplingHelper.setWindowVisible(true)
+    }
+
+    @Test
+    fun testStart_register() {
+        regionSamplingHelper.start(Rect(0, 0, 100, 100))
+        verify(compositionListener).register(any(), anyInt(), eq(wrappedSurfaceControl), any())
+    }
+
+    @Test
+    fun testStart_unregister() {
+        regionSamplingHelper.start(Rect(0, 0, 100, 100))
+        regionSamplingHelper.setWindowVisible(false)
+        verify(compositionListener).unregister(any())
+    }
+
+    @Test
+    fun testStart_hasBlur_neverRegisters() {
+        regionSamplingHelper.setWindowHasBlurs(true)
+        regionSamplingHelper.start(Rect(0, 0, 100, 100))
+        verify(compositionListener, never())
+                .register(any(), anyInt(), eq(wrappedSurfaceControl), any())
+    }
+
+    @Test
+    fun testStart_stopAndDestroy() {
+        regionSamplingHelper.start(Rect(0, 0, 100, 100))
+        regionSamplingHelper.stopAndDestroy()
+        verify(compositionListener).unregister(any())
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
new file mode 100644
index 0000000..6971c63
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
@@ -0,0 +1,44 @@
+package com.android.systemui.statusbar
+
+import android.testing.AndroidTestingRunner
+import android.util.DisplayMetrics
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger
+import com.android.systemui.util.mockito.mock
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class LSShadeTransitionLoggerTest : SysuiTestCase() {
+    lateinit var logger: LSShadeTransitionLogger
+    @Mock
+    lateinit var gestureLogger: LockscreenGestureLogger
+    @Mock
+    lateinit var displayMetrics: DisplayMetrics
+    @JvmField @Rule
+    val mockito = MockitoJUnit.rule()
+
+    @Before
+    fun setup() {
+        logger = LSShadeTransitionLogger(
+                LogBuffer("Test", 10, 10, mock()),
+                gestureLogger,
+                displayMetrics)
+    }
+
+    @Test
+    fun testLogDragDownStarted() {
+        val view: ExpandableView = mock()
+        // log a non-null, non row, ensure no crash
+        logger.logDragDownStarted(view)
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 704d739..70bd734 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13378,7 +13378,12 @@
                                         !intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false);
                                 final boolean fullUninstall = removed && !replacing;
                                 if (removed) {
-                                    if (!killProcess) {
+                                    if (killProcess) {
+                                        forceStopPackageLocked(ssp, UserHandle.getAppId(
+                                                intent.getIntExtra(Intent.EXTRA_UID, -1)),
+                                                false, true, true, false, fullUninstall, userId,
+                                                removed ? "pkg removed" : "pkg changed");
+                                    } else {
                                         // Kill any app zygotes always, since they can't fork new
                                         // processes with references to the old code
                                         forceStopAppZygoteLocked(ssp, UserHandle.getAppId(
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 9b731d5..b3e46cd 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -174,6 +174,9 @@
     boolean mFgsNotificationWasDeferred;
     // FGS notification was shown before the FGS finishes, or it wasn't deferred in the first place.
     boolean mFgsNotificationShown;
+    // Whether FGS package has permissions to show notifications.
+    // TODO(b/194833441): Output this field to logs in ActiveServices#logFGSStateChangeLocked.
+    boolean mFgsHasNotificationPermission;
 
     // allow the service becomes foreground service? Service started from background may not be
     // allowed to become a foreground service.
@@ -968,6 +971,9 @@
                     if (nm == null) {
                         return;
                     }
+                    // Record whether the package has permission to notify the user
+                    mFgsHasNotificationPermission = nm.areNotificationsEnabledForPackage(
+                            localPackageName, appUid);
                     Notification localForegroundNoti = _foregroundNoti;
                     try {
                         if (localForegroundNoti.getSmallIcon() == null) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 69765d2..805e45d 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -8541,7 +8541,7 @@
 
     /** @see Spatializer#getSpatializerCompatibleAudioDevices() */
     public @NonNull List<AudioDeviceAttributes> getSpatializerCompatibleAudioDevices() {
-        enforceModifyAudioRoutingPermission();
+        enforceModifyDefaultAudioEffectsPermission();
         return mSpatializerHelper.getCompatibleAudioDevices();
     }
 
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 9273a5d..6ec9836 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -102,8 +102,6 @@
     /*package*/  static final int SCO_MODE_UNDEFINED = -1;
     // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
     /*package*/  static final int SCO_MODE_VIRTUAL_CALL = 0;
-    // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
-    private  static final int SCO_MODE_RAW = 1;
     // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
     private  static final int SCO_MODE_VR = 2;
     // max valid SCO audio mode values
@@ -122,8 +120,6 @@
                 return "SCO_MODE_UNDEFINED";
             case SCO_MODE_VIRTUAL_CALL:
                 return "SCO_MODE_VIRTUAL_CALL";
-            case SCO_MODE_RAW:
-                return "SCO_MODE_RAW";
             case SCO_MODE_VR:
                 return "SCO_MODE_VR";
             default:
@@ -812,8 +808,6 @@
     private static boolean disconnectBluetoothScoAudioHelper(BluetoothHeadset bluetoothHeadset,
             BluetoothDevice device, int scoAudioMode) {
         switch (scoAudioMode) {
-            case SCO_MODE_RAW:
-                return bluetoothHeadset.disconnectAudio();
             case SCO_MODE_VIRTUAL_CALL:
                 return bluetoothHeadset.stopScoUsingVirtualVoiceCall();
             case SCO_MODE_VR:
@@ -826,8 +820,6 @@
     private static boolean connectBluetoothScoAudioHelper(BluetoothHeadset bluetoothHeadset,
             BluetoothDevice device, int scoAudioMode) {
         switch (scoAudioMode) {
-            case SCO_MODE_RAW:
-                return bluetoothHeadset.connectAudio();
             case SCO_MODE_VIRTUAL_CALL:
                 return bluetoothHeadset.startScoUsingVirtualVoiceCall();
             case SCO_MODE_VR:
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 6a716cb..066c263 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1223,8 +1223,11 @@
             for (RouteInfo route : mConfig.routes) {
                 lp.addRoute(route);
                 InetAddress address = route.getDestination().getAddress();
-                allowIPv4 |= address instanceof Inet4Address;
-                allowIPv6 |= address instanceof Inet6Address;
+
+                if (route.getType() == RouteInfo.RTN_UNICAST) {
+                    allowIPv4 |= address instanceof Inet4Address;
+                    allowIPv6 |= address instanceof Inet6Address;
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/media/OWNERS b/services/core/java/com/android/server/media/OWNERS
index 2e2d812..8097f4e 100644
--- a/services/core/java/com/android/server/media/OWNERS
+++ b/services/core/java/com/android/server/media/OWNERS
@@ -1,8 +1,6 @@
+# Bug component: 137631
 elaurent@google.com
-hdmoon@google.com
-insun@google.com
-jaewan@google.com
-jinpark@google.com
-klhyun@google.com
 lajos@google.com
-sungsoo@google.com
+
+# go/android-fwk-media-solutions for info on areas of ownership.
+include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index 5455738..c548e7e 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -39,4 +39,7 @@
 
     /** Get the number of notification channels for a given package */
     int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
+
+    /** Does the specified package/uid have permission to post notifications? */
+    boolean areNotificationsEnabledForPackage(String pkg, int uid);
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index a0eeb65..399ae53 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -6205,6 +6205,11 @@
             return NotificationManagerService.this
                     .getNumNotificationChannelsForPackage(pkg, uid, includeDeleted);
         }
+
+        @Override
+        public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
+            return areNotificationsEnabledForPackageInt(pkg, uid);
+        }
     };
 
     int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted) {
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 258ae8c..0246c0c 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -848,6 +848,9 @@
             if (r == null) {
                 throw new IllegalArgumentException("Invalid package");
             }
+            if (fromTargetApp) {
+                group.setBlocked(false);
+            }
             final NotificationChannelGroup oldGroup = r.groups.get(group.getId());
             if (oldGroup != null) {
                 group.setChannels(oldGroup.getChannels());
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 0556748..c285e27 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -799,7 +799,7 @@
                 throw new RuntimeException(re);
             } catch (Exception e) {
                 throw new PackageManagerException(
-                        PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                        PackageInstaller.SessionInfo.SESSION_VERIFICATION_FAILED,
                         "apexd verification failed : " + e.getMessage());
             }
         }
@@ -826,7 +826,7 @@
                 throw new RuntimeException(re);
             } catch (Exception e) {
                 throw new PackageManagerException(
-                        PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                        PackageInstaller.SessionInfo.SESSION_VERIFICATION_FAILED,
                         "Failed to mark apexd session as ready : " + e.getMessage());
             }
         }
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 05a51cc..31df0a5 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -896,10 +896,10 @@
         synchronized (mLock) {
             if (!mFinishedPostBootUpdate) {
                 mFinishedPostBootUpdate = true;
-                JobScheduler js = mInjector.getJobScheduler();
-                js.cancel(JOB_POST_BOOT_UPDATE);
             }
         }
+        // Safe to do this outside lock.
+        mInjector.getJobScheduler().cancel(JOB_POST_BOOT_UPDATE);
     }
 
     private void notifyPinService(ArraySet<String> updatedPackages) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 416b3a4..8ebd254 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -331,7 +331,7 @@
                 StagingManager.StagedSession stagedSession = session.mStagedSession;
                 if (!stagedSession.isInTerminalState() && stagedSession.hasParentSessionId()
                         && getSession(stagedSession.getParentSessionId()) == null) {
-                    stagedSession.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+                    stagedSession.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED,
                             "An orphan staged session " + stagedSession.sessionId() + " is found, "
                                 + "parent " + stagedSession.getParentSessionId() + " is missing");
                     continue;
@@ -843,7 +843,7 @@
                 mSilentUpdatePolicy, mInstallThread.getLooper(), mStagingManager, sessionId,
                 userId, callingUid, installSource, params, createdMillis, 0L, stageDir, stageCid,
                 null, null, false, false, false, false, null, SessionInfo.INVALID_ID,
-                false, false, false, SessionInfo.STAGED_SESSION_NO_ERROR, "");
+                false, false, false, SessionInfo.SESSION_NO_ERROR, "");
 
         synchronized (mSessions) {
             mSessions.put(sessionId, session);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index f45e54b..304ad72 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -460,7 +460,7 @@
     @GuardedBy("mLock")
     private boolean mSessionFailed;
     @GuardedBy("mLock")
-    private int mSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
+    private int mSessionErrorCode = SessionInfo.SESSION_NO_ERROR;
     @GuardedBy("mLock")
     private String mSessionErrorMessage;
 
@@ -2092,7 +2092,7 @@
         if (isStaged()) {
             // This will clean up the session when it reaches the terminal state
             mStagedSession.setSessionFailed(
-                    SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, msgWithErrorCode);
+                    SessionInfo.SESSION_VERIFICATION_FAILED, msgWithErrorCode);
             mStagedSession.notifyEndPreRebootVerification();
         } else {
             // Session is sealed and committed but could not be verified, we need to destroy it.
@@ -2547,7 +2547,7 @@
         if (isStaged()) {
             mSessionProvider.getSessionVerifier().verifyStaged(mStagedSession, (error, msg) -> {
                 mStagedSession.notifyEndPreRebootVerification();
-                if (error == SessionInfo.STAGED_SESSION_NO_ERROR) {
+                if (error == SessionInfo.SESSION_NO_ERROR) {
                     mStagingManager.commitSession(mStagedSession);
                 }
             });
@@ -4168,7 +4168,7 @@
             mSessionReady = true;
             mSessionApplied = false;
             mSessionFailed = false;
-            mSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
+            mSessionErrorCode = SessionInfo.SESSION_NO_ERROR;
             mSessionErrorMessage = "";
         }
         mCallback.onSessionChanged(this);
@@ -4196,7 +4196,7 @@
             mSessionReady = false;
             mSessionApplied = true;
             mSessionFailed = false;
-            mSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
+            mSessionErrorCode = SessionInfo.SESSION_NO_ERROR;
             mSessionErrorMessage = "";
             Slog.d(TAG, "Marking session " + sessionId + " as applied");
         }
@@ -4705,7 +4705,7 @@
         final boolean isFailed = in.getAttributeBoolean(null, ATTR_IS_FAILED, false);
         final boolean isApplied = in.getAttributeBoolean(null, ATTR_IS_APPLIED, false);
         final int sessionErrorCode = in.getAttributeInt(null, ATTR_SESSION_ERROR_CODE,
-                SessionInfo.STAGED_SESSION_NO_ERROR);
+                SessionInfo.SESSION_NO_ERROR);
         final String sessionErrorMessage = readStringAttribute(in, ATTR_SESSION_ERROR_MESSAGE);
 
         if (!isStagedSessionStateValid(isReady, isApplied, isFailed)) {
diff --git a/services/core/java/com/android/server/pm/PackageSessionVerifier.java b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
index a532fe3..ccabce7 100644
--- a/services/core/java/com/android/server/pm/PackageSessionVerifier.java
+++ b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
@@ -202,7 +202,7 @@
     }
 
     private void onVerificationSuccess(StagingManager.StagedSession session, Callback callback) {
-        callback.onResult(SessionInfo.STAGED_SESSION_NO_ERROR, null);
+        callback.onResult(SessionInfo.SESSION_NO_ERROR, null);
     }
 
     private void onVerificationFailure(StagingManager.StagedSession session, Callback callback,
@@ -298,7 +298,7 @@
             // Failed to get hold of StorageManager
             Slog.e(TAG, "Failed to get hold of StorageManager", e);
             throw new PackageManagerException(
-                    SessionInfo.STAGED_SESSION_UNKNOWN,
+                    SessionInfo.SESSION_UNKNOWN_ERROR,
                     "Failed to get hold of StorageManager");
         }
         // Proactively mark session as ready before calling apexd. Although this call order
@@ -336,7 +336,7 @@
         final ParseResult<SigningDetails> newResult = ApkSignatureVerifier.verify(
                 input.reset(), apexPath, minSignatureScheme);
         if (newResult.isError()) {
-            throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+            throw new PackageManagerException(SessionInfo.SESSION_VERIFICATION_FAILED,
                     "Failed to parse APEX package " + apexPath + " : "
                             + newResult.getException(), newResult.getException());
         }
@@ -355,7 +355,7 @@
                 input.reset(), existingApexPkg.applicationInfo.sourceDir,
                 SigningDetails.SignatureSchemeVersion.JAR);
         if (existingResult.isError()) {
-            throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+            throw new PackageManagerException(SessionInfo.SESSION_VERIFICATION_FAILED,
                     "Failed to parse APEX package " + existingApexPkg.applicationInfo.sourceDir
                             + " : " + existingResult.getException(), existingResult.getException());
         }
@@ -369,7 +369,7 @@
             return;
         }
 
-        throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+        throw new PackageManagerException(SessionInfo.SESSION_VERIFICATION_FAILED,
                 "APK-container signature of APEX package " + packageName + " with version "
                         + newApexPkg.versionCodeMajor + " and path " + apexPath + " is not"
                         + " compatible with the one currently installed on device");
@@ -412,11 +412,11 @@
                 packageInfo = PackageInfoWithoutStateUtils.generate(parsedPackage, apexInfo, flags);
                 if (packageInfo == null) {
                     throw new PackageManagerException(
-                            SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                            SessionInfo.SESSION_VERIFICATION_FAILED,
                             "Unable to generate package info: " + apexInfo.modulePath);
                 }
             } catch (PackageManagerException e) {
-                throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                throw new PackageManagerException(SessionInfo.SESSION_VERIFICATION_FAILED,
                         "Failed to parse APEX package " + apexInfo.modulePath + " : " + e, e);
             }
             result.add(packageInfo);
@@ -438,7 +438,7 @@
             }
         }
         throw new PackageManagerException(
-                SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                SessionInfo.SESSION_VERIFICATION_FAILED,
                 "Could not find rollback id for commit session: " + sessionId);
     }
 
@@ -546,7 +546,7 @@
         try {
             checkActiveSessions(PackageHelper.getStorageManager().supportsCheckpoint());
         } catch (RemoteException e) {
-            throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+            throw new PackageManagerException(SessionInfo.SESSION_VERIFICATION_FAILED,
                     "Can't query fs-checkpoint status : " + e);
         }
     }
@@ -562,7 +562,7 @@
         }
         if (!supportsCheckpoint && activeSessions > 1) {
             throw new PackageManagerException(
-                    SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                    SessionInfo.SESSION_VERIFICATION_FAILED,
                     "Cannot stage multiple sessions without checkpoint support");
         }
     }
@@ -593,13 +593,13 @@
                     // will be deleted.
                 }
                 stagedSession.setSessionFailed(
-                        SessionInfo.STAGED_SESSION_CONFLICT,
+                        SessionInfo.SESSION_CONFLICT,
                         "Session was failed by rollback session: " + session.sessionId());
                 Slog.i(TAG, "Session " + stagedSession.sessionId() + " is marked failed due to "
                         + "rollback session: " + session.sessionId());
             } else if (!isRollback(session) && isRollback(stagedSession)) {
                 throw new PackageManagerException(
-                        SessionInfo.STAGED_SESSION_CONFLICT,
+                        SessionInfo.SESSION_CONFLICT,
                         "Session was failed by rollback session: " + stagedSession.sessionId());
 
             }
@@ -622,7 +622,7 @@
         final String packageName = child.getPackageName();
         if (packageName == null) {
             throw new PackageManagerException(
-                    SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                    SessionInfo.SESSION_VERIFICATION_FAILED,
                     "Cannot stage session " + child.sessionId() + " with package name null");
         }
         for (StagingManager.StagedSession stagedSession : mStagedSessions) {
@@ -634,14 +634,14 @@
                 if (stagedSession.getCommittedMillis() < parent.getCommittedMillis()) {
                     // Fail the session committed later when there are overlapping packages
                     throw new PackageManagerException(
-                            SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                            SessionInfo.SESSION_VERIFICATION_FAILED,
                             "Package: " + packageName + " in session: "
                                     + child.sessionId()
                                     + " has been staged already by session: "
                                     + stagedSession.sessionId());
                 } else {
                     stagedSession.setSessionFailed(
-                            SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                            SessionInfo.SESSION_VERIFICATION_FAILED,
                             "Package: " + packageName + " in session: "
                                     + stagedSession.sessionId()
                                     + " has been staged already by session: "
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 8a6ef6b..29de555 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -284,7 +284,7 @@
             String packageName = apexSession.getPackageName();
             String errorMsg = mApexManager.getApkInApexInstallError(packageName);
             if (errorMsg != null) {
-                throw new PackageManagerException(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+                throw new PackageManagerException(SessionInfo.SESSION_ACTIVATION_FAILED,
                         "Failed to install apk-in-apex of " + packageName + " : " + errorMsg);
             }
         }
@@ -397,7 +397,7 @@
                 revertMsg += " Reason for revert: " + reasonForRevert;
             }
             Slog.d(TAG, revertMsg);
-            session.setSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN, revertMsg);
+            session.setSessionFailed(SessionInfo.SESSION_UNKNOWN_ERROR, revertMsg);
             return;
         }
 
@@ -484,7 +484,7 @@
             for (String apkInApex : mApexManager.getApksInApex(packageName)) {
                 if (!apkNames.add(apkInApex)) {
                     throw new PackageManagerException(
-                            SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+                            SessionInfo.SESSION_ACTIVATION_FAILED,
                             "Package: " + packageName + " in session: "
                                     + apexSession.sessionId() + " has duplicate apk-in-apex: "
                                     + apkInApex, null);
@@ -511,7 +511,7 @@
             Slog.e(TAG, "Failure to install APK staged session "
                     + session.sessionId() + " [" + errorMessage + "]");
             throw new PackageManagerException(
-                    SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMessage);
+                    SessionInfo.SESSION_ACTIVATION_FAILED, errorMessage);
         }
     }
 
@@ -665,7 +665,7 @@
             // is upgrading. Fail all the sessions and exit early.
             for (int i = 0; i < sessions.size(); i++) {
                 StagedSession session = sessions.get(i);
-                session.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+                session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED,
                         "Build fingerprint has changed");
             }
             return;
@@ -705,7 +705,7 @@
             final ApexSessionInfo apexSession = apexSessions.get(session.sessionId());
             if (apexSession == null || apexSession.isUnknown) {
                 hasFailedApexSession = true;
-                session.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, "apexd did "
+                session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED, "apexd did "
                         + "not know anything about a staged session supposed to be activated");
                 continue;
             } else if (isApexSessionFailed(apexSession)) {
@@ -721,7 +721,7 @@
                     errorMsg += " Error: " + apexSession.errorMessage;
                 }
                 Slog.d(TAG, errorMsg);
-                session.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMsg);
+                session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED, errorMsg);
                 continue;
             } else if (apexSession.isActivated || apexSession.isSuccess) {
                 hasAppliedApexSession = true;
@@ -730,13 +730,13 @@
                 // Apexd did not apply the session for some unknown reason. There is no guarantee
                 // that apexd will install it next time. Safer to proactively mark it as failed.
                 hasFailedApexSession = true;
-                session.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+                session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED,
                         "Staged session " + session.sessionId() + " at boot didn't activate nor "
                         + "fail. Marking it as failed anyway.");
             } else {
                 Slog.w(TAG, "Apex session " + session.sessionId() + " is in impossible state");
                 hasFailedApexSession = true;
-                session.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+                session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED,
                         "Impossible state");
             }
         }
@@ -756,7 +756,7 @@
                     // Session has been already failed in the loop above.
                     continue;
                 }
-                session.setSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+                session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED,
                         "Another apex session failed");
             }
             return;
@@ -772,7 +772,7 @@
             } catch (Exception e) {
                 Slog.e(TAG, "Staged install failed due to unhandled exception", e);
                 onInstallationFailure(session, new PackageManagerException(
-                        SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+                        SessionInfo.SESSION_ACTIVATION_FAILED,
                         "Staged install failed due to unhandled exception: " + e),
                         supportsCheckpoint, needsCheckpoint);
             }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 85e54f3..1cfcdf51 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -386,7 +386,8 @@
     @Override
     public void startOneTimePermissionSession(String packageName, @UserIdInt int userId,
             long timeoutMillis, int importanceToResetTimer, int importanceToKeepSessionAlive) {
-        mContext.enforceCallingPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS,
+        mContext.enforceCallingOrSelfPermission(
+                Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS,
                 "Must hold " + Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS
                         + " to register permissions as one time.");
         Objects.requireNonNull(packageName);
@@ -557,6 +558,12 @@
     }
 
     @Override
+    public void selfRevokePermissions(@NonNull String packageName,
+            @NonNull List<String> permissions) {
+        mPermissionManagerServiceImpl.selfRevokePermissions(packageName, permissions);
+    }
+
+    @Override
     public boolean shouldShowRequestPermissionRationale(String packageName, String permissionName,
             int userId) {
         return mPermissionManagerServiceImpl.shouldShowRequestPermissionRationale(packageName,
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 21cb2c9..7833c43 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -1591,6 +1591,25 @@
         }
     }
 
+    @Override
+    public void selfRevokePermissions(String packageName, List<String> permissions) {
+        final int callingUid = Binder.getCallingUid();
+        int callingUserId = UserHandle.getUserId(callingUid);
+        int targetPackageUid = mPackageManagerInt.getPackageUid(packageName, 0, callingUserId);
+        if (targetPackageUid != callingUid) {
+            throw new SecurityException("uid " + callingUid
+                    + " cannot revoke permissions for package " + packageName + " with uid "
+                    + targetPackageUid);
+        }
+        for (String permName : permissions) {
+            if (!checkCallingOrSelfPermission(permName)) {
+                throw new SecurityException("uid " + callingUid + " cannot revoke permission "
+                        + permName + " because it does not hold that permission");
+            }
+        }
+        mPermissionControllerManager.selfRevokePermissions(packageName, permissions);
+    }
+
     private boolean mayManageRolePermission(int uid) {
         final PackageManager packageManager = mContext.getPackageManager();
         final String[] packageNames = packageManager.getPackagesForUid(uid);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 3771f03..c582f9e 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -327,6 +327,26 @@
     void revokePostNotificationPermissionWithoutKillForTest(String packageName, int userId);
 
     /**
+     * Triggers the revocation of one or more permissions for a package, under the following
+     * conditions:
+     * <ul>
+     * <li>The package {@code packageName} must be under the same UID as the calling process
+     *   (typically, the target package is the calling package).
+     * <li>Each permission in {@code permissions} must be granted to the package
+     * {@code packageName}.
+     * <li>Each permission in {@code permissions} must be a runtime permission.
+     * </ul>
+     * <p>
+     * For every permission in {@code permissions}, the entire permission group it belongs to will
+     * be revoked. This revocation happens asynchronously and kills all processes running in the
+     * same UID as {@code packageName}. It will be triggered once it is safe to do so.
+     *
+     * @param packageName The name of the package for which the permissions will be revoked.
+     * @param permissions List of permissions to be revoked.
+     */
+    void selfRevokePermissions(String packageName, List<String> permissions);
+
+    /**
      * Get whether you should show UI with rationale for requesting a permission. You should do this
      * only if you do not have the permission and the context in which the permission is requested
      * does not clearly communicate to the user what would be the benefit from grating this
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
index ef0079e..ca67597 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
@@ -35,7 +35,6 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
-
 import com.android.server.powerstats.PowerStatsHALWrapper.IPowerStatsHALWrapper;
 import com.android.server.powerstats.ProtoStreamUtils.ChannelUtils;
 import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerResultUtils;
@@ -313,12 +312,12 @@
         return mStartWallTime;
     }
 
-    public PowerStatsLogger(Context context, File dataStoragePath,
+    public PowerStatsLogger(Context context, Looper looper, File dataStoragePath,
             String meterFilename, String meterCacheFilename,
             String modelFilename, String modelCacheFilename,
             String residencyFilename, String residencyCacheFilename,
             IPowerStatsHALWrapper powerStatsHALWrapper) {
-        super(Looper.getMainLooper());
+        super(looper);
         mStartWallTime = currentTimeMillis() - SystemClock.elapsedRealtime();
         if (DEBUG) Slog.d(TAG, "mStartWallTime: " + mStartWallTime);
         mPowerStatsHALWrapper = powerStatsHALWrapper;
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsService.java b/services/core/java/com/android/server/powerstats/PowerStatsService.java
index bb52c1d..9953ca8 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsService.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsService.java
@@ -28,6 +28,7 @@
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.Looper;
 import android.os.UserHandle;
 import android.power.PowerStatsInternal;
 import android.util.Slog;
@@ -79,6 +80,9 @@
     private StatsPullAtomCallbackImpl mPullAtomCallback;
     @Nullable
     private PowerStatsInternal mPowerStatsInternal;
+    @Nullable
+    @GuardedBy("this")
+    private Looper mLooper;
 
     @VisibleForTesting
     static class Injector {
@@ -127,12 +131,12 @@
             }
         }
 
-        PowerStatsLogger createPowerStatsLogger(Context context, File dataStoragePath,
-                String meterFilename, String meterCacheFilename,
+        PowerStatsLogger createPowerStatsLogger(Context context, Looper looper,
+                File dataStoragePath, String meterFilename, String meterCacheFilename,
                 String modelFilename, String modelCacheFilename,
                 String residencyFilename, String residencyCacheFilename,
                 IPowerStatsHALWrapper powerStatsHALWrapper) {
-            return new PowerStatsLogger(context, dataStoragePath,
+            return new PowerStatsLogger(context, looper, dataStoragePath,
                 meterFilename, meterCacheFilename,
                 modelFilename, modelCacheFilename,
                 residencyFilename, residencyCacheFilename,
@@ -229,11 +233,11 @@
             mDataStoragePath = mInjector.createDataStoragePath();
 
             // Only start logger and triggers if initialization is successful.
-            mPowerStatsLogger = mInjector.createPowerStatsLogger(mContext, mDataStoragePath,
-                mInjector.createMeterFilename(), mInjector.createMeterCacheFilename(),
-                mInjector.createModelFilename(), mInjector.createModelCacheFilename(),
-                mInjector.createResidencyFilename(), mInjector.createResidencyCacheFilename(),
-                getPowerStatsHal());
+            mPowerStatsLogger = mInjector.createPowerStatsLogger(mContext, getLooper(),
+                    mDataStoragePath, mInjector.createMeterFilename(),
+                    mInjector.createMeterCacheFilename(), mInjector.createModelFilename(),
+                    mInjector.createModelCacheFilename(), mInjector.createResidencyFilename(),
+                    mInjector.createResidencyCacheFilename(), getPowerStatsHal());
             mBatteryTrigger = mInjector.createBatteryTrigger(mContext, mPowerStatsLogger);
             mTimerTrigger = mInjector.createTimerTrigger(mContext, mPowerStatsLogger);
         } else {
@@ -245,6 +249,17 @@
         return mInjector.getPowerStatsHALWrapperImpl();
     }
 
+    private Looper getLooper() {
+        synchronized (this) {
+            if (mLooper == null) {
+                HandlerThread thread = new HandlerThread(TAG);
+                thread.start();
+                return thread.getLooper();
+            }
+            return mLooper;
+        }
+    }
+
     public PowerStatsService(Context context) {
         this(context, new Injector());
     }
@@ -260,9 +275,7 @@
         private final Handler mHandler;
 
         LocalService() {
-            HandlerThread thread = new HandlerThread(TAG);
-            thread.start();
-            mHandler = new Handler(thread.getLooper());
+            mHandler = new Handler(getLooper());
         }
 
 
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index e98fa28..fe74167 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -528,12 +528,13 @@
                     callback.onFailure();
                     return;
                 }
-                textClassifierServiceConsumer.accept(serviceState.mService);
+                consumeServiceNoExceptLocked(textClassifierServiceConsumer, serviceState.mService);
             } else {
                 serviceState.mPendingRequests.add(
                         new PendingRequest(
                                 methodName,
-                                () -> textClassifierServiceConsumer.accept(serviceState.mService),
+                                () -> consumeServiceNoExceptLocked(
+                                        textClassifierServiceConsumer, serviceState.mService),
                                 callback::onFailure, callback.asBinder(),
                                 this,
                                 serviceState,
@@ -542,6 +543,16 @@
         }
     }
 
+    private static void consumeServiceNoExceptLocked(
+            @NonNull ThrowingConsumer<ITextClassifierService> textClassifierServiceConsumer,
+            @Nullable ITextClassifierService service) {
+        try {
+            textClassifierServiceConsumer.accept(service);
+        } catch (RuntimeException | Error e) {
+            Slog.e(LOG_TAG, "Exception when consume textClassifierService: " + e);
+        }
+    }
+
     private static ITextClassifierCallback wrap(ITextClassifierCallback orig) {
         return new CallbackWrapper(orig);
     }
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 568e4b8..e066ca3 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -69,6 +69,7 @@
 import android.media.tv.TvInputService;
 import android.media.tv.TvStreamConfig;
 import android.media.tv.TvTrackInfo;
+import android.media.tv.tunerresourcemanager.TunerResourceManager;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -2538,6 +2539,31 @@
         }
 
         @Override
+        public int getClientPriority(int useCase, String sessionId) {
+            final int callingPid = Binder.getCallingPid();
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                int clientPid = TvInputManager.UNKNOWN_CLIENT_PID;
+                if (sessionId != null) {
+                    synchronized (mLock) {
+                        try {
+                            clientPid = getClientPidLocked(sessionId);
+                        } catch (ClientPidNotFoundException e) {
+                            Slog.e(TAG, "error in getClientPriority", e);
+                        }
+                    }
+                } else {
+                    clientPid = callingPid;
+                }
+                TunerResourceManager trm = (TunerResourceManager)
+                        mContext.getSystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE);
+                return trm.getClientPriority(useCase, clientPid);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public List<TunedInfo> getCurrentTunedInfos(@UserIdInt int userId) {
             if (mContext.checkCallingPermission(android.Manifest.permission.ACCESS_TUNED_INFO)
                     != PackageManager.PERMISSION_GRANTED) {
@@ -2585,9 +2611,9 @@
 
         @GuardedBy("mLock")
         private int getClientPidLocked(String sessionId)
-                throws IllegalStateException {
+                throws ClientPidNotFoundException {
             if (mSessionIdToSessionStateMap.get(sessionId) == null) {
-                throw new IllegalStateException("Client Pid not found with sessionId "
+                throw new ClientPidNotFoundException("Client Pid not found with sessionId "
                         + sessionId);
             }
             return mSessionIdToSessionStateMap.get(sessionId).callingPid;
diff --git a/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
index a2bf2fe..a4732c1 100644
--- a/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
@@ -906,6 +906,94 @@
         }
 
         @Override
+        public void notifyVideoAvailable(IBinder sessionToken, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int callingPid = Binder.getCallingPid();
+            final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
+                    "notifyVideoAvailable");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).notifyVideoAvailable();
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slogf.e(TAG, "error in notifyVideoAvailable", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void notifyVideoUnavailable(IBinder sessionToken, int reason, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int callingPid = Binder.getCallingPid();
+            final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
+                    "notifyVideoUnavailable");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).notifyVideoUnavailable(reason);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slogf.e(TAG, "error in notifyVideoUnavailable", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void notifyContentAllowed(IBinder sessionToken, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int callingPid = Binder.getCallingPid();
+            final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
+                    "notifyContentAllowed");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).notifyContentAllowed();
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slogf.e(TAG, "error in notifyContentAllowed", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void notifyContentBlocked(IBinder sessionToken, String rating, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int callingPid = Binder.getCallingPid();
+            final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
+                    "notifyContentBlocked");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).notifyContentBlocked(rating);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slogf.e(TAG, "error in notifyContentBlocked", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void startIApp(IBinder sessionToken, int userId) {
             if (DEBUG) {
                 Slogf.d(TAG, "BinderService#start(userId=%d)", userId);
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index 63f4c68..af705d5 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -289,6 +289,23 @@
         }
 
         @Override
+        public boolean transferOwner(int resourceType, int currentOwnerId, int newOwnerId) {
+            enforceTunerAccessPermission("transferOwner");
+            enforceTrmAccessPermission("transferOwner");
+            synchronized (mLock) {
+                if (!checkClientExists(currentOwnerId)) {
+                    Slog.e(TAG, "currentOwnerId:" + currentOwnerId + " does not exit");
+                    return false;
+                }
+                if (!checkClientExists(newOwnerId)) {
+                    Slog.e(TAG, "newOwnerId:" + newOwnerId + " does not exit");
+                    return false;
+                }
+                return transferOwnerInternal(resourceType, currentOwnerId, newOwnerId);
+            }
+        }
+
+        @Override
         public boolean requestDemux(@NonNull TunerDemuxRequest request,
                     @NonNull int[] demuxHandle) throws RemoteException {
             enforceTunerAccessPermission("requestDemux");
@@ -388,7 +405,11 @@
                 if (fe == null) {
                     throw new RemoteException("Releasing frontend does not exist.");
                 }
-                if (fe.getOwnerClientId() != clientId) {
+                int ownerClientId = fe.getOwnerClientId();
+                ClientProfile ownerProfile = getClientProfile(ownerClientId);
+                if (ownerClientId != clientId
+                        && (ownerProfile != null
+                              && !ownerProfile.getShareFeClientIds().contains(clientId))) {
                     throw new RemoteException(
                             "Client is not the current owner of the releasing fe.");
                 }
@@ -619,6 +640,21 @@
             }
         }
 
+        @Override
+        public int getClientPriority(int useCase, int pid) throws RemoteException {
+            enforceTrmAccessPermission("getClientPriority");
+            synchronized (mLock) {
+                return TunerResourceManagerService.this.getClientPriority(
+                        useCase, checkIsForeground(pid));
+            }
+        }
+        @Override
+        public int getConfigPriority(int useCase, boolean isForeground) throws RemoteException {
+            enforceTrmAccessPermission("getConfigPriority");
+            synchronized (mLock) {
+                return TunerResourceManagerService.this.getClientPriority(useCase, isForeground);
+            }
+        }
     }
 
     /**
@@ -976,6 +1012,83 @@
         getClientProfile(targetClientId).shareFrontend(selfClientId);
     }
 
+    private boolean transferFeOwner(int currentOwnerId, int newOwnerId) {
+        ClientProfile currentOwnerProfile = getClientProfile(currentOwnerId);
+        ClientProfile newOwnerProfile = getClientProfile(newOwnerId);
+        // change the owner of all the inUse frontend
+        newOwnerProfile.shareFrontend(currentOwnerId);
+        currentOwnerProfile.stopSharingFrontend(newOwnerId);
+        for (int inUseHandle : newOwnerProfile.getInUseFrontendHandles()) {
+            getFrontendResource(inUseHandle).setOwner(newOwnerId);
+        }
+        // double check there is no other resources tied to the previous owner
+        for (int inUseHandle : currentOwnerProfile.getInUseFrontendHandles()) {
+            int ownerId = getFrontendResource(inUseHandle).getOwnerClientId();
+            if (ownerId != newOwnerId) {
+                Slog.e(TAG, "something is wrong in transferFeOwner:" + inUseHandle
+                        + ", " + ownerId + ", " + newOwnerId);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean transferFeCiCamOwner(int currentOwnerId, int newOwnerId) {
+        ClientProfile currentOwnerProfile = getClientProfile(currentOwnerId);
+        ClientProfile newOwnerProfile = getClientProfile(newOwnerId);
+
+        // link ciCamId to the new profile
+        int ciCamId = currentOwnerProfile.getInUseCiCamId();
+        newOwnerProfile.useCiCam(ciCamId);
+
+        // set the new owner Id
+        CiCamResource ciCam = getCiCamResource(ciCamId);
+        ciCam.setOwner(newOwnerId);
+
+        // unlink cicam resource from the original owner profile
+        currentOwnerProfile.releaseCiCam();
+        return true;
+    }
+
+    private boolean transferLnbOwner(int currentOwnerId, int newOwnerId) {
+        ClientProfile currentOwnerProfile = getClientProfile(currentOwnerId);
+        ClientProfile newOwnerProfile = getClientProfile(newOwnerId);
+
+        Set<Integer> inUseLnbHandles = new HashSet<>();
+        for (Integer lnbHandle : currentOwnerProfile.getInUseLnbHandles()) {
+            // link lnb handle to the new profile
+            newOwnerProfile.useLnb(lnbHandle);
+
+            // set new owner Id
+            LnbResource lnb = getLnbResource(lnbHandle);
+            lnb.setOwner(newOwnerId);
+
+            inUseLnbHandles.add(lnbHandle);
+        }
+
+        // unlink lnb handles from the original owner
+        for (Integer lnbHandle : inUseLnbHandles) {
+            currentOwnerProfile.releaseLnb(lnbHandle);
+        }
+
+        return true;
+    }
+
+    @VisibleForTesting
+    protected boolean transferOwnerInternal(int resourceType, int currentOwnerId, int newOwnerId) {
+        switch (resourceType) {
+            case TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND:
+                return transferFeOwner(currentOwnerId, newOwnerId);
+            case TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND_CICAM:
+                return transferFeCiCamOwner(currentOwnerId, newOwnerId);
+            case TunerResourceManager.TUNER_RESOURCE_TYPE_LNB:
+                return transferLnbOwner(currentOwnerId, newOwnerId);
+            default:
+                Slog.e(TAG, "transferOwnerInternal. unsupported resourceType: " + resourceType);
+                return false;
+        }
+    }
+
     @VisibleForTesting
     protected boolean requestLnbInternal(TunerLnbRequest request, int[] lnbHandle) {
         if (DEBUG) {
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
index 47622bc..9661e8d 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
@@ -24,13 +24,11 @@
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
 import static android.window.DisplayAreaOrganizer.FEATURE_FULLSCREEN_MAGNIFICATION;
 import static android.window.DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT;
 import static android.window.DisplayAreaOrganizer.FEATURE_IME_PLACEHOLDER;
 import static android.window.DisplayAreaOrganizer.FEATURE_ONE_HANDED;
-import static android.window.DisplayAreaOrganizer.FEATURE_ONE_HANDED_BACKGROUND_PANEL;
 import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION;
 
 import static com.android.server.wm.DisplayAreaPolicyBuilder.Feature;
@@ -134,11 +132,6 @@
                         .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL, TYPE_STATUS_BAR,
                                 TYPE_NOTIFICATION_SHADE)
                         .build())
-                        .addFeature(new Feature.Builder(wmService.mPolicy,
-                                "OneHandedBackgroundPanel",
-                                FEATURE_ONE_HANDED_BACKGROUND_PANEL)
-                                .upTo(TYPE_WALLPAPER)
-                                .build())
                         .addFeature(new Feature.Builder(wmService.mPolicy, "OneHanded",
                                 FEATURE_ONE_HANDED)
                                 .all()
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 55f463d..8e0435f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -218,7 +218,6 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.SurfaceSession;
-import android.view.View;
 import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.WindowManager.DisplayImePolicy;
@@ -1425,7 +1424,7 @@
             mWaitingForConfig = true;
             if (mTransitionController.isShellTransitionsEnabled()) {
                 requestChangeTransitionIfNeeded(changes, null /* displayChange */);
-            } else {
+            } else if (mLastHasContent) {
                 mWmService.startFreezingDisplay(0 /* exitAnim */, 0 /* enterAnim */, this);
             }
             sendNewConfiguration();
@@ -1702,8 +1701,7 @@
             case SOFT_INPUT_STATE_HIDDEN:
                 return false;
         }
-        return r.mLastImeShown && mInputMethodWindow != null && mInputMethodWindow.mHasSurface
-                && mInputMethodWindow.mViewVisibility == View.VISIBLE;
+        return r.mLastImeShown;
     }
 
     /** Returns {@code true} if the top activity is transformed with the new rotation of display. */
@@ -3222,6 +3220,7 @@
      */
     void requestChangeTransitionIfNeeded(@ActivityInfo.Config int changes,
             @Nullable TransitionRequestInfo.DisplayChange displayChange) {
+        if (!mLastHasContent) return;
         final TransitionController controller = mTransitionController;
         if (controller.isCollecting()) {
             if (displayChange != null) {
@@ -5090,6 +5089,11 @@
         return mLastHasContent;
     }
 
+    @VisibleForTesting
+    void setLastHasContent() {
+        mLastHasContent = true;
+    }
+
     void registerPointerEventListener(@NonNull PointerEventListener listener) {
         mPointerEventDispatcher.registerInputEventListener(listener);
     }
diff --git a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
index c85e04d..2cefd99 100644
--- a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
+++ b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
@@ -256,7 +256,7 @@
                     false /* applyFixedTransformationHint */);
             for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
                 final SurfaceControl leash = mTargetWindowTokens.valueAt(i);
-                if (leash != null) {
+                if (leash != null && leash.isValid()) {
                     rotator.applyTransform(t, leash);
                 }
             }
@@ -265,7 +265,7 @@
         // Hide the windows immediately because a screenshot layer should cover the screen.
         for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
             final SurfaceControl leash = mTargetWindowTokens.valueAt(i);
-            if (leash != null) {
+            if (leash != null && leash.isValid()) {
                 t.setAlpha(leash, 0f);
             }
         }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index fe5c358..ac90ceb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -310,6 +310,8 @@
             "com.android.clockwork.connectivity.WearConnectivityService";
     private static final String WEAR_POWER_SERVICE_CLASS =
             "com.android.clockwork.power.WearPowerService";
+    private static final String HEALTH_SERVICE_CLASS =
+            "com.google.android.clockwork.healthservices.HealthService";
     private static final String WEAR_SIDEKICK_SERVICE_CLASS =
             "com.google.android.clockwork.sidekick.SidekickService";
     private static final String WEAR_DISPLAYOFFLOAD_SERVICE_CLASS =
@@ -2499,6 +2501,10 @@
             mSystemServiceManager.startService(WEAR_POWER_SERVICE_CLASS);
             t.traceEnd();
 
+            t.traceBegin("StartHealthService");
+            mSystemServiceManager.startService(HEALTH_SERVICE_CLASS);
+            t.traceEnd();
+
             t.traceBegin("StartWearConnectivityService");
             mSystemServiceManager.startService(WEAR_CONNECTIVITY_SERVICE_CLASS);
             t.traceEnd();
diff --git a/services/midi/OWNERS b/services/midi/OWNERS
new file mode 100644
index 0000000..f4d51f9
--- /dev/null
+++ b/services/midi/OWNERS
@@ -0,0 +1 @@
+philburk@google.com
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 0c3e472..bdeb2b4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -122,15 +122,14 @@
                 .when(() -> LocalServices.getService(ActivityManagerInternal.class));
         doReturn(mock(AppStandbyInternal.class))
                 .when(() -> LocalServices.getService(AppStandbyInternal.class));
+        doReturn(mock(BatteryManagerInternal.class))
+                .when(() -> LocalServices.getService(BatteryManagerInternal.class));
         doReturn(mock(UsageStatsManagerInternal.class))
                 .when(() -> LocalServices.getService(UsageStatsManagerInternal.class));
         when(mContext.getString(anyInt())).thenReturn("some_test_string");
         // Called in BackgroundJobsController constructor.
         doReturn(mock(AppStateTrackerImpl.class))
                 .when(() -> LocalServices.getService(AppStateTracker.class));
-        // Called in BatteryController constructor.
-        doReturn(mock(BatteryManagerInternal.class))
-                .when(() -> LocalServices.getService(BatteryManagerInternal.class));
         // Called in ConnectivityController constructor.
         when(mContext.getSystemService(ConnectivityManager.class))
                 .thenReturn(mock(ConnectivityManager.class));
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index a9853bf..f61d6ca 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -48,18 +48,14 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.job.JobInfo;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.PackageManagerInternal;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkPolicyManager;
-import android.os.BatteryManager;
-import android.os.BatteryManagerInternal;
 import android.os.Build;
 import android.os.Looper;
 import android.os.SystemClock;
@@ -74,7 +70,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatchers;
 import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
@@ -88,8 +83,6 @@
     @Mock
     private Context mContext;
     @Mock
-    private BatteryManagerInternal mBatteryManagerInternal;
-    @Mock
     private ConnectivityManager mConnManager;
     @Mock
     private NetworkPolicyManager mNetPolicyManager;
@@ -115,9 +108,6 @@
         LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
         LocalServices.addService(NetworkPolicyManagerInternal.class, mNetPolicyManagerInternal);
 
-        LocalServices.removeServiceForTest(BatteryManagerInternal.class);
-        LocalServices.addService(BatteryManagerInternal.class, mBatteryManagerInternal);
-
         when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
 
         // Freeze the clocks at this moment in time
@@ -158,18 +148,10 @@
                 .setMinimumNetworkChunkBytes(DataUnit.KIBIBYTES.toBytes(100))
                 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
 
-        final ArgumentCaptor<BroadcastReceiver> chargingCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
-        when(mBatteryManagerInternal.isPowered(eq(BatteryManager.BATTERY_PLUGGED_ANY)))
-                .thenReturn(false);
+        when(mService.isBatteryCharging()).thenReturn(false);
         final ConnectivityController controller = new ConnectivityController(mService);
-        verify(mContext).registerReceiver(chargingCaptor.capture(),
-                ArgumentMatchers.argThat(filter ->
-                        filter.hasAction(BatteryManager.ACTION_CHARGING)
-                                && filter.hasAction(BatteryManager.ACTION_DISCHARGING)));
         when(mService.getMaxJobExecutionTimeMs(any())).thenReturn(10 * 60_000L);
-        final BroadcastReceiver chargingReceiver = chargingCaptor.getValue();
-        chargingReceiver.onReceive(mContext, new Intent(BatteryManager.ACTION_DISCHARGING));
+        controller.onBatteryStateChangedLocked();
 
         // Slow network is too slow
         assertFalse(controller.isSatisfied(createJobStatus(job), net,
@@ -225,17 +207,15 @@
                 createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(130)
                         .setLinkDownstreamBandwidthKbps(130).build(), mConstants));
         // Slow network is too slow, but device is charging and network is unmetered.
-        when(mBatteryManagerInternal.isPowered(eq(BatteryManager.BATTERY_PLUGGED_ANY)))
-                .thenReturn(true);
-        chargingReceiver.onReceive(mContext, new Intent(BatteryManager.ACTION_CHARGING));
+        when(mService.isBatteryCharging()).thenReturn(true);
+        controller.onBatteryStateChangedLocked();
         assertTrue(controller.isSatisfied(createJobStatus(job), net,
                 createCapabilitiesBuilder().addCapability(NET_CAPABILITY_NOT_METERED)
                         .setLinkUpstreamBandwidthKbps(1).setLinkDownstreamBandwidthKbps(1).build(),
                 mConstants));
 
-        when(mBatteryManagerInternal.isPowered(eq(BatteryManager.BATTERY_PLUGGED_ANY)))
-                .thenReturn(false);
-        chargingReceiver.onReceive(mContext, new Intent(BatteryManager.ACTION_DISCHARGING));
+        when(mService.isBatteryCharging()).thenReturn(false);
+        controller.onBatteryStateChangedLocked();
         when(mService.getMaxJobExecutionTimeMs(any())).thenReturn(60_000L);
 
         // Slow network is too slow
@@ -259,9 +239,8 @@
                 createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(130)
                         .setLinkDownstreamBandwidthKbps(130).build(), mConstants));
         // Slow network is too slow, but device is charging and network is unmetered.
-        when(mBatteryManagerInternal.isPowered(eq(BatteryManager.BATTERY_PLUGGED_ANY)))
-                .thenReturn(true);
-        chargingReceiver.onReceive(mContext, new Intent(BatteryManager.ACTION_CHARGING));
+        when(mService.isBatteryCharging()).thenReturn(true);
+        controller.onBatteryStateChangedLocked();
         assertTrue(controller.isSatisfied(createJobStatus(job), net,
                 createCapabilitiesBuilder().addCapability(NET_CAPABILITY_NOT_METERED)
                         .setLinkUpstreamBandwidthKbps(1).setLinkDownstreamBandwidthKbps(1).build(),
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 300f93f..cfae9a3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -63,16 +63,13 @@
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManager;
 import android.app.usage.UsageStatsManagerInternal;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ServiceInfo;
-import android.os.BatteryManager;
 import android.os.BatteryManagerInternal;
 import android.os.Handler;
 import android.os.Looper;
@@ -126,7 +123,6 @@
     private static final String SOURCE_PACKAGE = "com.android.frameworks.mockingservicestests";
     private static final int SOURCE_USER_ID = 0;
 
-    private BroadcastReceiver mChargingReceiver;
     private QuotaController mQuotaController;
     private QuotaController.QcConstants mQcConstants;
     private JobSchedulerService.Constants mConstants = new JobSchedulerService.Constants();
@@ -225,8 +221,6 @@
 
         // Initialize real objects.
         // Capture the listeners.
-        ArgumentCaptor<BroadcastReceiver> receiverCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
         ArgumentCaptor<IUidObserver> uidObserverCaptor =
                 ArgumentCaptor.forClass(IUidObserver.class);
         ArgumentCaptor<PowerAllowlistInternal.TempAllowlistChangeListener> taChangeCaptor =
@@ -236,11 +230,6 @@
         mQuotaController = new QuotaController(mJobSchedulerService,
                 mock(BackgroundJobsController.class), mock(ConnectivityController.class));
 
-        verify(mContext).registerReceiver(receiverCaptor.capture(),
-                ArgumentMatchers.argThat(filter ->
-                        filter.hasAction(BatteryManager.ACTION_CHARGING)
-                                && filter.hasAction(BatteryManager.ACTION_DISCHARGING)));
-        mChargingReceiver = receiverCaptor.getValue();
         verify(mPowerAllowlistInternal)
                 .registerTempAllowlistChangeListener(taChangeCaptor.capture());
         mTempAllowlistListener = taChangeCaptor.getValue();
@@ -280,13 +269,17 @@
     }
 
     private void setCharging() {
-        Intent intent = new Intent(BatteryManager.ACTION_CHARGING);
-        mChargingReceiver.onReceive(mContext, intent);
+        doReturn(true).when(mJobSchedulerService).isBatteryCharging();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.onBatteryStateChangedLocked();
+        }
     }
 
     private void setDischarging() {
-        Intent intent = new Intent(BatteryManager.ACTION_DISCHARGING);
-        mChargingReceiver.onReceive(mContext, intent);
+        doReturn(false).when(mJobSchedulerService).isBatteryCharging();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.onBatteryStateChangedLocked();
+        }
     }
 
     private void setProcessState(int procState) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
index f2415b4..bdfdf77 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
@@ -158,10 +158,10 @@
 
         mStagingManager.restoreSessions(Arrays.asList(session1, session2), true);
 
-        assertThat(session1.getErrorCode()).isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+        assertThat(session1.getErrorCode()).isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
         assertThat(session1.getErrorMessage()).isEqualTo("Build fingerprint has changed");
 
-        assertThat(session2.getErrorCode()).isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+        assertThat(session2.getErrorCode()).isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
         assertThat(session2.getErrorMessage()).isEqualTo("Build fingerprint has changed");
     }
 
@@ -247,12 +247,12 @@
         verify(mStorageManager, never()).abortChanges(eq("abort-staged-install"), eq(false));
 
         assertThat(apexSession.getErrorCode())
-                .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+                .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
         assertThat(apexSession.getErrorMessage()).isEqualTo("apexd did not know anything about a "
                 + "staged session supposed to be activated");
 
         assertThat(apkSession.getErrorCode())
-                .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+                .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
         assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
     }
 
@@ -303,22 +303,22 @@
         verify(mStorageManager, never()).abortChanges(eq("abort-staged-install"), eq(false));
 
         assertThat(apexSession1.getErrorCode())
-                .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+                .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
         assertThat(apexSession1.getErrorMessage()).isEqualTo("APEX activation failed. "
                 + "Error: Failed for test");
 
         assertThat(apexSession2.getErrorCode())
-                .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+                .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
         assertThat(apexSession2.getErrorMessage()).isEqualTo("Staged session 101 at boot didn't "
                 + "activate nor fail. Marking it as failed anyway.");
 
         assertThat(apexSession3.getErrorCode())
-                .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+                .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
         assertThat(apexSession3.getErrorMessage()).isEqualTo("apexd did not know anything about a "
                 + "staged session supposed to be activated");
 
         assertThat(apkSession.getErrorCode())
-                .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+                .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
         assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
     }
 
@@ -351,12 +351,12 @@
         verify(mStorageManager, never()).abortChanges(eq("abort-staged-install"), eq(false));
 
         assertThat(apexSession.getErrorCode())
-                .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+                .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
         assertThat(apexSession.getErrorMessage()).isEqualTo("Staged session 1543 at boot didn't "
                 + "activate nor fail. Marking it as failed anyway.");
 
         assertThat(apkSession.getErrorCode())
-                .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+                .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
         assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
     }
 
@@ -445,11 +445,11 @@
         verify(mStorageManager, never()).abortChanges(eq("abort-staged-install"), eq(false));
 
         assertThat(apexSession.getErrorCode())
-                .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+                .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
         assertThat(apexSession.getErrorMessage()).isEqualTo("Impossible state");
 
         assertThat(apkSession.getErrorCode())
-                .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
+                .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
         assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
     }
 
@@ -754,7 +754,7 @@
                 /* isReady */ false,
                 /* isFailed */ false,
                 /* isApplied */false,
-                /* stagedSessionErrorCode */ PackageInstaller.SessionInfo.STAGED_SESSION_NO_ERROR,
+                /* stagedSessionErrorCode */ PackageInstaller.SessionInfo.SESSION_NO_ERROR,
                 /* stagedSessionErrorMessage */ "no error");
 
         StagingManager.StagedSession stagedSession = spy(session.mStagedSession);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index 62a2b1b..59f2ca4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -187,7 +187,7 @@
                 /* isFailed */ false,
                 /* isApplied */false,
                 /* stagedSessionErrorCode */
-                PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                PackageInstaller.SessionInfo.SESSION_VERIFICATION_FAILED,
                 /* stagedSessionErrorMessage */ "some error");
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
index 26b34fd..304fe5a 100644
--- a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
@@ -30,6 +30,7 @@
 import android.hardware.power.stats.State;
 import android.hardware.power.stats.StateResidency;
 import android.hardware.power.stats.StateResidencyResult;
+import android.os.Looper;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -145,12 +146,12 @@
         }
 
         @Override
-        PowerStatsLogger createPowerStatsLogger(Context context, File dataStoragePath,
-                String meterFilename, String meterCacheFilename,
+        PowerStatsLogger createPowerStatsLogger(Context context, Looper looper,
+                File dataStoragePath, String meterFilename, String meterCacheFilename,
                 String modelFilename, String modelCacheFilename,
                 String residencyFilename, String residencyCacheFilename,
                 IPowerStatsHALWrapper powerStatsHALWrapper) {
-            mPowerStatsLogger = new PowerStatsLogger(context, dataStoragePath,
+            mPowerStatsLogger = new PowerStatsLogger(context, looper, dataStoragePath,
                 meterFilename, meterCacheFilename,
                 modelFilename, modelCacheFilename,
                 residencyFilename, residencyCacheFilename,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 11777ef..d831903 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -182,7 +182,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
-import android.util.Slog;
 import android.util.TypedXmlPullParser;
 import android.util.TypedXmlSerializer;
 import android.util.Xml;
@@ -7174,6 +7173,14 @@
     }
 
     @Test
+    public void testAreNotificationsEnabledForPackage_viaInternalService() throws Exception {
+        assertEquals(mInternalService.areNotificationsEnabledForPackage(
+                mContext.getPackageName(), mUid),
+                mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), mUid));
+        verify(mPermissionHelper, never()).hasPermission(anyInt());
+    }
+
+    @Test
     public void testAreBubblesAllowedForPackage_crossUser() throws Exception {
         try {
             mBinderService.getBubblePreferenceForPackage(mContext.getPackageName(),
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
index 0c8fe35..1362628 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
@@ -536,6 +536,12 @@
     }
 
     @Test
+    public void testAreNotificationsEnabledForPackage_viaInternalService() {
+        mInternalService.areNotificationsEnabledForPackage(mContext.getPackageName(), mUid);
+        verify(mPermissionHelper).hasPermission(mUid);
+    }
+
+    @Test
     public void testGetPackageImportance() throws Exception {
         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
         assertThat(mBinderService.getPackageImportance(mContext.getPackageName()))
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index d49cf67..76bd4eb 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -3174,6 +3174,19 @@
     }
 
     @Test
+    public void testIsGroupBlocked_appCannotCreateAsBlocked() throws Exception {
+        NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
+        group.setBlocked(true);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true);
+        assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
+
+        NotificationChannelGroup group3 = group.clone();
+        group3.setBlocked(false);
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group3, true);
+        assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId()));
+    }
+
+    @Test
     public void testIsGroup_appCannotResetBlock() throws Exception {
         NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
         mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true);
@@ -4706,7 +4719,7 @@
     public void testGetConversations_noDisabledGroups() {
         NotificationChannelGroup group = new NotificationChannelGroup("a", "a");
         group.setBlocked(true);
-        mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true);
+        mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, false);
         NotificationChannel parent = new NotificationChannel("parent", "p", 1);
         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
index 525888d..cb9eb52 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
@@ -30,7 +30,6 @@
 import static android.window.DisplayAreaOrganizer.FEATURE_FULLSCREEN_MAGNIFICATION;
 import static android.window.DisplayAreaOrganizer.FEATURE_IME_PLACEHOLDER;
 import static android.window.DisplayAreaOrganizer.FEATURE_ONE_HANDED;
-import static android.window.DisplayAreaOrganizer.FEATURE_ONE_HANDED_BACKGROUND_PANEL;
 import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_LAST;
@@ -197,25 +196,6 @@
     }
 
     @Test
-    public void testBuilder_defaultPolicy_hasOneHandedBackgroundFeature() {
-        final DisplayAreaPolicy.Provider defaultProvider = DisplayAreaPolicy.Provider.fromResources(
-                resourcesWithProvider(""));
-        final DisplayAreaPolicyBuilder.Result defaultPolicy =
-                (DisplayAreaPolicyBuilder.Result) defaultProvider.instantiate(mWms, mDisplayContent,
-                        mRoot, mImeContainer);
-        if (mDisplayContent.isDefaultDisplay) {
-            final List<Feature> features = defaultPolicy.getFeatures();
-            boolean hasOneHandedBackgroundFeature = false;
-            for (Feature feature : features) {
-                hasOneHandedBackgroundFeature |=
-                        feature.getId() == FEATURE_ONE_HANDED_BACKGROUND_PANEL;
-            }
-
-            assertThat(hasOneHandedBackgroundFeature).isTrue();
-        }
-    }
-
-    @Test
     public void testBuilder_defaultPolicy_hasWindowedMagnificationFeature() {
         final DisplayAreaPolicy.Provider defaultProvider = DisplayAreaPolicy.Provider.fromResources(
                 resourcesWithProvider(""));
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 2ef59f6..2f78b58 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1718,6 +1718,7 @@
     @Test
     public void testShellTransitRotation() {
         DisplayContent dc = createNewDisplay();
+        dc.setLastHasContent();
 
         final TestTransitionPlayer testPlayer = registerTestTransitionPlayer();
         final DisplayRotation dr = dc.getDisplayRotation();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index ed3888c..141588a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -488,6 +488,7 @@
         final TestTransitionPlayer player = registerTestTransitionPlayer();
 
         mDisplayContent.getDisplayRotation().setRotation(mDisplayContent.getRotation() + 1);
+        mDisplayContent.setLastHasContent();
         mDisplayContent.requestChangeTransitionIfNeeded(1 /* any changes */,
                 null /* displayChange */);
         final FadeRotationAnimationController fadeController =
@@ -536,6 +537,7 @@
                 null /* remoteTransition */, null /* displayChange */);
         mDisplayContent.getDisplayRotation().setRotation(mDisplayContent.getRotation() + 1);
         final int anyChanges = 1;
+        mDisplayContent.setLastHasContent();
         mDisplayContent.requestChangeTransitionIfNeeded(anyChanges, null /* displayChange */);
         transition.setKnownConfigChanges(mDisplayContent, anyChanges);
         final FadeRotationAnimationController fadeController =
@@ -550,9 +552,11 @@
         assertTrue(app.getTask().inTransition());
 
         final SurfaceControl.Transaction startTransaction = mock(SurfaceControl.Transaction.class);
+        final SurfaceControl leash = statusBar.mToken.getAnimationLeash();
+        doReturn(true).when(leash).isValid();
         player.onTransactionReady(startTransaction);
         // The leash should be unrotated.
-        verify(startTransaction).setMatrix(eq(statusBar.mToken.getAnimationLeash()), any(), any());
+        verify(startTransaction).setMatrix(eq(leash), any(), any());
 
         // The redrawn window will be faded in when the transition finishes. And because this test
         // only use one non-activity window, the fade rotation controller should also be cleared.
diff --git a/telecomm/java/android/telecom/CallAudioState.java b/telecomm/java/android/telecom/CallAudioState.java
index 389df80..55957bd 100644
--- a/telecomm/java/android/telecom/CallAudioState.java
+++ b/telecomm/java/android/telecom/CallAudioState.java
@@ -259,10 +259,10 @@
             int route = source.readInt();
             int supportedRouteMask = source.readInt();
             BluetoothDevice activeBluetoothDevice = source.readParcelable(
-                    ClassLoader.getSystemClassLoader(), android.bluetooth.BluetoothDevice.class);
+                    ClassLoader.getSystemClassLoader());
             List<BluetoothDevice> supportedBluetoothDevices = new ArrayList<>();
             source.readParcelableList(supportedBluetoothDevices,
-                    ClassLoader.getSystemClassLoader(), android.bluetooth.BluetoothDevice.class);
+                    ClassLoader.getSystemClassLoader());
             return new CallAudioState(isMuted, route,
                     supportedRouteMask, activeBluetoothDevice, supportedBluetoothDevices);
         }
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 30d4959..d63cdc0 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -3546,9 +3546,9 @@
             mIsBlocked = in.readByte() != 0;
             mIsInContacts = in.readByte() != 0;
             CallScreeningService.ParcelableCallResponse response
-                    = in.readParcelable(CallScreeningService.class.getClassLoader(), android.telecom.CallScreeningService.ParcelableCallResponse.class);
+                    = in.readParcelable(CallScreeningService.class.getClassLoader());
             mCallResponse = response == null ? null : response.toCallResponse();
-            mCallScreeningComponent = in.readParcelable(ComponentName.class.getClassLoader(), android.content.ComponentName.class);
+            mCallScreeningComponent = in.readParcelable(ComponentName.class.getClassLoader());
         }
 
         @NonNull
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index 1172e13..be5fae4 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -272,17 +272,17 @@
     }
 
     private ConnectionRequest(Parcel in) {
-        mAccountHandle = in.readParcelable(getClass().getClassLoader(), android.telecom.PhoneAccountHandle.class);
-        mAddress = in.readParcelable(getClass().getClassLoader(), android.net.Uri.class);
-        mExtras = in.readParcelable(getClass().getClassLoader(), android.os.Bundle.class);
+        mAccountHandle = in.readParcelable(getClass().getClassLoader());
+        mAddress = in.readParcelable(getClass().getClassLoader());
+        mExtras = in.readParcelable(getClass().getClassLoader());
         mVideoState = in.readInt();
         mTelecomCallId = in.readString();
         mShouldShowIncomingCallUi = in.readInt() == 1;
-        mRttPipeFromInCall = in.readParcelable(getClass().getClassLoader(), android.os.ParcelFileDescriptor.class);
-        mRttPipeToInCall = in.readParcelable(getClass().getClassLoader(), android.os.ParcelFileDescriptor.class);
+        mRttPipeFromInCall = in.readParcelable(getClass().getClassLoader());
+        mRttPipeToInCall = in.readParcelable(getClass().getClassLoader());
 
         mParticipants = new ArrayList<Uri>();
-        in.readList(mParticipants, getClass().getClassLoader(), android.net.Uri.class);
+        in.readList(mParticipants, getClass().getClassLoader());
 
         mIsAdhocConference = in.readInt() == 1;
     }
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index 0f034ad..ed7b79f 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -287,7 +287,7 @@
             int tone = source.readInt();
             int telephonyDisconnectCause = source.readInt();
             int telephonyPreciseDisconnectCause = source.readInt();
-            ImsReasonInfo imsReasonInfo = source.readParcelable(null, android.telephony.ims.ImsReasonInfo.class);
+            ImsReasonInfo imsReasonInfo = source.readParcelable(null);
             return new DisconnectCause(code, label, description, reason, tone,
                     telephonyDisconnectCause, telephonyPreciseDisconnectCause, imsReasonInfo);
         }
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index f412a18..320308c 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -623,9 +623,9 @@
             ClassLoader classLoader = ParcelableCall.class.getClassLoader();
             String id = source.readString();
             int state = source.readInt();
-            DisconnectCause disconnectCause = source.readParcelable(classLoader, android.telecom.DisconnectCause.class);
+            DisconnectCause disconnectCause = source.readParcelable(classLoader);
             List<String> cannedSmsResponses = new ArrayList<>();
-            source.readList(cannedSmsResponses, classLoader, java.lang.String.class);
+            source.readList(cannedSmsResponses, classLoader);
             int capabilities = source.readInt();
             int properties = source.readInt();
             long connectTimeMillis = source.readLong();
@@ -633,23 +633,23 @@
             int handlePresentation = source.readInt();
             String callerDisplayName = source.readString();
             int callerDisplayNamePresentation = source.readInt();
-            GatewayInfo gatewayInfo = source.readParcelable(classLoader, android.telecom.GatewayInfo.class);
-            PhoneAccountHandle accountHandle = source.readParcelable(classLoader, android.telecom.PhoneAccountHandle.class);
+            GatewayInfo gatewayInfo = source.readParcelable(classLoader);
+            PhoneAccountHandle accountHandle = source.readParcelable(classLoader);
             boolean isVideoCallProviderChanged = source.readByte() == 1;
             IVideoProvider videoCallProvider =
                     IVideoProvider.Stub.asInterface(source.readStrongBinder());
             String parentCallId = source.readString();
             List<String> childCallIds = new ArrayList<>();
-            source.readList(childCallIds, classLoader, java.lang.String.class);
-            StatusHints statusHints = source.readParcelable(classLoader, android.telecom.StatusHints.class);
+            source.readList(childCallIds, classLoader);
+            StatusHints statusHints = source.readParcelable(classLoader);
             int videoState = source.readInt();
             List<String> conferenceableCallIds = new ArrayList<>();
-            source.readList(conferenceableCallIds, classLoader, java.lang.String.class);
+            source.readList(conferenceableCallIds, classLoader);
             Bundle intentExtras = source.readBundle(classLoader);
             Bundle extras = source.readBundle(classLoader);
             int supportedAudioRoutes = source.readInt();
             boolean isRttCallChanged = source.readByte() == 1;
-            ParcelableRttCall rttCall = source.readParcelable(classLoader, android.telecom.ParcelableRttCall.class);
+            ParcelableRttCall rttCall = source.readParcelable(classLoader);
             long creationTimeMillis = source.readLong();
             int callDirection = source.readInt();
             int callerNumberVerificationStatus = source.readInt();
diff --git a/telecomm/java/android/telecom/ParcelableConference.java b/telecomm/java/android/telecom/ParcelableConference.java
index e57c833..1f8aafb 100644
--- a/telecomm/java/android/telecom/ParcelableConference.java
+++ b/telecomm/java/android/telecom/ParcelableConference.java
@@ -292,24 +292,24 @@
         @Override
         public ParcelableConference createFromParcel(Parcel source) {
             ClassLoader classLoader = ParcelableConference.class.getClassLoader();
-            PhoneAccountHandle phoneAccount = source.readParcelable(classLoader, android.telecom.PhoneAccountHandle.class);
+            PhoneAccountHandle phoneAccount = source.readParcelable(classLoader);
             int state = source.readInt();
             int capabilities = source.readInt();
             List<String> connectionIds = new ArrayList<>(2);
-            source.readList(connectionIds, classLoader, java.lang.String.class);
+            source.readList(connectionIds, classLoader);
             long connectTimeMillis = source.readLong();
             IVideoProvider videoCallProvider =
                     IVideoProvider.Stub.asInterface(source.readStrongBinder());
             int videoState = source.readInt();
-            StatusHints statusHints = source.readParcelable(classLoader, android.telecom.StatusHints.class);
+            StatusHints statusHints = source.readParcelable(classLoader);
             Bundle extras = source.readBundle(classLoader);
             int properties = source.readInt();
             long connectElapsedTimeMillis = source.readLong();
-            Uri address = source.readParcelable(classLoader, android.net.Uri.class);
+            Uri address = source.readParcelable(classLoader);
             int addressPresentation = source.readInt();
             String callerDisplayName = source.readString();
             int callerDisplayNamePresentation = source.readInt();
-            DisconnectCause disconnectCause = source.readParcelable(classLoader, android.telecom.DisconnectCause.class);
+            DisconnectCause disconnectCause = source.readParcelable(classLoader);
             boolean isRingbackRequested = source.readInt() == 1;
             int callDirection = source.readInt();
 
diff --git a/telecomm/java/android/telecom/ParcelableConnection.java b/telecomm/java/android/telecom/ParcelableConnection.java
index 7b83338..2b9ce9b 100644
--- a/telecomm/java/android/telecom/ParcelableConnection.java
+++ b/telecomm/java/android/telecom/ParcelableConnection.java
@@ -261,10 +261,10 @@
         public ParcelableConnection createFromParcel(Parcel source) {
             ClassLoader classLoader = ParcelableConnection.class.getClassLoader();
 
-            PhoneAccountHandle phoneAccount = source.readParcelable(classLoader, android.telecom.PhoneAccountHandle.class);
+            PhoneAccountHandle phoneAccount = source.readParcelable(classLoader);
             int state = source.readInt();
             int capabilities = source.readInt();
-            Uri address = source.readParcelable(classLoader, android.net.Uri.class);
+            Uri address = source.readParcelable(classLoader);
             int addressPresentation = source.readInt();
             String callerDisplayName = source.readString();
             int callerDisplayNamePresentation = source.readInt();
@@ -274,8 +274,8 @@
             boolean ringbackRequested = source.readByte() == 1;
             boolean audioModeIsVoip = source.readByte() == 1;
             long connectTimeMillis = source.readLong();
-            StatusHints statusHints = source.readParcelable(classLoader, android.telecom.StatusHints.class);
-            DisconnectCause disconnectCause = source.readParcelable(classLoader, android.telecom.DisconnectCause.class);
+            StatusHints statusHints = source.readParcelable(classLoader);
+            DisconnectCause disconnectCause = source.readParcelable(classLoader);
             List<String> conferenceableConnectionIds = new ArrayList<>();
             source.readStringList(conferenceableConnectionIds);
             Bundle extras = Bundle.setDefusable(source.readBundle(classLoader), true);
diff --git a/telecomm/java/android/telecom/ParcelableRttCall.java b/telecomm/java/android/telecom/ParcelableRttCall.java
index b88473a..fbcf486 100644
--- a/telecomm/java/android/telecom/ParcelableRttCall.java
+++ b/telecomm/java/android/telecom/ParcelableRttCall.java
@@ -46,8 +46,8 @@
 
     protected ParcelableRttCall(Parcel in) {
         mRttMode = in.readInt();
-        mTransmitStream = in.readParcelable(ParcelFileDescriptor.class.getClassLoader(), android.os.ParcelFileDescriptor.class);
-        mReceiveStream = in.readParcelable(ParcelFileDescriptor.class.getClassLoader(), android.os.ParcelFileDescriptor.class);
+        mTransmitStream = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
+        mReceiveStream = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
     }
 
     public static final @android.annotation.NonNull Creator<ParcelableRttCall> CREATOR = new Creator<ParcelableRttCall>() {
diff --git a/telecomm/java/android/telecom/PhoneAccountSuggestion.java b/telecomm/java/android/telecom/PhoneAccountSuggestion.java
index d9f89d5..2589d95 100644
--- a/telecomm/java/android/telecom/PhoneAccountSuggestion.java
+++ b/telecomm/java/android/telecom/PhoneAccountSuggestion.java
@@ -84,7 +84,7 @@
     }
 
     private PhoneAccountSuggestion(Parcel in) {
-        mHandle = in.readParcelable(PhoneAccountHandle.class.getClassLoader(), android.telecom.PhoneAccountHandle.class);
+        mHandle = in.readParcelable(PhoneAccountHandle.class.getClassLoader());
         mReason = in.readInt();
         mShouldAutoSelect = in.readByte() != 0;
     }
diff --git a/telecomm/java/android/telecom/StatusHints.java b/telecomm/java/android/telecom/StatusHints.java
index 2faecc2..762c93a 100644
--- a/telecomm/java/android/telecom/StatusHints.java
+++ b/telecomm/java/android/telecom/StatusHints.java
@@ -132,8 +132,8 @@
 
     private StatusHints(Parcel in) {
         mLabel = in.readCharSequence();
-        mIcon = in.readParcelable(getClass().getClassLoader(), android.graphics.drawable.Icon.class);
-        mExtras = in.readParcelable(getClass().getClassLoader(), android.os.Bundle.class);
+        mIcon = in.readParcelable(getClass().getClassLoader());
+        mExtras = in.readParcelable(getClass().getClassLoader());
     }
 
     @Override
diff --git a/telephony/java/android/telephony/AvailableNetworkInfo.java b/telephony/java/android/telephony/AvailableNetworkInfo.java
index 6d673fb..2b355ae 100644
--- a/telephony/java/android/telephony/AvailableNetworkInfo.java
+++ b/telephony/java/android/telephony/AvailableNetworkInfo.java
@@ -185,9 +185,9 @@
         mMccMncs = new ArrayList<>();
         in.readStringList(mMccMncs);
         mBands = new ArrayList<>();
-        in.readList(mBands, Integer.class.getClassLoader(), java.lang.Integer.class);
+        in.readList(mBands, Integer.class.getClassLoader());
         mRadioAccessSpecifiers = new ArrayList<>();
-        in.readList(mRadioAccessSpecifiers, RadioAccessSpecifier.class.getClassLoader(), android.telephony.RadioAccessSpecifier.class);
+        in.readList(mRadioAccessSpecifiers, RadioAccessSpecifier.class.getClassLoader());
     }
 
     public AvailableNetworkInfo(int subId, int priority, @NonNull List<String> mccMncs,
diff --git a/telephony/java/android/telephony/BarringInfo.java b/telephony/java/android/telephony/BarringInfo.java
index 29152f1..0aa4b58 100644
--- a/telephony/java/android/telephony/BarringInfo.java
+++ b/telephony/java/android/telephony/BarringInfo.java
@@ -294,8 +294,8 @@
 
     /** @hide */
     public BarringInfo(Parcel p) {
-        mCellIdentity = p.readParcelable(CellIdentity.class.getClassLoader(), android.telephony.CellIdentity.class);
-        mBarringServiceInfos = p.readSparseArray(BarringServiceInfo.class.getClassLoader(), android.telephony.BarringInfo.BarringServiceInfo.class);
+        mCellIdentity = p.readParcelable(CellIdentity.class.getClassLoader());
+        mBarringServiceInfos = p.readSparseArray(BarringServiceInfo.class.getClassLoader());
     }
 
     @Override
diff --git a/telephony/java/android/telephony/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java
index b7bef39..0c258f4 100644
--- a/telephony/java/android/telephony/CallAttributes.java
+++ b/telephony/java/android/telephony/CallAttributes.java
@@ -53,9 +53,9 @@
     }
 
     private CallAttributes(Parcel in) {
-        this.mPreciseCallState = in.readParcelable(PreciseCallState.class.getClassLoader(), android.telephony.PreciseCallState.class);
+        this.mPreciseCallState = in.readParcelable(PreciseCallState.class.getClassLoader());
         this.mNetworkType = in.readInt();
-        this.mCallQuality = in.readParcelable(CallQuality.class.getClassLoader(), android.telephony.CallQuality.class);
+        this.mCallQuality = in.readParcelable(CallQuality.class.getClassLoader());
     }
 
     // getters
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index b4b8aee..4db00cf 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -379,7 +379,7 @@
         mBands = in.createIntArray();
         mBandwidth = in.readInt();
         mAdditionalPlmns = (ArraySet<String>) in.readArraySet(null);
-        mCsgInfo = in.readParcelable(null, android.telephony.ClosedSubscriberGroupInfo.class);
+        mCsgInfo = in.readParcelable(null);
 
         updateGlobalCellId();
         if (DBG) log(toString());
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index 90e6295..13d9373 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -297,7 +297,7 @@
         mCpid = in.readInt();
         mUarfcn = in.readInt();
         mAdditionalPlmns = (ArraySet<String>) in.readArraySet(null);
-        mCsgInfo = in.readParcelable(null, android.telephony.ClosedSubscriberGroupInfo.class);
+        mCsgInfo = in.readParcelable(null);
 
         updateGlobalCellId();
         if (DBG) log(toString());
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 72282cd..9b463da 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -313,7 +313,7 @@
         mPsc = in.readInt();
         mUarfcn = in.readInt();
         mAdditionalPlmns = (ArraySet<String>) in.readArraySet(null);
-        mCsgInfo = in.readParcelable(null, android.telephony.ClosedSubscriberGroupInfo.class);
+        mCsgInfo = in.readParcelable(null);
 
         updateGlobalCellId();
         if (DBG) log(toString());
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index f5ba3ab..cd22abd 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -326,7 +326,7 @@
         mCsiRsrq = in.readInt();
         mCsiSinr = in.readInt();
         mCsiCqiTableIndex = in.readInt();
-        mCsiCqiReport = in.readArrayList(Integer.class.getClassLoader(), java.lang.Integer.class);
+        mCsiCqiReport = in.readArrayList(Integer.class.getClassLoader());
         mSsRsrp = in.readInt();
         mSsRsrq = in.readInt();
         mSsSinr = in.readInt();
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
index 837124f..957f683 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
@@ -105,7 +105,7 @@
         isDcNrRestricted = source.readBoolean();
         isNrAvailable = source.readBoolean();
         isEnDcAvailable = source.readBoolean();
-        mVopsSupportInfo = source.readParcelable(VopsSupportInfo.class.getClassLoader(), android.telephony.VopsSupportInfo.class);
+        mVopsSupportInfo = source.readParcelable(VopsSupportInfo.class.getClassLoader());
     }
 
     @Override
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index c18443e..6a80766 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -311,12 +311,12 @@
         mRejectCause = source.readInt();
         mEmergencyOnly = source.readBoolean();
         mAvailableServices = new ArrayList<>();
-        source.readList(mAvailableServices, Integer.class.getClassLoader(), java.lang.Integer.class);
-        mCellIdentity = source.readParcelable(CellIdentity.class.getClassLoader(), android.telephony.CellIdentity.class);
+        source.readList(mAvailableServices, Integer.class.getClassLoader());
+        mCellIdentity = source.readParcelable(CellIdentity.class.getClassLoader());
         mVoiceSpecificInfo = source.readParcelable(
-                VoiceSpecificRegistrationInfo.class.getClassLoader(), android.telephony.VoiceSpecificRegistrationInfo.class);
+                VoiceSpecificRegistrationInfo.class.getClassLoader());
         mDataSpecificInfo = source.readParcelable(
-                DataSpecificRegistrationInfo.class.getClassLoader(), android.telephony.DataSpecificRegistrationInfo.class);
+                DataSpecificRegistrationInfo.class.getClassLoader());
         mNrState = source.readInt();
         mRplmn = source.readString();
         mIsUsingCarrierAggregation = source.readBoolean();
diff --git a/telephony/java/android/telephony/PhoneCapability.java b/telephony/java/android/telephony/PhoneCapability.java
index 63e3468..a3aaf61 100644
--- a/telephony/java/android/telephony/PhoneCapability.java
+++ b/telephony/java/android/telephony/PhoneCapability.java
@@ -150,7 +150,7 @@
         mMaxActiveDataSubscriptions = in.readInt();
         mNetworkValidationBeforeSwitchSupported = in.readBoolean();
         mLogicalModemList = new ArrayList<>();
-        in.readList(mLogicalModemList, ModemInfo.class.getClassLoader(), android.telephony.ModemInfo.class);
+        in.readList(mLogicalModemList, ModemInfo.class.getClassLoader());
         mDeviceNrCapabilities = in.createIntArray();
     }
 
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index 2670b03..ce2f3f9 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -125,9 +125,9 @@
         mId = in.readInt();
         mState = in.readInt();
         mNetworkType = in.readInt();
-        mLinkProperties = in.readParcelable(LinkProperties.class.getClassLoader(), android.net.LinkProperties.class);
+        mLinkProperties = in.readParcelable(LinkProperties.class.getClassLoader());
         mFailCause = in.readInt();
-        mApnSetting = in.readParcelable(ApnSetting.class.getClassLoader(), android.telephony.data.ApnSetting.class);
+        mApnSetting = in.readParcelable(ApnSetting.class.getClassLoader());
     }
 
     /**
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 70da9b9..5affb62 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -479,7 +479,7 @@
         mIsEmergencyOnly = in.readInt() != 0;
         mArfcnRsrpBoost = in.readInt();
         synchronized (mNetworkRegistrationInfos) {
-            in.readList(mNetworkRegistrationInfos, NetworkRegistrationInfo.class.getClassLoader(), android.telephony.NetworkRegistrationInfo.class);
+            in.readList(mNetworkRegistrationInfos, NetworkRegistrationInfo.class.getClassLoader());
         }
         mChannelNumber = in.readInt();
         mCellBandwidths = in.createIntArray();
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index f74ef0f..b7bc467 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -275,12 +275,12 @@
     public SignalStrength(Parcel in) {
         if (DBG) log("Size of signalstrength parcel:" + in.dataSize());
 
-        mCdma = in.readParcelable(CellSignalStrengthCdma.class.getClassLoader(), android.telephony.CellSignalStrengthCdma.class);
-        mGsm = in.readParcelable(CellSignalStrengthGsm.class.getClassLoader(), android.telephony.CellSignalStrengthGsm.class);
-        mWcdma = in.readParcelable(CellSignalStrengthWcdma.class.getClassLoader(), android.telephony.CellSignalStrengthWcdma.class);
-        mTdscdma = in.readParcelable(CellSignalStrengthTdscdma.class.getClassLoader(), android.telephony.CellSignalStrengthTdscdma.class);
-        mLte = in.readParcelable(CellSignalStrengthLte.class.getClassLoader(), android.telephony.CellSignalStrengthLte.class);
-        mNr = in.readParcelable(CellSignalStrengthLte.class.getClassLoader(), android.telephony.CellSignalStrengthNr.class);
+        mCdma = in.readParcelable(CellSignalStrengthCdma.class.getClassLoader());
+        mGsm = in.readParcelable(CellSignalStrengthGsm.class.getClassLoader());
+        mWcdma = in.readParcelable(CellSignalStrengthWcdma.class.getClassLoader());
+        mTdscdma = in.readParcelable(CellSignalStrengthTdscdma.class.getClassLoader());
+        mLte = in.readParcelable(CellSignalStrengthLte.class.getClassLoader());
+        mNr = in.readParcelable(CellSignalStrengthLte.class.getClassLoader());
         mTimestampMillis = in.readLong();
     }
 
diff --git a/telephony/java/android/telephony/ThermalMitigationRequest.java b/telephony/java/android/telephony/ThermalMitigationRequest.java
index a0676ea..91ad9c3 100644
--- a/telephony/java/android/telephony/ThermalMitigationRequest.java
+++ b/telephony/java/android/telephony/ThermalMitigationRequest.java
@@ -100,7 +100,7 @@
 
     private ThermalMitigationRequest(Parcel in) {
         mThermalMitigationAction = in.readInt();
-        mDataThrottlingRequest = in.readParcelable(DataThrottlingRequest.class.getClassLoader(), android.telephony.DataThrottlingRequest.class);
+        mDataThrottlingRequest = in.readParcelable(DataThrottlingRequest.class.getClassLoader());
     }
 
      /**
diff --git a/telephony/java/android/telephony/VisualVoicemailSms.java b/telephony/java/android/telephony/VisualVoicemailSms.java
index bec715e..085f882 100644
--- a/telephony/java/android/telephony/VisualVoicemailSms.java
+++ b/telephony/java/android/telephony/VisualVoicemailSms.java
@@ -121,7 +121,7 @@
                 @Override
                 public VisualVoicemailSms createFromParcel(Parcel in) {
                     return new Builder()
-                            .setPhoneAccountHandle((PhoneAccountHandle) in.readParcelable(null, android.telecom.PhoneAccountHandle.class))
+                            .setPhoneAccountHandle((PhoneAccountHandle) in.readParcelable(null))
                             .setPrefix(in.readString())
                             .setFields(in.readBundle())
                             .setMessageBody(in.readString())
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 4ff59b5..977fe33 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1629,7 +1629,7 @@
                 .setApnName(in.readString())
                 .setProxyAddress(in.readString())
                 .setProxyPort(in.readInt())
-                .setMmsc(in.readParcelable(Uri.class.getClassLoader(), android.net.Uri.class))
+                .setMmsc(in.readParcelable(Uri.class.getClassLoader()))
                 .setMmsProxyAddress(in.readString())
                 .setMmsProxyPort(in.readInt())
                 .setUser(in.readString())
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index ae0d4e7..ef02589 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -241,24 +241,24 @@
         mProtocolType = source.readInt();
         mInterfaceName = source.readString();
         mAddresses = new ArrayList<>();
-        source.readList(mAddresses, LinkAddress.class.getClassLoader(), android.net.LinkAddress.class);
+        source.readList(mAddresses, LinkAddress.class.getClassLoader());
         mDnsAddresses = new ArrayList<>();
-        source.readList(mDnsAddresses, InetAddress.class.getClassLoader(), java.net.InetAddress.class);
+        source.readList(mDnsAddresses, InetAddress.class.getClassLoader());
         mGatewayAddresses = new ArrayList<>();
-        source.readList(mGatewayAddresses, InetAddress.class.getClassLoader(), java.net.InetAddress.class);
+        source.readList(mGatewayAddresses, InetAddress.class.getClassLoader());
         mPcscfAddresses = new ArrayList<>();
-        source.readList(mPcscfAddresses, InetAddress.class.getClassLoader(), java.net.InetAddress.class);
+        source.readList(mPcscfAddresses, InetAddress.class.getClassLoader());
         mMtu = source.readInt();
         mMtuV4 = source.readInt();
         mMtuV6 = source.readInt();
         mHandoverFailureMode = source.readInt();
         mPduSessionId = source.readInt();
-        mDefaultQos = source.readParcelable(Qos.class.getClassLoader(), android.telephony.data.Qos.class);
+        mDefaultQos = source.readParcelable(Qos.class.getClassLoader());
         mQosBearerSessions = new ArrayList<>();
-        source.readList(mQosBearerSessions, QosBearerSession.class.getClassLoader(), android.telephony.data.QosBearerSession.class);
-        mSliceInfo = source.readParcelable(NetworkSliceInfo.class.getClassLoader(), android.telephony.data.NetworkSliceInfo.class);
+        source.readList(mQosBearerSessions, QosBearerSession.class.getClassLoader());
+        mSliceInfo = source.readParcelable(NetworkSliceInfo.class.getClassLoader());
         mTrafficDescriptors = new ArrayList<>();
-        source.readList(mTrafficDescriptors, TrafficDescriptor.class.getClassLoader(), android.telephony.data.TrafficDescriptor.class);
+        source.readList(mTrafficDescriptors, TrafficDescriptor.class.getClassLoader());
     }
 
     /**
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index a166a5d..ec04c1a 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -107,8 +107,8 @@
 
     private DataProfile(Parcel source) {
         mType = source.readInt();
-        mApnSetting = source.readParcelable(ApnSetting.class.getClassLoader(), android.telephony.data.ApnSetting.class);
-        mTrafficDescriptor = source.readParcelable(TrafficDescriptor.class.getClassLoader(), android.telephony.data.TrafficDescriptor.class);
+        mApnSetting = source.readParcelable(ApnSetting.class.getClassLoader());
+        mTrafficDescriptor = source.readParcelable(TrafficDescriptor.class.getClassLoader());
         mPreferred = source.readBoolean();
         mSetupTimestamp = source.readLong();
     }
diff --git a/telephony/java/android/telephony/data/Qos.java b/telephony/java/android/telephony/data/Qos.java
index 9c2a3bb..8c437c8 100644
--- a/telephony/java/android/telephony/data/Qos.java
+++ b/telephony/java/android/telephony/data/Qos.java
@@ -136,8 +136,8 @@
 
     protected Qos(@NonNull Parcel source) {
         type = source.readInt();
-        downlink = source.readParcelable(QosBandwidth.class.getClassLoader(), android.telephony.data.Qos.QosBandwidth.class);
-        uplink = source.readParcelable(QosBandwidth.class.getClassLoader(), android.telephony.data.Qos.QosBandwidth.class);
+        downlink = source.readParcelable(QosBandwidth.class.getClassLoader());
+        uplink = source.readParcelable(QosBandwidth.class.getClassLoader());
     }
 
     /**
diff --git a/telephony/java/android/telephony/data/QosBearerFilter.java b/telephony/java/android/telephony/data/QosBearerFilter.java
index 0ab7b61..d6f0cb0 100644
--- a/telephony/java/android/telephony/data/QosBearerFilter.java
+++ b/telephony/java/android/telephony/data/QosBearerFilter.java
@@ -256,11 +256,11 @@
 
     private QosBearerFilter(Parcel source) {
         localAddresses = new ArrayList<>();
-        source.readList(localAddresses, LinkAddress.class.getClassLoader(), android.net.LinkAddress.class);
+        source.readList(localAddresses, LinkAddress.class.getClassLoader());
         remoteAddresses = new ArrayList<>();
-        source.readList(remoteAddresses, LinkAddress.class.getClassLoader(), android.net.LinkAddress.class);
-        localPort = source.readParcelable(PortRange.class.getClassLoader(), android.telephony.data.QosBearerFilter.PortRange.class);
-        remotePort = source.readParcelable(PortRange.class.getClassLoader(), android.telephony.data.QosBearerFilter.PortRange.class);
+        source.readList(remoteAddresses, LinkAddress.class.getClassLoader());
+        localPort = source.readParcelable(PortRange.class.getClassLoader());
+        remotePort = source.readParcelable(PortRange.class.getClassLoader());
         protocol = source.readInt();
         typeOfServiceMask = source.readInt();
         flowLabel = source.readLong();
diff --git a/telephony/java/android/telephony/data/QosBearerSession.java b/telephony/java/android/telephony/data/QosBearerSession.java
index dd08085..ffeb08a 100644
--- a/telephony/java/android/telephony/data/QosBearerSession.java
+++ b/telephony/java/android/telephony/data/QosBearerSession.java
@@ -46,9 +46,9 @@
 
     private QosBearerSession(Parcel source) {
         qosBearerSessionId = source.readInt();
-        qos = source.readParcelable(Qos.class.getClassLoader(), android.telephony.data.Qos.class);
+        qos = source.readParcelable(Qos.class.getClassLoader());
         qosBearerFilterList = new ArrayList<>();
-        source.readList(qosBearerFilterList, QosBearerFilter.class.getClassLoader(), android.telephony.data.QosBearerFilter.class);
+        source.readList(qosBearerFilterList, QosBearerFilter.class.getClassLoader());
     }
 
     public int getQosBearerSessionId() {
diff --git a/telephony/java/android/telephony/gba/GbaAuthRequest.java b/telephony/java/android/telephony/gba/GbaAuthRequest.java
index 2c6021a..5366e9a 100644
--- a/telephony/java/android/telephony/gba/GbaAuthRequest.java
+++ b/telephony/java/android/telephony/gba/GbaAuthRequest.java
@@ -120,7 +120,7 @@
                     int token = in.readInt();
                     int subId = in.readInt();
                     int appType = in.readInt();
-                    Uri nafUrl = in.readParcelable(GbaAuthRequest.class.getClassLoader(), android.net.Uri.class);
+                    Uri nafUrl = in.readParcelable(GbaAuthRequest.class.getClassLoader());
                     int len = in.readInt();
                     byte[] protocol = new byte[len];
                     in.readByteArray(protocol);
diff --git a/telephony/java/android/telephony/ims/DelegateRequest.java b/telephony/java/android/telephony/ims/DelegateRequest.java
index c5c9200..c322d92 100644
--- a/telephony/java/android/telephony/ims/DelegateRequest.java
+++ b/telephony/java/android/telephony/ims/DelegateRequest.java
@@ -63,7 +63,7 @@
      */
     private DelegateRequest(Parcel in) {
         mFeatureTags = new ArrayList<>();
-        in.readList(mFeatureTags, null /*classLoader*/, java.lang.String.class);
+        in.readList(mFeatureTags, null /*classLoader*/);
     }
 
     @Override
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index e6d7df3..8a665dc 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -843,7 +843,7 @@
         mServiceType = in.readInt();
         mCallType = in.readInt();
         mCallExtras = in.readBundle();
-        mMediaProfile = in.readParcelable(ImsStreamMediaProfile.class.getClassLoader(), android.telephony.ims.ImsStreamMediaProfile.class);
+        mMediaProfile = in.readParcelable(ImsStreamMediaProfile.class.getClassLoader());
         mEmergencyServiceCategories = in.readInt();
         mEmergencyUrns = in.createStringArrayList();
         mEmergencyCallRouting = in.readInt();
diff --git a/telephony/java/android/telephony/ims/ImsConferenceState.java b/telephony/java/android/telephony/ims/ImsConferenceState.java
index d4d8c44..1fa5f52 100644
--- a/telephony/java/android/telephony/ims/ImsConferenceState.java
+++ b/telephony/java/android/telephony/ims/ImsConferenceState.java
@@ -133,7 +133,7 @@
 
         for (int i = 0; i < size; ++i) {
             String user = in.readString();
-            Bundle state = in.readParcelable(null, android.os.Bundle.class);
+            Bundle state = in.readParcelable(null);
             mParticipants.put(user, state);
         }
     }
diff --git a/telephony/java/android/telephony/ims/ImsExternalCallState.java b/telephony/java/android/telephony/ims/ImsExternalCallState.java
index d451107..c663e39 100644
--- a/telephony/java/android/telephony/ims/ImsExternalCallState.java
+++ b/telephony/java/android/telephony/ims/ImsExternalCallState.java
@@ -141,8 +141,8 @@
     public ImsExternalCallState(Parcel in) {
         mCallId = in.readInt();
         ClassLoader classLoader = ImsExternalCallState.class.getClassLoader();
-        mAddress = in.readParcelable(classLoader, android.net.Uri.class);
-        mLocalAddress = in.readParcelable(classLoader, android.net.Uri.class);
+        mAddress = in.readParcelable(classLoader);
+        mLocalAddress = in.readParcelable(classLoader);
         mIsPullable = (in.readInt() != 0);
         mCallState = in.readInt();
         mCallType = in.readInt();
diff --git a/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java b/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java
index b77d306..ccb3231 100644
--- a/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java
+++ b/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java
@@ -153,7 +153,7 @@
         mTransportType = source.readInt();
         mImsAttributeFlags = source.readInt();
         mFeatureTags = new ArrayList<>();
-        source.readList(mFeatureTags, null /*classloader*/, java.lang.String.class);
+        source.readList(mFeatureTags, null /*classloader*/);
     }
 
     /**
diff --git a/telephony/java/android/telephony/ims/ImsSsData.java b/telephony/java/android/telephony/ims/ImsSsData.java
index 9f4b77e..868dea6a 100644
--- a/telephony/java/android/telephony/ims/ImsSsData.java
+++ b/telephony/java/android/telephony/ims/ImsSsData.java
@@ -365,8 +365,8 @@
         serviceClass = in.readInt();
         result = in.readInt();
         mSsInfo = in.createIntArray();
-        mCfInfo = in.readParcelableList(new ArrayList<>(), this.getClass().getClassLoader(), android.telephony.ims.ImsCallForwardInfo.class);
-        mImsSsInfo = in.readParcelableList(new ArrayList<>(), this.getClass().getClassLoader(), android.telephony.ims.ImsSsInfo.class);
+        mCfInfo = in.readParcelableList(new ArrayList<>(), this.getClass().getClassLoader());
+        mImsSsInfo = in.readParcelableList(new ArrayList<>(), this.getClass().getClassLoader());
     }
 
     public static final @android.annotation.NonNull Creator<ImsSsData> CREATOR = new Creator<ImsSsData>() {
diff --git a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
index 6a6c306..9c28c36 100644
--- a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
+++ b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
@@ -439,13 +439,13 @@
     }
 
     private RcsContactPresenceTuple(Parcel in) {
-        mContactUri = in.readParcelable(Uri.class.getClassLoader(), android.net.Uri.class);
+        mContactUri = in.readParcelable(Uri.class.getClassLoader());
         mTimestamp = convertStringFormatTimeToInstant(in.readString());
         mStatus = in.readString();
         mServiceId = in.readString();
         mServiceVersion = in.readString();
         mServiceDescription = in.readString();
-        mServiceCapabilities = in.readParcelable(ServiceCapabilities.class.getClassLoader(), android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities.class);
+        mServiceCapabilities = in.readParcelable(ServiceCapabilities.class.getClassLoader());
     }
 
     @Override
diff --git a/telephony/java/android/telephony/ims/RcsContactTerminatedReason.java b/telephony/java/android/telephony/ims/RcsContactTerminatedReason.java
index ea022de..ee02564 100644
--- a/telephony/java/android/telephony/ims/RcsContactTerminatedReason.java
+++ b/telephony/java/android/telephony/ims/RcsContactTerminatedReason.java
@@ -37,7 +37,7 @@
     }
 
     private RcsContactTerminatedReason(Parcel in) {
-        mContactUri = in.readParcelable(Uri.class.getClassLoader(), android.net.Uri.class);
+        mContactUri = in.readParcelable(Uri.class.getClassLoader());
         mReason = in.readString();
     }
 
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index 0f1b369..9112118 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -244,14 +244,14 @@
     }
 
     private RcsContactUceCapability(Parcel in) {
-        mContactUri = in.readParcelable(Uri.class.getClassLoader(), android.net.Uri.class);
+        mContactUri = in.readParcelable(Uri.class.getClassLoader());
         mCapabilityMechanism = in.readInt();
         mSourceType = in.readInt();
         mRequestResult = in.readInt();
         List<String> featureTagList = new ArrayList<>();
         in.readStringList(featureTagList);
         mFeatureTags.addAll(featureTagList);
-        in.readParcelableList(mPresenceTuples, RcsContactPresenceTuple.class.getClassLoader(), android.telephony.ims.RcsContactPresenceTuple.class);
+        in.readParcelableList(mPresenceTuples, RcsContactPresenceTuple.class.getClassLoader());
     }
 
     @Override
diff --git a/telephony/java/android/telephony/ims/RtpHeaderExtensionType.java b/telephony/java/android/telephony/ims/RtpHeaderExtensionType.java
index b9ffd24..af4e2347 100644
--- a/telephony/java/android/telephony/ims/RtpHeaderExtensionType.java
+++ b/telephony/java/android/telephony/ims/RtpHeaderExtensionType.java
@@ -63,7 +63,7 @@
 
     private RtpHeaderExtensionType(Parcel in) {
         mLocalIdentifier = in.readInt();
-        mUri = in.readParcelable(Uri.class.getClassLoader(), android.net.Uri.class);
+        mUri = in.readParcelable(Uri.class.getClassLoader());
     }
 
     public static final @NonNull Creator<RtpHeaderExtensionType> CREATOR =
diff --git a/telephony/java/android/telephony/ims/SipDelegateConfiguration.java b/telephony/java/android/telephony/ims/SipDelegateConfiguration.java
index db0ae03..1bf5cad 100644
--- a/telephony/java/android/telephony/ims/SipDelegateConfiguration.java
+++ b/telephony/java/android/telephony/ims/SipDelegateConfiguration.java
@@ -573,7 +573,7 @@
         mPrivateUserIdentifier = source.readString();
         mHomeDomain = source.readString();
         mImei = source.readString();
-        mGruu = source.readParcelable(null, android.net.Uri.class);
+        mGruu = source.readParcelable(null);
         mSipAuthHeader = source.readString();
         mSipAuthNonce = source.readString();
         mServiceRouteHeader = source.readString();
diff --git a/telephony/java/android/telephony/mbms/DownloadRequest.java b/telephony/java/android/telephony/mbms/DownloadRequest.java
index 81d5be8..eb59f87 100644
--- a/telephony/java/android/telephony/mbms/DownloadRequest.java
+++ b/telephony/java/android/telephony/mbms/DownloadRequest.java
@@ -242,8 +242,8 @@
 
     private DownloadRequest(Parcel in) {
         fileServiceId = in.readString();
-        sourceUri = in.readParcelable(getClass().getClassLoader(), android.net.Uri.class);
-        destinationUri = in.readParcelable(getClass().getClassLoader(), android.net.Uri.class);
+        sourceUri = in.readParcelable(getClass().getClassLoader());
+        destinationUri = in.readParcelable(getClass().getClassLoader());
         subscriptionId = in.readInt();
         serializedResultIntentForApp = in.readString();
         version = in.readInt();
diff --git a/telephony/java/android/telephony/mbms/FileInfo.java b/telephony/java/android/telephony/mbms/FileInfo.java
index ffd864e..e52b2ce 100644
--- a/telephony/java/android/telephony/mbms/FileInfo.java
+++ b/telephony/java/android/telephony/mbms/FileInfo.java
@@ -55,7 +55,7 @@
     }
 
     private FileInfo(Parcel in) {
-        uri = in.readParcelable(null, android.net.Uri.class);
+        uri = in.readParcelable(null);
         mimeType = in.readString();
     }
 
diff --git a/telephony/java/android/telephony/mbms/FileServiceInfo.java b/telephony/java/android/telephony/mbms/FileServiceInfo.java
index 0fc3be6..8777e7f 100644
--- a/telephony/java/android/telephony/mbms/FileServiceInfo.java
+++ b/telephony/java/android/telephony/mbms/FileServiceInfo.java
@@ -58,7 +58,7 @@
     FileServiceInfo(Parcel in) {
         super(in);
         files = new ArrayList<FileInfo>();
-        in.readList(files, FileInfo.class.getClassLoader(), android.telephony.mbms.FileInfo.class);
+        in.readList(files, FileInfo.class.getClassLoader());
     }
 
     @Override
diff --git a/telephony/java/android/telephony/mbms/ServiceInfo.java b/telephony/java/android/telephony/mbms/ServiceInfo.java
index 02424ff..f78e7a6 100644
--- a/telephony/java/android/telephony/mbms/ServiceInfo.java
+++ b/telephony/java/android/telephony/mbms/ServiceInfo.java
@@ -80,7 +80,7 @@
         }
         names = new HashMap(mapCount);
         while (mapCount-- > 0) {
-            Locale locale = (java.util.Locale) in.readSerializable(java.util.Locale.class.getClassLoader(), java.util.Locale.class);
+            Locale locale = (java.util.Locale) in.readSerializable();
             String name = in.readString();
             names.put(locale, name);
         }
@@ -91,12 +91,12 @@
         }
         locales = new ArrayList<Locale>(localesCount);
         while (localesCount-- > 0) {
-            Locale l = (java.util.Locale) in.readSerializable(java.util.Locale.class.getClassLoader(), java.util.Locale.class);
+            Locale l = (java.util.Locale) in.readSerializable();
             locales.add(l);
         }
         serviceId = in.readString();
-        sessionStartTime = (java.util.Date) in.readSerializable(java.util.Date.class.getClassLoader(), java.util.Date.class);
-        sessionEndTime = (java.util.Date) in.readSerializable(java.util.Date.class.getClassLoader(), java.util.Date.class);
+        sessionStartTime = (java.util.Date) in.readSerializable();
+        sessionEndTime = (java.util.Date) in.readSerializable();
     }
 
     /** @hide */
diff --git a/telephony/java/android/telephony/mbms/UriPathPair.java b/telephony/java/android/telephony/mbms/UriPathPair.java
index 54d9d9e..9258919 100644
--- a/telephony/java/android/telephony/mbms/UriPathPair.java
+++ b/telephony/java/android/telephony/mbms/UriPathPair.java
@@ -48,8 +48,8 @@
 
     /** @hide */
     private UriPathPair(Parcel in) {
-        mFilePathUri = in.readParcelable(Uri.class.getClassLoader(), android.net.Uri.class);
-        mContentUri = in.readParcelable(Uri.class.getClassLoader(), android.net.Uri.class);
+        mFilePathUri = in.readParcelable(Uri.class.getClassLoader());
+        mContentUri = in.readParcelable(Uri.class.getClassLoader());
     }
 
     public static final @android.annotation.NonNull Creator<UriPathPair> CREATOR = new Creator<UriPathPair>() {
diff --git a/telephony/java/com/android/internal/telephony/NetworkScanResult.java b/telephony/java/com/android/internal/telephony/NetworkScanResult.java
index 8b49f4b..d07d77c 100644
--- a/telephony/java/com/android/internal/telephony/NetworkScanResult.java
+++ b/telephony/java/com/android/internal/telephony/NetworkScanResult.java
@@ -83,7 +83,7 @@
         scanStatus = in.readInt();
         scanError = in.readInt();
         List<CellInfo> ni = new ArrayList<>();
-        in.readParcelableList(ni, Object.class.getClassLoader(), android.telephony.CellInfo.class);
+        in.readParcelableList(ni, Object.class.getClassLoader());
         networkInfos = ni;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/OperatorInfo.java b/telephony/java/com/android/internal/telephony/OperatorInfo.java
index 1820a1d..a6f0f66 100644
--- a/telephony/java/com/android/internal/telephony/OperatorInfo.java
+++ b/telephony/java/com/android/internal/telephony/OperatorInfo.java
@@ -189,7 +189,7 @@
                             in.readString(), /*operatorAlphaLong*/
                             in.readString(), /*operatorAlphaShort*/
                             in.readString(), /*operatorNumeric*/
-                            (State) in.readSerializable(com.android.internal.telephony.OperatorInfo.State.class.getClassLoader(), com.android.internal.telephony.OperatorInfo.State.class), /*state*/
+                            (State) in.readSerializable(), /*state*/
                             in.readInt()); /*ran*/
                     return opInfo;
                 }