Merge changes from topic "sc_reverts_for_b_183104573" into sc-dev

* changes:
  Revert "Correct recycling to take setViewId into account."
  Revert "Ensure the view being recycled has been inflated before."
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 2f3ac22..784c63a 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
@@ -32,7 +32,6 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
 import android.app.AppGlobals;
 import android.app.IUidObserver;
@@ -348,12 +347,20 @@
     private final SparseBooleanArray mTempAllowlistCache = new SparseBooleanArray();
 
     /**
-     * Mapping of app IDs to the when their temp allowlist grace period ends (in the elapsed
+     * Mapping of UIDs to the when their temp allowlist grace period ends (in the elapsed
      * realtime timebase).
      */
     private final SparseLongArray mTempAllowlistGraceCache = new SparseLongArray();
 
-    private final ActivityManagerInternal mActivityManagerInternal;
+    /** Current set of UIDs in the {@link ActivityManager#PROCESS_STATE_TOP} state. */
+    private final SparseBooleanArray mTopAppCache = new SparseBooleanArray();
+
+    /**
+     * Mapping of UIDs to the when their top app grace period ends (in the elapsed realtime
+     * timebase).
+     */
+    private final SparseLongArray mTopAppGraceCache = new SparseLongArray();
+
     private final AlarmManager mAlarmManager;
     private final ChargingTracker mChargeTracker;
     private final QcHandler mHandler;
@@ -412,7 +419,7 @@
                 }
             };
 
-    private final IUidObserver mUidObserver = new IUidObserver.Stub() {
+    private class QcUidObserver extends IUidObserver.Stub {
         @Override
         public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
             mHandler.obtainMessage(MSG_UID_PROCESS_STATE_CHANGED, uid, procState).sendToTarget();
@@ -433,7 +440,7 @@
         @Override
         public void onUidCachedChanged(int uid, boolean cached) {
         }
-    };
+    }
 
     private final BroadcastReceiver mPackageAddedReceiver = new BroadcastReceiver() {
         @Override
@@ -548,8 +555,10 @@
      */
     private long mEJRewardNotificationSeenMs = QcConstants.DEFAULT_EJ_REWARD_NOTIFICATION_SEEN_MS;
 
-    private long mEJTempAllowlistGracePeriodMs =
-            QcConstants.DEFAULT_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS;
+    private long mEJGracePeriodTempAllowlistMs =
+            QcConstants.DEFAULT_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS;
+
+    private long mEJGracePeriodTopAppMs = QcConstants.DEFAULT_EJ_GRACE_PERIOD_TOP_APP_MS;
 
     /** The package verifier app. */
     @Nullable
@@ -586,7 +595,6 @@
         mHandler = new QcHandler(mContext.getMainLooper());
         mChargeTracker = new ChargingTracker();
         mChargeTracker.startTracking();
-        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
         mQcConstants = new QcConstants();
         mBackgroundJobsController = backgroundJobsController;
@@ -606,9 +614,12 @@
         pai.registerTempAllowlistChangeListener(new TempAllowlistTracker());
 
         try {
-            ActivityManager.getService().registerUidObserver(mUidObserver,
+            ActivityManager.getService().registerUidObserver(new QcUidObserver(),
                     ActivityManager.UID_OBSERVER_PROCSTATE,
                     ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, null);
+            ActivityManager.getService().registerUidObserver(new QcUidObserver(),
+                    ActivityManager.UID_OBSERVER_PROCSTATE,
+                    ActivityManager.PROCESS_STATE_TOP, null);
         } catch (RemoteException e) {
             // ignored; both services live in system_server
         }
@@ -658,7 +669,7 @@
         }
 
         final int uid = jobStatus.getSourceUid();
-        if (mActivityManagerInternal.getUidProcessState(uid) <= ActivityManager.PROCESS_STATE_TOP) {
+        if (mTopAppCache.get(uid)) {
             if (DEBUG) {
                 Slog.d(TAG, jobStatus.toShortString() + " is top started job");
             }
@@ -715,6 +726,8 @@
         mUidToPackageCache.remove(uid);
         mTempAllowlistCache.delete(uid);
         mTempAllowlistGraceCache.delete(uid);
+        mTopAppCache.delete(uid);
+        mTopAppGraceCache.delete(uid);
     }
 
     @Override
@@ -770,14 +783,10 @@
 
     /** Returns the maximum amount of time this job could run for. */
     public long getMaxJobExecutionTimeMsLocked(@NonNull final JobStatus jobStatus) {
-        // Need to look at current proc state as well in the case where the job hasn't started yet.
-        final boolean isTop = mActivityManagerInternal
-                .getUidProcessState(jobStatus.getSourceUid()) <= ActivityManager.PROCESS_STATE_TOP;
-
         if (!jobStatus.shouldTreatAsExpeditedJob()) {
             // If quota is currently "free", then the job can run for the full amount of time.
             if (mChargeTracker.isCharging()
-                    || isTop
+                    || mTopAppCache.get(jobStatus.getSourceUid())
                     || isTopStartedJobLocked(jobStatus)
                     || isUidInForeground(jobStatus.getSourceUid())) {
                 return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
@@ -790,7 +799,7 @@
         if (mChargeTracker.isCharging()) {
             return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
         }
-        if (isTop || isTopStartedJobLocked(jobStatus)) {
+        if (mTopAppCache.get(jobStatus.getSourceUid()) || isTopStartedJobLocked(jobStatus)) {
             return Math.max(mEJLimitsMs[ACTIVE_INDEX] / 2,
                     getTimeUntilEJQuotaConsumedLocked(
                             jobStatus.getSourceUserId(), jobStatus.getSourcePackageName()));
@@ -817,14 +826,23 @@
         if (isTopStartedJobLocked(jobStatus) || isUidInForeground(jobStatus.getSourceUid())) {
             return true;
         }
+
+        final long nowElapsed = sElapsedRealtimeClock.millis();
         final long tempAllowlistGracePeriodEndElapsed =
                 mTempAllowlistGraceCache.get(jobStatus.getSourceUid());
         final boolean hasTempAllowlistExemption = mTempAllowlistCache.get(jobStatus.getSourceUid())
-                || sElapsedRealtimeClock.millis() < tempAllowlistGracePeriodEndElapsed;
+                || nowElapsed < tempAllowlistGracePeriodEndElapsed;
         if (hasTempAllowlistExemption) {
             return true;
         }
 
+        final long topAppGracePeriodEndElapsed = mTopAppGraceCache.get(jobStatus.getSourceUid());
+        final boolean hasTopAppExemption = mTopAppCache.get(jobStatus.getSourceUid())
+                || nowElapsed < topAppGracePeriodEndElapsed;
+        if (hasTopAppExemption) {
+            return true;
+        }
+
         Timer ejTimer = mEJPkgTimers.get(jobStatus.getSourceUserId(),
                 jobStatus.getSourcePackageName());
         // Any already executing expedited jobs should be allowed to finish.
@@ -2101,8 +2119,12 @@
             final boolean hasTempAllowlistExemption = !mRegularJobTimer
                     && (mTempAllowlistCache.get(mUid)
                     || nowElapsed < tempAllowlistGracePeriodEndElapsed);
+            final long topAppGracePeriodEndElapsed = mTopAppGraceCache.get(mUid);
+            final boolean hasTopAppExemption = !mRegularJobTimer
+                    && (mTopAppCache.get(mUid) || nowElapsed < topAppGracePeriodEndElapsed);
             return (standbyBucket == RESTRICTED_INDEX || !mChargeTracker.isCharging())
-                    && !mForegroundUids.get(mUid) && !hasTempAllowlistExemption;
+                    && !mForegroundUids.get(mUid) && !hasTempAllowlistExemption
+                    && !hasTopAppExemption;
         }
 
         void onStateChangedLocked(long nowElapsed, boolean isQuotaFree) {
@@ -2421,11 +2443,11 @@
         public void onAppRemoved(int uid) {
             synchronized (mLock) {
                 final long nowElapsed = sElapsedRealtimeClock.millis();
-                final long endElapsed = nowElapsed + mEJTempAllowlistGracePeriodMs;
+                final long endElapsed = nowElapsed + mEJGracePeriodTempAllowlistMs;
                 mTempAllowlistCache.delete(uid);
                 mTempAllowlistGraceCache.put(uid, endElapsed);
                 Message msg = mHandler.obtainMessage(MSG_END_GRACE_PERIOD, uid, 0);
-                mHandler.sendMessageDelayed(msg, mEJTempAllowlistGracePeriodMs);
+                mHandler.sendMessageDelayed(msg, mEJGracePeriodTempAllowlistMs);
             }
         }
     }
@@ -2571,12 +2593,37 @@
 
                         synchronized (mLock) {
                             boolean isQuotaFree;
-                            if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+                            if (procState <= ActivityManager.PROCESS_STATE_TOP) {
+                                mTopAppCache.put(uid, true);
+                                mTopAppGraceCache.delete(uid);
+                                if (mForegroundUids.get(uid)) {
+                                    // Went from FGS to TOP. We don't need to reprocess timers or
+                                    // jobs.
+                                    break;
+                                }
                                 mForegroundUids.put(uid, true);
                                 isQuotaFree = true;
                             } else {
-                                mForegroundUids.delete(uid);
-                                isQuotaFree = false;
+                                final boolean reprocess;
+                                if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+                                    reprocess = !mForegroundUids.get(uid);
+                                    mForegroundUids.put(uid, true);
+                                    isQuotaFree = true;
+                                } else {
+                                    reprocess = true;
+                                    mForegroundUids.delete(uid);
+                                    isQuotaFree = false;
+                                }
+                                if (mTopAppCache.get(uid)) {
+                                    final long endElapsed = nowElapsed + mEJGracePeriodTopAppMs;
+                                    mTopAppCache.delete(uid);
+                                    mTopAppGraceCache.put(uid, endElapsed);
+                                    sendMessageDelayed(obtainMessage(MSG_END_GRACE_PERIOD, uid, 0),
+                                            mEJGracePeriodTopAppMs);
+                                }
+                                if (!reprocess) {
+                                    break;
+                                }
                             }
                             // Update Timers first.
                             if (mPkgTimers.indexOfKey(userId) >= 0
@@ -2644,20 +2691,31 @@
                     case MSG_END_GRACE_PERIOD: {
                         final int uid = msg.arg1;
                         synchronized (mLock) {
-                            if (mTempAllowlistCache.get(uid)) {
-                                // App added back to the temp allowlist during the grace period.
+                            if (mTempAllowlistCache.get(uid) || mTopAppCache.get(uid)) {
+                                // App added back to the temp allowlist or became top again
+                                // during the grace period.
                                 if (DEBUG) {
                                     Slog.d(TAG, uid + " is still allowed");
                                 }
                                 break;
                             }
+                            final long nowElapsed = sElapsedRealtimeClock.millis();
+                            if (nowElapsed < mTempAllowlistGraceCache.get(uid)
+                                    || nowElapsed < mTopAppGraceCache.get(uid)) {
+                                // One of the grace periods is still in effect.
+                                if (DEBUG) {
+                                    Slog.d(TAG, uid + " is still in grace period");
+                                }
+                                break;
+                            }
                             if (DEBUG) {
                                 Slog.d(TAG, uid + " is now out of grace period");
                             }
+                            mTempAllowlistGraceCache.delete(uid);
+                            mTopAppGraceCache.delete(uid);
                             final ArraySet<String> packages = getPackagesForUidLocked(uid);
                             if (packages != null) {
                                 final int userId = UserHandle.getUserId(uid);
-                                final long nowElapsed = sElapsedRealtimeClock.millis();
                                 for (int i = packages.size() - 1; i >= 0; --i) {
                                     Timer t = mEJPkgTimers.get(userId, packages.valueAt(i));
                                     if (t != null) {
@@ -2989,8 +3047,11 @@
         static final String KEY_EJ_REWARD_NOTIFICATION_SEEN_MS =
                 QC_CONSTANT_PREFIX + "ej_reward_notification_seen_ms";
         @VisibleForTesting
-        static final String KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS =
-                QC_CONSTANT_PREFIX + "ej_temp_allowlist_grace_period_ms";
+        static final String KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS =
+                QC_CONSTANT_PREFIX + "ej_grace_period_temp_allowlist_ms";
+        @VisibleForTesting
+        static final String KEY_EJ_GRACE_PERIOD_TOP_APP_MS =
+                QC_CONSTANT_PREFIX + "ej_grace_period_top_app_ms";
 
         private static final long DEFAULT_ALLOWED_TIME_PER_PERIOD_MS =
                 10 * 60 * 1000L; // 10 minutes
@@ -3043,7 +3104,8 @@
         private static final long DEFAULT_EJ_REWARD_TOP_APP_MS = 10 * SECOND_IN_MILLIS;
         private static final long DEFAULT_EJ_REWARD_INTERACTION_MS = 15 * SECOND_IN_MILLIS;
         private static final long DEFAULT_EJ_REWARD_NOTIFICATION_SEEN_MS = 0;
-        private static final long DEFAULT_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS = 3 * MINUTE_IN_MILLIS;
+        private static final long DEFAULT_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS = 3 * MINUTE_IN_MILLIS;
+        private static final long DEFAULT_EJ_GRACE_PERIOD_TOP_APP_MS = 1 * MINUTE_IN_MILLIS;
 
         /** How much time each app will have to run jobs within their standby bucket window. */
         public long ALLOWED_TIME_PER_PERIOD_MS = DEFAULT_ALLOWED_TIME_PER_PERIOD_MS;
@@ -3275,7 +3337,12 @@
          * How much additional grace period to add to the end of an app's temp allowlist
          * duration.
          */
-        public long EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS = DEFAULT_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS;
+        public long EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS = DEFAULT_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS;
+
+        /**
+         * How much additional grace period to give an app when it leaves the TOP state.
+         */
+        public long EJ_GRACE_PERIOD_TOP_APP_MS = DEFAULT_EJ_GRACE_PERIOD_TOP_APP_MS;
 
         public void processConstantLocked(@NonNull DeviceConfig.Properties properties,
                 @NonNull String key) {
@@ -3470,13 +3537,21 @@
                     mEJRewardNotificationSeenMs = Math.min(5 * MINUTE_IN_MILLIS,
                             Math.max(0, EJ_REWARD_NOTIFICATION_SEEN_MS));
                     break;
-                case KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS:
+                case KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS:
                     // We don't need to re-evaluate execution stats or constraint status for this.
-                    EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS =
-                            properties.getLong(key, DEFAULT_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS);
+                    EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS =
+                            properties.getLong(key, DEFAULT_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS);
                     // Limit grace period to be in the range [0 minutes, 1 hour].
-                    mEJTempAllowlistGracePeriodMs = Math.min(HOUR_IN_MILLIS,
-                            Math.max(0, EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS));
+                    mEJGracePeriodTempAllowlistMs = Math.min(HOUR_IN_MILLIS,
+                            Math.max(0, EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS));
+                    break;
+                case KEY_EJ_GRACE_PERIOD_TOP_APP_MS:
+                    // We don't need to re-evaluate execution stats or constraint status for this.
+                    EJ_GRACE_PERIOD_TOP_APP_MS =
+                            properties.getLong(key, DEFAULT_EJ_GRACE_PERIOD_TOP_APP_MS);
+                    // Limit grace period to be in the range [0 minutes, 1 hour].
+                    mEJGracePeriodTopAppMs = Math.min(HOUR_IN_MILLIS,
+                            Math.max(0, EJ_GRACE_PERIOD_TOP_APP_MS));
                     break;
             }
         }
@@ -3739,8 +3814,9 @@
             pw.print(KEY_EJ_REWARD_TOP_APP_MS, EJ_REWARD_TOP_APP_MS).println();
             pw.print(KEY_EJ_REWARD_INTERACTION_MS, EJ_REWARD_INTERACTION_MS).println();
             pw.print(KEY_EJ_REWARD_NOTIFICATION_SEEN_MS, EJ_REWARD_NOTIFICATION_SEEN_MS).println();
-            pw.print(KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS,
-                    EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS).println();
+            pw.print(KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS,
+                    EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS).println();
+            pw.print(KEY_EJ_GRACE_PERIOD_TOP_APP_MS, EJ_GRACE_PERIOD_TOP_APP_MS).println();
 
             pw.decreaseIndent();
         }
@@ -3853,6 +3929,16 @@
     }
 
     @VisibleForTesting
+    long getEJGracePeriodTempAllowlistMs() {
+        return mEJGracePeriodTempAllowlistMs;
+    }
+
+    @VisibleForTesting
+    long getEJGracePeriodTopAppMs() {
+        return mEJGracePeriodTopAppMs;
+    }
+
+    @VisibleForTesting
     @NonNull
     long[] getEJLimitsMs() {
         return mEJLimitsMs;
@@ -3888,11 +3974,6 @@
     }
 
     @VisibleForTesting
-    long getEJTempAllowlistGracePeriodMs() {
-        return mEJTempAllowlistGracePeriodMs;
-    }
-
-    @VisibleForTesting
     @Nullable
     List<TimingSession> getEJTimingSessions(int userId, String packageName) {
         return mEJTimingSessions.get(userId, packageName);
@@ -3964,6 +4045,17 @@
         pw.println(mForegroundUids.toString());
         pw.println();
 
+        pw.print("Cached top apps: ");
+        pw.println(mTopAppCache.toString());
+        pw.print("Cached top app grace period: ");
+        pw.println(mTopAppGraceCache.toString());
+
+        pw.print("Cached temp allowlist: ");
+        pw.println(mTempAllowlistCache.toString());
+        pw.print("Cached temp allowlist grace period: ");
+        pw.println(mTempAllowlistGraceCache.toString());
+        pw.println();
+
         pw.println("Cached UID->package map:");
         pw.increaseIndent();
         for (int i = 0; i < mUidToPackageCache.size(); ++i) {
@@ -3975,12 +4067,6 @@
         pw.decreaseIndent();
         pw.println();
 
-        pw.print("Cached temp allowlist: ");
-        pw.println(mTempAllowlistCache.toString());
-        pw.print("Cached temp allowlist grace period: ");
-        pw.println(mTempAllowlistGraceCache.toString());
-
-        pw.println();
         mTrackedJobs.forEach((jobs) -> {
             for (int j = 0; j < jobs.size(); j++) {
                 final JobStatus js = jobs.valueAt(j);
diff --git a/core/api/current.txt b/core/api/current.txt
index 8bc603d..471f610 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -34828,6 +34828,7 @@
     field public static final String ACTION_QUICK_ACCESS_WALLET_SETTINGS = "android.settings.QUICK_ACCESS_WALLET_SETTINGS";
     field public static final String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
     field public static final String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
+    field public static final String ACTION_REQUEST_MANAGE_MEDIA = "android.settings.REQUEST_MANAGE_MEDIA";
     field public static final String ACTION_REQUEST_SCHEDULE_EXACT_ALARM = "android.settings.REQUEST_SCHEDULE_EXACT_ALARM";
     field public static final String ACTION_REQUEST_SET_AUTOFILL_SERVICE = "android.settings.REQUEST_SET_AUTOFILL_SERVICE";
     field public static final String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
@@ -40316,7 +40317,6 @@
     method public static boolean isConfigForIdentifiedCarrier(android.os.PersistableBundle);
     method public void notifyConfigChangedForSubId(int);
     field public static final String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
-    field public static final int CARRIER_NR_AVAILABILITY_NONE = 0; // 0x0
     field public static final int CARRIER_NR_AVAILABILITY_NSA = 1; // 0x1
     field public static final int CARRIER_NR_AVAILABILITY_SA = 2; // 0x2
     field public static final int CROSS_SIM_SPN_FORMAT_CARRIER_NAME_ONLY = 0; // 0x0
@@ -40381,7 +40381,7 @@
     field public static final String KEY_CARRIER_INSTANT_LETTERING_LENGTH_LIMIT_INT = "carrier_instant_lettering_length_limit_int";
     field public static final String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool";
     field public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string";
-    field public static final String KEY_CARRIER_NR_AVAILABILITY_INT = "carrier_nr_availability_int";
+    field public static final String KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY = "carrier_nr_availabilities_int_array";
     field public static final String KEY_CARRIER_PROVISIONS_WIFI_MERGED_NETWORKS_BOOL = "carrier_provisions_wifi_merged_networks_bool";
     field public static final String KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL = "carrier_rcs_provisioning_required_bool";
     field public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string";
@@ -40626,7 +40626,10 @@
 
   public static final class CarrierConfigManager.ImsServiceEntitlement {
     field public static final String KEY_ENTITLEMENT_SERVER_URL_STRING = "imsserviceentitlement.entitlement_server_url_string";
+    field public static final String KEY_FCM_SENDER_ID_STRING = "imsserviceentitlement.fcm_sender_id_string";
+    field public static final String KEY_IMS_PROVISIONING_BOOL = "imsserviceentitlement.ims_provisioning_bool";
     field public static final String KEY_PREFIX = "imsserviceentitlement.";
+    field public static final String KEY_SHOW_VOWIFI_WEBVIEW_BOOL = "imsserviceentitlement.show_vowifi_webview_bool";
   }
 
   public static final class CarrierConfigManager.Iwlan {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index fe8566f..e49ef2c 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -202,7 +202,6 @@
     field public static final String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG";
     field public static final String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE";
     field public static final String READ_INSTALL_SESSIONS = "android.permission.READ_INSTALL_SESSIONS";
-    field public static final String READ_NETWORK_DEVICE_CONFIG = "android.permission.READ_NETWORK_DEVICE_CONFIG";
     field public static final String READ_NETWORK_USAGE_HISTORY = "android.permission.READ_NETWORK_USAGE_HISTORY";
     field public static final String READ_OEM_UNLOCK_STATE = "android.permission.READ_OEM_UNLOCK_STATE";
     field public static final String READ_PEOPLE_DATA = "android.permission.READ_PEOPLE_DATA";
@@ -911,7 +910,6 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedKiosk();
-    method public boolean isNetworkSlicingEnabledForUser(@NonNull android.os.UserHandle);
     method public boolean isSecondaryLockscreenEnabled(@NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUnattendedManagedKiosk();
     method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 8497427..a97c3ae 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1033,6 +1033,14 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public String getUiPackage();
   }
 
+  public class BiometricPrompt {
+    method @NonNull public java.util.List<java.lang.Integer> getAllowedSensorIds();
+  }
+
+  public static class BiometricPrompt.Builder {
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.TEST_BIOMETRIC, "android.permission.USE_BIOMETRIC_INTERNAL"}) public android.hardware.biometrics.BiometricPrompt.Builder setAllowedSensorIds(@NonNull java.util.List<java.lang.Integer>);
+  }
+
   public class BiometricTestSession implements java.lang.AutoCloseable {
     method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void acceptAuthentication(int);
     method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void cleanupInternalState(int);
@@ -1045,6 +1053,7 @@
   }
 
   public class SensorProperties {
+    method @NonNull public java.util.List<android.hardware.biometrics.SensorProperties.ComponentInfo> getComponentInfo();
     method public int getSensorId();
     method public int getSensorStrength();
     field public static final int STRENGTH_CONVENIENCE = 0; // 0x0
@@ -1052,6 +1061,14 @@
     field public static final int STRENGTH_WEAK = 1; // 0x1
   }
 
+  public static final class SensorProperties.ComponentInfo {
+    method @NonNull public String getComponentId();
+    method @NonNull public String getFirmwareVersion();
+    method @NonNull public String getHardwareVersion();
+    method @NonNull public String getSerialNumber();
+    method @NonNull public String getSoftwareVersion();
+  }
+
 }
 
 package android.hardware.camera2 {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9dcb237..60506b5 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2684,7 +2684,17 @@
         if (headsUpContentView != null) headsUpContentView.visitUris(visitor);
 
         if (extras != null) {
-            visitor.accept(extras.getParcelable(EXTRA_AUDIO_CONTENTS_URI));
+            // NOTE: The documentation of EXTRA_AUDIO_CONTENTS_URI explicitly says that it is a
+            // String representation of a Uri, but the previous implementation (and unit test) of
+            // this method has always treated it as a Uri object. Given the inconsistency,
+            // supporting both going forward is the safest choice.
+            Object audioContentsUri = extras.get(EXTRA_AUDIO_CONTENTS_URI);
+            if (audioContentsUri instanceof Uri) {
+                visitor.accept((Uri) audioContentsUri);
+            } else if (audioContentsUri instanceof String) {
+                visitor.accept(Uri.parse((String) audioContentsUri));
+            }
+
             if (extras.containsKey(EXTRA_BACKGROUND_IMAGE_URI)) {
                 visitor.accept(Uri.parse(extras.getString(EXTRA_BACKGROUND_IMAGE_URI)));
             }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d4d3321..594b005 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -10023,37 +10023,6 @@
     }
 
     /**
-     * Indicates whether 5g slicing is enabled for specific user.
-     *
-     * This method can be called with permission
-     * {@link android.Manifest.permission#READ_NETWORK_DEVICE_CONFIG} by the profile owner of
-     * a managed profile. And the caller must hold the
-     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission if query for
-     * other users.
-     *
-     * @param userHandle indicates the user to query the state
-     * @return indicates whether 5g Slice is enabled.
-     * @throws SecurityException if the caller is not granted the permission
-     *         {@link android.Manifest.permission#READ_NETWORK_DEVICE_CONFIG}
-     *         and not profile owner of a managed profile, and not granted the permission
-     *         {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} if query for
-     *         other users.
-     * @hide
-     */
-    @SystemApi
-    public boolean isNetworkSlicingEnabledForUser(@NonNull UserHandle userHandle) {
-        throwIfParentInstance("isNetworkSlicingEnabledForUser");
-        if (mService == null) {
-            return false;
-        }
-        try {
-            return mService.isNetworkSlicingEnabled(userHandle.getIdentifier());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * This method is mostly deprecated.
      * Most of the settings that still have an effect have dedicated setter methods or user
      * restrictions. See individual settings for details.
diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java
index c0c1aa1..794b512 100644
--- a/core/java/android/bluetooth/le/ScanRecord.java
+++ b/core/java/android/bluetooth/le/ScanRecord.java
@@ -29,6 +29,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Predicate;
 
 /**
  * Represents a scan record from Bluetooth LE scan.
@@ -168,6 +169,27 @@
         return mBytes;
     }
 
+    /**
+     * Test if any fields contained inside this scan record are matched by the
+     * given matcher.
+     *
+     * @hide
+     */
+    public boolean matchesAnyField(@NonNull Predicate<byte[]> matcher) {
+        int pos = 0;
+        while (pos < mBytes.length) {
+            final int length = mBytes[pos] & 0xFF;
+            if (length == 0) {
+                break;
+            }
+            if (matcher.test(Arrays.copyOfRange(mBytes, pos, pos + length + 1))) {
+                return true;
+            }
+            pos += length + 1;
+        }
+        return false;
+    }
+
     private ScanRecord(List<ParcelUuid> serviceUuids,
             List<ParcelUuid> serviceSolicitationUuids,
             SparseArray<byte[]> manufacturerData,
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 29edd40..ba6416d 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -34,6 +34,7 @@
 import android.content.pm.parsing.component.ParsedProcess;
 import android.content.pm.parsing.component.ParsedProvider;
 import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.component.ParsedUsesPermission;
 import android.os.Bundle;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -89,7 +90,7 @@
 
     ParsingPackage addReqFeature(FeatureInfo reqFeature);
 
-    ParsingPackage addRequestedPermission(String permission);
+    ParsingPackage addUsesPermission(ParsedUsesPermission parsedUsesPermission);
 
     ParsingPackage addService(ParsedService parsedService);
 
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index 067787d..b3c26ab 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -44,6 +44,7 @@
 import android.content.pm.parsing.component.ParsedProcess;
 import android.content.pm.parsing.component.ParsedProvider;
 import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.component.ParsedUsesPermission;
 import android.content.res.TypedArray;
 import android.os.Build;
 import android.os.Bundle;
@@ -71,6 +72,7 @@
 import com.android.internal.util.Parcelling.BuiltIn.ForStringSet;
 
 import java.security.PublicKey;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
@@ -227,8 +229,8 @@
     protected List<String> adoptPermissions = emptyList();
 
     @NonNull
-    @DataClass.ParcelWith(ForInternedStringList.class)
-    private List<String> requestedPermissions = emptyList();
+    private List<ParsedUsesPermission> usesPermissions = emptyList();
+
     @NonNull
     @DataClass.ParcelWith(ForInternedStringList.class)
     private List<String> implicitPermissions = emptyList();
@@ -691,9 +693,8 @@
     }
 
     @Override
-    public ParsingPackageImpl addRequestedPermission(String permission) {
-        this.requestedPermissions = CollectionUtils.add(this.requestedPermissions,
-                TextUtils.safeIntern(permission));
+    public ParsingPackageImpl addUsesPermission(ParsedUsesPermission permission) {
+        this.usesPermissions = CollectionUtils.add(this.usesPermissions, permission);
         return this;
     }
 
@@ -1134,7 +1135,7 @@
         dest.writeByteArray(this.restrictUpdateHash);
         dest.writeStringList(this.originalPackages);
         sForInternedStringList.parcel(this.adoptPermissions, dest, flags);
-        sForInternedStringList.parcel(this.requestedPermissions, dest, flags);
+        dest.writeTypedList(this.usesPermissions);
         sForInternedStringList.parcel(this.implicitPermissions, dest, flags);
         sForStringSet.parcel(this.upgradeKeySets, dest, flags);
         dest.writeMap(this.keySetMapping);
@@ -1255,7 +1256,7 @@
         this.restrictUpdateHash = in.createByteArray();
         this.originalPackages = in.createStringArrayList();
         this.adoptPermissions = sForInternedStringList.unparcel(in);
-        this.requestedPermissions = sForInternedStringList.unparcel(in);
+        this.usesPermissions = in.createTypedArrayList(ParsedUsesPermission.CREATOR);
         this.implicitPermissions = sForInternedStringList.unparcel(in);
         this.upgradeKeySets = sForStringSet.unparcel(in);
         this.keySetMapping = in.readHashMap(boot);
@@ -1551,11 +1552,23 @@
     @NonNull
     @Override
     public List<String> getRequestedPermissions() {
+        final List<ParsedUsesPermission> usesPermissions = getUsesPermissions();
+        final int size = usesPermissions.size();
+        final List<String> requestedPermissions = new ArrayList<>(size);
+        for (int i = 0; i < size; i++) {
+            requestedPermissions.add(usesPermissions.get(i).name);
+        }
         return requestedPermissions;
     }
 
     @NonNull
     @Override
+    public List<ParsedUsesPermission> getUsesPermissions() {
+        return usesPermissions;
+    }
+
+    @NonNull
+    @Override
     public List<String> getImplicitPermissions() {
         return implicitPermissions;
     }
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index f7f3e19..9f52183 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -37,6 +37,7 @@
 import android.content.pm.parsing.component.ParsedProcess;
 import android.content.pm.parsing.component.ParsedProvider;
 import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.component.ParsedUsesPermission;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.util.ArraySet;
@@ -45,6 +46,7 @@
 import android.util.SparseIntArray;
 
 import java.security.PublicKey;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -193,6 +195,14 @@
     List<FeatureInfo> getReqFeatures();
 
     /**
+     * @deprecated consider migrating to {@link #getUsesPermissions} which has
+     *             more parsed details, such as flags
+     */
+    @NonNull
+    @Deprecated
+    List<String> getRequestedPermissions();
+
+    /**
      * All the permissions declared. This is an effective set, and may include permissions
      * transformed from split/migrated permissions from previous versions, so may not be exactly
      * what the package declares in its manifest.
@@ -200,7 +210,7 @@
      * @see R.styleable#AndroidManifestUsesPermission
      */
     @NonNull
-    List<String> getRequestedPermissions();
+    List<ParsedUsesPermission> getUsesPermissions();
 
     /**
      * Returns the properties set on the application
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 0c033fd..2be0157 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -67,6 +67,7 @@
 import android.content.pm.parsing.component.ParsedProviderUtils;
 import android.content.pm.parsing.component.ParsedService;
 import android.content.pm.parsing.component.ParsedServiceUtils;
+import android.content.pm.parsing.component.ParsedUsesPermission;
 import android.content.pm.parsing.result.ParseInput;
 import android.content.pm.parsing.result.ParseInput.DeferredError;
 import android.content.pm.parsing.result.ParseResult;
@@ -119,6 +120,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.StringTokenizer;
 
@@ -1206,6 +1208,10 @@
                 requiredNotFeatures.add(feature);
             }
 
+            final int usesPermissionFlags = sa.getInt(
+                com.android.internal.R.styleable.AndroidManifestUsesPermission_usesPermissionFlags,
+                0);
+
             final int outerDepth = parser.getDepth();
             int type;
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1270,14 +1276,31 @@
                 }
             }
 
-            if (!pkg.getRequestedPermissions().contains(name)) {
-                pkg.addRequestedPermission(name.intern());
-            } else {
-                Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
-                        + name + " in package: " + pkg.getPackageName() + " at: "
-                        + parser.getPositionDescription());
+            // Quietly ignore duplicate permission requests, but fail loudly if
+            // the two requests have conflicting flags
+            boolean found = false;
+            final List<ParsedUsesPermission> usesPermissions = pkg.getUsesPermissions();
+            final int size = usesPermissions.size();
+            for (int i = 0; i < size; i++) {
+                final ParsedUsesPermission usesPermission = usesPermissions.get(i);
+                if (Objects.equals(usesPermission.name, name)) {
+                    if (usesPermission.usesPermissionFlags != usesPermissionFlags) {
+                        return input.error("Conflicting uses-permissions flags: "
+                                + name + " in package: " + pkg.getPackageName() + " at: "
+                                + parser.getPositionDescription());
+                    } else {
+                        Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
+                                + name + " in package: " + pkg.getPackageName() + " at: "
+                                + parser.getPositionDescription());
+                    }
+                    found = true;
+                    break;
+                }
             }
 
+            if (!found) {
+                pkg.addUsesPermission(new ParsedUsesPermission(name, usesPermissionFlags));
+            }
             return success;
         } finally {
             sa.recycle();
@@ -2755,7 +2778,7 @@
                     newPermsMsg.append(' ');
                 }
                 newPermsMsg.append(npi.name);
-                pkg.addRequestedPermission(npi.name)
+                pkg.addUsesPermission(new ParsedUsesPermission(npi.name, 0))
                         .addImplicitPermission(npi.name);
             }
         }
@@ -2777,7 +2800,7 @@
             for (int in = 0; in < newPerms.size(); in++) {
                 final String perm = newPerms.get(in);
                 if (!requestedPermissions.contains(perm)) {
-                    pkg.addRequestedPermission(perm)
+                    pkg.addUsesPermission(new ParsedUsesPermission(perm, 0))
                             .addImplicitPermission(perm);
                 }
             }
diff --git a/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java b/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java
new file mode 100644
index 0000000..b9c2e36
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing.component;
+
+import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A {@link android.R.styleable#AndroidManifestUsesPermission
+ * &lt;uses-permission&gt;} tag parsed from the manifest.
+ *
+ * @hide
+ */
+public class ParsedUsesPermission implements Parcelable {
+    /** Name of the permission requested */
+    public @NonNull String name;
+
+    /** Set of flags that should apply to this permission request. */
+    public @UsesPermissionFlags int usesPermissionFlags;
+
+    /**
+     * Strong assertion by a developer that they will never use this permission
+     * to derive the physical location of the device, regardless of
+     * ACCESS_FINE_LOCATION and/or ACCESS_COARSE_LOCATION being granted.
+     */
+    public static final int FLAG_NEVER_FOR_LOCATION = 0x1;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = { "FLAG_" }, value = {
+            FLAG_NEVER_FOR_LOCATION
+    })
+    public @interface UsesPermissionFlags {}
+
+    public ParsedUsesPermission(@NonNull String name,
+            @UsesPermissionFlags int usesPermissionFlags) {
+        this.name = name.intern();
+        this.usesPermissionFlags = usesPermissionFlags;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        sForInternedString.parcel(this.name, dest, flags);
+        dest.writeInt(usesPermissionFlags);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    protected ParsedUsesPermission(@NonNull Parcel in) {
+        this.name = sForInternedString.unparcel(in);
+        this.usesPermissionFlags = in.readInt();
+    }
+
+    public static final @NonNull Parcelable.Creator<ParsedUsesPermission> CREATOR
+            = new Parcelable.Creator<ParsedUsesPermission>() {
+        @Override
+        public ParsedUsesPermission[] newArray(int size) {
+            return new ParsedUsesPermission[size];
+        }
+
+        @Override
+        public ParsedUsesPermission createFromParcel(@NonNull Parcel in) {
+            return new ParsedUsesPermission(in);
+        }
+    };
+}
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index acfad13..304b2af 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -48,13 +48,6 @@
     private static final String TAG = "BiometricManager";
 
     /**
-     * An ID that should match any biometric sensor on the device.
-     *
-     * @hide
-     */
-    public static final int SENSOR_ID_ANY = -1;
-
-    /**
      * No error detected.
      */
     public static final int BIOMETRIC_SUCCESS =
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 4f6a7c7..1258247 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -16,6 +16,7 @@
 
 package android.hardware.biometrics;
 
+import static android.Manifest.permission.TEST_BIOMETRIC;
 import static android.Manifest.permission.USE_BIOMETRIC;
 import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
 import static android.hardware.biometrics.BiometricManager.Authenticators;
@@ -25,6 +26,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.hardware.face.FaceManager;
@@ -45,6 +47,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.security.Signature;
+import java.util.List;
 import java.util.concurrent.Executor;
 
 import javax.crypto.Cipher;
@@ -339,6 +342,32 @@
         }
 
         /**
+         * If non-empty, requests authentication to be performed only if the sensor is contained
+         * within the list. Note that the actual sensor presented to the user/test will meet all
+         * constraints specified within this builder. For example, on a device with the below
+         * configuration:
+         *
+         * SensorId: 1, Strength: BIOMETRIC_STRONG
+         * SensorId: 2, Strength: BIOMETRIC_WEAK
+         *
+         * If authentication is invoked with setAllowedAuthenticators(BIOMETRIC_STRONG) and
+         * setAllowedSensorIds(2), then no sensor will be eligible for authentication.
+         *
+         * @see {@link BiometricManager#getSensorProperties()}
+         *
+         * @param sensorIds Sensor IDs to constrain this authentication to.
+         * @return This builder
+         * @hide
+         */
+        @TestApi
+        @NonNull
+        @RequiresPermission(anyOf = {TEST_BIOMETRIC, USE_BIOMETRIC_INTERNAL})
+        public Builder setAllowedSensorIds(@NonNull List<Integer> sensorIds) {
+            mPromptInfo.setAllowedSensorIds(sensorIds);
+            return this;
+        }
+
+        /**
          * If set check the Device Policy Manager for disabled biometrics.
          *
          * @param checkDevicePolicyManager
@@ -364,21 +393,6 @@
         }
 
         /**
-         * If set, authenticate using the biometric sensor with the given ID.
-         *
-         * @param sensorId The ID of a biometric sensor, or -1 to allow any sensor (default).
-         * @return This builder.
-         *
-         * @hide
-         */
-        @RequiresPermission(USE_BIOMETRIC_INTERNAL)
-        @NonNull
-        public Builder setSensorId(int sensorId) {
-            mPromptInfo.setSensorId(sensorId);
-            return this;
-        }
-
-        /**
          * Creates a {@link BiometricPrompt}.
          *
          * @return An instance of {@link BiometricPrompt}.
@@ -596,6 +610,16 @@
     }
 
     /**
+     * @return The values set by {@link Builder#setAllowedSensorIds(List)}
+     * @hide
+     */
+    @TestApi
+    @NonNull
+    public List<Integer> getAllowedSensorIds() {
+        return mPromptInfo.getAllowedSensorIds();
+    }
+
+    /**
      * A wrapper class for the cryptographic operations supported by BiometricPrompt.
      *
      * <p>Currently the framework supports {@link Signature}, {@link Cipher}, {@link Mac}, and
diff --git a/core/java/android/hardware/biometrics/ComponentInfoInternal.aidl b/core/java/android/hardware/biometrics/ComponentInfoInternal.aidl
new file mode 100644
index 0000000..0c780cc
--- /dev/null
+++ b/core/java/android/hardware/biometrics/ComponentInfoInternal.aidl
@@ -0,0 +1,18 @@
+/*
+ * 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 android.hardware.biometrics;
+
+parcelable ComponentInfoInternal;
\ No newline at end of file
diff --git a/core/java/android/hardware/biometrics/ComponentInfoInternal.java b/core/java/android/hardware/biometrics/ComponentInfoInternal.java
new file mode 100644
index 0000000..fa34e0b
--- /dev/null
+++ b/core/java/android/hardware/biometrics/ComponentInfoInternal.java
@@ -0,0 +1,100 @@
+/*
+ * 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 android.hardware.biometrics;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * The internal class for storing the component info for a subsystem of the biometric sensor,
+ * as defined in {@link android.hardware.biometrics.common.ComponentInfo}.
+ * @hide
+ */
+public class ComponentInfoInternal implements Parcelable {
+
+    public final String componentId;
+    public final String hardwareVersion;
+    public final String firmwareVersion;
+    public final String serialNumber;
+    public final String softwareVersion;
+
+    /**
+     * Constructs a {@link ComponentInfoInternal} from another instance.
+     * @hide
+     */
+    public static ComponentInfoInternal from(@NonNull ComponentInfoInternal comp) {
+        return new ComponentInfoInternal(comp.componentId, comp.hardwareVersion,
+                comp.firmwareVersion, comp.serialNumber, comp.softwareVersion);
+    }
+
+    /**
+     * @hide
+     */
+    public ComponentInfoInternal(String componentId, String hardwareVersion,
+            String firmwareVersion, String serialNumber, String softwareVersion) {
+        this.componentId = componentId;
+        this.hardwareVersion = hardwareVersion;
+        this.firmwareVersion = firmwareVersion;
+        this.serialNumber = serialNumber;
+        this.softwareVersion = softwareVersion;
+    }
+
+    protected ComponentInfoInternal(Parcel in) {
+        componentId = in.readString();
+        hardwareVersion = in.readString();
+        firmwareVersion = in.readString();
+        serialNumber = in.readString();
+        softwareVersion = in.readString();
+    }
+
+    public static final Creator<ComponentInfoInternal> CREATOR =
+            new Creator<ComponentInfoInternal>() {
+        @Override
+        public ComponentInfoInternal createFromParcel(Parcel in) {
+            return new ComponentInfoInternal(in);
+        }
+
+        @Override
+        public ComponentInfoInternal[] newArray(int size) {
+            return new ComponentInfoInternal[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(componentId);
+        dest.writeString(hardwareVersion);
+        dest.writeString(firmwareVersion);
+        dest.writeString(serialNumber);
+        dest.writeString(softwareVersion);
+    }
+
+    @Override
+    public String toString() {
+        return "ComponentId: " + componentId
+                + ", HardwareVersion: " + hardwareVersion
+                + ", FirmwareVersion: " + firmwareVersion
+                + ", SerialNumber " + serialNumber
+                + ", SoftwareVersion: " + softwareVersion;
+    }
+}
diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java
index 0e99f31..20c25fb 100644
--- a/core/java/android/hardware/biometrics/PromptInfo.java
+++ b/core/java/android/hardware/biometrics/PromptInfo.java
@@ -21,6 +21,9 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Contains the information set/requested by the caller of the {@link BiometricPrompt}
  * @hide
@@ -40,7 +43,7 @@
     private @BiometricManager.Authenticators.Types int mAuthenticators;
     private boolean mDisallowBiometricsIfPolicyExists;
     private boolean mReceiveSystemEvents;
-    private int mSensorId = -1;
+    @NonNull private List<Integer> mAllowedSensorIds = new ArrayList<>();
 
     public PromptInfo() {
 
@@ -60,7 +63,7 @@
         mAuthenticators = in.readInt();
         mDisallowBiometricsIfPolicyExists = in.readBoolean();
         mReceiveSystemEvents = in.readBoolean();
-        mSensorId = in.readInt();
+        mAllowedSensorIds = in.readArrayList(Integer.class.getClassLoader());
     }
 
     public static final Creator<PromptInfo> CREATOR = new Creator<PromptInfo>() {
@@ -95,7 +98,14 @@
         dest.writeInt(mAuthenticators);
         dest.writeBoolean(mDisallowBiometricsIfPolicyExists);
         dest.writeBoolean(mReceiveSystemEvents);
-        dest.writeInt(mSensorId);
+        dest.writeList(mAllowedSensorIds);
+    }
+
+    public boolean containsTestConfigurations() {
+        if (!mAllowedSensorIds.isEmpty()) {
+            return true;
+        }
+        return false;
     }
 
     public boolean containsPrivateApiConfigurations() {
@@ -169,8 +179,8 @@
         mReceiveSystemEvents = receiveSystemEvents;
     }
 
-    public void setSensorId(int sensorId) {
-        mSensorId = sensorId;
+    public void setAllowedSensorIds(@NonNull List<Integer> sensorIds) {
+        mAllowedSensorIds = sensorIds;
     }
 
     // Getters
@@ -234,7 +244,8 @@
         return mReceiveSystemEvents;
     }
 
-    public int getSensorId() {
-        return mSensorId;
+    @NonNull
+    public List<Integer> getAllowedSensorIds() {
+        return mAllowedSensorIds;
     }
 }
diff --git a/core/java/android/hardware/biometrics/SensorProperties.java b/core/java/android/hardware/biometrics/SensorProperties.java
index 360f138..3b9cad4 100644
--- a/core/java/android/hardware/biometrics/SensorProperties.java
+++ b/core/java/android/hardware/biometrics/SensorProperties.java
@@ -17,10 +17,13 @@
 package android.hardware.biometrics;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.TestApi;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * The base class containing all modality-agnostic information.
@@ -56,15 +59,93 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface Strength {}
 
+    /**
+     * A class storing the component info for a subsystem of the sensor.
+     */
+    public static final class ComponentInfo {
+        @NonNull private final String mComponentId;
+        @NonNull private final String mHardwareVersion;
+        @NonNull private final String mFirmwareVersion;
+        @NonNull private final String mSerialNumber;
+        @NonNull private final String mSoftwareVersion;
+
+        /**
+         * @hide
+         */
+        public ComponentInfo(@NonNull String componentId, @NonNull String hardwareVersion,
+                @NonNull String firmwareVersion, @NonNull String serialNumber,
+                @NonNull String softwareVersion) {
+            mComponentId = componentId;
+            mHardwareVersion = hardwareVersion;
+            mFirmwareVersion = firmwareVersion;
+            mSerialNumber = serialNumber;
+            mSoftwareVersion = softwareVersion;
+        }
+
+        /**
+         * @return The unique identifier for the subsystem.
+         */
+        @NonNull
+        public String getComponentId() {
+            return mComponentId;
+        }
+
+        /**
+         * @return The hardware version for the subsystem. For example, <vendor>/<model>/<revision>.
+         */
+        @NonNull
+        public String getHardwareVersion() {
+            return mHardwareVersion;
+        }
+
+        /**
+         * @return The firmware version for the subsystem.
+         */
+        @NonNull
+        public String getFirmwareVersion() {
+            return mFirmwareVersion;
+        }
+
+        /**
+         * @return The serial number for the subsystem.
+         */
+        @NonNull
+        public String getSerialNumber() {
+            return mSerialNumber;
+        }
+
+        /**
+         * @return The software version for the subsystem.
+         * For example, <vendor>/<version>/<revision>.
+         */
+        @NonNull
+        public String getSoftwareVersion() {
+            return mSoftwareVersion;
+        }
+
+        /**
+         * Constructs a {@link ComponentInfo} from the internal parcelable representation.
+         * @hide
+         */
+        public static ComponentInfo from(ComponentInfoInternal internalComp) {
+            return new ComponentInfo(internalComp.componentId, internalComp.hardwareVersion,
+                    internalComp.firmwareVersion, internalComp.serialNumber,
+                    internalComp.softwareVersion);
+        }
+    }
+
     private final int mSensorId;
     @Strength private final int mSensorStrength;
+    private final List<ComponentInfo> mComponentInfo;
 
     /**
      * @hide
      */
-    public SensorProperties(int sensorId, @Strength int sensorStrength) {
+    public SensorProperties(int sensorId, @Strength int sensorStrength,
+            List<ComponentInfo> componentInfo) {
         mSensorId = sensorId;
         mSensorStrength = sensorStrength;
+        mComponentInfo = componentInfo;
     }
 
     /**
@@ -83,10 +164,23 @@
     }
 
     /**
+     * @return The sensor's component info.
+     */
+    @NonNull
+    public List<ComponentInfo> getComponentInfo() {
+        return mComponentInfo;
+    }
+
+    /**
      * Constructs a {@link SensorProperties} from the internal parcelable representation.
      * @hide
      */
     public static SensorProperties from(SensorPropertiesInternal internalProp) {
-        return new SensorProperties(internalProp.sensorId, internalProp.sensorStrength);
+        final List<ComponentInfo> componentInfo = new ArrayList<>();
+        for (ComponentInfoInternal internalComp : internalProp.componentInfo) {
+            componentInfo.add(ComponentInfo.from(internalComp));
+        }
+        return new SensorProperties(internalProp.sensorId, internalProp.sensorStrength,
+                componentInfo);
     }
 }
diff --git a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
index 909f456..eda0ded 100644
--- a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
+++ b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
@@ -20,6 +20,9 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * The base class containing all modality-agnostic information. This is a superset of the
  * {@link android.hardware.biometrics.common.CommonProps}, and provides backwards-compatible
@@ -31,21 +34,23 @@
     public final int sensorId;
     @SensorProperties.Strength public final int sensorStrength;
     public final int maxEnrollmentsPerUser;
+    public final List<ComponentInfoInternal> componentInfo;
     public final boolean resetLockoutRequiresHardwareAuthToken;
     public final boolean resetLockoutRequiresChallenge;
 
     public static SensorPropertiesInternal from(@NonNull SensorPropertiesInternal prop) {
         return new SensorPropertiesInternal(prop.sensorId, prop.sensorStrength,
-                prop.maxEnrollmentsPerUser, prop.resetLockoutRequiresHardwareAuthToken,
-                prop.resetLockoutRequiresChallenge);
+                prop.maxEnrollmentsPerUser, prop.componentInfo,
+                prop.resetLockoutRequiresHardwareAuthToken, prop.resetLockoutRequiresChallenge);
     }
 
     protected SensorPropertiesInternal(int sensorId, @SensorProperties.Strength int sensorStrength,
-            int maxEnrollmentsPerUser, boolean resetLockoutRequiresHardwareAuthToken,
-            boolean resetLockoutRequiresChallenge) {
+            int maxEnrollmentsPerUser, @NonNull List<ComponentInfoInternal> componentInfo,
+            boolean resetLockoutRequiresHardwareAuthToken, boolean resetLockoutRequiresChallenge) {
         this.sensorId = sensorId;
         this.sensorStrength = sensorStrength;
         this.maxEnrollmentsPerUser = maxEnrollmentsPerUser;
+        this.componentInfo = componentInfo;
         this.resetLockoutRequiresHardwareAuthToken = resetLockoutRequiresHardwareAuthToken;
         this.resetLockoutRequiresChallenge = resetLockoutRequiresChallenge;
     }
@@ -54,6 +59,8 @@
         sensorId = in.readInt();
         sensorStrength = in.readInt();
         maxEnrollmentsPerUser = in.readInt();
+        componentInfo = new ArrayList<>();
+        in.readList(componentInfo, ComponentInfoInternal.class.getClassLoader());
         resetLockoutRequiresHardwareAuthToken = in.readBoolean();
         resetLockoutRequiresChallenge = in.readBoolean();
     }
@@ -81,13 +88,23 @@
         dest.writeInt(sensorId);
         dest.writeInt(sensorStrength);
         dest.writeInt(maxEnrollmentsPerUser);
+        dest.writeList(componentInfo);
         dest.writeBoolean(resetLockoutRequiresHardwareAuthToken);
         dest.writeBoolean(resetLockoutRequiresChallenge);
     }
 
     @Override
     public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("[ ");
+        for (ComponentInfoInternal info : componentInfo) {
+            sb.append("[").append(info.toString());
+            sb.append("] ");
+        }
+        sb.append("]");
+
         return "ID: " + sensorId + ", Strength: " + sensorStrength
-                + ", MaxEnrollmentsPerUser: " + maxEnrollmentsPerUser;
+                + ", MaxEnrollmentsPerUser: " + maxEnrollmentsPerUser
+                + ", ComponentInfo: " + sb.toString();
     }
 }
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 157e333..9ac2ff5 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -3345,7 +3345,7 @@
      * <p>A control for selecting whether optical stabilization (OIS) position
      * information is included in output result metadata.</p>
      * <p>Since optical image stabilization generally involves motion much faster than the duration
-     * of individualq image exposure, multiple OIS samples can be included for a single capture
+     * of individual image exposure, multiple OIS samples can be included for a single capture
      * result. For example, if the OIS reporting operates at 200 Hz, a typical camera operating
      * at 30fps may have 6-7 OIS samples per capture result. This information can be combined
      * with the rolling shutter skew to account for lens motion during image exposure in
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index c0eb068..e7457e7 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -4635,7 +4635,7 @@
      * <p>A control for selecting whether optical stabilization (OIS) position
      * information is included in output result metadata.</p>
      * <p>Since optical image stabilization generally involves motion much faster than the duration
-     * of individualq image exposure, multiple OIS samples can be included for a single capture
+     * of individual image exposure, multiple OIS samples can be included for a single capture
      * result. For example, if the OIS reporting operates at 200 Hz, a typical camera operating
      * at 30fps may have 6-7 OIS samples per capture result. This information can be combined
      * with the rolling shutter skew to account for lens motion during image exposure in
diff --git a/core/java/android/hardware/face/FaceSensorProperties.java b/core/java/android/hardware/face/FaceSensorProperties.java
index e61d931..6ddea50 100644
--- a/core/java/android/hardware/face/FaceSensorProperties.java
+++ b/core/java/android/hardware/face/FaceSensorProperties.java
@@ -16,25 +16,75 @@
 
 package android.hardware.face;
 
+import android.annotation.IntDef;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.SensorProperties;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Container for face sensor properties.
  * @hide
  */
 public class FaceSensorProperties extends SensorProperties {
+    /**
+     * @hide
+     */
+    public static final int TYPE_UNKNOWN = 0;
+
+    /**
+     * @hide
+     */
+    public static final int TYPE_RGB = 1;
+
+    /**
+     * @hide
+     */
+    public static final int TYPE_IR = 2;
+
+    /**
+     * @hide
+     */
+    @IntDef({TYPE_UNKNOWN,
+            TYPE_RGB,
+            TYPE_IR})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SensorType {}
+
+    @FaceSensorProperties.SensorType
+    final int mSensorType;
 
     /**
      * @hide
      */
     public static FaceSensorProperties from(FaceSensorPropertiesInternal internalProp) {
-        return new FaceSensorProperties(internalProp.sensorId, internalProp.sensorStrength);
+        final List<ComponentInfo> componentInfo = new ArrayList<>();
+        for (ComponentInfoInternal internalComp : internalProp.componentInfo) {
+            componentInfo.add(ComponentInfo.from(internalComp));
+        }
+        return new FaceSensorProperties(internalProp.sensorId,
+                internalProp.sensorStrength,
+                componentInfo,
+                internalProp.sensorType);
     }
     /**
      * @hide
      */
-    public FaceSensorProperties(int sensorId, int sensorStrength) {
-        super(sensorId, sensorStrength);
+    public FaceSensorProperties(int sensorId, int sensorStrength,
+            List<ComponentInfo> componentInfo, @FaceSensorProperties.SensorType int sensorType) {
+        super(sensorId, sensorStrength, componentInfo);
+        mSensorType = sensorType;
     }
 
+    /**
+     * @hide
+     * @return The sensor's type.
+     */
+    @FaceSensorProperties.SensorType
+    public int getSensorType() {
+        return mSensorType;
+    }
 }
diff --git a/core/java/android/hardware/face/FaceSensorPropertiesInternal.java b/core/java/android/hardware/face/FaceSensorPropertiesInternal.java
index 34cbcb4..50ea60a2 100644
--- a/core/java/android/hardware/face/FaceSensorPropertiesInternal.java
+++ b/core/java/android/hardware/face/FaceSensorPropertiesInternal.java
@@ -16,16 +16,24 @@
 
 package android.hardware.face;
 
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.SensorProperties;
 import android.hardware.biometrics.SensorPropertiesInternal;
 import android.os.Parcel;
 
+import java.util.List;
+
 /**
  * Container for face sensor properties.
  * @hide
  */
 public class FaceSensorPropertiesInternal extends SensorPropertiesInternal {
     /**
+     * See {@link FaceSensorProperties.SensorType}.
+     */
+    public final @FaceSensorProperties.SensorType int sensorType;
+
+    /**
      * True if the sensor is able to perform generic face detection, without running the
      * matching algorithm, and without affecting the lockout counter.
      */
@@ -40,18 +48,21 @@
      * Initializes SensorProperties with specified values
      */
     public FaceSensorPropertiesInternal(int sensorId, @SensorProperties.Strength int strength,
-            int maxEnrollmentsPerUser, boolean supportsFaceDetection,
+            int maxEnrollmentsPerUser, List<ComponentInfoInternal> componentInfo,
+            @FaceSensorProperties.SensorType int sensorType, boolean supportsFaceDetection,
             boolean supportsSelfIllumination, boolean resetLockoutRequiresChallenge) {
         // resetLockout is managed by the HAL and requires a HardwareAuthToken for all face
         // HAL interfaces (IBiometricsFace@1.0 HIDL and IFace@1.0 AIDL).
-        super(sensorId, strength, maxEnrollmentsPerUser,
-                true /* resetLockoutRequiresHardwareAuthToken */, resetLockoutRequiresChallenge);
+        super(sensorId, strength, maxEnrollmentsPerUser, componentInfo,
+            true /* resetLockoutRequiresHardwareAuthToken */, resetLockoutRequiresChallenge);
+        this.sensorType = sensorType;
         this.supportsFaceDetection = supportsFaceDetection;
         this.supportsSelfIllumination = supportsSelfIllumination;
     }
 
     protected FaceSensorPropertiesInternal(Parcel in) {
         super(in);
+        sensorType = in.readInt();
         supportsFaceDetection = in.readBoolean();
         supportsSelfIllumination = in.readBoolean();
     }
@@ -77,12 +88,13 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         super.writeToParcel(dest, flags);
+        dest.writeInt(sensorType);
         dest.writeBoolean(supportsFaceDetection);
         dest.writeBoolean(supportsSelfIllumination);
     }
 
     @Override
     public String toString() {
-        return "ID: " + sensorId + ", Strength: " + sensorStrength;
+        return "ID: " + sensorId + ", Strength: " + sensorStrength + ", Type: " + sensorType;
     }
 }
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java b/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
index 684d7d9..a338575 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
@@ -17,10 +17,13 @@
 package android.hardware.fingerprint;
 
 import android.annotation.IntDef;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.SensorProperties;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Container for fingerprint sensor properties.
@@ -77,8 +80,13 @@
      */
     public static FingerprintSensorProperties from(
             FingerprintSensorPropertiesInternal internalProp) {
+        final List<ComponentInfo> componentInfo = new ArrayList<>();
+        for (ComponentInfoInternal internalComp : internalProp.componentInfo) {
+            componentInfo.add(ComponentInfo.from(internalComp));
+        }
         return new FingerprintSensorProperties(internalProp.sensorId,
                 internalProp.sensorStrength,
+                componentInfo,
                 internalProp.sensorType);
     }
 
@@ -86,8 +94,8 @@
      * @hide
      */
     public FingerprintSensorProperties(int sensorId, int sensorStrength,
-            @SensorType int sensorType) {
-        super(sensorId, sensorStrength);
+            List<ComponentInfo> componentInfo, @SensorType int sensorType) {
+        super(sensorId, sensorStrength, componentInfo);
         mSensorType = sensorType;
     }
 
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
index adc61a7..1b13370 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
@@ -21,10 +21,13 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.SensorProperties;
 import android.hardware.biometrics.SensorPropertiesInternal;
 import android.os.Parcel;
 
+import java.util.List;
+
 /**
  * Container for fingerprint sensor properties.
  * @hide
@@ -59,6 +62,7 @@
 
     public FingerprintSensorPropertiesInternal(int sensorId,
             @SensorProperties.Strength int strength, int maxEnrollmentsPerUser,
+            List<ComponentInfoInternal> componentInfo,
             @FingerprintSensorProperties.SensorType int sensorType,
             boolean resetLockoutRequiresHardwareAuthToken, int sensorLocationX, int sensorLocationY,
             int sensorRadius) {
@@ -66,8 +70,8 @@
         // required as it can only be generated/attested/verified by TEE components.
         // IFingerprint@1.0 handles lockout below the HAL, but does not require a challenge. See
         // the HAL interface for more details.
-        super(sensorId, strength, maxEnrollmentsPerUser, resetLockoutRequiresHardwareAuthToken,
-                false /* resetLockoutRequiresChallenge */);
+        super(sensorId, strength, maxEnrollmentsPerUser, componentInfo,
+            resetLockoutRequiresHardwareAuthToken, false /* resetLockoutRequiresChallenge */);
         this.sensorType = sensorType;
         this.sensorLocationX = sensorLocationX;
         this.sensorLocationY = sensorLocationY;
@@ -79,10 +83,11 @@
      */
     public FingerprintSensorPropertiesInternal(int sensorId,
             @SensorProperties.Strength int strength, int maxEnrollmentsPerUser,
+            List<ComponentInfoInternal> componentInfo,
             @FingerprintSensorProperties.SensorType int sensorType,
             boolean resetLockoutRequiresHardwareAuthToken) {
         // TODO(b/179175438): Value should be provided from the HAL
-        this(sensorId, strength, maxEnrollmentsPerUser, sensorType,
+        this(sensorId, strength, maxEnrollmentsPerUser, componentInfo, sensorType,
                 resetLockoutRequiresHardwareAuthToken, 540 /* sensorLocationX */,
                 1636 /* sensorLocationY */, 130 /* sensorRadius */);
     }
@@ -94,10 +99,11 @@
     // TODO(b/179175438): Remove this constructor once all HALs move to AIDL.
     public FingerprintSensorPropertiesInternal(@NonNull Context context, int sensorId,
             @SensorProperties.Strength int strength, int maxEnrollmentsPerUser,
+            List<ComponentInfoInternal> componentInfo,
             @FingerprintSensorProperties.SensorType int sensorType,
             boolean resetLockoutRequiresHardwareAuthToken) {
-        super(sensorId, strength, maxEnrollmentsPerUser, resetLockoutRequiresHardwareAuthToken,
-                false /* resetLockoutRequiresChallenge */);
+        super(sensorId, strength, maxEnrollmentsPerUser, componentInfo,
+            resetLockoutRequiresHardwareAuthToken, false /* resetLockoutRequiresChallenge */);
         this.sensorType = sensorType;
 
         int[] props = context.getResources().getIntArray(
diff --git a/core/java/android/os/BytesMatcher.java b/core/java/android/os/BytesMatcher.java
index 8537f47..8974c5e 100644
--- a/core/java/android/os/BytesMatcher.java
+++ b/core/java/android/os/BytesMatcher.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.bluetooth.BluetoothUuid;
 import android.net.MacAddress;
+import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.util.HexDump;
@@ -42,207 +43,273 @@
  * @hide
  */
 public class BytesMatcher implements Predicate<byte[]> {
-   private static final String TAG = "BytesMatcher";
+    private static final String TAG = "BytesMatcher";
 
-   private static final char TYPE_ACCEPT = '+';
-   private static final char TYPE_REJECT = '-';
+    private static final char TYPE_EXACT_ACCEPT = '+';
+    private static final char TYPE_EXACT_REJECT = '-';
+    private static final char TYPE_PREFIX_ACCEPT = '⊆';
+    private static final char TYPE_PREFIX_REJECT = '⊈';
 
-   private final ArrayList<Rule> mRules = new ArrayList<>();
+    private final ArrayList<Rule> mRules = new ArrayList<>();
 
-   private static class Rule {
-       public final char type;
-       public final @NonNull byte[] value;
-       public final @Nullable byte[] mask;
+    private static class Rule {
+        public final char type;
+        public final @NonNull byte[] value;
+        public final @Nullable byte[] mask;
 
-       public Rule(char type, @NonNull byte[] value, @Nullable byte[] mask) {
-           if (mask != null && value.length != mask.length) {
-               throw new IllegalArgumentException(
-                       "Expected length " + value.length + " but found " + mask.length);
-           }
-           this.type = type;
-           this.value = value;
-           this.mask = mask;
-       }
+        public Rule(char type, @NonNull byte[] value, @Nullable byte[] mask) {
+            if (mask != null && value.length != mask.length) {
+                throw new IllegalArgumentException(
+                        "Expected length " + value.length + " but found " + mask.length);
+            }
+            this.type = type;
+            this.value = value;
+            this.mask = mask;
+        }
 
-       @Override
-       public String toString() {
-           StringBuilder builder = new StringBuilder();
-           encode(builder);
-           return builder.toString();
-       }
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            encode(builder);
+            return builder.toString();
+        }
 
-       public void encode(@NonNull StringBuilder builder) {
-           builder.append(type);
-           builder.append(HexDump.toHexString(value));
-           if (mask != null) {
-               builder.append('/');
-               builder.append(HexDump.toHexString(mask));
-           }
-       }
+        public void encode(@NonNull StringBuilder builder) {
+            builder.append(type);
+            builder.append(HexDump.toHexString(value));
+            if (mask != null) {
+                builder.append('/');
+                builder.append(HexDump.toHexString(mask));
+            }
+        }
 
-       public boolean test(@NonNull byte[] value) {
-           if (value.length != this.value.length) {
-               return false;
-           }
-           for (int i = 0; i < this.value.length; i++) {
-               byte local = this.value[i];
-               byte remote = value[i];
-               if (this.mask != null) {
-                   local &= this.mask[i];
-                   remote &= this.mask[i];
-               }
-               if (local != remote) {
-                   return false;
-               }
-           }
-           return true;
-       }
-   }
+        public boolean test(@NonNull byte[] value) {
+            switch (type) {
+                case TYPE_EXACT_ACCEPT:
+                case TYPE_EXACT_REJECT:
+                    if (value.length != this.value.length) {
+                        return false;
+                    }
+                    break;
+                case TYPE_PREFIX_ACCEPT:
+                case TYPE_PREFIX_REJECT:
+                    if (value.length < this.value.length) {
+                        return false;
+                    }
+                    break;
+            }
+            for (int i = 0; i < this.value.length; i++) {
+                byte local = this.value[i];
+                byte remote = value[i];
+                if (this.mask != null) {
+                    local &= this.mask[i];
+                    remote &= this.mask[i];
+                }
+                if (local != remote) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
 
-   /**
-    * Add a rule that will result in {@link #test(byte[])} returning
-    * {@code true} when a value being tested matches it.
-    * <p>
-    * Rules are tested in the order in which they were originally added, which
-    * means a narrow rule can reject a specific value before a later broader
-    * rule might accept that same value, or vice versa.
-    *
-    * @param value to be matched
-    * @param mask to be applied to both values before testing for equality; if
-    *            {@code null} then both values must match exactly
-    */
-   public void addAcceptRule(@NonNull byte[] value, @Nullable byte[] mask) {
-       mRules.add(new Rule(TYPE_ACCEPT, value, mask));
-   }
+    /**
+     * Add a rule that will result in {@link #test(byte[])} returning
+     * {@code true} when a value being tested matches it. This rule will only
+     * match values of the exact same length.
+     * <p>
+     * Rules are tested in the order in which they were originally added, which
+     * means a narrow rule can reject a specific value before a later broader
+     * rule might accept that same value, or vice versa.
+     *
+     * @param value to be matched
+     * @param mask to be applied to both values before testing for equality; if
+     *            {@code null} then both values must match exactly
+     */
+    public void addExactAcceptRule(@NonNull byte[] value, @Nullable byte[] mask) {
+        mRules.add(new Rule(TYPE_EXACT_ACCEPT, value, mask));
+    }
 
-   /**
-    * Add a rule that will result in {@link #test(byte[])} returning
-    * {@code false} when a value being tested matches it.
-    * <p>
-    * Rules are tested in the order in which they were originally added, which
-    * means a narrow rule can reject a specific value before a later broader
-    * rule might accept that same value, or vice versa.
-    *
-    * @param value to be matched
-    * @param mask to be applied to both values before testing for equality; if
-    *            {@code null} then both values must match exactly
-    */
-   public void addRejectRule(@NonNull byte[] value, @Nullable byte[] mask) {
-       mRules.add(new Rule(TYPE_REJECT, value, mask));
-   }
+    /**
+     * Add a rule that will result in {@link #test(byte[])} returning
+     * {@code false} when a value being tested matches it. This rule will only
+     * match values of the exact same length.
+     * <p>
+     * Rules are tested in the order in which they were originally added, which
+     * means a narrow rule can reject a specific value before a later broader
+     * rule might accept that same value, or vice versa.
+     *
+     * @param value to be matched
+     * @param mask to be applied to both values before testing for equality; if
+     *            {@code null} then both values must match exactly
+     */
+    public void addExactRejectRule(@NonNull byte[] value, @Nullable byte[] mask) {
+        mRules.add(new Rule(TYPE_EXACT_REJECT, value, mask));
+    }
 
-   /**
-    * Test if the given {@code ParcelUuid} value matches the set of rules
-    * configured in this matcher.
-    */
-   public boolean testBluetoothUuid(@NonNull ParcelUuid value) {
-       return test(BluetoothUuid.uuidToBytes(value));
-   }
+    /**
+     * Add a rule that will result in {@link #test(byte[])} returning
+     * {@code true} when a value being tested matches it. This rule will match
+     * values of the exact same length or longer.
+     * <p>
+     * Rules are tested in the order in which they were originally added, which
+     * means a narrow rule can reject a specific value before a later broader
+     * rule might accept that same value, or vice versa.
+     *
+     * @param value to be matched
+     * @param mask to be applied to both values before testing for equality; if
+     *            {@code null} then both values must match exactly
+     */
+    public void addPrefixAcceptRule(@NonNull byte[] value, @Nullable byte[] mask) {
+        mRules.add(new Rule(TYPE_PREFIX_ACCEPT, value, mask));
+    }
 
-   /**
-    * Test if the given {@code MacAddress} value matches the set of rules
-    * configured in this matcher.
-    */
-   public boolean testMacAddress(@NonNull MacAddress value) {
-       return test(value.toByteArray());
-   }
+    /**
+     * Add a rule that will result in {@link #test(byte[])} returning
+     * {@code false} when a value being tested matches it. This rule will match
+     * values of the exact same length or longer.
+     * <p>
+     * Rules are tested in the order in which they were originally added, which
+     * means a narrow rule can reject a specific value before a later broader
+     * rule might accept that same value, or vice versa.
+     *
+     * @param value to be matched
+     * @param mask to be applied to both values before testing for equality; if
+     *            {@code null} then both values must match exactly
+     */
+    public void addPrefixRejectRule(@NonNull byte[] value, @Nullable byte[] mask) {
+        mRules.add(new Rule(TYPE_PREFIX_REJECT, value, mask));
+    }
 
-   /**
-    * Test if the given {@code byte[]} value matches the set of rules
-    * configured in this matcher.
-    */
-   @Override
-   public boolean test(@NonNull byte[] value) {
-       return test(value, false);
-   }
+    /**
+     * Test if the given {@code ParcelUuid} value matches the set of rules
+     * configured in this matcher.
+     */
+    public boolean testBluetoothUuid(@NonNull ParcelUuid value) {
+        return test(BluetoothUuid.uuidToBytes(value));
+    }
 
-   /**
-    * Test if the given {@code byte[]} value matches the set of rules
-    * configured in this matcher.
-    */
-   public boolean test(@NonNull byte[] value, boolean defaultValue) {
-       final int size = mRules.size();
-       for (int i = 0; i < size; i++) {
-           final Rule rule = mRules.get(i);
-           if (rule.test(value)) {
-               return (rule.type == TYPE_ACCEPT);
-           }
-       }
-       return defaultValue;
-   }
+    /**
+     * Test if the given {@code MacAddress} value matches the set of rules
+     * configured in this matcher.
+     */
+    public boolean testMacAddress(@NonNull MacAddress value) {
+        return test(value.toByteArray());
+    }
 
-   /**
-    * Encode the given matcher into a human-readable {@link String} which can
-    * be used to transport matchers across device boundaries.
-    * <p>
-    * The human-readable format is an ordered list separated by commas, where
-    * each rule is a {@code +} or {@code -} symbol indicating if the match
-    * should be accepted or rejected, then followed by a hex value and an
-    * optional hex mask. For example, {@code -caff,+cafe/ff00} is a valid
-    * encoded matcher.
-    *
-    * @see #decode(String)
-    */
-   public static @NonNull String encode(@NonNull BytesMatcher matcher) {
-       final StringBuilder builder = new StringBuilder();
-       final int size = matcher.mRules.size();
-       for (int i = 0; i < size; i++) {
-           final Rule rule = matcher.mRules.get(i);
-           rule.encode(builder);
-           builder.append(',');
-       }
-       builder.deleteCharAt(builder.length() - 1);
-       return builder.toString();
-   }
+    /**
+     * Test if the given {@code byte[]} value matches the set of rules
+     * configured in this matcher.
+     */
+    @Override
+    public boolean test(@NonNull byte[] value) {
+        return test(value, false);
+    }
 
-   /**
-    * Decode the given human-readable {@link String} used to transport matchers
-    * across device boundaries.
-    * <p>
-    * The human-readable format is an ordered list separated by commas, where
-    * each rule is a {@code +} or {@code -} symbol indicating if the match
-    * should be accepted or rejected, then followed by a hex value and an
-    * optional hex mask. For example, {@code -caff,+cafe/ff00} is a valid
-    * encoded matcher.
-    *
-    * @see #encode(BytesMatcher)
-    */
-   public static @NonNull BytesMatcher decode(@NonNull String value) {
-       final BytesMatcher matcher = new BytesMatcher();
-       final int length = value.length();
-       for (int i = 0; i < length;) {
-           final char type = value.charAt(i);
+    /**
+     * Test if the given {@code byte[]} value matches the set of rules
+     * configured in this matcher.
+     */
+    public boolean test(@NonNull byte[] value, boolean defaultValue) {
+        final int size = mRules.size();
+        for (int i = 0; i < size; i++) {
+            final Rule rule = mRules.get(i);
+            if (rule.test(value)) {
+                switch (rule.type) {
+                    case TYPE_EXACT_ACCEPT:
+                    case TYPE_PREFIX_ACCEPT:
+                        return true;
+                    case TYPE_EXACT_REJECT:
+                    case TYPE_PREFIX_REJECT:
+                        return false;
+                }
+            }
+        }
+        return defaultValue;
+    }
 
-           int nextRule = value.indexOf(',', i);
-           int nextMask = value.indexOf('/', i);
+    /**
+     * Encode the given matcher into a human-readable {@link String} which can
+     * be used to transport matchers across device boundaries.
+     * <p>
+     * The human-readable format is an ordered list separated by commas, where
+     * each rule is a {@code +} or {@code -} symbol indicating if the match
+     * should be accepted or rejected, then followed by a hex value and an
+     * optional hex mask. For example, {@code -caff,+cafe/ff00} is a valid
+     * encoded matcher.
+     *
+     * @see #decode(String)
+     */
+    public static @NonNull String encode(@NonNull BytesMatcher matcher) {
+        final StringBuilder builder = new StringBuilder();
+        final int size = matcher.mRules.size();
+        for (int i = 0; i < size; i++) {
+            final Rule rule = matcher.mRules.get(i);
+            rule.encode(builder);
+            builder.append(',');
+        }
+        if (builder.length() > 0) {
+            builder.deleteCharAt(builder.length() - 1);
+        }
+        return builder.toString();
+    }
 
-           if (nextRule == -1) nextRule = length;
-           if (nextMask > nextRule) nextMask = -1;
+    /**
+     * Decode the given human-readable {@link String} used to transport matchers
+     * across device boundaries.
+     * <p>
+     * The human-readable format is an ordered list separated by commas, where
+     * each rule is a {@code +} or {@code -} symbol indicating if the match
+     * should be accepted or rejected, then followed by a hex value and an
+     * optional hex mask. For example, {@code -caff,+cafe/ff00} is a valid
+     * encoded matcher.
+     *
+     * @see #encode(BytesMatcher)
+     */
+    public static @NonNull BytesMatcher decode(@Nullable String value) {
+        final BytesMatcher matcher = new BytesMatcher();
+        if (TextUtils.isEmpty(value)) return matcher;
 
-           final byte[] ruleValue;
-           final byte[] ruleMask;
-           if (nextMask >= 0) {
-               ruleValue = HexDump.hexStringToByteArray(value.substring(i + 1, nextMask));
-               ruleMask = HexDump.hexStringToByteArray(value.substring(nextMask + 1, nextRule));
-           } else {
-               ruleValue = HexDump.hexStringToByteArray(value.substring(i + 1, nextRule));
-               ruleMask = null;
-           }
+        final int length = value.length();
+        for (int i = 0; i < length;) {
+            final char type = value.charAt(i);
 
-           switch (type) {
-               case TYPE_ACCEPT:
-                   matcher.addAcceptRule(ruleValue, ruleMask);
-                   break;
-               case TYPE_REJECT:
-                   matcher.addRejectRule(ruleValue, ruleMask);
-                   break;
-               default:
-                   Log.w(TAG, "Ignoring unknown type " + type);
-                   break;
-           }
+            int nextRule = value.indexOf(',', i);
+            int nextMask = value.indexOf('/', i);
 
-           i = nextRule + 1;
-       }
-       return matcher;
-   }
+            if (nextRule == -1) nextRule = length;
+            if (nextMask > nextRule) nextMask = -1;
+
+            final byte[] ruleValue;
+            final byte[] ruleMask;
+            if (nextMask >= 0) {
+                ruleValue = HexDump.hexStringToByteArray(value.substring(i + 1, nextMask));
+                ruleMask = HexDump.hexStringToByteArray(value.substring(nextMask + 1, nextRule));
+            } else {
+                ruleValue = HexDump.hexStringToByteArray(value.substring(i + 1, nextRule));
+                ruleMask = null;
+            }
+
+            switch (type) {
+                case TYPE_EXACT_ACCEPT:
+                    matcher.addExactAcceptRule(ruleValue, ruleMask);
+                    break;
+                case TYPE_EXACT_REJECT:
+                    matcher.addExactRejectRule(ruleValue, ruleMask);
+                    break;
+                case TYPE_PREFIX_ACCEPT:
+                    matcher.addPrefixAcceptRule(ruleValue, ruleMask);
+                    break;
+                case TYPE_PREFIX_REJECT:
+                    matcher.addPrefixRejectRule(ruleValue, ruleMask);
+                    break;
+                default:
+                    Log.w(TAG, "Ignoring unknown type " + type);
+                    break;
+            }
+
+            i = nextRule + 1;
+        }
+        return matcher;
+    }
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 13f3979..f1c80af 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -433,6 +433,20 @@
             "android.settings.REQUEST_SCHEDULE_EXACT_ALARM";
 
     /**
+     * Activity Action: Show settings to allow configuration of
+     * {@link Manifest.permission#MANAGE_MEDIA} permission
+     *
+     * Input: Optionally, the Intent's data URI can specify the application package name to
+     * directly invoke the management GUI specific to the package name. For example
+     * "package:com.my.app".
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_REQUEST_MANAGE_MEDIA =
+            "android.settings.REQUEST_MANAGE_MEDIA";
+
+    /**
      * Activity Action: Show settings to allow configuration of cross-profile access for apps
      *
      * Input: Optionally, the Intent's data URI can specify the application package name to
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index ff4d671..9872dc0 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -462,11 +462,25 @@
      */
     @UnsupportedAppUsage
     String mCurId;
+
     /**
-     * The actual instance of the method to make calls on it.
+     * Kept for {@link UnsupportedAppUsage}.  Not officially maintained.
+     *
+     * @deprecated New code should use {@link #mCurrentInputMethodSession}.
      */
+    @Deprecated
+    @GuardedBy("mH")
+    @Nullable
     @UnsupportedAppUsage
     IInputMethodSession mCurMethod;
+
+    /**
+     * Encapsulates IPCs to the currently connected InputMethodService.
+     */
+    @Nullable
+    @GuardedBy("mH")
+    private InputMethodSessionWrapper mCurrentInputMethodSession = null;
+
     InputChannel mCurChannel;
     ImeInputEventSender mCurSender;
 
@@ -623,11 +637,8 @@
         public void finishInputAndReportToIme() {
             synchronized (mH) {
                 finishInputLocked();
-                if (mCurMethod != null) {
-                    try {
-                        mCurMethod.finishInput();
-                    } catch (RemoteException e) {
-                    }
+                if (mCurrentInputMethodSession != null) {
+                    mCurrentInputMethodSession.finishInput();
                 }
             }
         }
@@ -754,7 +765,8 @@
         @Override
         public boolean hasActiveConnection(View view) {
             synchronized (mH) {
-                if (!hasServedByInputMethodLocked(view) || mCurMethod == null) {
+                if (!hasServedByInputMethodLocked(view)
+                        || mCurrentInputMethodSession == null) {
                     return false;
                 }
 
@@ -861,7 +873,9 @@
                                 REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE;
 
                         setInputChannelLocked(res.channel);
-                        mCurMethod = res.method;
+                        mCurMethod = res.method; // for @UnsupportedAppUsage
+                        mCurrentInputMethodSession =
+                                InputMethodSessionWrapper.createOrNull(res.method);
                         mCurId = res.id;
                         mBindSequence = res.sequence;
                         mActivityViewToScreenMatrix = res.getActivityViewToScreenMatrix();
@@ -1004,7 +1018,7 @@
                         }
                         mActivityViewToScreenMatrix.setValues(matrixValues);
 
-                        if (mCursorAnchorInfo == null || mCurMethod == null
+                        if (mCursorAnchorInfo == null || mCurrentInputMethodSession == null
                                 || mServedInputConnectionWrapper == null) {
                             return;
                         }
@@ -1015,13 +1029,9 @@
                         }
                         // Since the host ActivityView is moved, we need to issue
                         // IMS#updateCursorAnchorInfo() again.
-                        try {
-                            mCurMethod.updateCursorAnchorInfo(
-                                    CursorAnchorInfo.createForAdditionalParentMatrix(
-                                            mCursorAnchorInfo, mActivityViewToScreenMatrix));
-                        } catch (RemoteException e) {
-                            Log.w(TAG, "IME died: " + mCurId, e);
-                        }
+                        mCurrentInputMethodSession.updateCursorAnchorInfo(
+                                CursorAnchorInfo.createForAdditionalParentMatrix(
+                                        mCursorAnchorInfo, mActivityViewToScreenMatrix));
                     }
                     return;
                 }
@@ -1498,7 +1508,8 @@
         setInputChannelLocked(null);
         mBindSequence = -1;
         mCurId = null;
-        mCurMethod = null;
+        mCurMethod = null; // for @UnsupportedAppUsage
+        mCurrentInputMethodSession = null;
     }
 
     void setInputChannelLocked(InputChannel channel) {
@@ -1562,11 +1573,8 @@
             }
 
             mCompletions = completions;
-            if (mCurMethod != null) {
-                try {
-                    mCurMethod.displayCompletions(mCompletions);
-                } catch (RemoteException e) {
-                }
+            if (mCurrentInputMethodSession != null) {
+                mCurrentInputMethodSession.displayCompletions(mCompletions);
             }
         }
     }
@@ -1585,11 +1593,8 @@
                 return;
             }
 
-            if (mCurMethod != null) {
-                try {
-                    mCurMethod.updateExtractedText(token, text);
-                } catch (RemoteException e) {
-                }
+            if (mCurrentInputMethodSession != null) {
+                mCurrentInputMethodSession.updateExtractedText(token, text);
             }
         }
     }
@@ -1850,11 +1855,8 @@
             if (servedView == null || servedView.getWindowToken() != windowToken) {
                 return;
             }
-            if (mCurMethod != null) {
-                try {
-                    mCurMethod.toggleSoftInput(showFlags, hideFlags);
-                } catch (RemoteException e) {
-                }
+            if (mCurrentInputMethodSession != null) {
+                mCurrentInputMethodSession.toggleSoftInput(showFlags, hideFlags);
             }
         }
     }
@@ -1875,11 +1877,8 @@
         ImeTracing.getInstance().triggerClientDump(
                 "InputMethodManager#toggleSoftInput", InputMethodManager.this,
                 null /* icProto */);
-        if (mCurMethod != null) {
-            try {
-                mCurMethod.toggleSoftInput(showFlags, hideFlags);
-            } catch (RemoteException e) {
-            }
+        if (mCurrentInputMethodSession != null) {
+            mCurrentInputMethodSession.toggleSoftInput(showFlags, hideFlags);
         }
     }
 
@@ -2062,7 +2061,8 @@
                 if (res.id != null) {
                     setInputChannelLocked(res.channel);
                     mBindSequence = res.sequence;
-                    mCurMethod = res.method;
+                    mCurMethod = res.method; // for @UnsupportedAppUsage
+                    mCurrentInputMethodSession = InputMethodSessionWrapper.createOrNull(res.method);
                     mCurId = res.id;
                 } else if (res.channel != null && res.channel != mCurChannel) {
                     res.channel.dispose();
@@ -2072,11 +2072,8 @@
                         mRestartOnNextWindowFocus = true;
                         break;
                 }
-                if (mCurMethod != null && mCompletions != null) {
-                    try {
-                        mCurMethod.displayCompletions(mCompletions);
-                    } catch (RemoteException e) {
-                    }
+                if (mCurrentInputMethodSession != null && mCompletions != null) {
+                    mCurrentInputMethodSession.displayCompletions(mCompletions);
                 }
             } catch (RemoteException e) {
                 Log.w(TAG, "IME died: " + mCurId, e);
@@ -2234,12 +2231,9 @@
         ImeTracing.getInstance().triggerClientDump("InputMethodManager#notifyImeHidden", this,
                 null /* icProto */);
         synchronized (mH) {
-            try {
-                if (mCurMethod != null && mCurRootView != null
-                        && mCurRootView.getWindowToken() == windowToken) {
-                    mCurMethod.notifyImeHidden();
-                }
-            } catch (RemoteException re) {
+            if (mCurrentInputMethodSession != null && mCurRootView != null
+                    && mCurRootView.getWindowToken() == windowToken) {
+                mCurrentInputMethodSession.notifyImeHidden();
             }
         }
     }
@@ -2284,7 +2278,7 @@
         checkFocus();
         synchronized (mH) {
             if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null
-                    || mCurMethod == null) {
+                    || mCurrentInputMethodSession == null) {
                 return;
             }
 
@@ -2293,22 +2287,20 @@
                     || mCursorCandEnd != candidatesEnd) {
                 if (DEBUG) Log.d(TAG, "updateSelection");
 
-                try {
-                    if (DEBUG) Log.v(TAG, "SELECTION CHANGE: " + mCurMethod);
-                    final int oldSelStart = mCursorSelStart;
-                    final int oldSelEnd = mCursorSelEnd;
-                    // Update internal values before sending updateSelection to the IME, because
-                    // if it changes the text within its onUpdateSelection handler in a way that
-                    // does not move the cursor we don't want to call it again with the same values.
-                    mCursorSelStart = selStart;
-                    mCursorSelEnd = selEnd;
-                    mCursorCandStart = candidatesStart;
-                    mCursorCandEnd = candidatesEnd;
-                    mCurMethod.updateSelection(oldSelStart, oldSelEnd,
-                            selStart, selEnd, candidatesStart, candidatesEnd);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "IME died: " + mCurId, e);
+                if (DEBUG) {
+                    Log.v(TAG, "SELECTION CHANGE: " + mCurrentInputMethodSession);
                 }
+                final int oldSelStart = mCursorSelStart;
+                final int oldSelEnd = mCursorSelEnd;
+                // Update internal values before sending updateSelection to the IME, because
+                // if it changes the text within its onUpdateSelection handler in a way that
+                // does not move the cursor we don't want to call it again with the same values.
+                mCursorSelStart = selStart;
+                mCursorSelEnd = selEnd;
+                mCursorCandStart = candidatesStart;
+                mCursorCandEnd = candidatesEnd;
+                mCurrentInputMethodSession.updateSelection(
+                        oldSelStart, oldSelEnd, selStart, selEnd, candidatesStart, candidatesEnd);
             }
         }
     }
@@ -2342,15 +2334,11 @@
         checkFocus();
         synchronized (mH) {
             if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null
-                    || mCurMethod == null) {
+                    || mCurrentInputMethodSession == null) {
                 return;
             }
-            try {
-                if (DEBUG) Log.v(TAG, "onViewClicked: " + focusChanged);
-                mCurMethod.viewClicked(focusChanged);
-            } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-            }
+            if (DEBUG) Log.v(TAG, "onViewClicked: " + focusChanged);
+            mCurrentInputMethodSession.viewClicked(focusChanged);
         }
     }
 
@@ -2411,21 +2399,16 @@
         checkFocus();
         synchronized (mH) {
             if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null
-                    || mCurMethod == null) {
+                    || mCurrentInputMethodSession == null) {
                 return;
             }
 
             mTmpCursorRect.set(left, top, right, bottom);
             if (!mCursorRect.equals(mTmpCursorRect)) {
-                if (DEBUG) Log.d(TAG, "updateCursor");
+                if (DEBUG) Log.d(TAG, "updateCursor: " + mCurrentInputMethodSession);
 
-                try {
-                    if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod);
-                    mCurMethod.updateCursor(mTmpCursorRect);
-                    mCursorRect.set(mTmpCursorRect);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "IME died: " + mCurId, e);
-                }
+                mCurrentInputMethodSession.updateCursor(mTmpCursorRect);
+                mCursorRect.set(mTmpCursorRect);
             }
         }
     }
@@ -2448,7 +2431,7 @@
         checkFocus();
         synchronized (mH) {
             if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null
-                    || mCurMethod == null) {
+                    || mCurrentInputMethodSession == null) {
                 return;
             }
             // If immediate bit is set, we will call updateCursorAnchorInfo() even when the data has
@@ -2465,21 +2448,16 @@
                 return;
             }
             if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo);
-            try {
-                if (mActivityViewToScreenMatrix != null) {
-                    mCurMethod.updateCursorAnchorInfo(
-                            CursorAnchorInfo.createForAdditionalParentMatrix(
-                                    cursorAnchorInfo, mActivityViewToScreenMatrix));
-                } else {
-                    mCurMethod.updateCursorAnchorInfo(cursorAnchorInfo);
-                }
-                mCursorAnchorInfo = cursorAnchorInfo;
-                // Clear immediate bit (if any).
-                mRequestUpdateCursorAnchorInfoMonitorMode &=
-                        ~InputConnection.CURSOR_UPDATE_IMMEDIATE;
-            } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
+            if (mActivityViewToScreenMatrix != null) {
+                mCurrentInputMethodSession.updateCursorAnchorInfo(
+                        CursorAnchorInfo.createForAdditionalParentMatrix(
+                            cursorAnchorInfo, mActivityViewToScreenMatrix));
+            } else {
+                mCurrentInputMethodSession.updateCursorAnchorInfo(cursorAnchorInfo);
             }
+            mCursorAnchorInfo = cursorAnchorInfo;
+            // Clear immediate bit (if any).
+            mRequestUpdateCursorAnchorInfoMonitorMode &= ~InputConnection.CURSOR_UPDATE_IMMEDIATE;
         }
     }
 
@@ -2505,15 +2483,11 @@
         checkFocus();
         synchronized (mH) {
             if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null
-                    || mCurMethod == null) {
+                    || mCurrentInputMethodSession == null) {
                 return;
             }
-            try {
-                if (DEBUG) Log.v(TAG, "APP PRIVATE COMMAND " + action + ": " + data);
-                mCurMethod.appPrivateCommand(action, data);
-            } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-            }
+            if (DEBUG) Log.v(TAG, "APP PRIVATE COMMAND " + action + ": " + data);
+            mCurrentInputMethodSession.appPrivateCommand(action, data);
         }
     }
 
@@ -2671,7 +2645,7 @@
     public int dispatchInputEvent(InputEvent event, Object token,
             FinishedInputEventCallback callback, Handler handler) {
         synchronized (mH) {
-            if (mCurMethod != null) {
+            if (mCurrentInputMethodSession != null) {
                 if (event instanceof KeyEvent) {
                     KeyEvent keyEvent = (KeyEvent)event;
                     if (keyEvent.getAction() == KeyEvent.ACTION_DOWN
@@ -2682,7 +2656,9 @@
                     }
                 }
 
-                if (DEBUG) Log.v(TAG, "DISPATCH INPUT EVENT: " + mCurMethod);
+                if (DEBUG) {
+                    Log.v(TAG, "DISPATCH INPUT EVENT: " + mCurrentInputMethodSession);
+                }
 
                 PendingEvent p = obtainPendingEventLocked(
                         event, token, mCurId, callback, handler);
@@ -2772,8 +2748,7 @@
                 return DISPATCH_IN_PROGRESS;
             }
 
-            Log.w(TAG, "Unable to send input event to IME: "
-                    + mCurId + " dropping: " + event);
+            Log.w(TAG, "Unable to send input event to IME: " + mCurId + " dropping: " + event);
         }
         return DISPATCH_NOT_HANDLED;
     }
@@ -3230,7 +3205,11 @@
                 + " mBindSequence=" + mBindSequence
                 + " mCurId=" + mCurId);
         p.println("  mFullscreenMode=" + mFullscreenMode);
-        p.println("  mCurMethod=" + mCurMethod);
+        if (mCurrentInputMethodSession != null) {
+            p.println("  mCurMethod=" + mCurrentInputMethodSession);
+        } else {
+            p.println("  mCurMethod= null");
+        }
         p.println("  mCurRootView=" + mCurRootView);
         p.println("  mServedView=" + getServedViewLocked());
         p.println("  mNextServedView=" + getNextServedViewLocked());
@@ -3346,7 +3325,7 @@
      */
     @GuardedBy("mH")
     public void dumpDebug(ProtoOutputStream proto, ProtoOutputStream icProto) {
-        if (mCurMethod == null) {
+        if (mCurrentInputMethodSession == null) {
             return;
         }
 
diff --git a/core/java/android/view/inputmethod/InputMethodSessionWrapper.java b/core/java/android/view/inputmethod/InputMethodSessionWrapper.java
new file mode 100644
index 0000000..c4a3773
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputMethodSessionWrapper.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+import android.annotation.AnyThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.view.IInputMethodSession;
+
+/**
+ * This class wrap the {@link IInputMethodSession} object from {@link InputMethodManager}.
+ * Using current {@link IInputMethodSession} object to communicate with
+ * {@link android.inputmethodservice.InputMethodService}.
+ */
+final class InputMethodSessionWrapper {
+
+    private static final String TAG = "InputMethodSessionWrapper";
+
+    /**
+     * The actual instance of the method to make calls on it.
+     */
+    @NonNull
+    private final IInputMethodSession mSession;
+
+    private InputMethodSessionWrapper(@NonNull IInputMethodSession inputMethodSession) {
+        mSession = inputMethodSession;
+    }
+
+    /**
+     * Create a {@link InputMethodSessionWrapper} instance if applicability.
+     *
+     * @param inputMethodSession {@link IInputMethodSession} object to be wrapped.
+     * @return an instance of {@link InputMethodSessionWrapper} if {@code inputMethodSession} is not
+     *         {@code null}. {@code null} otherwise.
+     */
+    @Nullable
+    public static InputMethodSessionWrapper createOrNull(
+            @NonNull IInputMethodSession inputMethodSession) {
+        return inputMethodSession != null ? new InputMethodSessionWrapper(inputMethodSession)
+                : null;
+    }
+
+    @AnyThread
+    void finishInput() {
+        try {
+            mSession.finishInput();
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void updateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) {
+        try {
+            mSession.updateCursorAnchorInfo(cursorAnchorInfo);
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void displayCompletions(CompletionInfo[] completions) {
+        try {
+            mSession.displayCompletions(completions);
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void updateExtractedText(int token, ExtractedText text) {
+        try {
+            mSession.updateExtractedText(token, text);
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void toggleSoftInput(int showFlags, int hideFlags) {
+        try {
+            mSession.toggleSoftInput(showFlags, hideFlags);
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void appPrivateCommand(String action, Bundle data) {
+        try {
+            mSession.appPrivateCommand(action, data);
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void notifyImeHidden() {
+        try {
+            mSession.notifyImeHidden();
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void viewClicked(boolean focusChanged) {
+        try {
+            mSession.viewClicked(focusChanged);
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void updateCursor(Rect newCursor) {
+        try {
+            mSession.updateCursor(newCursor);
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void updateSelection(int oldSelStart, int oldSelEnd, int selStart, int selEnd,
+            int candidatesStart, int candidatesEnd) {
+        try {
+            mSession.updateSelection(
+                    oldSelStart, oldSelEnd, selStart, selEnd, candidatesStart, candidatesEnd);
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    /**
+     * @return {@link IInputMethodSession#toString()} as a debug string.
+     */
+    @AnyThread
+    @NonNull
+    @Override
+    public String toString() {
+        return mSession.toString();
+    }
+}
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 499ce25..a0b4e24 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -16,6 +16,7 @@
 
 package android.window;
 
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_NONE;
@@ -31,6 +32,7 @@
 import android.graphics.Rect;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 
@@ -284,6 +286,8 @@
         private final Rect mEndAbsBounds = new Rect();
         private final Point mEndRelOffset = new Point();
         private ActivityManager.RunningTaskInfo mTaskInfo = null;
+        private int mStartRotation = ROTATION_UNDEFINED;
+        private int mEndRotation = ROTATION_UNDEFINED;
 
         public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) {
             mContainer = container;
@@ -301,6 +305,8 @@
             mEndAbsBounds.readFromParcel(in);
             mEndRelOffset.readFromParcel(in);
             mTaskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
+            mStartRotation = in.readInt();
+            mEndRotation = in.readInt();
         }
 
         /** Sets the parent of this change's container. The parent must be a participant or null. */
@@ -341,6 +347,12 @@
             mTaskInfo = taskInfo;
         }
 
+        /** Sets the start and end rotation of this container. */
+        public void setRotation(@Surface.Rotation int start, @Surface.Rotation int end) {
+            mStartRotation = start;
+            mEndRotation = end;
+        }
+
         /** @return the container that is changing. May be null if non-remotable (eg. activity) */
         @Nullable
         public WindowContainerToken getContainer() {
@@ -404,6 +416,14 @@
             return mTaskInfo;
         }
 
+        public int getStartRotation() {
+            return mStartRotation;
+        }
+
+        public int getEndRotation() {
+            return mEndRotation;
+        }
+
         @Override
         /** @hide */
         public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -416,6 +436,8 @@
             mEndAbsBounds.writeToParcel(dest, flags);
             mEndRelOffset.writeToParcel(dest, flags);
             dest.writeTypedObject(mTaskInfo, flags);
+            dest.writeInt(mStartRotation);
+            dest.writeInt(mEndRotation);
         }
 
         @NonNull
@@ -442,7 +464,8 @@
         public String toString() {
             return "{" + mContainer + "(" + mParent + ") leash=" + mLeash
                     + " m=" + modeToString(mMode) + " f=" + flagsToString(mFlags) + " sb="
-                    + mStartAbsBounds + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + "}";
+                    + mStartAbsBounds + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + " r="
+                    + mStartRotation + "->" + mEndRotation + "}";
         }
     }
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index da750de..5507261 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2310,11 +2310,6 @@
     <permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @SystemApi Allows read access to privileged network state in the device config.
-         @hide Used internally. -->
-    <permission android:name="android.permission.READ_NETWORK_DEVICE_CONFIG"
-        android:protectionLevel="signature|privileged" />
-
     <!-- Allows to read device identifiers and use ICC based authentication like EAP-AKA.
          Often required in authentication to access the carrier's server and manage services
          of the subscriber.
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 601d66e..0318be7 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2063,6 +2063,14 @@
         requested.  If it does support the feature, it will be as if the manifest didn't
         request it at all. -->
         <attr name="requiredNotFeature" format="string" />
+        <!-- Optional: set of flags that should apply to this permission request. -->
+        <attr name="usesPermissionFlags">
+            <!-- Strong assertion by a developer that they will never use this
+                 permission to derive the physical location of the device, even
+                 when the app has been granted the ACCESS_FINE_LOCATION and/or
+                 ACCESS_COARSE_LOCATION permissions. -->
+            <flag name="neverForLocation" value="0x1" />
+        </attr>
     </declare-styleable>
 
     <!-- <code>required-feature</code> and <code>required-not-feature</code> elements inside
diff --git a/core/tests/bluetoothtests/AndroidTest.xml b/core/tests/bluetoothtests/AndroidTest.xml
new file mode 100644
index 0000000..f93c4eb
--- /dev/null
+++ b/core/tests/bluetoothtests/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<configuration description="Config for Bluetooth test cases">
+    <option name="test-suite-tag" value="apct"/>
+    <option name="test-suite-tag" value="apct-instrumentation"/>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="BluetoothTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct"/>
+    <option name="test-tag" value="BluetoothTests"/>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.bluetooth.tests" />
+        <option name="hidden-api-checks" value="false"/>
+        <option name="runner" value="android.bluetooth.BluetoothTestRunner"/>
+    </test>
+</configuration>
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java
index 8b3db7e..c287ea9 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java
@@ -16,13 +16,18 @@
 
 package android.bluetooth.le;
 
-import android.bluetooth.le.ScanRecord;
+import android.os.BytesMatcher;
 import android.os.ParcelUuid;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.internal.util.HexDump;
+
 import junit.framework.TestCase;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
+import java.util.function.Predicate;
 
 /**
  * Unit test cases for {@link ScanRecord}.
@@ -31,6 +36,66 @@
  * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner'
  */
 public class ScanRecordTest extends TestCase {
+    /**
+     * Example raw beacons captured from a Blue Charm BC011
+     */
+    private static final String RECORD_URL = "0201060303AAFE1716AAFE10EE01626C7565636861726D626561636F6E730009168020691E0EFE13551109426C7565436861726D5F313639363835000000";
+    private static final String RECORD_UUID = "0201060303AAFE1716AAFE00EE626C7565636861726D31000000000001000009168020691E0EFE13551109426C7565436861726D5F313639363835000000";
+    private static final String RECORD_TLM = "0201060303AAFE1116AAFE20000BF017000008874803FB93540916802069080EFE13551109426C7565436861726D5F313639363835000000000000000000";
+    private static final String RECORD_IBEACON = "0201061AFF4C000215426C7565436861726D426561636F6E730EFE1355C509168020691E0EFE13551109426C7565436861726D5F31363936383500000000";
+
+    @SmallTest
+    public void testMatchesAnyField_Eddystone_Parser() {
+        final List<String> found = new ArrayList<>();
+        final Predicate<byte[]> matcher = (v) -> {
+            found.add(HexDump.toHexString(v));
+            return false;
+        };
+        ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(RECORD_URL))
+                .matchesAnyField(matcher);
+
+        assertEquals(Arrays.asList(
+                "020106",
+                "0303AAFE",
+                "1716AAFE10EE01626C7565636861726D626561636F6E7300",
+                "09168020691E0EFE1355",
+                "1109426C7565436861726D5F313639363835"), found);
+    }
+
+    @SmallTest
+    public void testMatchesAnyField_Eddystone() {
+        final BytesMatcher matcher = BytesMatcher.decode("⊆0016AAFE/00FFFFFF");
+        assertMatchesAnyField(RECORD_URL, matcher);
+        assertMatchesAnyField(RECORD_UUID, matcher);
+        assertMatchesAnyField(RECORD_TLM, matcher);
+        assertNotMatchesAnyField(RECORD_IBEACON, matcher);
+    }
+
+    @SmallTest
+    public void testMatchesAnyField_iBeacon_Parser() {
+        final List<String> found = new ArrayList<>();
+        final Predicate<byte[]> matcher = (v) -> {
+            found.add(HexDump.toHexString(v));
+            return false;
+        };
+        ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(RECORD_IBEACON))
+                .matchesAnyField(matcher);
+
+        assertEquals(Arrays.asList(
+                "020106",
+                "1AFF4C000215426C7565436861726D426561636F6E730EFE1355C5",
+                "09168020691E0EFE1355",
+                "1109426C7565436861726D5F313639363835"), found);
+    }
+
+    @SmallTest
+    public void testMatchesAnyField_iBeacon() {
+        final BytesMatcher matcher = BytesMatcher.decode("⊆00FF4C0002/00FFFFFFFF");
+        assertNotMatchesAnyField(RECORD_URL, matcher);
+        assertNotMatchesAnyField(RECORD_UUID, matcher);
+        assertNotMatchesAnyField(RECORD_TLM, matcher);
+        assertMatchesAnyField(RECORD_IBEACON, matcher);
+    }
 
     @SmallTest
     public void testParser() {
@@ -70,4 +135,14 @@
         }
 
     }
+
+    private static void assertMatchesAnyField(String record, BytesMatcher matcher) {
+        assertTrue(ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(record))
+                .matchesAnyField(matcher));
+    }
+
+    private static void assertNotMatchesAnyField(String record, BytesMatcher matcher) {
+        assertFalse(ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(record))
+                .matchesAnyField(matcher));
+    }
 }
diff --git a/core/tests/coretests/src/android/os/BytesMatcherTest.java b/core/tests/coretests/src/android/os/BytesMatcherTest.java
index 67c1b3c9..b28e309 100644
--- a/core/tests/coretests/src/android/os/BytesMatcherTest.java
+++ b/core/tests/coretests/src/android/os/BytesMatcherTest.java
@@ -59,6 +59,19 @@
     }
 
     @Test
+    public void testPrefix() throws Exception {
+        BytesMatcher matcher = BytesMatcher.decode("⊆cafe,⊆beef/ff00");
+        assertTrue(matcher.test(hexStringToByteArray("cafe")));
+        assertFalse(matcher.test(hexStringToByteArray("caff")));
+        assertTrue(matcher.test(hexStringToByteArray("cafecafe")));
+        assertFalse(matcher.test(hexStringToByteArray("ca")));
+        assertTrue(matcher.test(hexStringToByteArray("beef")));
+        assertTrue(matcher.test(hexStringToByteArray("beff")));
+        assertTrue(matcher.test(hexStringToByteArray("beffbeff")));
+        assertFalse(matcher.test(hexStringToByteArray("be")));
+    }
+
+    @Test
     public void testMacAddress() throws Exception {
         BytesMatcher matcher = BytesMatcher.decode("+cafe00112233/ffffff000000");
         assertTrue(matcher.testMacAddress(
@@ -94,13 +107,23 @@
     }
 
     @Test
-    public void testSerialize() throws Exception {
+    public void testSerialize_Empty() throws Exception {
         BytesMatcher matcher = new BytesMatcher();
-        matcher.addRejectRule(hexStringToByteArray("cafe00112233"),
+        matcher = BytesMatcher.decode(BytesMatcher.encode(matcher));
+
+        // Also very empty and null values
+        BytesMatcher.decode("");
+        BytesMatcher.decode(null);
+    }
+
+    @Test
+    public void testSerialize_Exact() throws Exception {
+        BytesMatcher matcher = new BytesMatcher();
+        matcher.addExactRejectRule(hexStringToByteArray("cafe00112233"),
                 hexStringToByteArray("ffffff000000"));
-        matcher.addRejectRule(hexStringToByteArray("beef00112233"),
+        matcher.addExactRejectRule(hexStringToByteArray("beef00112233"),
                 null);
-        matcher.addAcceptRule(hexStringToByteArray("000000000000"),
+        matcher.addExactAcceptRule(hexStringToByteArray("000000000000"),
                 hexStringToByteArray("000000000000"));
 
         assertFalse(matcher.test(hexStringToByteArray("cafe00ffffff")));
@@ -116,6 +139,28 @@
     }
 
     @Test
+    public void testSerialize_Prefix() throws Exception {
+        BytesMatcher matcher = new BytesMatcher();
+        matcher.addExactRejectRule(hexStringToByteArray("aa"), null);
+        matcher.addExactAcceptRule(hexStringToByteArray("bb"), null);
+        matcher.addPrefixAcceptRule(hexStringToByteArray("aa"), null);
+        matcher.addPrefixRejectRule(hexStringToByteArray("bb"), null);
+
+        assertFalse(matcher.test(hexStringToByteArray("aa")));
+        assertTrue(matcher.test(hexStringToByteArray("bb")));
+        assertTrue(matcher.test(hexStringToByteArray("aaaa")));
+        assertFalse(matcher.test(hexStringToByteArray("bbbb")));
+
+        // Bounce through serialization pass and confirm it still works
+        matcher = BytesMatcher.decode(BytesMatcher.encode(matcher));
+
+        assertFalse(matcher.test(hexStringToByteArray("aa")));
+        assertTrue(matcher.test(hexStringToByteArray("bb")));
+        assertTrue(matcher.test(hexStringToByteArray("aaaa")));
+        assertFalse(matcher.test(hexStringToByteArray("bbbb")));
+    }
+
+    @Test
     public void testOrdering_RejectFirst() throws Exception {
         BytesMatcher matcher = BytesMatcher.decode("-ff/0f,+ff/f0");
         assertFalse(matcher.test(hexStringToByteArray("ff")));
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
index 4319740..623e77e 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
@@ -29,6 +29,8 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -74,10 +76,9 @@
  *
  * or
  *
- * bit FrameworksCoreTests:com.android.internal.os.BatteryStatsCpuTimesTest
+ * atest FrameworksCoreTests:com.android.internal.os.BatteryStatsCpuTimesTest
  */
 @SmallTest
-@SkipPresubmit("b/180015146")
 @RunWith(AndroidJUnit4.class)
 public class BatteryStatsCpuTimesTest {
     @Mock
@@ -89,6 +90,8 @@
     @Mock
     KernelCpuUidClusterTimeReader mCpuUidClusterTimeReader;
     @Mock
+    SystemServerCpuThreadReader mSystemServerCpuThreadReader;
+    @Mock
     BatteryStatsImpl.UserInfoProvider mUserInfoProvider;
     @Mock
     PowerProfile mPowerProfile;
@@ -107,6 +110,7 @@
                 .setKernelCpuUidFreqTimeReader(mCpuUidFreqTimeReader)
                 .setKernelCpuUidActiveTimeReader(mCpuUidActiveTimeReader)
                 .setKernelCpuUidClusterTimeReader(mCpuUidClusterTimeReader)
+                .setSystemServerCpuThreadReader(mSystemServerCpuThreadReader)
                 .setUserInfoProvider(mUserInfoProvider);
     }
 
@@ -125,8 +129,8 @@
 
         // VERIFY
         assertArrayEquals("Unexpected cpu freqs", freqs, mBatteryStatsImpl.getCpuFreqs());
-        verify(mCpuUidUserSysTimeReader).readDelta(null);
-        verify(mCpuUidFreqTimeReader).readDelta(null);
+        verify(mCpuUidUserSysTimeReader).readDelta(anyBoolean(), isNull());
+        verify(mCpuUidFreqTimeReader).readDelta(anyBoolean(), isNull());
         for (int i = 0; i < numClusters; ++i) {
             verify(mKernelCpuSpeedReaders[i]).readDelta();
         }
@@ -145,16 +149,16 @@
 
         // VERIFY
         verify(mUserInfoProvider).refreshUserIds();
-        verify(mCpuUidUserSysTimeReader).readDelta(
+        verify(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidUserSysTimeReader.Callback.class));
         // perClusterTimesAvailable is called twice, once in updateCpuTimeLocked() and the other
         // in readKernelUidCpuFreqTimesLocked.
         verify(mCpuUidFreqTimeReader, times(2)).perClusterTimesAvailable();
-        verify(mCpuUidFreqTimeReader).readDelta(
+        verify(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
-        verify(mCpuUidActiveTimeReader).readDelta(
+        verify(mCpuUidActiveTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidActiveTimeReader.Callback.class));
-        verify(mCpuUidClusterTimeReader).readDelta(
+        verify(mCpuUidClusterTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidClusterTimeReader.Callback.class));
         verifyNoMoreInteractions(mCpuUidFreqTimeReader);
         for (int i = 0; i < numClusters; ++i) {
@@ -256,16 +260,16 @@
                 FIRST_APPLICATION_UID + 33
         });
         final long[][] uidTimesUs = {
-                {12, 34}, {34897394, 3123983}, {79775429834l, 8430434903489l}
+                {12, 34}, {34897394, 3123983}, {79775429834L, 8430434903489L}
         };
         doAnswer(invocation -> {
             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
-                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesUs[i]);
             }
             return null;
-        }).when(mCpuUidUserSysTimeReader).readDelta(
+        }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
@@ -291,16 +295,16 @@
 
         // PRECONDITIONS
         final long[][] deltasUs = {
-                {9379, 3332409833484l}, {493247, 723234}, {3247819, 123348}
+                {9379, 3332409833484L}, {493247, 723234}, {3247819, 123348}
         };
         doAnswer(invocation -> {
             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
-                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], deltasUs[i]);
             }
             return null;
-        }).when(mCpuUidUserSysTimeReader).readDelta(
+        }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
@@ -331,16 +335,16 @@
                 FIRST_APPLICATION_UID + 33
         });
         final long[][] uidTimesUs = {
-                {12, 34}, {34897394, 3123983}, {79775429834l, 8430434903489l}
+                {12, 34}, {34897394, 3123983}, {79775429834L, 8430434903489L}
         };
         doAnswer(invocation -> {
             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
-                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesUs[i]);
             }
             return null;
-        }).when(mCpuUidUserSysTimeReader).readDelta(
+        }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
@@ -367,16 +371,16 @@
         final int ownerUid = UserHandle.getUid(testUserId, FIRST_APPLICATION_UID + 42);
         mBatteryStatsImpl.addIsolatedUidLocked(isolatedUid, ownerUid);
         final long[][] deltasUs = {
-                {9379, 3332409833484l}, {493247, 723234}, {3247819, 123348}
+                {9379, 3332409833484L}, {493247, 723234}, {3247819, 123348}
         };
         doAnswer(invocation -> {
             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
-                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], deltasUs[i]);
             }
             return null;
-        }).when(mCpuUidUserSysTimeReader).readDelta(
+        }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
@@ -421,18 +425,18 @@
                 FIRST_APPLICATION_UID + 33
         });
         final long[][] uidTimesUs = {
-                {12, 34}, {34897394, 3123983}, {79775429834l, 8430434903489l}
+                {12, 34}, {34897394, 3123983}, {79775429834L, 8430434903489L}
         };
         doAnswer(invocation -> {
             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
-                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesUs[i]);
             }
             // And one for the invalid uid
             callback.onUidCpuTime(invalidUid, new long[]{3879, 239});
             return null;
-        }).when(mCpuUidUserSysTimeReader).readDelta(
+        }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
@@ -474,12 +478,12 @@
         };
         doAnswer(invocation -> {
             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
-                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesUs[i]);
             }
             return null;
-        }).when(mCpuUidUserSysTimeReader).readDelta(
+        }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
@@ -553,13 +557,13 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
@@ -582,17 +586,17 @@
         updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
         final long[][] deltasMs = {
                 {3, 12, 55, 100, 32},
-                {3248327490475l, 232349349845043l, 123, 2398, 0},
+                {3248327490475L, 232349349845043L, 123, 2398, 0},
                 {43, 3345, 2143, 123, 4554}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
@@ -636,13 +640,13 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
         when(mCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
 
@@ -676,17 +680,17 @@
         updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
         final long[][] deltasMs = {
                 {3, 12, 55, 100, 32},
-                {3248327490475l, 232349349845043l, 123, 2398, 0},
+                {3248327490475L, 232349349845043L, 123, 2398, 0},
                 {43, 3345, 2143, 123, 4554}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
@@ -746,13 +750,13 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
         when(mCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
 
@@ -836,13 +840,13 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
@@ -865,17 +869,17 @@
         updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
         final long[][] deltasMs = {
                 {3, 12, 55, 100, 32, 34984, 27983},
-                {3248327490475l, 232349349845043l, 123, 2398, 0, 398, 0},
-                {43, 3345, 2143, 123, 4554, 9374983794839l, 979875}
+                {3248327490475L, 232349349845043L, 123, 2398, 0, 398, 0},
+                {43, 3345, 2143, 123, 4554, 9374983794839L, 979875}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
@@ -913,13 +917,13 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
@@ -953,13 +957,13 @@
                 {43, 3345, 2143, 123, 4554}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
@@ -1008,15 +1012,15 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             // And one for the invalid uid
             callback.onUidCpuTime(invalidUid, new long[]{12, 839, 32, 34, 21});
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
@@ -1051,13 +1055,13 @@
         });
         final long[] uidTimesMs = {8000, 25000, 3000, 0, 42000};
         doAnswer(invocation -> {
-            final KernelCpuUidActiveTimeReader.Callback callback =
-                    (KernelCpuUidActiveTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidActiveTimeReader.Callback<Long> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mCpuUidActiveTimeReader).readDelta(
+        }).when(mCpuUidActiveTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidActiveTimeReader.Callback.class));
 
         // RUN
@@ -1077,13 +1081,13 @@
         updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
         final long[] deltasMs = {43000, 3345000, 2143000, 123000, 4554000};
         doAnswer(invocation -> {
-            final KernelCpuUidActiveTimeReader.Callback callback =
-                    (KernelCpuUidActiveTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidActiveTimeReader.Callback<Long> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mCpuUidActiveTimeReader).readDelta(
+        }).when(mCpuUidActiveTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidActiveTimeReader.Callback.class));
 
         // RUN
@@ -1115,15 +1119,15 @@
         });
         final long[] uidTimesMs = {8000, 25000, 3000, 0, 42000};
         doAnswer(invocation -> {
-            final KernelCpuUidActiveTimeReader.Callback callback =
-                    (KernelCpuUidActiveTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidActiveTimeReader.Callback<Long> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             // And one for the invalid uid
             callback.onUidCpuTime(invalidUid, 1200L);
             return null;
-        }).when(mCpuUidActiveTimeReader).readDelta(
+        }).when(mCpuUidActiveTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidActiveTimeReader.Callback.class));
 
         // RUN
@@ -1159,13 +1163,13 @@
                 {8000, 0}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidClusterTimeReader.Callback callback =
-                    (KernelCpuUidClusterTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidClusterTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mCpuUidClusterTimeReader).readDelta(
+        }).when(mCpuUidClusterTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidClusterTimeReader.Callback.class));
 
         // RUN
@@ -1189,13 +1193,13 @@
                 {43000, 3345000}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidClusterTimeReader.Callback callback =
-                    (KernelCpuUidClusterTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidClusterTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mCpuUidClusterTimeReader).readDelta(
+        }).when(mCpuUidClusterTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidClusterTimeReader.Callback.class));
 
         // RUN
@@ -1232,15 +1236,15 @@
                 {8000, 0}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidClusterTimeReader.Callback callback =
-                    (KernelCpuUidClusterTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidClusterTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             // And one for the invalid uid
             callback.onUidCpuTime(invalidUid, new long[]{400, 1000});
             return null;
-        }).when(mCpuUidClusterTimeReader).readDelta(
+        }).when(mCpuUidClusterTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidClusterTimeReader.Callback.class));
 
         // RUN
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 5b57f19..c70d6b0 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1231,6 +1231,12 @@
       "group": "WM_DEBUG_TASKS",
       "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
+    "-672355406": {
+      "message": "  Rejecting as no-op: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
     "-672228342": {
       "message": "resumeTopActivityLocked: Top activity resumed %s",
       "level": "DEBUG",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
index cb39b4e..e3594d0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
@@ -35,6 +35,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
+import java.util.function.Consumer;
 
 /**
  * Singleton source of truth for the current state of PIP bounds.
@@ -84,6 +85,7 @@
 
     private @Nullable Runnable mOnMinimalSizeChangeCallback;
     private @Nullable TriConsumer<Boolean, Integer, Boolean> mOnShelfVisibilityChangeCallback;
+    private @Nullable Consumer<Rect> mOnPipExclusionBoundsChangeCallback;
 
     public PipBoundsState(@NonNull Context context) {
         mContext = context;
@@ -102,6 +104,9 @@
     /** Set the current PIP bounds. */
     public void setBounds(@NonNull Rect bounds) {
         mBounds.set(bounds);
+        if (mOnPipExclusionBoundsChangeCallback != null) {
+            mOnPipExclusionBoundsChangeCallback.accept(bounds);
+        }
     }
 
     /** Get the current PIP bounds. */
@@ -386,6 +391,18 @@
         mOnShelfVisibilityChangeCallback = onShelfVisibilityChangeCallback;
     }
 
+    /**
+     * Set a callback to watch out for PiP bounds. This is mostly used by SystemUI's
+     * Back-gesture handler, to avoid conflicting with PiP when it's stashed.
+     */
+    public void setPipExclusionBoundsChangeCallback(
+            @Nullable Consumer<Rect> onPipExclusionBoundsChangeCallback) {
+        mOnPipExclusionBoundsChangeCallback = onPipExclusionBoundsChangeCallback;
+        if (mOnPipExclusionBoundsChangeCallback != null) {
+            mOnPipExclusionBoundsChangeCallback.accept(getBounds());
+        }
+    }
+
     /** Source of truth for the current bounds of PIP that may be in motion. */
     public static class MotionBoundsState {
         /** The bounds used when PIP is in motion (e.g. during a drag or animation) */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 36dc4e4..fa31a0a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -566,6 +566,8 @@
         mInSwipePipToHomeTransition = false;
         mPictureInPictureParams = null;
         mState = State.UNDEFINED;
+        // Re-set the PIP bounds to none.
+        mPipBoundsState.setBounds(new Rect());
         mPipUiEventLoggerLogger.setTaskInfo(null);
         mPipMenuController.detach();
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 9a584c6..1f5c136 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -494,15 +494,6 @@
         mPipTaskOrganizer.stopSwipePipToHome(componentName, destinationBounds);
     }
 
-    /**
-     * Set a listener to watch out for PiP bounds. This is mostly used by SystemUI's
-     * Back-gesture handler, to avoid conflicting with PiP when it's stashed.
-     */
-    private void setPipExclusionBoundsChangeListener(
-            Consumer<Rect> pipExclusionBoundsChangeListener) {
-        mTouchHandler.setPipExclusionBoundsChangeListener(pipExclusionBoundsChangeListener);
-    }
-
     @Override
     public void onPipTransitionStarted(int direction, Rect pipBounds) {
         if (isOutPipDirection(direction)) {
@@ -712,7 +703,7 @@
         @Override
         public void setPipExclusionBoundsChangeListener(Consumer<Rect> listener) {
             mMainExecutor.execute(() -> {
-                PipController.this.setPipExclusionBoundsChangeListener(listener);
+                mPipBoundsState.setPipExclusionBoundsChangeCallback(listener);
             });
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index 81a7ae1..402846f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -29,7 +29,6 @@
 import android.util.Log;
 import android.view.Choreographer;
 
-import androidx.annotation.VisibleForTesting;
 import androidx.dynamicanimation.animation.AnimationHandler;
 import androidx.dynamicanimation.animation.AnimationHandler.FrameCallbackScheduler;
 import androidx.dynamicanimation.animation.SpringForce;
@@ -489,8 +488,7 @@
     /**
      * Animates the PiP to offset it from the IME or shelf.
      */
-    @VisibleForTesting
-    public void animateToOffset(Rect originalBounds, int offset) {
+    void animateToOffset(Rect originalBounds, int offset) {
         if (DEBUG) {
             Log.d(TAG, "animateToOffset: originalBounds=" + originalBounds + " offset=" + offset
                     + " callers=\n" + Debug.getCallers(5, "    "));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 44e2624..b0a7319 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -57,8 +57,6 @@
 import com.android.wm.shell.pip.PipUiEventLogger;
 
 import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
-import java.util.function.Consumer;
 
 /**
  * Manages all the touch handling for PIP on the Phone, including moving, dismissing and expanding
@@ -73,7 +71,6 @@
     // Allow PIP to resize to a slightly bigger state upon touch
     private boolean mEnableResize;
     private final Context mContext;
-    private final PipTaskOrganizer mPipTaskOrganizer;
     private final PipBoundsAlgorithm mPipBoundsAlgorithm;
     private final @NonNull PipBoundsState mPipBoundsState;
     private final PipUiEventLogger mPipUiEventLogger;
@@ -81,7 +78,6 @@
     private final ShellExecutor mMainExecutor;
 
     private PipResizeGestureHandler mPipResizeGestureHandler;
-    private WeakReference<Consumer<Rect>> mPipExclusionBoundsChangeListener;
 
     private final PhonePipMenuController mMenuController;
     private final AccessibilityManager mAccessibilityManager;
@@ -170,7 +166,6 @@
         mContext = context;
         mMainExecutor = mainExecutor;
         mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
-        mPipTaskOrganizer = pipTaskOrganizer;
         mPipBoundsAlgorithm = pipBoundsAlgorithm;
         mPipBoundsState = pipBoundsState;
         mMenuController = menuController;
@@ -290,11 +285,6 @@
 
             mFloatingContentCoordinator.onContentRemoved(mMotionHelper);
         }
-        // Reset exclusion to none.
-        if (mPipExclusionBoundsChangeListener != null
-                && mPipExclusionBoundsChangeListener.get() != null) {
-            mPipExclusionBoundsChangeListener.get().accept(new Rect());
-        }
         mPipResizeGestureHandler.onActivityUnpinned();
     }
 
@@ -931,10 +921,6 @@
         }
 
         private void stashEndAction() {
-            if (mPipExclusionBoundsChangeListener != null
-                    && mPipExclusionBoundsChangeListener.get() != null) {
-                mPipExclusionBoundsChangeListener.get().accept(mPipBoundsState.getBounds());
-            }
             if (mPipBoundsState.getBounds().left < 0
                     && mPipBoundsState.getStashedState() != STASH_TYPE_LEFT) {
                 mPipUiEventLogger.log(
@@ -954,11 +940,6 @@
                 // dismiss overlay, so just finish it after the animation completes
                 mMenuController.hideMenu();
             }
-            // Reset exclusion to none.
-            if (mPipExclusionBoundsChangeListener != null
-                    && mPipExclusionBoundsChangeListener.get() != null) {
-                mPipExclusionBoundsChangeListener.get().accept(new Rect());
-            }
         }
 
         private boolean shouldStash(PointF vel, Rect motionBounds) {
@@ -982,13 +963,6 @@
         }
     }
 
-    void setPipExclusionBoundsChangeListener(Consumer<Rect> pipExclusionBoundsChangeListener) {
-        mPipExclusionBoundsChangeListener = new WeakReference<>(pipExclusionBoundsChangeListener);
-        pipExclusionBoundsChangeListener.accept(mPipTaskOrganizer.isInPip()
-                ? mPipBoundsState.getBounds() : new Rect());
-
-    }
-
     /**
      * Updates the current movement bounds based on whether the menu is currently visible and
      * resized.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index 2b0a0cd..963a3dc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -28,7 +28,7 @@
     // with those in the framework ProtoLogGroup
     WM_SHELL_TASK_ORG(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
             Consts.TAG_WM_SHELL),
-    WM_SHELL_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+    WM_SHELL_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
             Consts.TAG_WM_SHELL),
     WM_SHELL_DRAG_AND_DROP(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
             Consts.TAG_WM_SHELL),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index a694e52..d7cae36 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -150,6 +150,13 @@
                 }
                 return false;
             }
+            if (!snapshot.getTopActivityComponent().equals(windowInfo.taskInfo.topActivity)) {
+                if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+                    Slog.d(TAG, "isSnapshotCompatible obsoleted snapshot "
+                            + windowInfo.taskInfo.topActivity);
+                }
+                return false;
+            }
 
             final int taskRotation = windowInfo.taskInfo.configuration
                     .windowConfiguration.getRotation();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 629ff0d..b29b18b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -96,6 +96,17 @@
         };
         for (int i = info.getChanges().size() - 1; i >= 0; --i) {
             final TransitionInfo.Change change = info.getChanges().get(i);
+            if (change.getMode() == TRANSIT_CHANGE) {
+                // No default animation for this, so just update bounds/position.
+                t.setPosition(change.getLeash(),
+                        change.getEndAbsBounds().left - change.getEndRelOffset().x,
+                        change.getEndAbsBounds().top - change.getEndRelOffset().y);
+                if (change.getTaskInfo() != null) {
+                    // Skip non-tasks since those usually have null bounds.
+                    t.setWindowCrop(change.getLeash(),
+                            change.getEndAbsBounds().width(), change.getEndAbsBounds().height());
+                }
+            }
 
             // Don't animate anything that isn't independent.
             if (!TransitionInfo.isIndependent(change, info)) continue;
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNonResizableNotDock.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
similarity index 72%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNonResizableNotDock.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
index 219da27..7d22d4d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNonResizableNotDock.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
@@ -16,6 +16,8 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
+import android.platform.test.annotations.Postsubmit
+import android.provider.Settings
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -28,7 +30,9 @@
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.After
 import org.junit.Assert
+import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -36,27 +40,31 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test open non-resizable activity will auto exit split screen mode
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenNonResizableNotDock`
+ * Test enter split screen from non-resizable activity. When the device doesn't support
+ * non-resizable in multi window, there should be no button to enter split screen for non-resizable
+ * activity.
+ *
+ * To run this test: `atest WMShellFlickerTests:EnterSplitScreenNotSupportNonResizable`
  */
+@Postsubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FlakyTest(bugId = 173875043)
-class EnterSplitScreenNonResizableNotDock(
+class EnterSplitScreenNotSupportNonResizable(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
+    var prevSupportNonResizableInMultiWindow = 0
+
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
-            super.transition(this, configuration)
-            teardown {
+            cleanSetup(this, configuration)
+            setup {
                 eachRun {
-                    nonResizeableApp.exit(wmHelper)
+                    nonResizeableApp.launchViaIntent(wmHelper)
                 }
             }
             transitions {
-                nonResizeableApp.launchViaIntent(wmHelper)
                 device.openQuickstep(wmHelper)
                 if (device.canSplitScreen(wmHelper)) {
                     Assert.fail("Non-resizeable app should not enter split screen")
@@ -71,8 +79,23 @@
             nonResizeableApp.defaultWindowName,
             splitScreenApp.defaultWindowName)
 
-    @Test
-    fun dockedStackDividerIsInvisible() = testSpec.dockedStackDividerIsInvisible()
+    @Before
+    fun setup() {
+        prevSupportNonResizableInMultiWindow = Settings.Global.getInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
+        if (prevSupportNonResizableInMultiWindow == 1) {
+            // Not support non-resizable in multi window
+            Settings.Global.putInt(context.contentResolver,
+                    Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 0)
+        }
+    }
+
+    @After
+    fun teardown() {
+        Settings.Global.putInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
+                prevSupportNonResizableInMultiWindow)
+    }
 
     @FlakyTest(bugId = 178447631)
     @Test
@@ -84,6 +107,9 @@
         super.visibleWindowsShownMoreThanOneConsecutiveEntry()
 
     @Test
+    fun dockedStackDividerIsInvisible() = testSpec.dockedStackDividerIsInvisible()
+
+    @Test
     fun appWindowIsVisible() {
         testSpec.assertWmEnd {
             isInvisible(nonResizeableApp.defaultWindowName)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt
new file mode 100644
index 0000000..9b4a103
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.legacysplitscreen
+
+import android.platform.test.annotations.Postsubmit
+import android.provider.Settings
+import android.view.Surface
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import com.android.wm.shell.flicker.dockedStackDividerIsVisible
+import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.After
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test enter split screen from non-resizable activity. When the device supports
+ * non-resizable in multi window, there should be a button to enter split screen for non-resizable
+ * activity.
+ *
+ * To run this test: `atest WMShellFlickerTests:EnterSplitScreenSupportNonResizable`
+ */
+@Postsubmit
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+class EnterSplitScreenSupportNonResizable(
+    testSpec: FlickerTestParameter
+) : LegacySplitScreenTransition(testSpec) {
+    var prevSupportNonResizableInMultiWindow = 0
+
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = { configuration ->
+            cleanSetup(this, configuration)
+            setup {
+                eachRun {
+                    nonResizeableApp.launchViaIntent(wmHelper)
+                }
+            }
+            transitions {
+                device.launchSplitScreen(wmHelper)
+            }
+        }
+
+    override val ignoredWindows: List<String>
+        get() = listOf(LAUNCHER_PACKAGE_NAME,
+                WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+                WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME,
+                nonResizeableApp.defaultWindowName,
+                splitScreenApp.defaultWindowName)
+
+    @Before
+    fun setup() {
+        prevSupportNonResizableInMultiWindow = Settings.Global.getInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
+        if (prevSupportNonResizableInMultiWindow != 1) {
+            // Support non-resizable in multi window
+            Settings.Global.putInt(context.contentResolver,
+                    Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 1)
+        }
+    }
+
+    @After
+    fun teardown() {
+        Settings.Global.putInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
+                prevSupportNonResizableInMultiWindow)
+    }
+
+    @FlakyTest(bugId = 178447631)
+    @Test
+    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+            super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+    @Test
+    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+            super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+    @Test
+    fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible()
+
+    @Test
+    fun appWindowIsVisible() {
+        testSpec.assertWmEnd {
+            isVisible(nonResizeableApp.defaultWindowName)
+        }
+    }
+
+    companion object {
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): Collection<FlickerTestParameter> {
+            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+                    repetitions = SplitScreenHelper.TEST_REPETITIONS,
+                    supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
+        }
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt
similarity index 60%
copy from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt
copy to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt
index 4c6705f..8923845 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt
@@ -16,7 +16,8 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.Postsubmit
+import android.provider.Settings
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -31,7 +32,10 @@
 import com.android.server.wm.flicker.layerBecomesVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
+import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.After
+import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -39,18 +43,20 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test launch non resizable activity in split screen mode will trigger exit split screen mode
- * (Non resizable activity launch via intent)
- * To run this test: `atest WMShellFlickerTests:NonResizableLaunchInLegacySplitScreen`
+ * Test launch non-resizable activity via intent in split screen mode. When the device does not
+ * support non-resizable in multi window, it should trigger exit split screen.
+ * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromIntentNotSupportNonResizable`
  */
-@Presubmit
+@Postsubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class NonResizableLaunchInLegacySplitScreen(
+class LegacySplitScreenFromIntentNotSupportNonResizable(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
+    var prevSupportNonResizableInMultiWindow = 0
+
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             cleanSetup(this, configuration)
@@ -72,33 +78,60 @@
             WindowManagerStateHelper.SPLASH_SCREEN_NAME,
             WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
 
-    @Presubmit
-    @Test
-    fun layerBecomesVisible() = testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+    @Before
+    fun setup() {
+        prevSupportNonResizableInMultiWindow = Settings.Global.getInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
+        if (prevSupportNonResizableInMultiWindow == 1) {
+            // Not support non-resizable in multi window
+            Settings.Global.putInt(context.contentResolver,
+                    Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 0)
+        }
+    }
 
-    @Presubmit
-    @Test
-    fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+    @After
+    fun teardown() {
+        Settings.Global.putInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
+                prevSupportNonResizableInMultiWindow)
+    }
 
     @FlakyTest(bugId = 178447631)
     @Test
     override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
-    @Presubmit
-    @Test
-    fun appWindowBecomesVisible() =
-        testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
-
-    @Presubmit
-    @Test
-    fun appWindowBecomesInVisible() =
-        testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
+            super.visibleLayersShownMoreThanOneConsecutiveEntry()
 
     @FlakyTest(bugId = 178447631)
     @Test
     override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+            super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+    @Test
+    fun resizableAppLayerBecomesInvisible() =
+            testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+
+    @Test
+    fun nonResizableAppLayerBecomesVisible() =
+            testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+
+    @Test
+    fun resizableAppWindowBecomesInvisible() =
+            testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
+
+    @Test
+    fun nonResizableAppWindowBecomesVisible() =
+            testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
+
+    @Test
+    fun dockedStackDividerIsInvisibleAtEnd() = testSpec.dockedStackDividerIsInvisible()
+
+    @Test
+    fun onlyNonResizableAppWindowIsVisibleAtEnd() {
+        testSpec.assertWmEnd {
+            isInvisible(splitScreenApp.defaultWindowName)
+            isVisible(nonResizeableApp.defaultWindowName)
+        }
+    }
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt
similarity index 63%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt
index 4c6705f..2f5e0bd 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt
@@ -16,22 +16,24 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.Postsubmit
+import android.provider.Settings
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.appWindowBecomesInVisible
 import com.android.server.wm.flicker.appWindowBecomesVisible
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.layerBecomesInvisible
 import com.android.server.wm.flicker.layerBecomesVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
+import com.android.wm.shell.flicker.dockedStackDividerIsVisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.After
+import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -39,18 +41,20 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test launch non resizable activity in split screen mode will trigger exit split screen mode
- * (Non resizable activity launch via intent)
- * To run this test: `atest WMShellFlickerTests:NonResizableLaunchInLegacySplitScreen`
+ * Test launch non-resizable activity via intent in split screen mode. When the device supports
+ * non-resizable in multi window, it should show the non-resizable app in split screen.
+ * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromIntentSupportNonResizable`
  */
-@Presubmit
+@Postsubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class NonResizableLaunchInLegacySplitScreen(
+class LegacySplitScreenFromIntentSupportNonResizable(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
+    var prevSupportNonResizableInMultiWindow = 0
+
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             cleanSetup(this, configuration)
@@ -72,33 +76,52 @@
             WindowManagerStateHelper.SPLASH_SCREEN_NAME,
             WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
 
-    @Presubmit
-    @Test
-    fun layerBecomesVisible() = testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+    @Before
+    fun setup() {
+        prevSupportNonResizableInMultiWindow = Settings.Global.getInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
+        if (prevSupportNonResizableInMultiWindow == 0) {
+            // Support non-resizable in multi window
+            Settings.Global.putInt(context.contentResolver,
+                    Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 1)
+        }
+    }
 
-    @Presubmit
-    @Test
-    fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+    @After
+    fun teardown() {
+        Settings.Global.putInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
+                prevSupportNonResizableInMultiWindow)
+    }
 
     @FlakyTest(bugId = 178447631)
     @Test
     override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
-    @Presubmit
-    @Test
-    fun appWindowBecomesVisible() =
-        testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
-
-    @Presubmit
-    @Test
-    fun appWindowBecomesInVisible() =
-        testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
+            super.visibleLayersShownMoreThanOneConsecutiveEntry()
 
     @FlakyTest(bugId = 178447631)
     @Test
     override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+            super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+    @Test
+    fun nonResizableAppLayerBecomesVisible() =
+            testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+
+    @Test
+    fun nonResizableAppWindowBecomesVisible() =
+            testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
+
+    @Test
+    fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisible()
+
+    @Test
+    fun bothAppsWindowsAreVisibleAtEnd() {
+        testSpec.assertWmEnd {
+            isVisible(splitScreenApp.defaultWindowName)
+            isVisible(nonResizeableApp.defaultWindowName)
+        }
+    }
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt
similarity index 61%
copy from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt
copy to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt
index 8a1715e..a42774d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt
@@ -16,7 +16,8 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.Postsubmit
+import android.provider.Settings
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -32,7 +33,10 @@
 import com.android.server.wm.flicker.layerBecomesVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
+import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.After
+import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -40,17 +44,20 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test launch non resizable activity in split screen mode will trigger exit split screen mode
- * (Non resizable activity launch via recent overview)
- * To run this test: `atest WMShellFlickerTests:NonResizableDismissInLegacySplitScreen`
+ * Test launch non-resizable activity via recent overview in split screen mode. When the device does
+ * not support non-resizable in multi window, it should trigger exit split screen.
+ * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromRecentNotSupportNonResizable`
  */
+@Postsubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class NonResizableDismissInLegacySplitScreen(
+class LegacySplitScreenFromRecentNotSupportNonResizable(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
+    var prevSupportNonResizableInMultiWindow = 0
+
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             cleanSetup(this, configuration)
@@ -68,37 +75,64 @@
 
     override val ignoredWindows: List<String>
         get() = listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME, LETTERBOX_NAME, TOAST_NAME,
-            splitScreenApp.defaultWindowName, nonResizeableApp.defaultWindowName,
-            WindowManagerStateHelper.SPLASH_SCREEN_NAME,
-            WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
+                splitScreenApp.defaultWindowName, nonResizeableApp.defaultWindowName,
+                WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+                WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
 
-    @Presubmit
-    @Test
-    fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+    @Before
+    fun setup() {
+        prevSupportNonResizableInMultiWindow = Settings.Global.getInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
+        if (prevSupportNonResizableInMultiWindow == 1) {
+            // Not support non-resizable in multi window
+            Settings.Global.putInt(context.contentResolver,
+                    Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 0)
+        }
+    }
+
+    @After
+    fun teardown() {
+        Settings.Global.putInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
+                prevSupportNonResizableInMultiWindow)
+    }
 
     @FlakyTest(bugId = 178447631)
     @Test
     override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
         super.visibleLayersShownMoreThanOneConsecutiveEntry()
 
-    @Presubmit
-    @Test
-    fun layerBecomesVisible() = testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
-
-    @Presubmit
-    @Test
-    fun appWindowBecomesVisible() =
-        testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
-
-    @Presubmit
-    @Test
-    fun appWindowBecomesInVisible() =
-        testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
-
     @FlakyTest(bugId = 178447631)
     @Test
     override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+            super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+    @Test
+    fun resizableAppLayerBecomesInvisible() =
+            testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+
+    @Test
+    fun nonResizableAppLayerBecomesVisible() =
+            testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+
+    @Test
+    fun resizableAppWindowBecomesInvisible() =
+        testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
+
+    @Test
+    fun nonResizableAppWindowBecomesVisible() =
+        testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
+
+    @Test
+    fun dockedStackDividerIsInvisibleAtEnd() = testSpec.dockedStackDividerIsInvisible()
+
+    @Test
+    fun onlyNonResizableAppWindowIsVisibleAtEnd() {
+        testSpec.assertWmEnd {
+            isInvisible(splitScreenApp.defaultWindowName)
+            isVisible(nonResizeableApp.defaultWindowName)
+        }
+    }
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt
similarity index 62%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt
index 8a1715e..14f6dee 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt
@@ -16,23 +16,25 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.Postsubmit
+import android.provider.Settings
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.appWindowBecomesInVisible
 import com.android.server.wm.flicker.appWindowBecomesVisible
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.launchSplitScreen
 import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.layerBecomesInvisible
 import com.android.server.wm.flicker.layerBecomesVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
+import com.android.wm.shell.flicker.dockedStackDividerIsVisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.After
+import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -40,17 +42,20 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test launch non resizable activity in split screen mode will trigger exit split screen mode
- * (Non resizable activity launch via recent overview)
- * To run this test: `atest WMShellFlickerTests:NonResizableDismissInLegacySplitScreen`
+ * Test launch non-resizable activity via recent overview in split screen mode. When the device
+ * supports non-resizable in multi window, it should show the non-resizable app in split screen.
+ * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromRecentSupportNonResizable`
  */
+@Postsubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class NonResizableDismissInLegacySplitScreen(
+class LegacySplitScreenFromRecentSupportNonResizable(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
+    var prevSupportNonResizableInMultiWindow = 0
+
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             cleanSetup(this, configuration)
@@ -68,37 +73,56 @@
 
     override val ignoredWindows: List<String>
         get() = listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME, LETTERBOX_NAME, TOAST_NAME,
-            splitScreenApp.defaultWindowName, nonResizeableApp.defaultWindowName,
-            WindowManagerStateHelper.SPLASH_SCREEN_NAME,
-            WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
+                splitScreenApp.defaultWindowName, nonResizeableApp.defaultWindowName,
+                WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+                WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
 
-    @Presubmit
-    @Test
-    fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+    @Before
+    fun setup() {
+        prevSupportNonResizableInMultiWindow = Settings.Global.getInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
+        if (prevSupportNonResizableInMultiWindow == 0) {
+            // Support non-resizable in multi window
+            Settings.Global.putInt(context.contentResolver,
+                    Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 1)
+        }
+    }
+
+    @After
+    fun teardown() {
+        Settings.Global.putInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
+                prevSupportNonResizableInMultiWindow)
+    }
 
     @FlakyTest(bugId = 178447631)
     @Test
     override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
         super.visibleLayersShownMoreThanOneConsecutiveEntry()
 
-    @Presubmit
-    @Test
-    fun layerBecomesVisible() = testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
-
-    @Presubmit
-    @Test
-    fun appWindowBecomesVisible() =
-        testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
-
-    @Presubmit
-    @Test
-    fun appWindowBecomesInVisible() =
-        testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
-
     @FlakyTest(bugId = 178447631)
     @Test
     override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+            super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+    @Test
+    fun nonResizableAppLayerBecomesVisible() =
+            testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+
+    @Test
+    fun nonResizableAppWindowBecomesVisible() =
+        testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
+
+    @Test
+    fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisible()
+
+    @Test
+    fun bothAppsWindowsAreVisibleAtEnd() {
+        testSpec.assertWmEnd {
+            isVisible(splitScreenApp.defaultWindowName)
+            isVisible(nonResizeableApp.defaultWindowName)
+        }
+    }
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
index 319fde1..e13056c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
@@ -17,6 +17,7 @@
 package com.android.wm.shell.flicker.legacysplitscreen
 
 import android.app.Instrumentation
+import android.content.Context
 import android.platform.test.annotations.Presubmit
 import android.support.test.launcherhelper.LauncherStrategyFactory
 import android.view.Surface
@@ -36,6 +37,7 @@
 
 abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestParameter) {
     protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    protected val context: Context = instrumentation.context
     protected val isRotated = testSpec.config.startRotation.isRotated()
     protected val splitScreenApp = SplitScreenHelper.getPrimary(instrumentation)
     protected val secondaryApp = SplitScreenHelper.getSecondary(instrumentation)
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 9e9d02e..f957a73 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1988,7 +1988,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
-    public boolean setPreferredDeviceForCapturePreset(int capturePreset,
+    public boolean setPreferredDeviceForCapturePreset(@MediaRecorder.SystemSource int capturePreset,
                                                       @NonNull AudioDeviceAttributes device) {
         return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device));
     }
@@ -2002,7 +2002,8 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
-    public boolean clearPreferredDevicesForCapturePreset(int capturePreset) {
+    public boolean clearPreferredDevicesForCapturePreset(
+            @MediaRecorder.SystemSource int capturePreset) {
         if (!MediaRecorder.isValidAudioSource(capturePreset)) {
             return false;
         }
@@ -2024,7 +2025,8 @@
     @NonNull
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
-    public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(int capturePreset) {
+    public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(
+            @MediaRecorder.SystemSource int capturePreset) {
         if (!MediaRecorder.isValidAudioSource(capturePreset)) {
             return new ArrayList<AudioDeviceAttributes>();
         }
@@ -2036,7 +2038,8 @@
     }
 
     private boolean setPreferredDevicesForCapturePreset(
-            int capturePreset, @NonNull List<AudioDeviceAttributes> devices) {
+            @MediaRecorder.SystemSource int capturePreset,
+            @NonNull List<AudioDeviceAttributes> devices) {
         Objects.requireNonNull(devices);
         if (!MediaRecorder.isValidAudioSource(capturePreset)) {
             return false;
@@ -2081,7 +2084,8 @@
          * @param devices a list of newly set preferred audio devices
          */
         void onPreferredDevicesForCapturePresetChanged(
-                int capturePreset, @NonNull List<AudioDeviceAttributes> devices);
+                @MediaRecorder.SystemSource int capturePreset,
+                @NonNull List<AudioDeviceAttributes> devices);
     }
 
     /**
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 87e1e5b..dd08d8a 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -395,6 +395,26 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface Source {}
 
+    /** @hide */
+    @IntDef({
+        AudioSource.DEFAULT,
+        AudioSource.MIC,
+        AudioSource.VOICE_UPLINK,
+        AudioSource.VOICE_DOWNLINK,
+        AudioSource.VOICE_CALL,
+        AudioSource.CAMCORDER,
+        AudioSource.VOICE_RECOGNITION,
+        AudioSource.VOICE_COMMUNICATION,
+        AudioSource.REMOTE_SUBMIX,
+        AudioSource.UNPROCESSED,
+        AudioSource.VOICE_PERFORMANCE,
+        AudioSource.ECHO_REFERENCE,
+        AudioSource.RADIO_TUNER,
+        AudioSource.HOTWORD,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SystemSource {}
+
     // TODO make AudioSource static (API change) and move this method inside the AudioSource class
     /**
      * @hide
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index 5afe0b5d..10d68ba 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -86,7 +86,7 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mCm = ConnectivityManager.from(this);
+        mCm = getSystemService(ConnectivityManager.class);
         mUrl = getUrlForCaptivePortal();
         if (mUrl == null) {
             done(false);
@@ -161,7 +161,6 @@
         if (network != null) {
             network = network.getPrivateDnsBypassingCopy();
             mCm.bindProcessToNetwork(network);
-            mCm.setProcessDefaultNetworkForHostResolution(network);
         }
         mNetwork = network;
     }
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/ProvisionObserver.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/ProvisionObserver.java
index 78a02d7..43ca739 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/ProvisionObserver.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/ProvisionObserver.java
@@ -49,7 +49,7 @@
             case PROVISION_OBSERVER_REEVALUATION_JOB_ID:
                 if (isProvisioned(this)) {
                     Log.d(TAG, "device provisioned, force network re-evaluation");
-                    final ConnectivityManager connMgr = ConnectivityManager.from(this);
+                    final ConnectivityManager connMgr = getSystemService(ConnectivityManager.class);
                     Network[] info = connMgr.getAllNetworks();
                     for (Network nw : info) {
                         final NetworkCapabilities nc = connMgr.getNetworkCapabilities(nw);
diff --git a/core/java/android/net/NetworkScore.aidl b/packages/Connectivity/framework/aidl-export/android/net/NetworkScore.aidl
similarity index 100%
rename from core/java/android/net/NetworkScore.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/NetworkScore.aidl
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index eac896c..b0b3d78 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -4659,7 +4659,7 @@
                 Log.e(TAG, "Can't set proxy properties", e);
             }
             // Must flush DNS cache as new network may have different DNS resolutions.
-            InetAddress.clearDnsCache();
+            InetAddressCompat.clearDnsCache();
             // Must flush socket pool as idle sockets will be bound to previous network and may
             // cause subsequent fetches to be performed on old network.
             NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged();
diff --git a/core/java/android/net/IOnCompleteListener.aidl b/packages/Connectivity/framework/src/android/net/IOnCompleteListener.aidl
similarity index 100%
rename from core/java/android/net/IOnCompleteListener.aidl
rename to packages/Connectivity/framework/src/android/net/IOnCompleteListener.aidl
diff --git a/packages/Connectivity/framework/src/android/net/InetAddressCompat.java b/packages/Connectivity/framework/src/android/net/InetAddressCompat.java
new file mode 100644
index 0000000..8404441
--- /dev/null
+++ b/packages/Connectivity/framework/src/android/net/InetAddressCompat.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Compatibility utility for InetAddress core platform APIs.
+ *
+ * Connectivity has access to such APIs, but they are not part of the module_current stubs yet
+ * (only core_current). Most stable core platform APIs are included manually in the connectivity
+ * build rules, but because InetAddress is also part of the base java SDK that is earlier on the
+ * classpath, the extra core platform APIs are not seen.
+ *
+ * TODO (b/183097033): remove this utility as soon as core_current is part of module_current
+ * @hide
+ */
+public class InetAddressCompat {
+
+    /**
+     * @see InetAddress#clearDnsCache()
+     */
+    public static void clearDnsCache() {
+        try {
+            InetAddress.class.getMethod("clearDnsCache").invoke(null);
+        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
+            Log.wtf(InetAddressCompat.class.getSimpleName(), "Error clearing DNS cache", e);
+        }
+    }
+
+    /**
+     * @see InetAddress#getAllByNameOnNet(String, int)
+     */
+    public static InetAddress[] getAllByNameOnNet(String host, int netId) throws
+            UnknownHostException {
+        try {
+            return (InetAddress[]) InetAddress.class.getMethod("getAllByNameOnNet",
+                    String.class, int.class).invoke(null, host, netId);
+        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
+            Log.wtf(InetAddressCompat.class.getSimpleName(), "Error calling getAllByNameOnNet", e);
+            throw new IllegalStateException("Error querying via getAllNameOnNet", e);
+        }
+    }
+
+    /**
+     * @see InetAddress#getByNameOnNet(String, int)
+     */
+    public static InetAddress getByNameOnNet(String host, int netId) throws
+            UnknownHostException {
+        try {
+            return (InetAddress) InetAddress.class.getMethod("getByNameOnNet",
+                    String.class, int.class).invoke(null, host, netId);
+        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
+            Log.wtf(InetAddressCompat.class.getSimpleName(), "Error calling getAllByNameOnNet", e);
+            throw new IllegalStateException("Error querying via getByNameOnNet", e);
+        }
+    }
+}
diff --git a/packages/Connectivity/framework/src/android/net/Network.java b/packages/Connectivity/framework/src/android/net/Network.java
index 7245db3..0741414 100644
--- a/packages/Connectivity/framework/src/android/net/Network.java
+++ b/packages/Connectivity/framework/src/android/net/Network.java
@@ -142,7 +142,7 @@
      * @throws UnknownHostException if the address lookup fails.
      */
     public InetAddress[] getAllByName(String host) throws UnknownHostException {
-        return InetAddress.getAllByNameOnNet(host, getNetIdForResolv());
+        return InetAddressCompat.getAllByNameOnNet(host, getNetIdForResolv());
     }
 
     /**
@@ -155,7 +155,7 @@
      *             if the address lookup fails.
      */
     public InetAddress getByName(String host) throws UnknownHostException {
-        return InetAddress.getByNameOnNet(host, getNetIdForResolv());
+        return InetAddressCompat.getByNameOnNet(host, getNetIdForResolv());
     }
 
     /**
diff --git a/core/java/android/net/NetworkScore.java b/packages/Connectivity/framework/src/android/net/NetworkScore.java
similarity index 100%
rename from core/java/android/net/NetworkScore.java
rename to packages/Connectivity/framework/src/android/net/NetworkScore.java
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
index 63edc77..4344e94 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
@@ -66,6 +66,8 @@
 
     private static final String INCREMENTAL_DIR = "_delta";
     private static final String FULL_DATA_DIR = "_full";
+    private static final String DEVICE_NAME_FOR_D2D_RESTORE_SET = "D2D";
+    private static final String DEFAULT_DEVICE_NAME_FOR_RESTORE_SET = "flash";
 
     // The currently-active restore set always has the same (nonzero!) token
     private static final long CURRENT_SET_TOKEN = 1;
@@ -603,8 +605,10 @@
         existing[num++] = CURRENT_SET_TOKEN;
 
         RestoreSet[] available = new RestoreSet[num];
+        String deviceName = mParameters.isDeviceTransfer() ? DEVICE_NAME_FOR_D2D_RESTORE_SET
+                : DEFAULT_DEVICE_NAME_FOR_RESTORE_SET;
         for (int i = 0; i < available.length; i++) {
-            available[i] = new RestoreSet("Local disk image", "flash", existing[i]);
+            available[i] = new RestoreSet("Local disk image", deviceName, existing[i]);
         }
         return available;
     }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
index 400bf15..2f38f0a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
@@ -23,6 +23,7 @@
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 import static android.view.WindowManager.TransitionOldType;
+import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
 
 import android.os.RemoteException;
 import android.util.Log;
@@ -35,6 +36,8 @@
 import android.window.IRemoteTransitionFinishedCallback;
 import android.window.TransitionInfo;
 
+import java.util.ArrayList;
+
 /**
  * @see RemoteAnimationAdapter
  */
@@ -100,6 +103,52 @@
         };
     }
 
+    private static class CounterRotator {
+        SurfaceControl mSurface = null;
+        ArrayList<SurfaceControl> mRotateChildren = null;
+
+        void setup(SurfaceControl.Transaction t, SurfaceControl parent, int rotateDelta,
+                float displayW, float displayH) {
+            if (rotateDelta == 0) return;
+            mRotateChildren = new ArrayList<>();
+            // We want to counter-rotate, so subtract from 4
+            rotateDelta = 4 - (rotateDelta + 4) % 4;
+            mSurface = new SurfaceControl.Builder()
+                    .setName("Transition Unrotate")
+                    .setContainerLayer()
+                    .setParent(parent)
+                    .build();
+            // column-major
+            if (rotateDelta == 1) {
+                t.setMatrix(mSurface, 0, 1, -1, 0);
+                t.setPosition(mSurface, displayW, 0);
+            } else if (rotateDelta == 2) {
+                t.setMatrix(mSurface, -1, 0, 0, -1);
+                t.setPosition(mSurface, displayW, displayH);
+            } else if (rotateDelta == 3) {
+                t.setMatrix(mSurface, 0, -1, 1, 0);
+                t.setPosition(mSurface, 0, displayH);
+            }
+            t.show(mSurface);
+        }
+
+        void addChild(SurfaceControl.Transaction t, SurfaceControl child) {
+            if (mSurface == null) return;
+            t.reparent(child, mSurface);
+            mRotateChildren.add(child);
+        }
+
+        void cleanUp(SurfaceControl rootLeash) {
+            if (mSurface == null) return;
+            SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+            for (int i = mRotateChildren.size() - 1; i >= 0; --i) {
+                t.reparent(mRotateChildren.get(i), rootLeash);
+            }
+            t.remove(mSurface);
+            t.apply();
+        }
+    }
+
     private static IRemoteTransition.Stub wrapRemoteTransition(
             final RemoteAnimationRunnerCompat remoteAnimationAdapter) {
         return new IRemoteTransition.Stub() {
@@ -116,17 +165,46 @@
 
                 // TODO(b/177438007): Move this set-up logic into launcher's animation impl.
                 boolean isReturnToHome = false;
+                TransitionInfo.Change launcherTask = null;
+                TransitionInfo.Change wallpaper = null;
+                int launcherLayer = 0;
+                int rotateDelta = 0;
+                float displayW = 0;
+                float displayH = 0;
                 for (int i = info.getChanges().size() - 1; i >= 0; --i) {
                     final TransitionInfo.Change change = info.getChanges().get(i);
                     if (change.getTaskInfo() != null
                             && change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME) {
                         isReturnToHome = change.getMode() == TRANSIT_OPEN
                                 || change.getMode() == TRANSIT_TO_FRONT;
-                        break;
+                        launcherTask = change;
+                        launcherLayer = info.getChanges().size() - i;
+                    } else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
+                        wallpaper = change;
+                    }
+                    if (change.getParent() == null && change.getEndRotation() >= 0
+                            && change.getEndRotation() != change.getStartRotation()) {
+                        rotateDelta = change.getEndRotation() - change.getStartRotation();
+                        displayW = change.getEndAbsBounds().width();
+                        displayH = change.getEndAbsBounds().height();
+                    }
+                }
+
+                // Prepare for rotation if there is one
+                final CounterRotator counterLauncher = new CounterRotator();
+                final CounterRotator counterWallpaper = new CounterRotator();
+                if (launcherTask != null && rotateDelta != 0 && launcherTask.getParent() != null) {
+                    counterLauncher.setup(t, info.getChange(launcherTask.getParent()).getLeash(),
+                            rotateDelta, displayW, displayH);
+                    if (counterLauncher.mSurface != null) {
+                        t.setLayer(counterLauncher.mSurface, launcherLayer);
                     }
                 }
 
                 if (isReturnToHome) {
+                    if (counterLauncher.mSurface != null) {
+                        t.setLayer(counterLauncher.mSurface, info.getChanges().size() * 3);
+                    }
                     // Need to "boost" the closing things since that's what launcher expects.
                     for (int i = info.getChanges().size() - 1; i >= 0; --i) {
                         final TransitionInfo.Change change = info.getChanges().get(i);
@@ -136,6 +214,7 @@
                         if (!TransitionInfo.isIndependent(change, info)) continue;
                         if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
                             t.setLayer(leash, info.getChanges().size() * 3 - i);
+                            counterLauncher.addChild(t, leash);
                         }
                     }
                     // Make wallpaper visible immediately since launcher apparently won't do this.
@@ -143,6 +222,18 @@
                         t.show(wallpapersCompat[i].leash.getSurfaceControl());
                         t.setAlpha(wallpapersCompat[i].leash.getSurfaceControl(), 1.f);
                     }
+                } else {
+                    if (launcherTask != null) {
+                        counterLauncher.addChild(t, launcherTask.getLeash());
+                    }
+                    if (wallpaper != null && rotateDelta != 0 && wallpaper.getParent() != null) {
+                        counterWallpaper.setup(t, info.getChange(wallpaper.getParent()).getLeash(),
+                                rotateDelta, displayW, displayH);
+                        if (counterWallpaper.mSurface != null) {
+                            t.setLayer(counterWallpaper.mSurface, -1);
+                            counterWallpaper.addChild(t, wallpaper.getLeash());
+                        }
+                    }
                 }
                 t.apply();
 
@@ -150,6 +241,8 @@
                     @Override
                     public void run() {
                         try {
+                            counterLauncher.cleanUp(info.getRootLeash());
+                            counterWallpaper.cleanUp(info.getRootLeash());
                             finishCallback.onTransitionFinished(null /* wct */);
                         } catch (RemoteException e) {
                             Log.e("ActivityOptionsCompat", "Failed to call app controlled animation"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index 87f6b82..246476a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -56,6 +56,7 @@
     public final boolean isNotInRecents;
     public final Rect contentInsets;
     public final PictureInPictureParams pictureInPictureParams;
+    public final int rotationChange;
 
     private final SurfaceControl mStartLeash;
 
@@ -74,6 +75,7 @@
         contentInsets = app.contentInsets;
         activityType = app.windowConfiguration.getActivityType();
         pictureInPictureParams = app.pictureInPictureParams;
+        rotationChange = 0;
 
         mStartLeash = app.startLeash;
     }
@@ -102,7 +104,7 @@
         localBounds = new Rect(change.getEndAbsBounds());
         localBounds.offsetTo(change.getEndRelOffset().x, change.getEndRelOffset().y);
         sourceContainerBounds = null;
-        screenSpaceBounds = change.getEndAbsBounds();
+        screenSpaceBounds = new Rect(change.getEndAbsBounds());
         prefixOrderIndex = order;
         // TODO(shell-transitions): I guess we need to send content insets? evaluate how its used.
         contentInsets = new Rect(0, 0, 0, 0);
@@ -115,6 +117,7 @@
         }
         pictureInPictureParams = null;
         mStartLeash = null;
+        rotationChange = change.getEndRotation() - change.getStartRotation();
     }
 
     public static RemoteAnimationTargetCompat[] wrap(RemoteAnimationTarget[] apps) {
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 1765627..cd53a34 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -326,6 +326,9 @@
         if (mBatteryPercentView != null) {
             if (mShowPercentMode == MODE_ESTIMATE && !mCharging) {
                 mBatteryController.getEstimatedTimeRemainingString((String estimate) -> {
+                    if (mBatteryPercentView == null) {
+                        return;
+                    }
                     if (estimate != null) {
                         mBatteryPercentView.setText(estimate);
                         setContentDescription(getContext().getString(
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index e35e987..52e2016 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -50,6 +50,7 @@
 import android.content.pm.ServiceInfo;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricSourceType;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
 import android.hardware.face.FaceManager;
 import android.hardware.face.FaceSensorProperties;
@@ -192,9 +193,19 @@
 
         // IBiometricsFace@1.0 does not support detection, only authentication.
         when(mFaceSensorProperties.isEmpty()).thenReturn(false);
+
+        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+                "00000001" /* serialNumber */, "" /* softwareVersion */));
+        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+                "vendor/version/revision" /* softwareVersion */));
+
         when(mFaceSensorProperties.get(anyInt())).thenReturn(new FaceSensorPropertiesInternal(
                 0 /* id */,
                 FaceSensorProperties.STRENGTH_STRONG, 1 /* maxTemplatesAllowed */,
+                componentInfo, FaceSensorProperties.TYPE_UNKNOWN,
                 false /* supportsFaceDetection */, true /* supportsSelfIllumination */,
                 false /* resetLockoutRequiresChallenge */));
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
index 7f8be91..1565dee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.PromptInfo;
 import android.hardware.biometrics.SensorProperties;
 import android.hardware.fingerprint.FingerprintSensorProperties;
@@ -49,6 +50,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 @SmallTest
@@ -341,8 +345,18 @@
         final int sensorLocationX = 540;
         final int sensorLocationY = 1600;
         final int sensorRadius = 100;
+
+        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+                "00000001" /* serialNumber */, "" /* softwareVersion */));
+        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+                "vendor/version/revision" /* softwareVersion */));
+
         final FingerprintSensorPropertiesInternal props = new FingerprintSensorPropertiesInternal(
                 0 /* sensorId */, SensorProperties.STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */,
+                componentInfo,
                 FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
                 true /* resetLockoutRequiresHardwareAuthToken */, sensorLocationX, sensorLocationY,
                 sensorRadius);
@@ -379,8 +393,18 @@
         final int sensorLocationX = 540;
         final int sensorLocationY = 1600;
         final int sensorRadius = 100;
+
+        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+                "00000001" /* serialNumber */, "" /* softwareVersion */));
+        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+                "vendor/version/revision" /* softwareVersion */));
+
         final FingerprintSensorPropertiesInternal props = new FingerprintSensorPropertiesInternal(
                 0 /* sensorId */, SensorProperties.STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */,
+                componentInfo,
                 FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
                 true /* resetLockoutRequiresHardwareAuthToken */, sensorLocationX, sensorLocationY,
                 sensorRadius);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
index 5088a53..f41c100 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
@@ -34,8 +34,8 @@
 
 import android.annotation.Nullable;
 import android.content.Context;
-import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.PromptInfo;
 import android.hardware.biometrics.SensorProperties;
 import android.hardware.face.FaceSensorPropertiesInternal;
@@ -248,9 +248,19 @@
         config.mPromptInfo = promptInfo;
 
         final List<FingerprintSensorPropertiesInternal> fpProps = new ArrayList<>();
+
+        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+                "00000001" /* serialNumber */, "" /* softwareVersion */));
+        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+                "vendor/version/revision" /* softwareVersion */));
+
         fpProps.add(new FingerprintSensorPropertiesInternal(0,
                 SensorProperties.STRENGTH_STRONG,
                 5 /* maxEnrollmentsPerUser */,
+                componentInfo,
                 FingerprintSensorProperties.TYPE_REAR,
                 false /* resetLockoutRequiresHardwareAuthToken */));
         mAuthContainer = new TestableAuthContainer(config, fpProps, null /* faceProps */);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 30c4cf6..fa190a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -34,7 +34,6 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
-import android.app.IActivityTaskManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -43,6 +42,7 @@
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.IBiometricSysuiReceiver;
 import android.hardware.biometrics.PromptInfo;
 import android.hardware.biometrics.SensorProperties;
@@ -123,10 +123,20 @@
         when(mDialog2.isAllowDeviceCredentials()).thenReturn(false);
 
         when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+
+        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+                "00000001" /* serialNumber */, "" /* softwareVersion */));
+        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+                "vendor/version/revision" /* softwareVersion */));
+
         FingerprintSensorPropertiesInternal prop = new FingerprintSensorPropertiesInternal(
                 1 /* sensorId */,
                 SensorProperties.STRENGTH_STRONG,
                 1 /* maxEnrollmentsPerUser */,
+                componentInfo,
                 FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
                 true /* resetLockoutRequireHardwareAuthToken */);
         List<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index be110fc..3f1a927 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -26,6 +26,7 @@
 
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.SensorProperties;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.FingerprintSensorProperties;
@@ -120,9 +121,19 @@
         setUpResources();
         when(mLayoutInflater.inflate(R.layout.udfps_view, null, false)).thenReturn(mUdfpsView);
         final List<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
+
+        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+                "00000001" /* serialNumber */, "" /* softwareVersion */));
+        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+                "vendor/version/revision" /* softwareVersion */));
+
         props.add(new FingerprintSensorPropertiesInternal(TEST_UDFPS_SENSOR_ID,
                 SensorProperties.STRENGTH_STRONG,
                 5 /* maxEnrollmentsPerUser */,
+                componentInfo,
                 FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
                 true /* resetLockoutRequiresHardwareAuthToken */));
         when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index 3d07da5..5b74cbd 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -114,6 +114,8 @@
         private boolean mUnregisterPending;
         private boolean mDeleteAfterUnregister;
 
+        private boolean mForceShowMagnifiableBounds;
+
         private final int mDisplayId;
 
         private static final int INVALID_ID = -1;
@@ -420,12 +422,18 @@
         @GuardedBy("mLock")
         void setForceShowMagnifiableBounds(boolean show) {
             if (mRegistered) {
+                mForceShowMagnifiableBounds = show;
                 mControllerCtx.getWindowManager().setForceShowMagnifiableBounds(
                         mDisplayId, show);
             }
         }
 
         @GuardedBy("mLock")
+        boolean isForceShowMagnifiableBounds() {
+            return mRegistered && mForceShowMagnifiableBounds;
+        }
+
+        @GuardedBy("mLock")
         boolean reset(boolean animate) {
             return reset(transformToStubCallback(animate));
         }
@@ -442,6 +450,7 @@
                 onMagnificationChangedLocked();
             }
             mIdOfLastServiceToMagnify = INVALID_ID;
+            mForceShowMagnifiableBounds = false;
             sendSpecToAnimation(spec, animationCallback);
             return changed;
         }
@@ -1158,6 +1167,21 @@
         }
     }
 
+    /**
+     * Returns {@code true} if the magnifiable regions of the display is forced to be shown.
+     *
+     * @param displayId The logical display id.
+     */
+    public boolean isForceShowMagnifiableBounds(int displayId) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return false;
+            }
+            return display.isForceShowMagnifiableBounds();
+        }
+    }
+
     private void onScreenTurnedOff() {
         final Message m = PooledLambda.obtainMessage(
                 FullScreenMagnificationController::resetAllIfNeeded, this, false);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 17a7d39..2073c70 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -52,6 +52,9 @@
  *   <li> 4. {@link #onTripleTapped} updates magnification switch UI depending on magnification
  *   capabilities and magnification active state when triple-tap gesture is detected. </li>
  * </ol>
+ *
+ *  <b>Note</b>  Updates magnification switch UI when magnification mode transition
+ *  is done {@link DisableMagnificationCallback#onResult}.
  */
 public class MagnificationController implements WindowMagnificationManager.Callback,
         MagnificationGestureHandler.Callback,
@@ -358,7 +361,8 @@
         boolean isActivated = false;
         if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
                 && mFullScreenMagnificationController != null) {
-            isActivated = mFullScreenMagnificationController.isMagnifying(displayId);
+            isActivated = mFullScreenMagnificationController.isMagnifying(displayId)
+                    || mFullScreenMagnificationController.isForceShowMagnifiableBounds(displayId);
         } else if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
                 && mWindowMagnificationMgr != null) {
             isActivated = mWindowMagnificationMgr.isWindowMagnifierEnabled(displayId);
@@ -400,6 +404,7 @@
                     adjustCurrentCenterIfNeededLocked();
                     applyMagnificationModeLocked(mTargetMode);
                 }
+                updateMagnificationButton(mDisplayId, mTargetMode);
                 mTransitionCallBack.onResult(success);
             }
         }
@@ -424,6 +429,7 @@
                 }
                 setExpiredAndRemoveFromListLocked();
                 applyMagnificationModeLocked(mCurrentMode);
+                updateMagnificationButton(mDisplayId, mCurrentMode);
                 mTransitionCallBack.onResult(true);
             }
         }
diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
index 602dc24..d0a8881 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -16,6 +16,8 @@
 
 package com.android.server.backup.restore;
 
+import static android.app.backup.BackupManager.OperationType;
+
 import static com.android.server.backup.BackupManagerService.DEBUG;
 import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_SESSION_TIMEOUT;
@@ -24,6 +26,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.backup.BackupManager;
 import android.app.backup.IBackupManagerMonitor;
 import android.app.backup.IRestoreObserver;
 import android.app.backup.IRestoreSession;
@@ -51,6 +54,7 @@
  */
 public class ActiveRestoreSession extends IRestoreSession.Stub {
     private static final String TAG = "RestoreSession";
+    private static final String DEVICE_NAME_FOR_D2D_SET = "D2D";
 
     private final TransportManager mTransportManager;
     private final String mTransportName;
@@ -174,6 +178,7 @@
             for (int i = 0; i < mRestoreSets.length; i++) {
                 if (token == mRestoreSets[i].token) {
                     final long oldId = Binder.clearCallingIdentity();
+                    RestoreSet restoreSet = mRestoreSets[i];
                     try {
                         return sendRestoreToHandlerLocked(
                                 (transportClient, listener) ->
@@ -183,7 +188,7 @@
                                                 monitor,
                                                 token,
                                                 listener,
-                                                mBackupEligibilityRules),
+                                                getBackupEligibilityRules(restoreSet)),
                                 "RestoreSession.restoreAll()");
                     } finally {
                         Binder.restoreCallingIdentity(oldId);
@@ -266,6 +271,7 @@
             for (int i = 0; i < mRestoreSets.length; i++) {
                 if (token == mRestoreSets[i].token) {
                     final long oldId = Binder.clearCallingIdentity();
+                    RestoreSet restoreSet = mRestoreSets[i];
                     try {
                         return sendRestoreToHandlerLocked(
                                 (transportClient, listener) ->
@@ -277,7 +283,7 @@
                                                 packages,
                                                 /* isSystemRestore */ packages.length > 1,
                                                 listener,
-                                                mBackupEligibilityRules),
+                                                getBackupEligibilityRules(restoreSet)),
                                 "RestoreSession.restorePackages(" + packages.length + " packages)");
                     } finally {
                         Binder.restoreCallingIdentity(oldId);
@@ -290,6 +296,14 @@
         return -1;
     }
 
+    private BackupEligibilityRules getBackupEligibilityRules(RestoreSet restoreSet) {
+        // TODO(b/182986784): Remove device name comparison once a designated field for operation
+        //  type is added to RestoreSet object.
+        int operationType = DEVICE_NAME_FOR_D2D_SET.equals(restoreSet.device)
+                ? OperationType.MIGRATION : OperationType.BACKUP;
+        return mBackupManagerService.getEligibilityRulesForOperation(operationType);
+    }
+
     public synchronized int restorePackage(String packageName, IRestoreObserver observer,
             IBackupManagerMonitor monitor) {
         if (DEBUG) {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 92af080..9ac93d9 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -1078,6 +1078,7 @@
         Date lastSeen = mDevicesLastNearby.get(address);
         if (isDeviceDisappeared(lastSeen)) {
             onDeviceDisappeared(address);
+            unscheduleTriggerDeviceDisappearedRunnable(address);
         }
     }
 
@@ -1213,7 +1214,18 @@
         @Override
         public void run() {
             Slog.d(LOG_TAG, "TriggerDeviceDisappearedRunnable.run(address = " + mAddress + ")");
-            onDeviceDisappeared(mAddress);
+            if (!mCurrentlyConnectedDevices.contains(mAddress)) {
+                onDeviceDisappeared(mAddress);
+            }
+        }
+    }
+
+    private void unscheduleTriggerDeviceDisappearedRunnable(String address) {
+        Runnable r = mTriggerDeviceDisappearedRunnables.get(address);
+        if (r != null) {
+            Slog.d(LOG_TAG,
+                    "unscheduling TriggerDeviceDisappearedRunnable(address = " + address + ")");
+            mMainHandler.removeCallbacks(r);
         }
     }
 
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index f4a8ccd..25ea12b 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -58,6 +58,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
@@ -69,7 +70,6 @@
 import android.service.contentcapture.ActivityEvent.ActivityEventType;
 import android.service.contentcapture.IDataShareCallback;
 import android.service.contentcapture.IDataShareReadAdapter;
-import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.LocalLog;
 import android.util.Pair;
@@ -174,6 +174,9 @@
     @GuardedBy("mLock")
     private final Set<String> mPackagesWithShareRequests = new HashSet<>();
 
+    private final RemoteCallbackList<IContentCaptureOptionsCallback> mCallbacks =
+            new RemoteCallbackList<>();
+
     final GlobalContentCaptureOptions mGlobalContentCaptureOptions =
             new GlobalContentCaptureOptions();
 
@@ -497,16 +500,15 @@
     }
 
     void updateOptions(String packageName, ContentCaptureOptions options) {
-        ArraySet<CallbackRecord> records;
-        synchronized (mLock) {
-            records = mContentCaptureManagerServiceStub.mCallbacks.get(packageName);
-            if (records != null) {
-                int N = records.size();
-                for (int i = 0; i < N; i++) {
-                    records.valueAt(i).setContentCaptureOptions(options);
+        mCallbacks.broadcast((callback, pkg) -> {
+            if (pkg.equals(packageName)) {
+                try {
+                    callback.setContentCaptureOptions(options);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Unable to send setContentCaptureOptions(): " + e);
                 }
             }
-        }
+        });
     }
 
     private ActivityManagerInternal getAmInternal() {
@@ -616,8 +618,6 @@
     }
 
     final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
-        @GuardedBy("mLock")
-        private final ArrayMap<String, ArraySet<CallbackRecord>> mCallbacks = new ArrayMap<>();
 
         @Override
         public void startSession(@NonNull IBinder activityToken,
@@ -778,39 +778,19 @@
                 IContentCaptureOptionsCallback callback) {
             assertCalledByPackageOwner(packageName);
 
-            CallbackRecord record = new CallbackRecord(callback, packageName);
-            record.registerObserver();
-
-            synchronized (mLock) {
-                ArraySet<CallbackRecord> records = mCallbacks.get(packageName);
-                if (records == null) {
-                    records = new ArraySet<>();
-                }
-                records.add(record);
-                mCallbacks.put(packageName, records);
-            }
+            mCallbacks.register(callback, packageName);
 
             // Set options here in case it was updated before this was registered.
             final int userId = UserHandle.getCallingUserId();
             final ContentCaptureOptions options = mGlobalContentCaptureOptions.getOptions(userId,
                     packageName);
             if (options != null) {
-                record.setContentCaptureOptions(options);
-            }
-        }
-
-        private void unregisterContentCaptureOptionsCallback(CallbackRecord record) {
-            synchronized (mLock) {
-                ArraySet<CallbackRecord> records = mCallbacks.get(record.mPackageName);
-                if (records != null) {
-                    records.remove(record);
-                }
-
-                if (records == null || records.isEmpty()) {
-                    mCallbacks.remove(record.mPackageName);
+                try {
+                    callback.setContentCaptureOptions(options);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Unable to send setContentCaptureOptions(): " + e);
                 }
             }
-            record.unregisterObserver();
         }
 
         @Override
@@ -1277,39 +1257,4 @@
                     mDataShareRequest.getPackageName());
         }
     }
-
-    private final class CallbackRecord implements IBinder.DeathRecipient {
-        private final String mPackageName;
-        private final IContentCaptureOptionsCallback mCallback;
-
-        private CallbackRecord(IContentCaptureOptionsCallback callback, String packageName) {
-            mCallback = callback;
-            mPackageName = packageName;
-        }
-
-        private void setContentCaptureOptions(ContentCaptureOptions options) {
-            try {
-                mCallback.setContentCaptureOptions(options);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Unable to send setContentCaptureOptions(): " + e);
-            }
-        }
-
-        private void registerObserver() {
-            try {
-                mCallback.asBinder().linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Failed to register callback cleanup " + e);
-            }
-        }
-
-        private void unregisterObserver() {
-            mCallback.asBinder().unlinkToDeath(this, 0);
-        }
-
-        @Override
-        public void binderDied() {
-            mContentCaptureManagerServiceStub.unregisterContentCaptureOptionsCallback(this);
-        }
-    }
 }
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index c295778..b089014 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -1141,4 +1141,12 @@
      */
     public abstract boolean isPackageFrozen(
             @NonNull String packageName, int callingUid, int userId);
+
+    /**
+     * Returns true if the given {@code packageName} has declared the
+     * {@code neverForLocation} flag in the {@code uses-permission} manifest tag
+     * where they request the given {@code permissionName}.
+     */
+    public abstract boolean isPackageUsesPermissionNeverForLocation(@NonNull String packageName,
+            @NonNull String permissionName);
 }
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 871de0d..ebd32e8 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -521,13 +521,6 @@
         return pinKeys;
     }
 
-    private static boolean shouldPinSplitApks() {
-        // For now this is disabled by default bcause the pinlist support for split APKs are
-        // missing in the toolchain. This flag should be removed once it is ready. b/174697187.
-        return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
-                "pin_split_apks", false);
-    }
-
     private synchronized ArraySet<Integer> getPinKeys() {
         return mPinKeys;
     }
@@ -685,7 +678,7 @@
         List<String> apks = new ArrayList<>();
         apks.add(appInfo.sourceDir);
 
-        if (shouldPinSplitApks() && appInfo.splitSourceDirs != null) {
+        if (appInfo.splitSourceDirs != null) {
             for (String splitApk : appInfo.splitSourceDirs) {
                 apks.add(splitApk);
             }
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 5b9fa79..7296679 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -214,6 +214,13 @@
                 return;
             }
 
+            if (promptInfo.containsTestConfigurations()) {
+                if (getContext().checkCallingOrSelfPermission(TEST_BIOMETRIC)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    checkInternalPermission();
+                }
+            }
+
             // Only allow internal clients to enable non-public options.
             if (promptInfo.containsPrivateApiConfigurations()) {
                 checkInternalPermission();
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index 6851d71..ef43bc5 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -23,6 +23,7 @@
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.ITrustManager;
 import android.hardware.biometrics.BiometricAuthenticator;
@@ -112,7 +113,8 @@
 
                 @AuthenticatorStatus int status = getStatusForBiometricAuthenticator(
                         devicePolicyManager, settingObserver, sensor, userId, opPackageName,
-                        checkDevicePolicyManager, requestedStrength, promptInfo.getSensorId());
+                        checkDevicePolicyManager, requestedStrength,
+                        promptInfo.getAllowedSensorIds());
 
                 Slog.d(TAG, "Package: " + opPackageName
                         + " Sensor ID: " + sensor.id
@@ -142,9 +144,10 @@
             DevicePolicyManager devicePolicyManager,
             BiometricService.SettingObserver settingObserver,
             BiometricSensor sensor, int userId, String opPackageName,
-            boolean checkDevicePolicyManager, int requestedStrength, int requestedSensorId) {
+            boolean checkDevicePolicyManager, int requestedStrength,
+            @NonNull List<Integer> requestedSensorIds) {
 
-        if (requestedSensorId != BiometricManager.SENSOR_ID_ANY && sensor.id != requestedSensorId) {
+        if (!requestedSensorIds.isEmpty() && !requestedSensorIds.contains(sensor.id)) {
             return BIOMETRIC_NO_HARDWARE;
         }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 07a653f..ebf13e0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -23,6 +23,7 @@
 import android.app.TaskStackListener;
 import android.content.Context;
 import android.content.pm.UserInfo;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
 import android.hardware.biometrics.ITestSessionCallback;
@@ -134,10 +135,21 @@
         for (SensorProps prop : props) {
             final int sensorId = prop.commonProps.sensorId;
 
+            final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+            if (prop.commonProps.componentInfo != null) {
+                for (android.hardware.biometrics.common.ComponentInfo info
+                        : prop.commonProps.componentInfo) {
+                    componentInfo.add(new ComponentInfoInternal(info.componentId,
+                            info.hardwareVersion, info.firmwareVersion, info.serialNumber,
+                            info.softwareVersion));
+                }
+            }
+
             final FaceSensorPropertiesInternal internalProp = new FaceSensorPropertiesInternal(
                     prop.commonProps.sensorId, prop.commonProps.sensorStrength,
-                    prop.commonProps.maxEnrollmentsPerUser, false /* supportsFaceDetection */,
-                    prop.halControlsPreview, false /* resetLockoutRequiresChallenge */);
+                    prop.commonProps.maxEnrollmentsPerUser, componentInfo, prop.sensorType,
+                    false /* supportsFaceDetection */, prop.halControlsPreview,
+                    false /* resetLockoutRequiresChallenge */);
             final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext, mHandler,
                     internalProp);
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index 40c050f..55e9a83 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -27,11 +27,13 @@
 import android.hardware.biometrics.BiometricFaceConstants;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.ITestSession;
 import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.face.V1_0.IBiometricsFace;
 import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
 import android.hardware.face.Face;
+import android.hardware.face.FaceSensorProperties;
 import android.hardware.face.FaceSensorPropertiesInternal;
 import android.hardware.face.IFaceServiceReceiver;
 import android.os.Binder;
@@ -332,8 +334,9 @@
             @NonNull BiometricScheduler scheduler) {
         mSensorProperties = new FaceSensorPropertiesInternal(sensorId,
                 Utils.authenticatorStrengthToPropertyStrength(strength),
-                maxTemplatesAllowed, false /* supportsFaceDetect */, supportsSelfIllumination,
-                true /* resetLockoutRequiresChallenge */);
+                maxTemplatesAllowed, new ArrayList<ComponentInfoInternal>() /* componentInfo */,
+                FaceSensorProperties.TYPE_UNKNOWN, false /* supportsFaceDetect */,
+                supportsSelfIllumination, true /* resetLockoutRequiresChallenge */);
         mContext = context;
         mSensorId = sensorId;
         mScheduler = scheduler;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 3f489e9..aa5afb7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -315,7 +315,8 @@
                                     Slog.e(TAG, "Remote exception in negative button onClick()", e);
                                 }
                             })
-                    .setSensorId(props.sensorId)
+                    .setAllowedSensorIds(new ArrayList<>(
+                            Collections.singletonList(props.sensorId)))
                     .build();
 
             final BiometricPrompt.AuthenticationCallback promptCallback =
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index d798198..2c85dc9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -25,6 +25,7 @@
 import android.app.TaskStackListener;
 import android.content.Context;
 import android.content.pm.UserInfo;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
 import android.hardware.biometrics.ITestSessionCallback;
@@ -138,10 +139,21 @@
         for (SensorProps prop : props) {
             final int sensorId = prop.commonProps.sensorId;
 
+            final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+            if (prop.commonProps.componentInfo != null) {
+                for (android.hardware.biometrics.common.ComponentInfo info
+                        : prop.commonProps.componentInfo) {
+                    componentInfo.add(new ComponentInfoInternal(info.componentId,
+                            info.hardwareVersion, info.firmwareVersion, info.serialNumber,
+                            info.softwareVersion));
+                }
+            }
+
             final FingerprintSensorPropertiesInternal internalProp =
                     new FingerprintSensorPropertiesInternal(prop.commonProps.sensorId,
                             prop.commonProps.sensorStrength,
                             prop.commonProps.maxEnrollmentsPerUser,
+                            componentInfo,
                             prop.sensorType,
                             true /* resetLockoutRequiresHardwareAuthToken */);
             final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext, mHandler,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index e737677..f112549 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -28,6 +28,7 @@
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
 import android.hardware.biometrics.ITestSessionCallback;
@@ -355,7 +356,8 @@
 
         mSensorProperties = new FingerprintSensorPropertiesInternal(context, sensorId,
                 Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser,
-                sensorType, resetLockoutRequiresHardwareAuthToken);
+                new ArrayList<ComponentInfoInternal>() /* componentInfo */, sensorType,
+                resetLockoutRequiresHardwareAuthToken);
     }
 
     public static Fingerprint21 newInstance(@NonNull Context context, int sensorId, int strength,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index 2394a70..90c4b4a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -22,6 +22,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
 import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
@@ -421,6 +422,7 @@
                 .getInteger(R.integer.config_fingerprintMaxTemplatesPerUser);
         mSensorProperties = new FingerprintSensorPropertiesInternal(sensorId,
                 Utils.authenticatorStrengthToPropertyStrength(strength), maxTemplatesAllowed,
+                new ArrayList<ComponentInfoInternal>() /* componentInfo */,
                 FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
                 resetLockoutRequiresHardwareAuthToken);
         mMockHalResultController = controller;
diff --git a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
index 60e8cce..348a03b 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
@@ -92,6 +92,9 @@
                 break;
             }
         }
+        if (keyToIndexMap.size() < 2) {
+            throw new IllegalStateException("Indexing file is corrupt.");
+        }
         return keyToIndexMap;
     }
 
@@ -106,6 +109,9 @@
 
     private static List<String> searchKeysRangeContainingKey(
             List<String> sortedKeyList, String key, int startIndex, int endIndex) {
+        if (endIndex <= startIndex) {
+            throw new IllegalStateException("Indexing file is corrupt.");
+        }
         if (endIndex - startIndex == 1) {
             return Arrays.asList(sortedKeyList.get(startIndex), sortedKeyList.get(endIndex));
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 1530e41..ff042c2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -252,6 +252,7 @@
 import android.content.pm.parsing.component.ParsedProcess;
 import android.content.pm.parsing.component.ParsedProvider;
 import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.component.ParsedUsesPermission;
 import android.content.pm.parsing.result.ParseResult;
 import android.content.pm.parsing.result.ParseTypeImpl;
 import android.content.res.Resources;
@@ -882,7 +883,7 @@
     // Lock for global state used when modifying package state or settings.
     // Methods that must be called with this lock held have
     // the suffix "Locked". Some methods may use the legacy suffix "LP"
-    final Object mLock;
+    final PackageManagerTracedLock mLock;
 
     // Keys are String (package name), values are Package.
     @Watched
@@ -1041,7 +1042,7 @@
 
         private final PackageAbiHelper mAbiHelper;
         private final Context mContext;
-        private final Object mLock;
+        private final PackageManagerTracedLock mLock;
         private final Installer mInstaller;
         private final Object mInstallLock;
         private final Handler mBackgroundHandler;
@@ -1081,7 +1082,7 @@
                 mDomainVerificationManagerInternalProducer;
         private final Singleton<Handler> mHandlerProducer;
 
-        Injector(Context context, Object lock, Installer installer,
+        Injector(Context context, PackageManagerTracedLock lock, Installer installer,
                 Object installLock, PackageAbiHelper abiHelper,
                 Handler backgroundHandler,
                 List<ScanPartition> systemPartitions,
@@ -1181,7 +1182,7 @@
             return mUserManagerProducer.get(this, mPackageManager);
         }
 
-        public Object getLock() {
+        public PackageManagerTracedLock getLock() {
             return mLock;
         }
 
@@ -5963,7 +5964,7 @@
         final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
                 Trace.TRACE_TAG_PACKAGE_MANAGER);
         t.traceBegin("create package manager");
-        final Object lock = new Object();
+        final PackageManagerTracedLock lock = new PackageManagerTracedLock();
         final Object installLock = new Object();
         HandlerThread backgroundThread = new HandlerThread("PackageManagerBg");
         backgroundThread.start();
@@ -26889,11 +26890,12 @@
                     outUpdatedPackageNames.add(targetPackageName);
                     modified = true;
                 }
+
+                if (modified) {
+                    invalidatePackageInfoCache();
+                }
             }
 
-            if (modified) {
-                invalidatePackageInfoCache();
-            }
             return true;
         }
 
@@ -27322,6 +27324,28 @@
             return PackageManagerService.this.getPackageStartability(
                     packageName, callingUid, userId) == PACKAGE_STARTABILITY_FROZEN;
         }
+
+        @Override
+        public boolean isPackageUsesPermissionNeverForLocation(@NonNull String packageName,
+                @NonNull String permissionName) {
+            Objects.requireNonNull(packageName);
+            Objects.requireNonNull(permissionName);
+            final AndroidPackage pkg;
+            synchronized (mLock) {
+                pkg = mPackages.get(packageName);
+            }
+            if (pkg == null) return false;
+            final List<ParsedUsesPermission> usesPermissions = pkg.getUsesPermissions();
+            final int size = usesPermissions.size();
+            for (int i = 0; i < size; i++) {
+                final ParsedUsesPermission usesPermission = usesPermissions.get(i);
+                if (Objects.equals(usesPermission.name, permissionName)) {
+                    return (usesPermission.usesPermissionFlags
+                            & ParsedUsesPermission.FLAG_NEVER_FOR_LOCATION) != 0;
+                }
+            }
+            return false;
+        }
     }
 
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerTracedLock.java b/services/core/java/com/android/server/pm/PackageManagerTracedLock.java
new file mode 100644
index 0000000..e15e8a8
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageManagerTracedLock.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+/**
+ * This is a unique class that is used as the PackageManager lock.  It can be targeted for lock
+ * injection, similar to {@link ActivityManagerGlobalLock}.
+ */
+public class PackageManagerTracedLock {
+}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index ec7b451..b51b833 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -353,7 +353,7 @@
     private static final String ATTR_DATABASE_VERSION = "databaseVersion";
     private static final String ATTR_VALUE = "value";
 
-    private final Object mLock;
+    private final PackageManagerTracedLock mLock;
 
     private final RuntimePermissionPersistence mRuntimePermissionsPersistence;
 
@@ -525,7 +525,7 @@
 
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     public Settings(Map<String, PackageSetting> pkgSettings) {
-        mLock = new Object();
+        mLock = new PackageManagerTracedLock();
         mPackages.putAll(pkgSettings);
         mAppIds = new WatchedArrayList<>();
         mOtherAppIds = new WatchedSparseArray<>();
@@ -562,7 +562,7 @@
     Settings(File dataDir, RuntimePermissionsPersistence runtimePermissionsPersistence,
             LegacyPermissionDataProvider permissionDataProvider,
             @NonNull DomainVerificationManagerInternal domainVerificationManager,
-            @NonNull Object lock)  {
+            @NonNull PackageManagerTracedLock lock)  {
         mLock = lock;
         mAppIds = new WatchedArrayList<>();
         mOtherAppIds = new WatchedSparseArray<>();
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 0a74032..8f87b19 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -214,7 +214,7 @@
             newSigningDetails = ApkSignatureVerifier.verify(apexPath, minSignatureScheme);
         } catch (PackageParserException e) {
             throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
-                    "Failed to parse APEX package " + apexPath, e);
+                    "Failed to parse APEX package " + apexPath + " : " + e, e);
         }
 
         // Get signing details of the existing package
@@ -232,7 +232,8 @@
                 existingApexPkg.applicationInfo.sourceDir, SignatureSchemeVersion.JAR);
         } catch (PackageParserException e) {
             throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
-                    "Failed to parse APEX package " + existingApexPkg.applicationInfo.sourceDir, e);
+                    "Failed to parse APEX package " + existingApexPkg.applicationInfo.sourceDir
+                            + " : " + e, e);
         }
 
         // Verify signing details for upgrade
@@ -291,7 +292,7 @@
                 }
             } catch (PackageParserException e) {
                 throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
-                        "Failed to parse APEX package " + apexInfo.modulePath, e);
+                        "Failed to parse APEX package " + apexInfo.modulePath + " : " + e, e);
             }
             final PackageInfo activePackage = mApexManager.getPackageInfo(packageInfo.packageName,
                     ApexManager.MATCH_ACTIVE_PACKAGE);
diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
index 9c3a394..5b48abb 100644
--- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java
+++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
@@ -24,11 +24,11 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
-import android.net.ConnectivityManager;
 import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
@@ -113,7 +113,7 @@
     private boolean mDeviceProvisioned = false;
     private ToggleAction.State mAirplaneState = ToggleAction.State.Off;
     private boolean mIsWaitingForEcmExit = false;
-    private boolean mHasTelephony;
+    private final boolean mHasTelephony;
     private boolean mHasVibrator;
     private final boolean mShowSilentToggle;
     private final EmergencyAffordanceManager mEmergencyAffordanceManager;
@@ -137,9 +137,8 @@
         filter.addAction(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
         context.registerReceiver(mBroadcastReceiver, filter);
 
-        ConnectivityManager cm = (ConnectivityManager)
-                context.getSystemService(Context.CONNECTIVITY_SERVICE);
-        mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+        mHasTelephony =
+                context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
 
         // get notified of phone state changes
         TelephonyManager telephonyManager =
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b12ce67..5884102 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2114,6 +2114,10 @@
         if (snapshot == null) {
             return false;
         }
+        if (!snapshot.getTopActivityComponent().equals(mActivityComponent)) {
+            // Obsoleted snapshot.
+            return false;
+        }
         final int rotation = mDisplayContent.rotationForActivityInDifferentOrientation(this);
         final int targetRotation = rotation != ROTATION_UNDEFINED
                 // The display may rotate according to the orientation of this activity.
diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java
index 28a509b..0ec0142 100644
--- a/services/core/java/com/android/server/wm/CompatModePackages.java
+++ b/services/core/java/com/android/server/wm/CompatModePackages.java
@@ -74,45 +74,59 @@
     /**
      * CompatModePackages#DOWNSCALED is the gatekeeper of all per-app buffer downscaling
      * changes.  Disabling this change will prevent the following scaling factors from working:
-     * CompatModePackages#DOWNSCALE_87_5
-     * CompatModePackages#DOWNSCALE_75
-     * CompatModePackages#DOWNSCALE_62_5
+     * CompatModePackages#DOWNSCALE_90
+     * CompatModePackages#DOWNSCALE_80
+     * CompatModePackages#DOWNSCALE_70
+     * CompatModePackages#DOWNSCALE_60
      * CompatModePackages#DOWNSCALE_50
      *
      * If CompatModePackages#DOWNSCALED is enabled for an app package, then the app will be forcibly
-     * resized to the highest enabled scaling factor e.g. 87.5% if both 87.5% and 75% were
-     * enabled.
+     * resized to the highest enabled scaling factor e.g. 80% if both 80% and 70% were enabled.
      */
     @ChangeId
     @Disabled
-    private static final long DOWNSCALED = 168419799L;
+    @Overridable
+    public static final long DOWNSCALED = 168419799L;
 
     /**
      * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
-     * CompatModePackages#DOWNSCALE_87_5 for a package will force the app to assume it's
-     * running on a display with 87.5% the vertical and horizontal resolution of the real display.
+     * CompatModePackages#DOWNSCALE_90 for a package will force the app to assume it's
+     * running on a display with 90% the vertical and horizontal resolution of the real display.
      */
     @ChangeId
     @Disabled
-    private static final long DOWNSCALE_87_5 = 176926753L;
+    @Overridable
+    public static final long DOWNSCALE_90 = 182811243L;
 
     /**
      * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
-     * CompatModePackages#DOWNSCALE_75 for a package will force the app to assume it's
-     * running on a display with 75% the vertical and horizontal resolution of the real display.
+     * CompatModePackages#DOWNSCALE_80 for a package will force the app to assume it's
+     * running on a display with 80% the vertical and horizontal resolution of the real display.
      */
     @ChangeId
     @Disabled
-    private static final long DOWNSCALE_75 = 176926829L;
+    @Overridable
+    public static final long DOWNSCALE_80 = 176926753L;
 
     /**
      * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
-     * CompatModePackages#DOWNSCALE_62_5 for a package will force the app to assume it's
-     * running on a display with 62.5% the vertical and horizontal resolution of the real display.
+     * CompatModePackages#DOWNSCALE_70 for a package will force the app to assume it's
+     * running on a display with 70% the vertical and horizontal resolution of the real display.
      */
     @ChangeId
     @Disabled
-    private static final long DOWNSCALE_62_5 = 176926771L;
+    @Overridable
+    public static final long DOWNSCALE_70 = 176926829L;
+
+    /**
+     * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+     * CompatModePackages#DOWNSCALE_60 for a package will force the app to assume it's
+     * running on a display with 60% the vertical and horizontal resolution of the real display.
+     */
+    @ChangeId
+    @Disabled
+    @Overridable
+    public static final long DOWNSCALE_60 = 176926771L;
 
     /**
      * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
@@ -121,7 +135,8 @@
      */
     @ChangeId
     @Disabled
-    private static final long DOWNSCALE_50 = 176926741L;
+    @Overridable
+    public static final long DOWNSCALE_50 = 176926741L;
 
     /**
      * On Android TV applications that target pre-S are not expecting to receive a Window larger
@@ -273,17 +288,20 @@
     float getCompatScale(String packageName, int uid) {
         final UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
         if (CompatChanges.isChangeEnabled(DOWNSCALED, packageName, userHandle)) {
-            if (CompatChanges.isChangeEnabled(DOWNSCALE_87_5, packageName, userHandle)) {
-                return 8f / 7f; // 1.14285714286
+            if (CompatChanges.isChangeEnabled(DOWNSCALE_90, packageName, userHandle)) {
+                return 1f / 0.9f;
             }
-            if (CompatChanges.isChangeEnabled(DOWNSCALE_75, packageName, userHandle)) {
-                return 4f / 3f; // 1.333333333
+            if (CompatChanges.isChangeEnabled(DOWNSCALE_80, packageName, userHandle)) {
+                return 1f / 0.8f;
             }
-            if (CompatChanges.isChangeEnabled(DOWNSCALE_62_5, packageName, userHandle)) {
-                return /* 1 / 0.625 */ 1.6f;
+            if (CompatChanges.isChangeEnabled(DOWNSCALE_70, packageName, userHandle)) {
+                return 1f / 0.7f;
+            }
+            if (CompatChanges.isChangeEnabled(DOWNSCALE_60, packageName, userHandle)) {
+                return 1f / 0.6f;
             }
             if (CompatChanges.isChangeEnabled(DOWNSCALE_50, packageName, userHandle)) {
-                return /* 1 / 0.5 */ 2f;
+                return 1f / 0.5f;
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 95b2b5d..6d24105 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1428,7 +1428,8 @@
             computeScreenConfiguration(config);
         } else if (currentConfig != null
                 // If waiting for a remote rotation, don't prematurely update configuration.
-                && !mDisplayRotation.isWaitingForRemoteRotation()) {
+                && !(mDisplayRotation.isWaitingForRemoteRotation()
+                        || mAtmService.getTransitionController().isCollecting(this))) {
             // No obvious action we need to take, but if our current state mismatches the
             // activity manager's, update it, disregarding font scale, which should remain set
             // to the value of the previous configuration.
@@ -1470,6 +1471,12 @@
         return mDisplayRotation.updateOrientation(orientation, forceUpdate);
     }
 
+    @Override
+    boolean isSyncFinished() {
+        if (mDisplayRotation.isWaitingForRemoteRotation()) return false;
+        return super.isSyncFinished();
+    }
+
     /**
      * Returns a valid rotation if the activity can use different orientation than the display.
      * Otherwise {@link #ROTATION_UNDEFINED}.
@@ -1763,7 +1770,7 @@
      * Update rotation of the display.
      *
      * @return {@code true} if the rotation has been changed.  In this case YOU MUST CALL
-     *         {@link #sendNewConfiguration} TO UNFREEZE THE SCREEN.
+     *         {@link #sendNewConfiguration} TO UNFREEZE THE SCREEN unless using Shell transitions.
      */
     boolean updateRotationUnchecked() {
         return mDisplayRotation.updateRotationUnchecked(false /* forceUpdate */);
@@ -1778,8 +1785,12 @@
      */
     private void applyRotation(final int oldRotation, final int rotation) {
         mDisplayRotation.applyCurrentRotation(rotation);
-        final boolean rotateSeamlessly = mDisplayRotation.isRotatingSeamlessly();
-        final Transaction transaction = getPendingTransaction();
+        final boolean shellTransitions =
+                mWmService.mAtmService.getTransitionController().getTransitionPlayer() != null;
+        final boolean rotateSeamlessly =
+                mDisplayRotation.isRotatingSeamlessly() && !shellTransitions;
+        final Transaction transaction =
+                shellTransitions ? getSyncTransaction() : getPendingTransaction();
         ScreenRotationAnimation screenRotationAnimation = rotateSeamlessly
                 ? null : getRotationAnimation();
         // We need to update our screen size information to match the new rotation. If the rotation
@@ -1795,9 +1806,11 @@
             screenRotationAnimation.setRotation(transaction, rotation);
         }
 
-        forAllWindows(w -> {
-            w.seamlesslyRotateIfAllowed(transaction, oldRotation, rotation, rotateSeamlessly);
-        }, true /* traverseTopToBottom */);
+        if (!shellTransitions) {
+            forAllWindows(w -> {
+                w.seamlesslyRotateIfAllowed(transaction, oldRotation, rotation, rotateSeamlessly);
+            }, true /* traverseTopToBottom */);
+        }
 
         mWmService.mDisplayManagerInternal.performTraversal(transaction);
         scheduleAnimation();
@@ -4573,6 +4586,12 @@
         return mWmService.makeSurfaceBuilder(mSession).setParent(getOverlayLayer());
     }
 
+    @Override
+    public SurfaceControl.Builder makeAnimationLeash() {
+        return mWmService.makeSurfaceBuilder(mSession).setParent(mSurfaceControl)
+                .setContainerLayer();
+    }
+
     /**
      * Reparents the given surface to {@link #mOverlayLayer} SurfaceControl.
      */
@@ -5919,4 +5938,9 @@
         return mDisplayAreaPolicy.getDisplayAreaForWindowToken(windowType, options,
                 ownerCanManageAppToken, roundedCornerOverlay);
     }
+
+    @Override
+    DisplayContent asDisplayContent() {
+        return this;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 5df1355..d0e4c40 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -22,6 +22,7 @@
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
+import static android.view.WindowManager.TRANSIT_CHANGE;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
@@ -408,8 +409,11 @@
      *         THE SCREEN.
      */
     boolean updateRotationUnchecked(boolean forceUpdate) {
+        final boolean useShellTransitions =
+                mService.mAtmService.getTransitionController().getTransitionPlayer() != null;
+
         final int displayId = mDisplayContent.getDisplayId();
-        if (!forceUpdate) {
+        if (!forceUpdate && !useShellTransitions) {
             if (mDeferredRotationPauseCount > 0) {
                 // Rotation updates have been paused temporarily. Defer the update until updates
                 // have been resumed.
@@ -472,6 +476,12 @@
             return false;
         }
 
+        final Transition t = (useShellTransitions
+                && !mService.mAtmService.getTransitionController().isCollecting())
+                ? mService.mAtmService.getTransitionController().createTransition(TRANSIT_CHANGE)
+                : null;
+        mService.mAtmService.getTransitionController().collect(mDisplayContent);
+
         ProtoLog.v(WM_DEBUG_ORIENTATION,
                 "Display id=%d rotation changed to %d from %d, lastOrientation=%d",
                         displayId, rotation, oldRotation, lastOrientation);
@@ -484,6 +494,20 @@
 
         mDisplayContent.setLayoutNeeded();
 
+        if (useShellTransitions) {
+            if (t != null) {
+                // This created its own transition, so send a start request.
+                mService.mAtmService.getTransitionController().requestStartTransition(
+                        t, null /* trigger */, null /* remote */);
+            } else {
+                // Use remote-rotation infra since the transition has already been requested
+                // TODO(shell-transitions): Remove this once lifecycle management can cover all
+                //                          rotation cases.
+                startRemoteRotation(oldRotation, mRotation);
+            }
+            return true;
+        }
+
         mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
         mService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,
                 mDisplayContent, WINDOW_FREEZE_TIMEOUT_DURATION);
@@ -504,6 +528,19 @@
     }
 
     /**
+     * Utility to get a rotating displaycontent from a Transition.
+     * @return null if the transition doesn't contain a rotating display.
+     */
+    static DisplayContent getDisplayFromTransition(Transition transition) {
+        for (int i = transition.mParticipants.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = transition.mParticipants.valueAt(i);
+            if (!(wc instanceof DisplayContent)) continue;
+            return (DisplayContent) wc;
+        }
+        return null;
+    }
+
+    /**
      * A Remote rotation is when we are waiting for some registered (remote)
      * {@link IDisplayWindowRotationController} to calculate and return some hierarchy operations
      *  to perform in sync with the rotation.
@@ -537,6 +574,22 @@
             }
             mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
             mIsWaitingForRemoteRotation = false;
+
+            if (mService.mAtmService.getTransitionController().getTransitionPlayer() != null) {
+                if (!mService.mAtmService.getTransitionController().isCollecting()) {
+                    throw new IllegalStateException("Trying to rotate outside a transition");
+                }
+                mService.mAtmService.getTransitionController().collect(mDisplayContent);
+                // Go through all tasks and collect them before the rotation
+                // TODO(shell-transitions): move collect() to onConfigurationChange once wallpaper
+                //       handling is synchronized.
+                mDisplayContent.forAllTasks(task -> {
+                    if (task.isVisible()) {
+                        mService.mAtmService.getTransitionController().collect(task);
+                    }
+                });
+                mDisplayContent.getInsetsStateController().addProvidersToTransition();
+            }
             mService.mAtmService.deferWindowLayout();
             try {
                 mDisplayContent.sendNewConfiguration();
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index a971794..b6057c6 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -248,6 +248,16 @@
         return result;
     }
 
+    public void addProvidersToTransition() {
+        for (int i = mProviders.size() - 1; i >= 0; --i) {
+            final InsetsSourceProvider p = mProviders.valueAt(i);
+            if (p == null) continue;
+            final WindowContainer wc = p.mWin;
+            if (wc == null) continue;
+            mDisplayContent.mAtmService.getTransitionController().collect(wc);
+        }
+    }
+
     /**
      * @return The provider of a specific type.
      */
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index aadb272..75be444 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
@@ -411,8 +412,9 @@
     private static boolean reportIfNotTop(WindowContainer wc) {
         // Organized tasks need to be reported anyways because Core won't show() their surfaces
         // and we can't rely on onTaskAppeared because it isn't in sync.
+        // Also report wallpaper so it can be handled properly during display change/rotation.
         // TODO(shell-transitions): switch onTaskAppeared usage over to transitions OPEN.
-        return wc.isOrganized();
+        return wc.isOrganized() || isWallpaper(wc);
     }
 
     /** @return the depth of child within ancestor, 0 if child == ancestor, or -1 if not a child. */
@@ -430,7 +432,7 @@
     }
 
     private static boolean isWallpaper(WindowContainer wc) {
-        return wc instanceof WallpaperWindowToken;
+        return wc.asWallpaperToken() != null;
     }
 
     /**
@@ -576,7 +578,8 @@
         final ArrayList<WindowContainer> tmpList = new ArrayList<>();
 
         // Build initial set of top-level participants by removing any participants that are no-ops
-        // or children of other participants or are otherwise invalid.
+        // or children of other participants or are otherwise invalid; however, keep around a list
+        // of participants that should always be reported even if they aren't top.
         for (WindowContainer wc : participants) {
             // Don't include detached windows.
             if (!wc.isAttached()) continue;
@@ -584,7 +587,11 @@
             final ChangeInfo changeInfo = changes.get(wc);
 
             // Reject no-ops
-            if (!changeInfo.hasChanged(wc)) continue;
+            if (!changeInfo.hasChanged(wc)) {
+                ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+                        "  Rejecting as no-op: %s", wc);
+                continue;
+            }
 
             // Search through ancestors to find the top-most participant (if one exists)
             WindowContainer topParent = null;
@@ -651,10 +658,21 @@
 
     /** Gets the leash surface for a window container */
     private static SurfaceControl getLeashSurface(WindowContainer wc) {
+        final DisplayContent asDC = wc.asDisplayContent();
+        if (asDC != null) {
+            // DisplayContent is the "root", so we use the windowing layer instead to avoid
+            // hardware-screen-level surfaces.
+            return asDC.getWindowingLayer();
+        }
         return wc.getSurfaceControl();
     }
 
     private static SurfaceControl getOrigParentSurface(WindowContainer wc) {
+        if (wc.asDisplayContent() != null) {
+            // DisplayContent is the "root", so we reinterpret it's wc as the window layer
+            // making the parent surface the displaycontent's surface.
+            return wc.getSurfaceControl();
+        }
         return wc.getParent().getSurfaceControl();
     }
 
@@ -744,6 +762,7 @@
             change.setEndRelOffset(target.getBounds().left - target.getParent().getBounds().left,
                     target.getBounds().top - target.getParent().getBounds().top);
             change.setFlags(info.getChangeFlags(target));
+            change.setRotation(info.mRotation, target.getWindowConfiguration().getRotation());
             final Task task = target.asTask();
             if (task != null) {
                 final ActivityManager.RunningTaskInfo tinfo = new ActivityManager.RunningTaskInfo();
@@ -773,12 +792,14 @@
         int mWindowingMode;
         final Rect mAbsoluteBounds = new Rect();
         boolean mShowWallpaper;
+        int mRotation = ROTATION_UNDEFINED;
 
         ChangeInfo(@NonNull WindowContainer origState) {
             mVisible = origState.isVisibleRequested();
             mWindowingMode = origState.getWindowingMode();
             mAbsoluteBounds.set(origState.getBounds());
             mShowWallpaper = origState.showWallpaper();
+            mRotation = origState.getWindowConfiguration().getRotation();
         }
 
         @VisibleForTesting
@@ -797,7 +818,8 @@
                     // if mWindowingMode is 0, this container wasn't attached at collect time, so
                     // assume no change in windowing-mode.
                     || (mWindowingMode != 0 && newState.getWindowingMode() != mWindowingMode)
-                    || !newState.getBounds().equals(mAbsoluteBounds);
+                    || !newState.getBounds().equals(mAbsoluteBounds)
+                    || mRotation != newState.getWindowConfiguration().getRotation();
         }
 
         @TransitionInfo.TransitionMode
@@ -826,8 +848,7 @@
                 //                    checks to use requested visibility.
                 flags |= FLAG_TRANSLUCENT;
             }
-            if (wc instanceof ActivityRecord
-                    && wc.asActivityRecord().mUseTransferredAnimation) {
+            if (wc.asActivityRecord() != null && wc.asActivityRecord().mUseTransferredAnimation) {
                 flags |= FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
             }
             if (isWallpaper(wc)) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 0bb9854..a5843d4 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3084,6 +3084,11 @@
         return null;
     }
 
+    /** Cheap way of doing cast and instanceof. */
+    DisplayContent asDisplayContent() {
+        return null;
+    }
+
     /**
      * @return {@code true} if window container is manage by a
      *          {@link android.window.WindowOrganizer}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c5e0000..57394d6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4148,12 +4148,19 @@
                                 .notifyOnActivityRotation(displayContent.mDisplayId);
                     }
 
-                    if (!rotationChanged || forceRelayout) {
-                        displayContent.setLayoutNeeded();
-                        layoutNeeded = true;
-                    }
-                    if (rotationChanged || alwaysSendConfiguration) {
-                        displayContent.sendNewConfiguration();
+                    final boolean pendingRemoteRotation = rotationChanged
+                            && (displayContent.getDisplayRotation().isWaitingForRemoteRotation()
+                            || mAtmService.getTransitionController().isCollecting());
+                    // Even if alwaysSend, we are waiting for a transition or remote to provide
+                    // rotated configuration, so we can't update configuration yet.
+                    if (!pendingRemoteRotation) {
+                        if (!rotationChanged || forceRelayout) {
+                            displayContent.setLayoutNeeded();
+                            layoutNeeded = true;
+                        }
+                        if (rotationChanged || alwaysSendConfiguration) {
+                            displayContent.sendNewConfiguration();
+                        }
                     }
                 }
 
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 9973664..e3d549b 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -246,6 +246,21 @@
         ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
         mService.deferWindowLayout();
         try {
+            if (transition != null) {
+                // First check if we have a display rotation transition and if so, update it.
+                final DisplayContent dc = DisplayRotation.getDisplayFromTransition(transition);
+                if (dc != null && transition.mChanges.get(dc).mRotation != dc.getRotation()) {
+                    // Go through all tasks and collect them before the rotation
+                    // TODO(shell-transitions): move collect() to onConfigurationChange once
+                    //       wallpaper handling is synchronized.
+                    dc.forAllTasks(task -> {
+                        if (task.isVisible()) transition.collect(task);
+                    });
+                    dc.getInsetsStateController().addProvidersToTransition();
+                    dc.sendNewConfiguration();
+                    effects |= TRANSACT_EFFECTS_LIFECYCLE;
+                }
+            }
             ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>();
             Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
                     t.getChanges().entrySet().iterator();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f2b4529..a8131e4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -101,6 +101,8 @@
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+// TODO (b/178655595) import static android.net.ConnectivityManager.USER_PREFERENCE_ENTERPRISE;
+// TODO (b/178655595) import static android.net.ConnectivityManager.USER_PREFERENCE_SYSTEM_DEFAULT;
 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
 import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
 import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
@@ -3076,6 +3078,13 @@
         updatePermissionPolicyCache(userId);
         updateAdminCanGrantSensorsPermissionCache(userId);
 
+        boolean enableEnterpriseNetworkSlice = true;
+        synchronized (getLockObject()) {
+            ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId);
+            enableEnterpriseNetworkSlice = owner != null ? owner.mNetworkSlicingEnabled : true;
+        }
+        updateNetworkPreferenceForUser(userId, enableEnterpriseNetworkSlice);
+
         startOwnerService(userId, "start-user");
     }
 
@@ -3091,6 +3100,7 @@
 
     @Override
     void handleStopUser(int userId) {
+        updateNetworkPreferenceForUser(userId, false);
         stopOwnerService(userId, "stop-user");
     }
 
@@ -11394,21 +11404,22 @@
         if (!mHasFeature) {
             return;
         }
-
         final CallerIdentity caller = getCallerIdentity();
         Preconditions.checkCallAuthorization(isProfileOwner(caller),
                 "Caller is not profile owner; only profile owner may control the network slicing");
-
         synchronized (getLockObject()) {
             final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(
                     caller.getUserId());
             if (requiredAdmin != null && requiredAdmin.mNetworkSlicingEnabled != enabled) {
                 requiredAdmin.mNetworkSlicingEnabled = enabled;
                 saveSettingsLocked(caller.getUserId());
-                // TODO(b/178655595) notify CS the change.
-                // TODO(b/178655595) DevicePolicyEventLogger metrics
             }
         }
+        updateNetworkPreferenceForUser(caller.getUserId(), enabled);
+        DevicePolicyEventLogger
+                .createEvent(DevicePolicyEnums.SET_NETWORK_SLICING_ENABLED)
+                .setBoolean(enabled)
+                .write();
     }
 
     @Override
@@ -11418,11 +11429,8 @@
         }
 
         final CallerIdentity caller = getCallerIdentity();
-        Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
-        Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
-                permission.READ_NETWORK_DEVICE_CONFIG) || isProfileOwner(caller),
-                        "Caller is not profile owner and not granted"
-                                + " READ_NETWORK_DEVICE_CONFIG permission");
+        Preconditions.checkCallAuthorization(isProfileOwner(caller),
+                "Caller is not profile owner");
         synchronized (getLockObject()) {
             final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(userHandle);
             if (requiredAdmin != null) {
@@ -16946,6 +16954,20 @@
         }
     }
 
+    private void updateNetworkPreferenceForUser(int userId, boolean enableEnterprise) {
+        if (!isManagedProfile(userId)) {
+            return;
+        }
+        // TODO(b/178655595)
+        // int networkPreference = enable ? ConnectivityManager.USER_PREFERENCE_ENTERPRISE :
+        //        ConnectivityManager.USER_PREFERENCE_SYSTEM_DEFAULT;
+        // mInjector.binderWithCleanCallingIdentity(() ->
+        //         mInjector.getConnectivityManager().setNetworkPreferenceForUser(
+        //                 UserHandle.of(userId),
+        //                 networkPreference,
+        //                 null /* executor */, null /* listener */));
+    }
+
     @Override
     public boolean canAdminGrantSensorsPermissionsForUser(int userId) {
         if (!mHasFeature) {
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 8f12b2e..9869b07 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -255,13 +255,12 @@
 binder::Status BinderIncrementalService::isFileFullyLoaded(int32_t storageId,
                                                            const std::string& path,
                                                            int32_t* _aidl_return) {
-    *_aidl_return = mImpl.isFileFullyLoaded(storageId, path);
+    *_aidl_return = (int)mImpl.isFileFullyLoaded(storageId, path);
     return ok();
 }
 
 binder::Status BinderIncrementalService::isFullyLoaded(int32_t storageId, int32_t* _aidl_return) {
-    *_aidl_return = mImpl.getLoadingProgress(storageId, /*stopOnFirstIncomplete=*/true)
-                            .blocksRemainingOrError();
+    *_aidl_return = (int)mImpl.isMountFullyLoaded(storageId);
     return ok();
 }
 
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index db70d44..ebfcc32 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -1980,35 +1980,30 @@
     return 0;
 }
 
-int IncrementalService::isFileFullyLoaded(StorageId storage, std::string_view filePath) const {
+incfs::LoadingState IncrementalService::isFileFullyLoaded(StorageId storage,
+                                                          std::string_view filePath) const {
     std::unique_lock l(mLock);
     const auto ifs = getIfsLocked(storage);
     if (!ifs) {
         LOG(ERROR) << "isFileFullyLoaded failed, invalid storageId: " << storage;
-        return -EINVAL;
+        return incfs::LoadingState(-EINVAL);
     }
     const auto storageInfo = ifs->storages.find(storage);
     if (storageInfo == ifs->storages.end()) {
         LOG(ERROR) << "isFileFullyLoaded failed, no storage: " << storage;
-        return -EINVAL;
+        return incfs::LoadingState(-EINVAL);
     }
     l.unlock();
-    return isFileFullyLoadedFromPath(*ifs, filePath);
+    return mIncFs->isFileFullyLoaded(ifs->control, filePath);
 }
 
-int IncrementalService::isFileFullyLoadedFromPath(const IncFsMount& ifs,
-                                                  std::string_view filePath) const {
-    const auto [filledBlocks, totalBlocks] = mIncFs->countFilledBlocks(ifs.control, filePath);
-    if (filledBlocks < 0) {
-        LOG(ERROR) << "isFileFullyLoadedFromPath failed to get filled blocks count for: "
-                   << filePath << " errno: " << filledBlocks;
-        return filledBlocks;
+incfs::LoadingState IncrementalService::isMountFullyLoaded(StorageId storage) const {
+    const auto ifs = getIfs(storage);
+    if (!ifs) {
+        LOG(ERROR) << "isMountFullyLoaded failed, invalid storageId: " << storage;
+        return incfs::LoadingState(-EINVAL);
     }
-    if (totalBlocks < filledBlocks) {
-        LOG(ERROR) << "isFileFullyLoadedFromPath failed to get total num of blocks";
-        return -EINVAL;
-    }
-    return totalBlocks - filledBlocks;
+    return mIncFs->isEverythingFullyLoaded(ifs->control);
 }
 
 IncrementalService::LoadingProgress IncrementalService::getLoadingProgress(
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index bc441c7..aa80bd4 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -164,7 +164,8 @@
              std::string_view newPath);
     int unlink(StorageId storage, std::string_view path);
 
-    int isFileFullyLoaded(StorageId storage, std::string_view filePath) const;
+    incfs::LoadingState isFileFullyLoaded(StorageId storage, std::string_view filePath) const;
+    incfs::LoadingState isMountFullyLoaded(StorageId storage) const;
 
     LoadingProgress getLoadingProgress(StorageId storage, bool stopOnFirstIncomplete) const;
 
@@ -412,7 +413,6 @@
     int setStorageParams(IncFsMount& ifs, StorageId storageId, bool enableReadLogs);
     binder::Status applyStorageParams(IncFsMount& ifs, bool enableReadLogs);
 
-    int isFileFullyLoadedFromPath(const IncFsMount& ifs, std::string_view filePath) const;
     LoadingProgress getLoadingProgressFromPath(const IncFsMount& ifs, std::string_view path,
                                                bool stopOnFirstIncomplete) const;
 
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 2a06122..eb204c5 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -197,6 +197,13 @@
         }
         return {filledBlockCount, totalBlocksCount};
     }
+    incfs::LoadingState isFileFullyLoaded(const Control& control,
+                                          std::string_view path) const final {
+        return incfs::isFullyLoaded(control, path);
+    }
+    incfs::LoadingState isEverythingFullyLoaded(const Control& control) const final {
+        return incfs::isEverythingFullyLoaded(control);
+    }
     ErrorCode link(const Control& control, std::string_view from, std::string_view to) const final {
         return incfs::link(control, from, to);
     }
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index 231b76f..2f3eb24 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -102,6 +102,9 @@
     virtual std::string toString(FileId fileId) const = 0;
     virtual std::pair<IncFsBlockIndex, IncFsBlockIndex> countFilledBlocks(
             const Control& control, std::string_view path) const = 0;
+    virtual incfs::LoadingState isFileFullyLoaded(const Control& control,
+                                                  std::string_view path) const = 0;
+    virtual incfs::LoadingState isEverythingFullyLoaded(const Control& control) const = 0;
     virtual ErrorCode link(const Control& control, std::string_view from,
                            std::string_view to) const = 0;
     virtual ErrorCode unlink(const Control& control, std::string_view path) const = 0;
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 45b796b..50d1e36 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -366,6 +366,9 @@
     MOCK_CONST_METHOD2(countFilledBlocks,
                        std::pair<IncFsBlockIndex, IncFsBlockIndex>(const Control& control,
                                                                    std::string_view path));
+    MOCK_CONST_METHOD2(isFileFullyLoaded,
+                       incfs::LoadingState(const Control& control, std::string_view path));
+    MOCK_CONST_METHOD1(isEverythingFullyLoaded, incfs::LoadingState(const Control& control));
     MOCK_CONST_METHOD3(link,
                        ErrorCode(const Control& control, std::string_view from,
                                  std::string_view to));
@@ -1563,51 +1566,37 @@
     ASSERT_EQ(res, 0);
 }
 
-TEST_F(IncrementalServiceTest, testIsFileFullyLoadedFailsWithNoFile) {
-    mIncFs->countFilledBlocksFails();
-    mFs->hasNoFile();
-
+TEST_F(IncrementalServiceTest, testIsFileFullyLoadedNoData) {
     TemporaryDir tempDir;
     int storageId =
             mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
                                                IncrementalService::CreateOptions::CreateNew);
-    ASSERT_EQ(-1, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+    EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, _))
+            .Times(1)
+            .WillOnce(Return(incfs::LoadingState::MissingBlocks));
+    ASSERT_GT((int)mIncrementalService->isFileFullyLoaded(storageId, "base.apk"), 0);
 }
 
-TEST_F(IncrementalServiceTest, testIsFileFullyLoadedFailsWithFailedRanges) {
-    mIncFs->countFilledBlocksFails();
-    mFs->hasFiles();
-
+TEST_F(IncrementalServiceTest, testIsFileFullyLoadedError) {
     TemporaryDir tempDir;
     int storageId =
             mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
                                                IncrementalService::CreateOptions::CreateNew);
-    EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
-    ASSERT_EQ(-1, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
-}
-
-TEST_F(IncrementalServiceTest, testIsFileFullyLoadedSuccessWithEmptyRanges) {
-    mIncFs->countFilledBlocksEmpty();
-    mFs->hasFiles();
-
-    TemporaryDir tempDir;
-    int storageId =
-            mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
-                                               IncrementalService::CreateOptions::CreateNew);
-    EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
-    ASSERT_EQ(0, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+    EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, _))
+            .Times(1)
+            .WillOnce(Return(incfs::LoadingState(-1)));
+    ASSERT_LT((int)mIncrementalService->isFileFullyLoaded(storageId, "base.apk"), 0);
 }
 
 TEST_F(IncrementalServiceTest, testIsFileFullyLoadedSuccess) {
-    mIncFs->countFilledBlocksFullyLoaded();
-    mFs->hasFiles();
-
     TemporaryDir tempDir;
     int storageId =
             mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
                                                IncrementalService::CreateOptions::CreateNew);
-    EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
-    ASSERT_EQ(0, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+    EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, _))
+            .Times(1)
+            .WillOnce(Return(incfs::LoadingState::Full));
+    ASSERT_EQ(0, (int)mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
 }
 
 TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccessWithNoFile) {
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 7e4bc1e..281c1aa 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
@@ -75,6 +75,7 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.platform.test.annotations.LargeTest;
 import android.provider.DeviceConfig;
 import android.util.SparseBooleanArray;
 
@@ -286,14 +287,20 @@
             doReturn(procState).when(mActivityMangerInternal).getUidProcessState(uid);
             SparseBooleanArray foregroundUids = mQuotaController.getForegroundUids();
             spyOn(foregroundUids);
+            final boolean contained = foregroundUids.get(uid);
             mUidObserver.onUidStateChanged(uid, procState, 0,
                     ActivityManager.PROCESS_CAPABILITY_NONE);
             if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
-                verify(foregroundUids, timeout(2 * SECOND_IN_MILLIS).times(1))
-                        .put(eq(uid), eq(true));
+                if (!contained) {
+                    verify(foregroundUids, timeout(2 * SECOND_IN_MILLIS).times(1))
+                            .put(eq(uid), eq(true));
+                }
                 assertTrue(foregroundUids.get(uid));
             } else {
-                verify(foregroundUids, timeout(2 * SECOND_IN_MILLIS).times(1)).delete(eq(uid));
+                if (contained) {
+                    verify(foregroundUids, timeout(2 * SECOND_IN_MILLIS).times(1))
+                            .delete(eq(uid));
+                }
                 assertFalse(foregroundUids.get(uid));
             }
             waitForNonDelayedMessagesProcessed();
@@ -1993,7 +2000,7 @@
 
         setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
         final long gracePeriodMs = 15 * SECOND_IN_MILLIS;
-        setDeviceConfigLong(QcConstants.KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS, gracePeriodMs);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS, gracePeriodMs);
         Handler handler = mQuotaController.getHandler();
         spyOn(handler);
 
@@ -2017,6 +2024,52 @@
         }
     }
 
+    /**
+     * Tests that Timers properly track sessions when an app becomes top and is closed.
+     */
+    @Test
+    public void testIsWithinEJQuotaLocked_TopApp() {
+        setDischarging();
+        JobStatus js = createExpeditedJobStatus("testIsWithinEJQuotaLocked_TopApp", 1);
+        setStandbyBucket(FREQUENT_INDEX, js);
+        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, 10 * MINUTE_IN_MILLIS);
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (30 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (5 * MINUTE_IN_MILLIS), 4 * MINUTE_IN_MILLIS, 5), true);
+        setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
+        synchronized (mQuotaController.mLock) {
+            assertFalse(mQuotaController.isWithinEJQuotaLocked(js));
+        }
+
+        final long gracePeriodMs = 15 * SECOND_IN_MILLIS;
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TOP_APP_MS, gracePeriodMs);
+        Handler handler = mQuotaController.getHandler();
+        spyOn(handler);
+
+        // Apps on top should be able to schedule & start EJs, even if they're out
+        // of quota (as long as they are in the top grace period).
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        synchronized (mQuotaController.mLock) {
+            assertTrue(mQuotaController.isWithinEJQuotaLocked(js));
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        // Still in grace period
+        synchronized (mQuotaController.mLock) {
+            assertTrue(mQuotaController.isWithinEJQuotaLocked(js));
+        }
+        advanceElapsedClock(6 * SECOND_IN_MILLIS);
+        // Out of grace period.
+        synchronized (mQuotaController.mLock) {
+            assertFalse(mQuotaController.isWithinEJQuotaLocked(js));
+        }
+    }
+
     @Test
     public void testMaybeScheduleCleanupAlarmLocked() {
         // No sessions saved yet.
@@ -2657,8 +2710,9 @@
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, 87 * SECOND_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_INTERACTION_MS, 86 * SECOND_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_NOTIFICATION_SEEN_MS, 85 * SECOND_IN_MILLIS);
-        setDeviceConfigLong(QcConstants.KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS,
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS,
                 84 * SECOND_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TOP_APP_MS, 83 * SECOND_IN_MILLIS);
 
         assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
         assertEquals(2 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs());
@@ -2697,7 +2751,8 @@
         assertEquals(87 * SECOND_IN_MILLIS, mQuotaController.getEJRewardTopAppMs());
         assertEquals(86 * SECOND_IN_MILLIS, mQuotaController.getEJRewardInteractionMs());
         assertEquals(85 * SECOND_IN_MILLIS, mQuotaController.getEJRewardNotificationSeenMs());
-        assertEquals(84 * SECOND_IN_MILLIS, mQuotaController.getEJTempAllowlistGracePeriodMs());
+        assertEquals(84 * SECOND_IN_MILLIS, mQuotaController.getEJGracePeriodTempAllowlistMs());
+        assertEquals(83 * SECOND_IN_MILLIS, mQuotaController.getEJGracePeriodTopAppMs());
     }
 
     @Test
@@ -2737,7 +2792,8 @@
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, -1);
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_INTERACTION_MS, -1);
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_NOTIFICATION_SEEN_MS, -1);
-        setDeviceConfigLong(QcConstants.KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS, -1);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS, -1);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TOP_APP_MS, -1);
 
         assertEquals(MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
         assertEquals(0, mQuotaController.getInQuotaBufferMs());
@@ -2773,7 +2829,8 @@
         assertEquals(10 * SECOND_IN_MILLIS, mQuotaController.getEJRewardTopAppMs());
         assertEquals(5 * SECOND_IN_MILLIS, mQuotaController.getEJRewardInteractionMs());
         assertEquals(0, mQuotaController.getEJRewardNotificationSeenMs());
-        assertEquals(0, mQuotaController.getEJTempAllowlistGracePeriodMs());
+        assertEquals(0, mQuotaController.getEJGracePeriodTempAllowlistMs());
+        assertEquals(0, mQuotaController.getEJGracePeriodTopAppMs());
 
         // Invalid configurations.
         // In_QUOTA_BUFFER should never be greater than ALLOWED_TIME_PER_PERIOD
@@ -2807,7 +2864,8 @@
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, 25 * HOUR_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_INTERACTION_MS, 25 * HOUR_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_NOTIFICATION_SEEN_MS, 25 * HOUR_IN_MILLIS);
-        setDeviceConfigLong(QcConstants.KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS, 25 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS, 25 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TOP_APP_MS, 25 * HOUR_IN_MILLIS);
 
         assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
         assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs());
@@ -2833,7 +2891,8 @@
         assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getEJRewardTopAppMs());
         assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getEJRewardInteractionMs());
         assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getEJRewardNotificationSeenMs());
-        assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJTempAllowlistGracePeriodMs());
+        assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJGracePeriodTempAllowlistMs());
+        assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJGracePeriodTopAppMs());
     }
 
     /** Tests that TimingSessions aren't saved when the device is charging. */
@@ -3433,7 +3492,7 @@
         setDischarging();
         setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
         final long gracePeriodMs = 15 * SECOND_IN_MILLIS;
-        setDeviceConfigLong(QcConstants.KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS, gracePeriodMs);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS, gracePeriodMs);
         Handler handler = mQuotaController.getHandler();
         spyOn(handler);
 
@@ -4910,6 +4969,7 @@
     @Test
     public void testEJTimerTracking_TopAndNonTop() {
         setDischarging();
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TOP_APP_MS, 0);
 
         JobStatus jobBg1 = createExpeditedJobStatus("testEJTimerTracking_TopAndNonTop", 1);
         JobStatus jobBg2 = createExpeditedJobStatus("testEJTimerTracking_TopAndNonTop", 2);
@@ -5032,7 +5092,7 @@
         setDischarging();
         setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
         final long gracePeriodMs = 15 * SECOND_IN_MILLIS;
-        setDeviceConfigLong(QcConstants.KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS, gracePeriodMs);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS, gracePeriodMs);
         Handler handler = mQuotaController.getHandler();
         spyOn(handler);
 
@@ -5134,11 +5194,158 @@
     }
 
     /**
+     * Tests that Timers properly track sessions when TOP state and temp allowlisting overlaps.
+     */
+    @Test
+    @LargeTest
+    public void testEJTimerTracking_TopAndTempAllowlisting() throws Exception {
+        setDischarging();
+        setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
+        final long gracePeriodMs = 5 * SECOND_IN_MILLIS;
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS, gracePeriodMs);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TOP_APP_MS, gracePeriodMs);
+        Handler handler = mQuotaController.getHandler();
+        spyOn(handler);
+
+        JobStatus job1 = createExpeditedJobStatus("testEJTimerTracking_TopAndTempAllowlisting", 1);
+        JobStatus job2 = createExpeditedJobStatus("testEJTimerTracking_TopAndTempAllowlisting", 2);
+        JobStatus job3 = createExpeditedJobStatus("testEJTimerTracking_TopAndTempAllowlisting", 3);
+        JobStatus job4 = createExpeditedJobStatus("testEJTimerTracking_TopAndTempAllowlisting", 4);
+        JobStatus job5 = createExpeditedJobStatus("testEJTimerTracking_TopAndTempAllowlisting", 5);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job1, null);
+        }
+        assertNull(mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+        List<TimingSession> expected = new ArrayList<>();
+
+        // Case 1: job starts in TA grace period then app becomes TOP
+        long start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mTempAllowlistListener.onAppAdded(mSourceUid);
+        mTempAllowlistListener.onAppRemoved(mSourceUid);
+        advanceElapsedClock(gracePeriodMs / 2);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(job1);
+        }
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        advanceElapsedClock(gracePeriodMs);
+        // Wait for the grace period to expire so the handler can process the message.
+        Thread.sleep(gracePeriodMs);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job1, job1, true);
+        }
+        assertNull(mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(gracePeriodMs);
+
+        // Case 2: job starts in TOP grace period then is TAed
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+        advanceElapsedClock(gracePeriodMs / 2);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job2, null);
+            mQuotaController.prepareForExecutionLocked(job2);
+        }
+        mTempAllowlistListener.onAppAdded(mSourceUid);
+        advanceElapsedClock(gracePeriodMs);
+        // Wait for the grace period to expire so the handler can process the message.
+        Thread.sleep(gracePeriodMs);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job2, null, false);
+        }
+        assertNull(mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(gracePeriodMs);
+
+        // Case 3: job starts in TA grace period then app becomes TOP; job ends after TOP grace
+        mTempAllowlistListener.onAppAdded(mSourceUid);
+        mTempAllowlistListener.onAppRemoved(mSourceUid);
+        advanceElapsedClock(gracePeriodMs / 2);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job3, null);
+            mQuotaController.prepareForExecutionLocked(job3);
+        }
+        advanceElapsedClock(SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        advanceElapsedClock(gracePeriodMs);
+        // Wait for the grace period to expire so the handler can process the message.
+        Thread.sleep(gracePeriodMs);
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+        advanceElapsedClock(gracePeriodMs);
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        // Wait for the grace period to expire so the handler can process the message.
+        Thread.sleep(2 * gracePeriodMs);
+        advanceElapsedClock(gracePeriodMs);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job3, job3, true);
+        }
+        expected.add(createTimingSession(start, gracePeriodMs, 1));
+        assertEquals(expected,
+                mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(gracePeriodMs);
+
+        // Case 4: job starts in TOP grace period then app becomes TAed; job ends after TA grace
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+        advanceElapsedClock(gracePeriodMs / 2);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job4, null);
+            mQuotaController.prepareForExecutionLocked(job4);
+        }
+        advanceElapsedClock(SECOND_IN_MILLIS);
+        mTempAllowlistListener.onAppAdded(mSourceUid);
+        advanceElapsedClock(gracePeriodMs);
+        // Wait for the grace period to expire so the handler can process the message.
+        Thread.sleep(gracePeriodMs);
+        mTempAllowlistListener.onAppRemoved(mSourceUid);
+        advanceElapsedClock(gracePeriodMs);
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        // Wait for the grace period to expire so the handler can process the message.
+        Thread.sleep(2 * gracePeriodMs);
+        advanceElapsedClock(gracePeriodMs);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job4, job4, true);
+        }
+        expected.add(createTimingSession(start, gracePeriodMs, 1));
+        assertEquals(expected,
+                mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(gracePeriodMs);
+
+        // Case 5: job starts during overlapping grace period
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        advanceElapsedClock(SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+        advanceElapsedClock(SECOND_IN_MILLIS);
+        mTempAllowlistListener.onAppAdded(mSourceUid);
+        advanceElapsedClock(SECOND_IN_MILLIS);
+        mTempAllowlistListener.onAppRemoved(mSourceUid);
+        advanceElapsedClock(gracePeriodMs - SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job5, null);
+            mQuotaController.prepareForExecutionLocked(job5);
+        }
+        advanceElapsedClock(SECOND_IN_MILLIS);
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        // Wait for the grace period to expire so the handler can process the message.
+        Thread.sleep(2 * gracePeriodMs);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job5, job5, true);
+        }
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        assertEquals(expected,
+                mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /**
      * Tests that expedited jobs aren't stopped when an app runs out of quota.
      */
     @Test
     public void testEJTracking_OutOfQuota_ForegroundAndBackground() {
         setDischarging();
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TOP_APP_MS, 0);
 
         JobStatus jobBg =
                 createExpeditedJobStatus("testEJTracking_OutOfQuota_ForegroundAndBackground", 1);
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index e853fd3..17c6b6f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -163,7 +163,7 @@
     /** Collection of mocks used for PackageManagerService tests. */
 
     class Mocks {
-        val lock = Any()
+        val lock = PackageManagerTracedLock()
         val installLock = Any()
         val injector: PackageManagerService.Injector = mock()
         val systemWrapper: PackageManagerService.SystemWrapper = mock()
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
index 872b955..29691fb 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
@@ -65,7 +65,6 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
-import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
 import java.util.Locale;
@@ -1115,6 +1114,23 @@
     }
 
     @Test
+    public void testSetForceShowMagnifiableBounds() {
+        register(DISPLAY_0);
+
+        mFullScreenMagnificationController.setForceShowMagnifiableBounds(DISPLAY_0, true);
+
+        verify(mMockWindowManager).setForceShowMagnifiableBounds(DISPLAY_0, true);
+    }
+
+    @Test
+    public void testIsForceShowMagnifiableBounds() {
+        register(DISPLAY_0);
+        mFullScreenMagnificationController.setForceShowMagnifiableBounds(DISPLAY_0, true);
+
+        assertTrue(mFullScreenMagnificationController.isForceShowMagnifiableBounds(DISPLAY_0));
+    }
+
+    @Test
     public void testSetScale_toMagnifying_shouldNotifyActivatedState() {
         setScaleToMagnifying();
 
@@ -1142,14 +1158,11 @@
         for (int i = 0; i < DISPLAY_COUNT; i++) {
             when(mMockWindowManager.setMagnificationCallbacks(eq(i), any())).thenReturn(true);
         }
-        doAnswer(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
-                Object[] args = invocationOnMock.getArguments();
-                Region regionArg = (Region) args[1];
-                regionArg.set(INITIAL_MAGNIFICATION_REGION);
-                return null;
-            }
+        doAnswer((Answer<Void>) invocationOnMock -> {
+            Object[] args = invocationOnMock.getArguments();
+            Region regionArg = (Region) args[1];
+            regionArg.set(INITIAL_MAGNIFICATION_REGION);
+            return null;
         }).when(mMockWindowManager).getMagnificationRegion(anyInt(), (Region) anyObject());
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index 84c76b7..cf23197 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -25,6 +25,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
@@ -174,6 +175,23 @@
     }
 
     @Test
+    public void transitionToWindowMode_disablingWindowMode_showMagnificationButton()
+            throws RemoteException {
+        setMagnificationEnabled(MODE_WINDOW);
+        mMagnificationController.transitionMagnificationModeLocked(TEST_DISPLAY,
+                MODE_FULLSCREEN,
+                mTransitionCallBack);
+
+        mMagnificationController.transitionMagnificationModeLocked(TEST_DISPLAY,
+                MODE_WINDOW,
+                mTransitionCallBack);
+
+        mMockConnection.invokeCallbacks();
+        verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+                eq(MODE_WINDOW));
+    }
+
+    @Test
     public void transitionToFullScreenMode_windowMagnifying_disableWindowAndEnableFullScreen()
             throws RemoteException {
         setMagnificationEnabled(MODE_WINDOW);
@@ -228,7 +246,6 @@
         verify(mTransitionCallBack).onResult(true);
     }
 
-
     @Test
     public void interruptDuringTransitionToFullScreenMode_windowMagnifying_notifyTransitionFailed()
             throws RemoteException {
@@ -365,6 +382,19 @@
                 eq(MODE_FULLSCREEN));
     }
 
+
+    @Test
+    public void onTouchInteractionChanged_fullscreenNotActivated_notShowMagnificationButton()
+            throws RemoteException {
+        setMagnificationModeSettings(MODE_FULLSCREEN);
+
+        mMagnificationController.onTouchInteractionStart(TEST_DISPLAY, MODE_FULLSCREEN);
+        mMagnificationController.onTouchInteractionEnd(TEST_DISPLAY, MODE_FULLSCREEN);
+
+        verify(mWindowMagnificationManager, never()).showMagnificationButton(eq(TEST_DISPLAY),
+                eq(MODE_FULLSCREEN));
+    }
+
     @Test
     public void onShortcutTriggered_windowModeEnabledAndCapabilitiesAll_showMagnificationButton()
             throws RemoteException {
@@ -427,6 +457,35 @@
         verify(mWindowMagnificationManager).removeMagnificationButton(eq(TEST_DISPLAY));
     }
 
+    @Test
+    public void transitionToFullScreenMode_fullscreenModeActivated_showMagnificationButton()
+            throws RemoteException {
+        setMagnificationEnabled(MODE_WINDOW);
+
+        mMagnificationController.transitionMagnificationModeLocked(TEST_DISPLAY,
+                MODE_FULLSCREEN, mTransitionCallBack);
+        mMockConnection.invokeCallbacks();
+
+        verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+                eq(MODE_FULLSCREEN));
+    }
+
+    @Test
+    public void transitionToWindow_windowModeActivated_showMagnificationButton()
+            throws RemoteException {
+        setMagnificationEnabled(MODE_FULLSCREEN);
+
+        mMagnificationController.transitionMagnificationModeLocked(TEST_DISPLAY,
+                MODE_WINDOW, mTransitionCallBack);
+
+        verify(mScreenMagnificationController).reset(eq(TEST_DISPLAY),
+                mCallbackArgumentCaptor.capture());
+        mCallbackArgumentCaptor.getValue().onResult(true);
+        mMockConnection.invokeCallbacks();
+        verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+                eq(MODE_WINDOW));
+    }
+
     private void setMagnificationEnabled(int mode) throws RemoteException {
 
         setMagnificationEnabled(mode, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
@@ -450,6 +509,8 @@
         }
         if (mode == MODE_FULLSCREEN) {
             when(mScreenMagnificationController.isMagnifying(TEST_DISPLAY)).thenReturn(true);
+            when(mScreenMagnificationController.isForceShowMagnifiableBounds(
+                    TEST_DISPLAY)).thenReturn(true);
             when(mScreenMagnificationController.getPersistedScale()).thenReturn(DEFAULT_SCALE);
             when(mScreenMagnificationController.getScale(TEST_DISPLAY)).thenReturn(DEFAULT_SCALE);
             when(mScreenMagnificationController.getCenterX(TEST_DISPLAY)).thenReturn(
@@ -457,6 +518,11 @@
             when(mScreenMagnificationController.getCenterY(TEST_DISPLAY)).thenReturn(
                     centerY);
         } else {
+            doAnswer(invocation -> {
+                when(mScreenMagnificationController.isMagnifying(TEST_DISPLAY)).thenReturn(true);
+                return null;
+            }).when(mScreenMagnificationController).setScaleAndCenter(eq(TEST_DISPLAY),
+                    eq(DEFAULT_SCALE), anyFloat(), anyFloat(), anyBoolean(), anyInt());
             mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, DEFAULT_SCALE,
                     centerX, centerY, null);
             mMockConnection.invokeCallbacks();
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
index 7a4b901..a6d146e 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
@@ -39,6 +39,7 @@
 import android.app.trust.ITrustManager;
 import android.content.Context;
 import android.hardware.biometrics.BiometricManager.Authenticators;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.IBiometricAuthenticator;
 import android.hardware.biometrics.IBiometricSensorReceiver;
 import android.hardware.biometrics.IBiometricServiceReceiver;
@@ -292,9 +293,18 @@
             }
         });
 
+        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+                "00000001" /* serialNumber */, "" /* softwareVersion */));
+        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+                "vendor/version/revision" /* softwareVersion */));
+
         mFingerprintSensorProps.add(new FingerprintSensorPropertiesInternal(id,
                 SensorProperties.STRENGTH_STRONG,
                 5 /* maxEnrollmentsPerUser */,
+                componentInfo,
                 type,
                 false /* resetLockoutRequiresHardwareAuthToken */));
     }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 77a39d8..576f9c2 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4016,6 +4016,27 @@
     }
 
     @Test
+    public void testUpdateNetworkPreferenceOnStartOnStopUser() throws Exception {
+        dpms.handleStartUser(CALLER_USER_HANDLE);
+        // TODO(b/178655595)
+        // verify(getServices().connectivityManager, times(1)).setNetworkPreferenceForUser(
+        //         any(UserHandle.class),
+        //         anyInt(),
+        //         any(Executor.class),
+        //         any(Runnable.class)
+        //);
+
+        dpms.handleStopUser(CALLER_USER_HANDLE);
+        // TODO(b/178655595)
+        // verify(getServices().connectivityManager, times(1)).setNetworkPreferenceForUser(
+        //         any(UserHandle.class),
+        //         eq(ConnectivityManager.USER_PREFERENCE_SYSTEM_DEFAULT),
+        //         any(Executor.class),
+        //         any(Runnable.class)
+        //);
+    }
+
+    @Test
     public void testGetSetNetworkSlicing() throws Exception {
         assertExpectException(SecurityException.class, null,
                 () -> dpm.setNetworkSlicingEnabled(false));
@@ -4023,20 +4044,26 @@
         assertExpectException(SecurityException.class, null,
                 () -> dpm.isNetworkSlicingEnabled());
 
-        assertExpectException(SecurityException.class, null,
-                () -> dpm.isNetworkSlicingEnabledForUser(UserHandle.of(CALLER_USER_HANDLE)));
-
-        mContext.callerPermissions.add(permission.READ_NETWORK_DEVICE_CONFIG);
-        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
-        try {
-            dpm.isNetworkSlicingEnabledForUser(UserHandle.of(CALLER_USER_HANDLE));
-        } catch (SecurityException se) {
-            fail("Threw SecurityException with right permission");
-        }
-
         setupProfileOwner();
         dpm.setNetworkSlicingEnabled(false);
         assertThat(dpm.isNetworkSlicingEnabled()).isFalse();
+        // TODO(b/178655595)
+        // verify(getServices().connectivityManager, times(1)).setNetworkPreferenceForUser(
+        //         any(UserHandle.class),
+        //         eq(ConnectivityManager.USER_PREFERENCE_SYSTEM_DEFAULT),
+        //         any(Executor.class),
+        //         any(Runnable.class)
+        //);
+
+        dpm.setNetworkSlicingEnabled(true);
+        assertThat(dpm.isNetworkSlicingEnabled()).isTrue();
+        // TODO(b/178655595)
+        // verify(getServices().connectivityManager, times(1)).setNetworkPreferenceForUser(
+        //         any(UserHandle.class),
+        //         eq(ConnectivityManager.USER_PREFERENCE_ENTERPRISE),
+        //         any(Executor.class),
+        //         any(Runnable.class)
+        //);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 6068fdf..2fcc021 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -224,6 +224,8 @@
                 return mMockSystemServices.accountManager;
             case Context.TELEPHONY_SERVICE:
                 return mMockSystemServices.telephonyManager;
+            case Context.CONNECTIVITY_SERVICE:
+                return mMockSystemServices.connectivityManager;
             case Context.APP_OPS_SERVICE:
                 return mMockSystemServices.appOpsManager;
             case Context.CROSS_PROFILE_APPS_SERVICE:
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index f6dee38..9cc0572 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -47,6 +47,7 @@
 import android.database.Cursor;
 import android.hardware.usb.UsbManager;
 import android.media.IAudioService;
+import android.net.ConnectivityManager;
 import android.net.IIpConnectivityMetrics;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
@@ -114,6 +115,7 @@
     public final SettingsForMock settings;
     public final MockContentResolver contentResolver;
     public final TelephonyManager telephonyManager;
+    public final ConnectivityManager connectivityManager;
     public final AccountManager accountManager;
     public final AlarmManager alarmManager;
     public final KeyChain.KeyChainConnection keyChainConnection;
@@ -159,6 +161,7 @@
         wifiManager = mock(WifiManager.class);
         settings = mock(SettingsForMock.class);
         telephonyManager = mock(TelephonyManager.class);
+        connectivityManager = mock(ConnectivityManager.class);
         accountManager = mock(AccountManager.class);
         alarmManager = mock(AlarmManager.class);
         keyChainConnection = mock(KeyChain.KeyChainConnection.class, RETURNS_DEEP_STUBS);
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
index 0784b7a..415e635 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
@@ -25,6 +25,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.testng.Assert.assertThrows;
+
 import android.content.integrity.AppInstallMetadata;
 
 import org.junit.Test;
@@ -163,6 +165,22 @@
                         new RuleIndexRange(900, 945));
     }
 
+    @Test
+    public void verifyIndexingFileIsCorrupt() throws IOException {
+        byte[] stringBytes =
+                getBytes(
+                        getKeyValueString(START_INDEXING_KEY, 100)
+                                + getKeyValueString("ccc", 200)
+                                + getKeyValueString(END_INDEXING_KEY, 300)
+                                + getKeyValueString(END_INDEXING_KEY, 900));
+        ByteBuffer rule = ByteBuffer.allocate(stringBytes.length);
+        rule.put(stringBytes);
+        InputStream inputStream = new ByteArrayInputStream(rule.array());
+
+        assertThrows(IllegalStateException.class,
+                () -> new RuleIndexingController(inputStream));
+    }
+
     private static InputStream obtainDefaultIndexingMapForTest() {
         byte[] stringBytes =
                 getBytes(
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 59458e8..d63a467 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -59,10 +59,10 @@
 
 import com.android.permission.persistence.RuntimePermissionsPersistence;
 import com.android.server.LocalServices;
-import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.pm.permission.LegacyPermissionDataProvider;
+import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
 import com.android.server.utils.WatchableTester;
 
 import com.google.common.truth.Truth;
@@ -1197,7 +1197,7 @@
     private Settings makeSettings() {
         return new Settings(InstrumentationRegistry.getContext().getFilesDir(),
                 mRuntimePermissionsPersistence, mPermissionDataProvider,
-                mDomainVerificationManager, new Object());
+                mDomainVerificationManager, new PackageManagerTracedLock());
     }
 
     private void verifyKeySetMetaData(Settings settings)
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index ba60111..128cbaa 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -48,6 +48,7 @@
 import android.content.pm.parsing.component.ParsedPermissionGroup;
 import android.content.pm.parsing.component.ParsedProvider;
 import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.component.ParsedUsesPermission;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
@@ -854,7 +855,7 @@
                 .addProvider(new ParsedProvider())
                 .addService(new ParsedService())
                 .addInstrumentation(new ParsedInstrumentation())
-                .addRequestedPermission("foo7")
+                .addUsesPermission(new ParsedUsesPermission("foo7", 0))
                 .addImplicitPermission("foo25")
                 .addProtectedBroadcast("foo8")
                 .setStaticSharedLibName("foo23")
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index b5add84..8e1fc16 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -43,6 +43,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.component.ParsedUsesPermission;
 import android.content.res.TypedArray;
 import android.os.Environment;
 import android.os.UserHandle;
@@ -429,7 +430,7 @@
     @Test
     public void factoryTestFlagSet() throws Exception {
         final ParsingPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
-                .addRequestedPermission(Manifest.permission.FACTORY_TEST);
+                .addUsesPermission(new ParsedUsesPermission(Manifest.permission.FACTORY_TEST, 0));
 
         final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
                 createBasicScanRequestBuilder(basicPackage).build(),
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 1905e2f..ec3a1af 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -4038,6 +4038,24 @@
     }
 
     @Test
+    public void testVisitUris_audioContentsString() throws Exception {
+        final Uri audioContents = Uri.parse("content://com.example/audio");
+
+        Bundle extras = new Bundle();
+        extras.putString(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents.toString());
+
+        Notification n = new Notification.Builder(mContext, "a")
+                .setContentTitle("notification with uris")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .addExtras(extras)
+                .build();
+
+        Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+        n.visitUris(visitor);
+        verify(visitor, times(1)).accept(eq(audioContents));
+    }
+
+    @Test
     public void testSetNotificationPolicy_preP_setOldFields() {
         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
         mService.mZenModeHelper = mZenModeHelper;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index c19f348..96ebd24 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1687,6 +1687,7 @@
     public void testIsSnapshotCompatible() {
         final ActivityRecord activity = createActivityWithTask();
         final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
+                .setTopActivityComponent(activity.mActivityComponent)
                 .setRotation(activity.getWindowConfiguration().getRotation())
                 .build();
 
@@ -1697,6 +1698,26 @@
         assertFalse(activity.isSnapshotCompatible(snapshot));
     }
 
+    /**
+     * Test that the snapshot should be obsoleted if the top activity changed.
+     */
+    @Test
+    public void testIsSnapshotCompatibleTopActivityChanged() {
+        final ActivityRecord activity = createActivityWithTask();
+        final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
+                .setTask(activity.getTask())
+                .setOnTop(true)
+                .build();
+        final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
+                .setTopActivityComponent(secondActivity.mActivityComponent)
+                .build();
+
+        assertTrue(secondActivity.isSnapshotCompatible(snapshot));
+
+        // Emulate the top activity changed.
+        assertFalse(activity.isSnapshotCompatible(snapshot));
+    }
+
     @Test
     public void testFixedRotationSnapshotStartingWindow() {
         final ActivityRecord activity = createActivityWithTask();
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 67fe7bf..33bcc5b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -119,6 +119,7 @@
 import android.view.SurfaceControl.Transaction;
 import android.view.View;
 import android.view.WindowManager;
+import android.window.WindowContainerToken;
 
 import androidx.test.filters.SmallTest;
 
@@ -1611,6 +1612,54 @@
     }
 
     @Test
+    public void testShellTransitRotation() {
+        DisplayContent dc = createNewDisplay();
+
+        // Set-up mock shell transitions
+        final TestTransitionPlayer testPlayer = new TestTransitionPlayer(
+                mAtm.getTransitionController(), mAtm.mWindowOrganizerController);
+        mAtm.getTransitionController().registerTransitionPlayer(testPlayer);
+
+        final DisplayRotation dr = dc.getDisplayRotation();
+        doCallRealMethod().when(dr).updateRotationUnchecked(anyBoolean());
+        // Rotate 180 degree so the display doesn't have configuration change. This condition is
+        // used for the later verification of stop-freezing (without setting mWaitingForConfig).
+        doReturn((dr.getRotation() + 2) % 4).when(dr).rotationForOrientation(anyInt(), anyInt());
+        mWm.mDisplayRotationController =
+                new IDisplayWindowRotationController.Stub() {
+                    @Override
+                    public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
+                            IDisplayWindowRotationCallback callback) {
+                        try {
+                            callback.continueRotateDisplay(toRotation, null);
+                        } catch (RemoteException e) {
+                            assertTrue(false);
+                        }
+                    }
+                };
+
+        // kill any existing rotation animation (vestigial from test setup).
+        dc.setRotationAnimation(null);
+
+        final int origRot = dc.getConfiguration().windowConfiguration.getRotation();
+
+        mWm.updateRotation(true /* alwaysSendConfiguration */, false /* forceRelayout */);
+        // Should create a transition request without performing rotation
+        assertNotNull(testPlayer.mLastRequest);
+        assertEquals(origRot, dc.getConfiguration().windowConfiguration.getRotation());
+
+        // Once transition starts, rotation is applied and transition shows DC rotating.
+        testPlayer.start();
+        assertNotEquals(origRot, dc.getConfiguration().windowConfiguration.getRotation());
+        assertNotNull(testPlayer.mLastReady);
+        assertEquals(dc, DisplayRotation.getDisplayFromTransition(testPlayer.mLastTransit));
+        WindowContainerToken dcToken = dc.mRemoteToken.toWindowContainerToken();
+        assertNotEquals(testPlayer.mLastReady.getChange(dcToken).getEndRotation(),
+                testPlayer.mLastReady.getChange(dcToken).getStartRotation());
+        testPlayer.finish();
+    }
+
+    @Test
     public void testGetOrCreateRootHomeTask_defaultDisplay() {
         TaskDisplayArea defaultTaskDisplayArea = mWm.mRoot.getDefaultTaskDisplayArea();
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index edf7056..b5219fd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -28,7 +28,6 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
-import android.window.TaskSnapshot;
 import android.content.ComponentName;
 import android.content.ContextWrapper;
 import android.content.res.Resources;
@@ -42,6 +41,7 @@
 import android.hardware.HardwareBuffer;
 import android.os.UserManager;
 import android.view.Surface;
+import android.window.TaskSnapshot;
 
 import com.android.server.LocalServices;
 import com.android.server.pm.UserManagerInternal;
@@ -154,10 +154,16 @@
         private int mWindowingMode = WINDOWING_MODE_FULLSCREEN;
         private int mSystemUiVisibility = 0;
         private int mRotation = Surface.ROTATION_0;
+        private ComponentName mTopActivityComponent = new ComponentName("", "");
 
         TaskSnapshotBuilder() {
         }
 
+        TaskSnapshotBuilder setTopActivityComponent(ComponentName topActivityComponent) {
+            mTopActivityComponent = topActivityComponent;
+            return this;
+        }
+
         TaskSnapshotBuilder setScaleFraction(float scale) {
             mScaleFraction = scale;
             return this;
@@ -199,7 +205,7 @@
             Canvas c = buffer.lockCanvas();
             c.drawColor(Color.RED);
             buffer.unlockCanvasAndPost(c);
-            return new TaskSnapshot(MOCK_SNAPSHOT_ID, new ComponentName("", ""),
+            return new TaskSnapshot(MOCK_SNAPSHOT_ID, mTopActivityComponent,
                     HardwareBuffer.createFromGraphicBuffer(buffer),
                     ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
                     mRotation, taskSize, TEST_INSETS,
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 779457b..b210dfb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -60,6 +60,7 @@
 import static org.mockito.Mockito.mock;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.IApplicationThread;
@@ -90,7 +91,10 @@
 import android.view.WindowManager;
 import android.view.WindowManager.DisplayImePolicy;
 import android.window.ITaskOrganizer;
+import android.window.ITransitionPlayer;
 import android.window.StartingWindowInfo;
+import android.window.TransitionInfo;
+import android.window.TransitionRequestInfo;
 
 import com.android.internal.policy.AttributeCache;
 import com.android.internal.util.ArrayUtils;
@@ -1359,4 +1363,48 @@
             mHasSurface = hadSurface;
         }
     }
+
+    class TestTransitionPlayer extends ITransitionPlayer.Stub {
+        final TransitionController mController;
+        final WindowOrganizerController mOrganizer;
+        Transition mLastTransit = null;
+        TransitionRequestInfo mLastRequest = null;
+        TransitionInfo mLastReady = null;
+
+        TestTransitionPlayer(@NonNull TransitionController controller,
+                @NonNull WindowOrganizerController organizer) {
+            mController = controller;
+            mOrganizer = organizer;
+        }
+
+        void clear() {
+            mLastTransit = null;
+            mLastReady = null;
+            mLastRequest = null;
+        }
+
+        @Override
+        public void onTransitionReady(IBinder transitToken, TransitionInfo transitionInfo,
+                SurfaceControl.Transaction transaction) throws RemoteException {
+            mLastTransit = Transition.fromBinder(transitToken);
+            mLastReady = transitionInfo;
+        }
+
+        @Override
+        public void requestStartTransition(IBinder transitToken,
+                TransitionRequestInfo request) throws RemoteException {
+            mLastTransit = Transition.fromBinder(transitToken);
+            mLastRequest = request;
+        }
+
+        public void start() {
+            mOrganizer.startTransition(mLastRequest.getType(), mLastTransit, null);
+            mLastTransit.onTransactionReady(mLastTransit.getSyncId(),
+                    mock(SurfaceControl.Transaction.class));
+        }
+
+        public void finish() {
+            mController.finishTransition(mLastTransit);
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 74421a0..04a0aba 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -44,8 +44,6 @@
 import com.android.internal.telephony.ICarrierConfigLoader;
 import com.android.telephony.Rlog;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -116,31 +114,17 @@
      */
     public static final int USSD_OVER_IMS_ONLY       = 3;
 
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "CARRIER_NR_AVAILABILITY_" }, value = {
-            CARRIER_NR_AVAILABILITY_NONE,
-            CARRIER_NR_AVAILABILITY_NSA,
-            CARRIER_NR_AVAILABILITY_SA,
-    })
-    public @interface DeviceNrCapability {}
-
-    /**
-     * Indicates CARRIER_NR_AVAILABILITY_NONE determine that the carrier does not enable 5G NR.
-     */
-    public static final int CARRIER_NR_AVAILABILITY_NONE = 0;
-
     /**
      * Indicates CARRIER_NR_AVAILABILITY_NSA determine that the carrier enable the non-standalone
      * (NSA) mode of 5G NR.
      */
-    public static final int CARRIER_NR_AVAILABILITY_NSA = 1 << 0;
+    public static final int CARRIER_NR_AVAILABILITY_NSA = 1;
 
     /**
      * Indicates CARRIER_NR_AVAILABILITY_SA determine that the carrier enable the standalone (SA)
      * mode of 5G NR.
      */
-    public static final int CARRIER_NR_AVAILABILITY_SA = 1 << 1;
+    public static final int CARRIER_NR_AVAILABILITY_SA = 2;
 
     private final Context mContext;
 
@@ -1882,23 +1866,20 @@
             "show_precise_failed_cause_bool";
 
     /**
-     * Bit-field integer to determine whether the carrier enable the non-standalone (NSA) mode of
-     * 5G NR, standalone (SA) mode of 5G NR
+     * A list of carrier nr availability is used to determine whether the carrier enable the
+     * non-standalone (NSA) mode of 5G NR, standalone (SA) mode of 5G NR
      *
-     * <UL>
-     *  <LI>CARRIER_NR_AVAILABILITY_NONE: non-NR = 0 </LI>
-     *  <LI>CARRIER_NR_AVAILABILITY_NSA: NSA = 1 << 0</LI>
-     *  <LI>CARRIER_NR_AVAILABILITY_SA: SA = 1 << 1</LI>
-     * </UL>
-     * <p> The value of this key must be bitwise OR of
-     * {@link #CARRIER_NR_AVAILABILITY_NONE}, {@link #CARRIER_NR_AVAILABILITY_NSA},
-     * {@link #CARRIER_NR_AVAILABILITY_SA}.
+     * <p> The value of list is
+     * {@link #CARRIER_NR_AVAILABILITY_NSA}, or {@link #CARRIER_NR_AVAILABILITY_SA}.
      *
-     * <p> For example, if both NSA and SA are used, the value of key is 3 (1 << 0 | 1 << 1).
-     * If the carrier doesn't support 5G NR, the value of key is 0 (non-NR).
-     * If the key is invalid or not configured, a default value 3 (NSA|SA = 3) will apply.
+     * <p> For example, if both NSA and SA are used, the list value is {
+     * {@link #CARRIER_NR_AVAILABILITY_NSA},{@link #CARRIER_NR_AVAILABILITY_SA}}.
+     * If the carrier doesn't support 5G NR, the value is the empty array.
+     * If the key is invalid or not configured, the default value {
+     * {@link #CARRIER_NR_AVAILABILITY_NSA},{@link #CARRIER_NR_AVAILABILITY_SA}} will apply.
      */
-    public static final String KEY_CARRIER_NR_AVAILABILITY_INT = "carrier_nr_availability_int";
+    public static final String KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY =
+            "carrier_nr_availabilities_int_array";
 
     /**
      * Boolean to decide whether LTE is enabled.
@@ -3784,13 +3765,64 @@
         /** Prefix of all ImsServiceEntitlement.KEY_* constants. */
         public static final String KEY_PREFIX = "imsserviceentitlement.";
 
-        /** The address of the entitlement configuration server. */
+        /**
+         * The address of the entitlement configuration server.
+         *
+         * Reference: GSMA TS.43-v5, section 2.1 Default Entitlement Configuration Server.
+         */
         public static final String KEY_ENTITLEMENT_SERVER_URL_STRING =
                 KEY_PREFIX + "entitlement_server_url_string";
 
+        /**
+         * For some carriers, end-users may be presented with a web portal of the carrier before
+         * being allowed to use the VoWiFi service.
+         * To support this feature, the app hosts a {@link android.webkit.WebView} in the foreground
+         * VoWiFi entitlement configuration flow to show the web portal.
+         *
+         * {@code true} - show the VoWiFi portal in a webview.
+         *
+         * Note: this is effective only if the {@link #KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING}
+         * is set to this app.
+         *
+         * Reference: GSMA TS.43-v5, section 3, VoWiFi entitlement configuration.
+         */
+        public static final String KEY_SHOW_VOWIFI_WEBVIEW_BOOL =
+                KEY_PREFIX + "show_vowifi_webview_bool";
+
+        /**
+         * For some carriers, the network is not provisioned by default to support
+         * IMS (VoLTE/VoWiFi/SMSoIP) service for all end users. Some type of network-side
+         * provisioning must then take place before offering the IMS service to the end-user.
+         *
+         * {@code true} - need this ImsServiceEntitlement app to do IMS (VoLTE/VoWiFi/SMSoIP)
+         * provisioning in the background before offering the IMS service to the end-user.
+         *
+         * Note: this is effective only if the carrier needs IMS provisioning, i.e.
+         * {@link #KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL} is set to true.
+         *
+         * Reference: GSMA TS.43-v5, section 3 - 5, VoWiFi/VoLTE/SMSoIP entitlement configuration.
+         */
+        public static final String KEY_IMS_PROVISIONING_BOOL = KEY_PREFIX + "ims_provisioning_bool";
+
+        /**
+         * The FCM sender ID for the carrier.
+         * Used to trigger a carrier network requested entitlement configuration
+         * via Firebase Cloud Messaging (FCM). Do not set if the carrier doesn't use FCM for network
+         * requested entitlement configuration.
+         *
+         * Reference: GSMA TS.43-v5, section 2.4, Network Requested Entitlement Configuration.
+         *
+         * @see <a href="https://firebase.google.com/docs/cloud-messaging/concept-options#senderid">
+         *     About FCM messages - Credentials</a>
+         */
+        public static final String KEY_FCM_SENDER_ID_STRING = KEY_PREFIX + "fcm_sender_id_string";
+
         private static PersistableBundle getDefaults() {
             PersistableBundle defaults = new PersistableBundle();
             defaults.putString(KEY_ENTITLEMENT_SERVER_URL_STRING, "");
+            defaults.putString(KEY_FCM_SENDER_ID_STRING, "");
+            defaults.putBoolean(KEY_SHOW_VOWIFI_WEBVIEW_BOOL, false);
+            defaults.putBoolean(KEY_IMS_PROVISIONING_BOOL, false);
             return defaults;
         }
     }
@@ -5199,8 +5231,8 @@
         sDefaults.putString(KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, "");
         sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true);
         sDefaults.putInt(KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT, 20000);
-        sDefaults.putInt(KEY_CARRIER_NR_AVAILABILITY_INT,
-                CARRIER_NR_AVAILABILITY_NSA | CARRIER_NR_AVAILABILITY_SA);
+        sDefaults.putIntArray(KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY,
+                new int[]{CARRIER_NR_AVAILABILITY_NSA, CARRIER_NR_AVAILABILITY_SA});
         sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true);
         sDefaults.putBoolean(KEY_SUPPORT_TDSCDMA_BOOL, false);
         sDefaults.putStringArray(KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY, null);
diff --git a/telephony/java/android/telephony/data/NetworkSliceInfo.java b/telephony/java/android/telephony/data/NetworkSliceInfo.java
index 3383696..1d90095 100644
--- a/telephony/java/android/telephony/data/NetworkSliceInfo.java
+++ b/telephony/java/android/telephony/data/NetworkSliceInfo.java
@@ -29,7 +29,12 @@
 import java.util.Objects;
 
 /**
- * Represents a S-NSSAI as defined in 3GPP TS 24.501.
+ * Represents a S-NSSAI as defined in 3GPP TS 24.501, which represents a network slice.
+ *
+ * There are 2 main fields that define a slice, SliceServiceType and SliceDifferentiator.
+ * SliceServiceType defines the type of service provided by the slice, and SliceDifferentiator is
+ * used to differentiate between multiple slices of the same type. If the devices is not on HPLMN,
+ * the mappedHplmn versions of these 2 fields indicate the corresponding values in HPLMN.
  *
  * @hide
  */