Merge "Add tests for new task animation"
diff --git a/Android.bp b/Android.bp
index f1f7a8e..a5367fe 100644
--- a/Android.bp
+++ b/Android.bp
@@ -417,9 +417,6 @@
     srcs: [
         "core/java/android/net/annotations/PolicyDirection.java",
         "core/java/com/android/internal/util/HexDump.java",
-        "core/java/com/android/internal/util/IState.java",
-        "core/java/com/android/internal/util/State.java",
-        "core/java/com/android/internal/util/StateMachine.java",
         "core/java/com/android/internal/util/WakeupMessage.java",
         "services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java",
         "telephony/java/android/telephony/Annotation.java",
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index b49bbc5..4ec2640 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -86,6 +86,7 @@
 
 /**
  * The main service implementation which contains AppSearch's platform functionality.
+ *
  * @hide
  */
 public class AppSearchManagerService extends SystemService {
@@ -183,7 +184,6 @@
      * when a user is removed.
      *
      * @param userHandle The multi-user handle of the user that need to be removed.
-     *
      * @see android.os.Environment#getDataSystemCeDirectory
      */
     private void handleUserRemoved(@NonNull UserHandle userHandle) {
@@ -1500,7 +1500,6 @@
         }
     }
 
-    // TODO(b/179160886): Cache the previous storage stats.
     private class AppSearchStorageStatsAugmenter implements StorageStatsAugmenter {
         @Override
         public void augmentStatsForPackageForUser(
@@ -1514,12 +1513,19 @@
 
             try {
                 verifyUserUnlocked(userHandle);
-                Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
                 AppSearchUserInstance instance =
-                        mAppSearchUserInstanceManager.getOrCreateUserInstance(
-                                userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
-                stats.dataSize += instance.getAppSearchImpl()
-                        .getStorageInfoForPackage(packageName).getSizeBytes();
+                        mAppSearchUserInstanceManager.getUserInstanceOrNull(userHandle);
+                if (instance == null) {
+                    // augment storage info from file
+                    UserStorageInfo userStorageInfo =
+                            mAppSearchUserInstanceManager.getOrCreateUserStorageInfoInstance(
+                                    userHandle);
+                    stats.dataSize +=
+                            userStorageInfo.getSizeBytesForPackage(packageName);
+                } else {
+                    stats.dataSize += instance.getAppSearchImpl()
+                            .getStorageInfoForPackage(packageName).getSizeBytes();
+                }
             } catch (Throwable t) {
                 Log.e(
                         TAG,
@@ -1543,13 +1549,22 @@
                 if (packagesForUid == null) {
                     return;
                 }
-                Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
                 AppSearchUserInstance instance =
-                        mAppSearchUserInstanceManager.getOrCreateUserInstance(
-                                userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
-                for (int i = 0; i < packagesForUid.length; i++) {
-                    stats.dataSize += instance.getAppSearchImpl()
-                            .getStorageInfoForPackage(packagesForUid[i]).getSizeBytes();
+                        mAppSearchUserInstanceManager.getUserInstanceOrNull(userHandle);
+                if (instance == null) {
+                    // augment storage info from file
+                    UserStorageInfo userStorageInfo =
+                            mAppSearchUserInstanceManager.getOrCreateUserStorageInfoInstance(
+                                    userHandle);
+                    for (int i = 0; i < packagesForUid.length; i++) {
+                        stats.dataSize += userStorageInfo.getSizeBytesForPackage(
+                                packagesForUid[i]);
+                    }
+                } else {
+                    for (int i = 0; i < packagesForUid.length; i++) {
+                        stats.dataSize += instance.getAppSearchImpl()
+                                .getStorageInfoForPackage(packagesForUid[i]).getSizeBytes();
+                    }
                 }
             } catch (Throwable t) {
                 Log.e(TAG, "Unable to augment storage stats for uid " + uid, t);
@@ -1567,19 +1582,24 @@
 
             try {
                 verifyUserUnlocked(userHandle);
-                List<PackageInfo> packagesForUser = mPackageManager.getInstalledPackagesAsUser(
-                        /*flags=*/0, userHandle.getIdentifier());
-                if (packagesForUser == null) {
-                    return;
-                }
-                Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
                 AppSearchUserInstance instance =
-                        mAppSearchUserInstanceManager.getOrCreateUserInstance(
-                                userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
-                for (int i = 0; i < packagesForUser.size(); i++) {
-                    String packageName = packagesForUser.get(i).packageName;
-                    stats.dataSize += instance.getAppSearchImpl()
-                            .getStorageInfoForPackage(packageName).getSizeBytes();
+                        mAppSearchUserInstanceManager.getUserInstanceOrNull(userHandle);
+                if (instance == null) {
+                    // augment storage info from file
+                    UserStorageInfo userStorageInfo =
+                            mAppSearchUserInstanceManager.getOrCreateUserStorageInfoInstance(
+                                    userHandle);
+                    stats.dataSize += userStorageInfo.getTotalSizeBytes();
+                } else {
+                    List<PackageInfo> packagesForUser = mPackageManager.getInstalledPackagesAsUser(
+                            /*flags=*/0, userHandle.getIdentifier());
+                    if (packagesForUser != null) {
+                        for (int i = 0; i < packagesForUser.size(); i++) {
+                            String packageName = packagesForUser.get(i).packageName;
+                            stats.dataSize += instance.getAppSearchImpl()
+                                    .getStorageInfoForPackage(packageName).getSizeBytes();
+                        }
+                    }
                 }
             } catch (Throwable t) {
                 Log.e(TAG, "Unable to augment storage stats for " + userHandle, t);
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java
index 529f2b0..ca56325 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java
@@ -17,6 +17,7 @@
 package com.android.server.appsearch;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.appsearch.exceptions.AppSearchException;
 import android.content.Context;
 import android.os.Environment;
@@ -50,6 +51,8 @@
 
     @GuardedBy("mInstancesLocked")
     private final Map<UserHandle, AppSearchUserInstance> mInstancesLocked = new ArrayMap<>();
+    @GuardedBy("mStorageInfoLocked")
+    private final Map<UserHandle, UserStorageInfo> mStorageInfoLocked = new ArrayMap<>();
 
     private AppSearchUserInstanceManager() {}
 
@@ -130,6 +133,9 @@
                 instance.getAppSearchImpl().close();
             }
         }
+        synchronized (mStorageInfoLocked) {
+            mStorageInfoLocked.remove(userHandle);
+        }
     }
 
     /**
@@ -160,6 +166,39 @@
     }
 
     /**
+     * Returns the initialized {@link AppSearchUserInstance} for the given user, or {@code null} if
+     * no such instance exists.
+     *
+     * @param userHandle The multi-user handle of the device user calling AppSearch
+     */
+    @Nullable
+    public AppSearchUserInstance getUserInstanceOrNull(@NonNull UserHandle userHandle) {
+        Objects.requireNonNull(userHandle);
+        synchronized (mInstancesLocked) {
+            return mInstancesLocked.get(userHandle);
+        }
+    }
+
+    /**
+     * Gets an {@link UserStorageInfo} for the given user.
+     *
+     * @param userHandle The multi-user handle of the device user
+     * @return An initialized {@link UserStorageInfo} for this user
+     */
+    @NonNull
+    public UserStorageInfo getOrCreateUserStorageInfoInstance(@NonNull UserHandle userHandle) {
+        Objects.requireNonNull(userHandle);
+        synchronized (mStorageInfoLocked) {
+            UserStorageInfo userStorageInfo = mStorageInfoLocked.get(userHandle);
+            if (userStorageInfo == null) {
+                userStorageInfo = new UserStorageInfo(getAppSearchDir(userHandle));
+                mStorageInfoLocked.put(userHandle, userStorageInfo);
+            }
+            return userStorageInfo;
+        }
+    }
+
+    /**
      * Returns the list of all {@link UserHandle}s.
      *
      * <p>It can return an empty list if there is no {@link AppSearchUserInstance} created yet.
@@ -197,6 +236,10 @@
                 VisibilityStoreImpl.create(appSearchImpl, userContext);
         long prepareVisibilityStoreLatencyEndMillis = SystemClock.elapsedRealtime();
 
+        // Update storage info file
+        UserStorageInfo userStorageInfo = getOrCreateUserStorageInfoInstance(userHandle);
+        userStorageInfo.updateStorageInfoFile(appSearchImpl);
+
         initStatsBuilder
                 .setTotalLatencyMillis(
                         (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis))
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/UserStorageInfo.java b/apex/appsearch/service/java/com/android/server/appsearch/UserStorageInfo.java
new file mode 100644
index 0000000..d6e8598
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/UserStorageInfo.java
@@ -0,0 +1,152 @@
+/*
+ * 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.appsearch;
+
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.getPackageName;
+
+import android.annotation.NonNull;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.appsearch.external.localstorage.AppSearchImpl;
+
+import com.google.android.icing.proto.DocumentStorageInfoProto;
+import com.google.android.icing.proto.NamespaceStorageInfoProto;
+import com.google.android.icing.proto.StorageInfoProto;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/** Saves the storage info read from file for a user. */
+public final class UserStorageInfo {
+    public static final String STORAGE_INFO_FILE = "appsearch_storage";
+    private static final String TAG = "AppSearchUserStorage";
+    private final ReadWriteLock mReadWriteLock = new ReentrantReadWriteLock();
+    private final File mStorageInfoFile;
+
+    // Saves storage usage byte size for each package under the user, keyed by package name.
+    private Map<String, Long> mPackageStorageSizeMap;
+    // Saves storage usage byte size for all packages under the user.
+    private long mTotalStorageSizeBytes;
+
+    public UserStorageInfo(@NonNull File fileParentPath) {
+        Objects.requireNonNull(fileParentPath);
+        mStorageInfoFile = new File(fileParentPath, STORAGE_INFO_FILE);
+        readStorageInfoFromFile();
+    }
+
+    /**
+     * Updates storage info file with the latest storage info queried through
+     * {@link AppSearchImpl}.
+     */
+    public void updateStorageInfoFile(@NonNull AppSearchImpl appSearchImpl) {
+        Objects.requireNonNull(appSearchImpl);
+        mReadWriteLock.writeLock().lock();
+        try (FileOutputStream out = new FileOutputStream(mStorageInfoFile)) {
+            appSearchImpl.getRawStorageInfoProto().writeTo(out);
+        } catch (Throwable e) {
+            Log.w(TAG, "Failed to dump storage info into file", e);
+        } finally {
+            mReadWriteLock.writeLock().unlock();
+        }
+    }
+
+    /**
+     * Gets storage usage byte size for a package with a given package name.
+     *
+     * <p> Please note the storage info cached in file may be stale.
+     */
+    public long getSizeBytesForPackage(@NonNull String packageName) {
+        Objects.requireNonNull(packageName);
+        return mPackageStorageSizeMap.getOrDefault(packageName, 0L);
+    }
+
+    /**
+     * Gets total storage usage byte size for all packages under the user.
+     *
+     * <p> Please note the storage info cached in file may be stale.
+     */
+    public long getTotalSizeBytes() {
+        return mTotalStorageSizeBytes;
+    }
+
+    @VisibleForTesting
+    void readStorageInfoFromFile() {
+        if (mStorageInfoFile.exists()) {
+            mReadWriteLock.readLock().lock();
+            try (InputStream in = new FileInputStream(mStorageInfoFile)) {
+                StorageInfoProto storageInfo = StorageInfoProto.parseFrom(in);
+                mTotalStorageSizeBytes = storageInfo.getTotalStorageSize();
+                mPackageStorageSizeMap = calculatePackageStorageInfoMap(storageInfo);
+                return;
+            } catch (Throwable e) {
+                Log.w(TAG, "Failed to read storage info from file", e);
+            } finally {
+                mReadWriteLock.readLock().unlock();
+            }
+        }
+        mTotalStorageSizeBytes = 0;
+        mPackageStorageSizeMap = Collections.emptyMap();
+    }
+
+    /** Calculates storage usage byte size for packages from a {@link StorageInfoProto}. */
+    // TODO(b/198553756): Storage cache effort has created two copies of the storage
+    // calculation/interpolation logic.
+    @NonNull
+    @VisibleForTesting
+    Map<String, Long> calculatePackageStorageInfoMap(@NonNull StorageInfoProto storageInfo) {
+        Map<String, Long> packageStorageInfoMap = new ArrayMap<>();
+        if (storageInfo.hasDocumentStorageInfo()) {
+            DocumentStorageInfoProto documentStorageInfo = storageInfo.getDocumentStorageInfo();
+            List<NamespaceStorageInfoProto> namespaceStorageInfoList =
+                    documentStorageInfo.getNamespaceStorageInfoList();
+
+            Map<String, Integer> packageDocumentCountMap = new ArrayMap<>();
+            long totalDocuments = 0;
+            for (int i = 0; i < namespaceStorageInfoList.size(); i++) {
+                NamespaceStorageInfoProto namespaceStorageInfo = namespaceStorageInfoList.get(i);
+                String packageName = getPackageName(namespaceStorageInfo.getNamespace());
+                int namespaceDocuments = namespaceStorageInfo.getNumAliveDocuments()
+                        + namespaceStorageInfo.getNumExpiredDocuments();
+                totalDocuments += namespaceDocuments;
+                packageDocumentCountMap.put(packageName,
+                        packageDocumentCountMap.getOrDefault(packageName, 0)
+                                + namespaceDocuments);
+            }
+
+            long totalStorageSize = storageInfo.getTotalStorageSize();
+            for (Map.Entry<String, Integer> entry : packageDocumentCountMap.entrySet()) {
+                // Since we don't have the exact size of all the documents, we do an estimation.
+                // Note that while the total storage takes into account schema, index, etc. in
+                // addition to documents, we'll only calculate the percentage based on number of
+                // documents under packages.
+                packageStorageInfoMap.put(entry.getKey(),
+                        (long) (entry.getValue() * 1.0 / totalDocuments * totalStorageSize));
+            }
+        }
+        return Collections.unmodifiableMap(packageStorageInfoMap);
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
index 9ffef9c..f5167b7 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
@@ -43,7 +43,7 @@
  */
 class Alarm {
     @VisibleForTesting
-    public static final int NUM_POLICIES = 4;
+    public static final int NUM_POLICIES = 5;
     /**
      * Index used to store the time the alarm was requested to expire. To be used with
      * {@link #setPolicyElapsed(int, long)}.
@@ -67,6 +67,12 @@
     public static final int BATTERY_SAVER_POLICY_INDEX = 3;
 
     /**
+     * Index used to store the earliest time the alarm can expire based on TARE policy.
+     * To be used with {@link #setPolicyElapsed(int, long)}.
+     */
+    public static final int TARE_POLICY_INDEX = 4;
+
+    /**
      * Reason to use for inexact alarms.
      */
     static final int EXACT_ALLOW_REASON_NOT_APPLICABLE = -1;
@@ -254,8 +260,10 @@
                 return "device_idle";
             case BATTERY_SAVER_POLICY_INDEX:
                 return "battery_saver";
+            case TARE_POLICY_INDEX:
+                return "tare";
             default:
-                return "--unknown--";
+                return "--unknown(" + index + ")--";
         }
     }
 
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 9572808..20a93fd 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -45,6 +45,7 @@
 import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_NOT_APPLICABLE;
 import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PERMISSION;
 import static com.android.server.alarm.Alarm.REQUESTER_POLICY_INDEX;
+import static com.android.server.alarm.Alarm.TARE_POLICY_INDEX;
 import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_ALARM_CANCELLED;
 import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_DATA_CLEARED;
 import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_EXACT_PERMISSION_REVOKED;
@@ -56,6 +57,7 @@
 import android.annotation.UserIdInt;
 import android.app.Activity;
 import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
 import android.app.AlarmManager;
 import android.app.AppOpsManager;
 import android.app.BroadcastOptions;
@@ -72,6 +74,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
+import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.Binder;
@@ -111,6 +114,7 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseArrayMap;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.SparseLongArray;
@@ -139,6 +143,8 @@
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.tare.AlarmManagerEconomicPolicy;
+import com.android.server.tare.EconomyManagerInternal;
 import com.android.server.usage.AppStandbyInternal;
 import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
 
@@ -184,6 +190,7 @@
     static final boolean DEBUG_WAKELOCK = localLOGV || false;
     static final boolean DEBUG_BG_LIMIT = localLOGV || false;
     static final boolean DEBUG_STANDBY = localLOGV || false;
+    static final boolean DEBUG_TARE = localLOGV || false;
     static final boolean RECORD_ALARMS_IN_HISTORY = true;
     static final boolean RECORD_DEVICE_IDLE_ALARMS = false;
     static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
@@ -212,6 +219,7 @@
     DeviceIdleInternal mLocalDeviceIdleController;
     private UsageStatsManagerInternal mUsageStatsManagerInternal;
     private ActivityManagerInternal mActivityManagerInternal;
+    private final EconomyManagerInternal mEconomyManagerInternal;
     private PackageManagerInternal mPackageManagerInternal;
     private volatile PermissionManagerServiceInternal mLocalPermissionManager;
 
@@ -229,6 +237,14 @@
     @GuardedBy("mLock")
     SparseIntArray mLastOpScheduleExactAlarm = new SparseIntArray();
 
+    /**
+     * Local cache of the ability of each userId-pkg to afford the various bills we're tracking for
+     * them.
+     */
+    @GuardedBy("mLock")
+    private final SparseArrayMap<String, ArrayMap<EconomyManagerInternal.ActionBill, Boolean>>
+            mAffordabilityCache = new SparseArrayMap<>();
+
     // List of alarms per uid deferred due to user applied background restrictions on the source app
     SparseArray<ArrayList<Alarm>> mPendingBackgroundAlarms = new SparseArray<>();
     private long mNextWakeup;
@@ -297,16 +313,20 @@
     interface Stats {
         int REORDER_ALARMS_FOR_STANDBY = 0;
         int HAS_SCHEDULE_EXACT_ALARM = 1;
+        int REORDER_ALARMS_FOR_TARE = 2;
     }
 
     private final StatLogger mStatLogger = new StatLogger("Alarm manager stats", new String[]{
             "REORDER_ALARMS_FOR_STANDBY",
             "HAS_SCHEDULE_EXACT_ALARM",
+            "REORDER_ALARMS_FOR_TARE",
     });
 
     BroadcastOptions mOptsWithFgs = BroadcastOptions.makeBasic();
     BroadcastOptions mOptsWithoutFgs = BroadcastOptions.makeBasic();
     BroadcastOptions mOptsTimeBroadcast = BroadcastOptions.makeBasic();
+    ActivityOptions mActivityOptsRestrictBal = ActivityOptions.makeBasic();
+    BroadcastOptions mBroadcastOptsRestrictBal = BroadcastOptions.makeBasic();
 
     // TODO(b/172085676): Move inside alarm store.
     private final SparseArray<AlarmManager.AlarmClockInfo> mNextAlarmClockForUser =
@@ -470,7 +490,8 @@
      * holding the AlarmManagerService.mLock lock.
      */
     @VisibleForTesting
-    final class Constants implements DeviceConfig.OnPropertiesChangedListener {
+    final class Constants extends ContentObserver
+            implements DeviceConfig.OnPropertiesChangedListener {
         @VisibleForTesting
         static final int MAX_EXACT_ALARM_DENY_LIST_SIZE = 250;
 
@@ -668,10 +689,13 @@
         public boolean KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED =
                 DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED;
 
+        public boolean USE_TARE_POLICY = Settings.Global.DEFAULT_ENABLE_TARE == 1;
+
         private long mLastAllowWhileIdleWhitelistDuration = -1;
         private int mVersion = 0;
 
-        Constants() {
+        Constants(Handler handler) {
+            super(handler);
             updateAllowWhileIdleWhitelistDurationLocked();
             for (int i = 0; i < APP_STANDBY_QUOTAS.length; i++) {
                 APP_STANDBY_QUOTAS[i] = DEFAULT_APP_STANDBY_QUOTAS[i];
@@ -685,8 +709,11 @@
         }
 
         public void start() {
+            mInjector.registerContentObserver(this,
+                    Settings.Global.getUriFor(Settings.Global.ENABLE_TARE));
             mInjector.registerDeviceConfigListener(this);
             onPropertiesChanged(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_ALARM_MANAGER));
+            updateTareSettings();
         }
 
         public void updateAllowWhileIdleWhitelistDurationLocked() {
@@ -858,6 +885,39 @@
             }
         }
 
+        @Override
+        public void onChange(boolean selfChange) {
+            updateTareSettings();
+        }
+
+        private void updateTareSettings() {
+            synchronized (mLock) {
+                final boolean isTareEnabled = Settings.Global.getInt(
+                        getContext().getContentResolver(),
+                        Settings.Global.ENABLE_TARE, Settings.Global.DEFAULT_ENABLE_TARE) == 1;
+                if (USE_TARE_POLICY != isTareEnabled) {
+                    USE_TARE_POLICY = isTareEnabled;
+                    final boolean changed = mAlarmStore.updateAlarmDeliveries(alarm -> {
+                        final boolean standbyChanged = adjustDeliveryTimeBasedOnBucketLocked(alarm);
+                        final boolean tareChanged = adjustDeliveryTimeBasedOnTareLocked(alarm);
+                        if (USE_TARE_POLICY) {
+                            registerTareListener(alarm);
+                        } else {
+                            mEconomyManagerInternal.unregisterAffordabilityChangeListener(
+                                    UserHandle.getUserId(alarm.uid), alarm.sourcePackage,
+                                    mAffordabilityChangeListener,
+                                    TareBill.getAppropriateBill(alarm));
+                        }
+                        return standbyChanged || tareChanged;
+                    });
+                    if (changed) {
+                        rescheduleKernelAlarmsLocked();
+                        updateNextAlarmClockLocked();
+                    }
+                }
+            }
+        }
+
         private void updateExactAlarmDenyList(String[] newDenyList) {
             final Set<String> newSet = Collections.unmodifiableSet(new ArraySet<>(newDenyList));
             final Set<String> removed = new ArraySet<>(EXACT_ALARM_DENY_LIST);
@@ -1057,6 +1117,9 @@
                     KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED);
             pw.println();
 
+            pw.print(Settings.Global.ENABLE_TARE, USE_TARE_POLICY);
+            pw.println();
+
             pw.decreaseIndent();
         }
 
@@ -1175,6 +1238,7 @@
     AlarmManagerService(Context context, Injector injector) {
         super(context);
         mInjector = injector;
+        mEconomyManagerInternal = LocalServices.getService(EconomyManagerInternal.class);
     }
 
     public AlarmManagerService(Context context) {
@@ -1281,6 +1345,29 @@
         return changed;
     }
 
+    /**
+     * Recalculates alarm send times based on TARE wealth.
+     *
+     * @param targetPackages [Package, User] pairs for which alarms need to be re-evaluated,
+     *                       null indicates all
+     * @return True if there was any reordering done to the current list.
+     */
+    boolean reorderAlarmsBasedOnTare(ArraySet<Pair<String, Integer>> targetPackages) {
+        final long start = mStatLogger.getTime();
+
+        final boolean changed = mAlarmStore.updateAlarmDeliveries(a -> {
+            final Pair<String, Integer> packageUser =
+                    Pair.create(a.sourcePackage, UserHandle.getUserId(a.creatorUid));
+            if (targetPackages != null && !targetPackages.contains(packageUser)) {
+                return false;
+            }
+            return adjustDeliveryTimeBasedOnTareLocked(a);
+        });
+
+        mStatLogger.logDurationStat(Stats.REORDER_ALARMS_FOR_TARE, start);
+        return changed;
+    }
+
     private boolean restoreRequestedTime(Alarm a) {
         return a.setPolicyElapsed(REQUESTER_POLICY_INDEX, convertToElapsed(a.origWhen, a.type));
     }
@@ -1610,6 +1697,11 @@
     @Override
     public void onStart() {
         mInjector.init();
+        mOptsWithFgs.setPendingIntentBackgroundActivityLaunchAllowed(false);
+        mOptsWithoutFgs.setPendingIntentBackgroundActivityLaunchAllowed(false);
+        mOptsTimeBroadcast.setPendingIntentBackgroundActivityLaunchAllowed(false);
+        mActivityOptsRestrictBal.setPendingIntentBackgroundActivityLaunchAllowed(false);
+        mBroadcastOptsRestrictBal.setPendingIntentBackgroundActivityLaunchAllowed(false);
         mMetricsHelper = new MetricsHelper(getContext(), mLock);
 
         mListenerDeathRecipient = new IBinder.DeathRecipient() {
@@ -1626,7 +1718,7 @@
 
         synchronized (mLock) {
             mHandler = new AlarmHandler();
-            mConstants = new Constants();
+            mConstants = new Constants(mHandler);
 
             mAlarmStore = mConstants.LAZY_BATCHING ? new LazyAlarmStore()
                     : new BatchingAlarmStore();
@@ -2249,7 +2341,7 @@
      */
     private boolean adjustDeliveryTimeBasedOnBucketLocked(Alarm alarm) {
         final long nowElapsed = mInjector.getElapsedRealtime();
-        if (isExemptFromAppStandby(alarm) || mAppStandbyParole) {
+        if (mConstants.USE_TARE_POLICY || isExemptFromAppStandby(alarm) || mAppStandbyParole) {
             return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, nowElapsed);
         }
 
@@ -2293,6 +2385,50 @@
         return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, nowElapsed);
     }
 
+    /**
+     * Adjusts the alarm's policy time for TARE.
+     *
+     * @param alarm The alarm to update.
+     * @return {@code true} if the actual delivery time of the given alarm was updated due to
+     * adjustments made in this call.
+     */
+    private boolean adjustDeliveryTimeBasedOnTareLocked(Alarm alarm) {
+        final long nowElapsed = mInjector.getElapsedRealtime();
+        if (!mConstants.USE_TARE_POLICY
+                || isExemptFromTare(alarm) || hasEnoughWealthLocked(alarm)) {
+            return alarm.setPolicyElapsed(TARE_POLICY_INDEX, nowElapsed);
+        }
+
+        // Not enough wealth. Just keep deferring indefinitely till the quota changes.
+        return alarm.setPolicyElapsed(TARE_POLICY_INDEX, nowElapsed + INDEFINITE_DELAY);
+    }
+
+    private void registerTareListener(Alarm alarm) {
+        if (!mConstants.USE_TARE_POLICY) {
+            return;
+        }
+        mEconomyManagerInternal.registerAffordabilityChangeListener(
+                UserHandle.getUserId(alarm.uid), alarm.sourcePackage,
+                mAffordabilityChangeListener, TareBill.getAppropriateBill(alarm));
+    }
+
+    /** Unregister the TARE listener associated with the alarm if it's no longer needed. */
+    private void maybeUnregisterTareListener(Alarm alarm) {
+        if (!mConstants.USE_TARE_POLICY) {
+            return;
+        }
+        final EconomyManagerInternal.ActionBill bill = TareBill.getAppropriateBill(alarm);
+        final Predicate<Alarm> isSameAlarmTypeForSameApp = (a) ->
+                alarm.creatorUid == a.creatorUid
+                        && alarm.sourcePackage.equals(a.sourcePackage)
+                        && bill.equals(TareBill.getAppropriateBill(a));
+        if (mAlarmStore.getCount(isSameAlarmTypeForSameApp) == 0) {
+            mEconomyManagerInternal.unregisterAffordabilityChangeListener(
+                    UserHandle.getUserId(alarm.uid), alarm.sourcePackage,
+                    mAffordabilityChangeListener, bill);
+        }
+    }
+
     private void setImplLocked(Alarm a) {
         if ((a.flags & AlarmManager.FLAG_IDLE_UNTIL) != 0) {
             adjustIdleUntilTime(a);
@@ -2339,6 +2475,8 @@
         }
         adjustDeliveryTimeBasedOnBatterySaver(a);
         adjustDeliveryTimeBasedOnBucketLocked(a);
+        adjustDeliveryTimeBasedOnTareLocked(a);
+        registerTareListener(a);
         mAlarmStore.add(a);
         rescheduleKernelAlarmsLocked();
         updateNextAlarmClockLocked();
@@ -2705,14 +2843,43 @@
             mConstants.dump(pw);
             pw.println();
 
-            if (mAppStateTracker != null) {
-                mAppStateTracker.dump(pw);
+            if (mConstants.USE_TARE_POLICY) {
+                pw.println("TARE details:");
+                pw.increaseIndent();
+
+                pw.println("Affordability cache:");
+                pw.increaseIndent();
+                mAffordabilityCache.forEach((userId, pkgName, billMap) -> {
+                    final int numBills = billMap.size();
+                    if (numBills > 0) {
+                        pw.print(userId);
+                        pw.print(":");
+                        pw.print(pkgName);
+                        pw.println(":");
+
+                        pw.increaseIndent();
+                        for (int i = 0; i < numBills; ++i) {
+                            pw.print(TareBill.getName(billMap.keyAt(i)));
+                            pw.print(": ");
+                            pw.println(billMap.valueAt(i));
+                        }
+                        pw.decreaseIndent();
+                    }
+                });
+                pw.decreaseIndent();
+
+                pw.decreaseIndent();
+                pw.println();
+            } else {
+                if (mAppStateTracker != null) {
+                    mAppStateTracker.dump(pw);
+                    pw.println();
+                }
+
+                pw.println("App Standby Parole: " + mAppStandbyParole);
                 pw.println();
             }
 
-            pw.println("App Standby Parole: " + mAppStandbyParole);
-            pw.println();
-
             final long nowELAPSED = mInjector.getElapsedRealtime();
             final long nowUPTIME = SystemClock.uptimeMillis();
             final long nowRTC = mInjector.getCurrentTimeMillis();
@@ -3667,6 +3834,7 @@
                 mRemovalHistory.put(removed.uid, bufferForUid);
             }
             bufferForUid.append(new RemovedAlarm(removed, reason, nowRtc, nowElapsed));
+            maybeUnregisterTareListener(removed);
         }
 
         if (removedFromStore) {
@@ -4004,6 +4172,11 @@
                             alarm.uid, alarm.statsTag);
                 }
                 mDeliveryTracker.deliverLocked(alarm, nowELAPSED);
+                reportAlarmEventToTare(alarm);
+                if (alarm.repeatInterval <= 0) {
+                    // Don't bother trying to unregister for a repeating alarm.
+                    maybeUnregisterTareListener(alarm);
+                }
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Failure sending alarm.", e);
             }
@@ -4012,6 +4185,48 @@
         }
     }
 
+    private void reportAlarmEventToTare(Alarm alarm) {
+        final boolean allowWhileIdle =
+                (alarm.flags & (FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED | FLAG_ALLOW_WHILE_IDLE)) != 0;
+        final int action;
+        if (alarm.alarmClock != null) {
+            action = AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK;
+        } else if (alarm.wakeup) {
+            if (alarm.windowLength == 0) {
+                if (allowWhileIdle) {
+                    action = AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE;
+                } else {
+                    action = AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT;
+                }
+            } else {
+                if (allowWhileIdle) {
+                    action =
+                            AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE;
+                } else {
+                    action = AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT;
+                }
+            }
+        } else {
+            if (alarm.windowLength == 0) {
+                if (allowWhileIdle) {
+                    action = AlarmManagerEconomicPolicy
+                            .ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE;
+                } else {
+                    action = AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_EXACT;
+                }
+            } else {
+                if (allowWhileIdle) {
+                    action = AlarmManagerEconomicPolicy
+                            .ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE;
+                } else {
+                    action = AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_INEXACT;
+                }
+            }
+        }
+        mEconomyManagerInternal.noteInstantaneousEvent(
+                UserHandle.getUserId(alarm.uid), alarm.sourcePackage, action, null);
+    }
+
     @VisibleForTesting
     static boolean isExemptFromAppStandby(Alarm a) {
         return a.alarmClock != null || UserHandle.isCore(a.creatorUid)
@@ -4019,6 +4234,12 @@
     }
 
     @VisibleForTesting
+    static boolean isExemptFromTare(Alarm a) {
+        return a.alarmClock != null || UserHandle.isCore(a.creatorUid)
+                || (a.flags & (FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED)) != 0;
+    }
+
+    @VisibleForTesting
     static class Injector {
         private long mNativeData;
         private Context mContext;
@@ -4111,6 +4332,10 @@
             return service.new ClockReceiver();
         }
 
+        void registerContentObserver(ContentObserver contentObserver, Uri uri) {
+            mContext.getContentResolver().registerContentObserver(uri, false, contentObserver);
+        }
+
         void registerDeviceConfigListener(DeviceConfig.OnPropertiesChangedListener listener) {
             DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ALARM_MANAGER,
                     JobSchedulerBackgroundThread.getExecutor(), listener);
@@ -4243,13 +4468,23 @@
                                     new ArraySet<>();
                             for (int i = 0; i < triggerList.size(); i++) {
                                 final Alarm a = triggerList.get(i);
-                                if (!isExemptFromAppStandby(a)) {
+                                if (mConstants.USE_TARE_POLICY) {
+                                    if (!isExemptFromTare(a)) {
+                                        triggerPackages.add(Pair.create(
+                                                a.sourcePackage,
+                                                UserHandle.getUserId(a.creatorUid)));
+                                    }
+                                } else if (!isExemptFromAppStandby(a)) {
                                     triggerPackages.add(Pair.create(
                                             a.sourcePackage, UserHandle.getUserId(a.creatorUid)));
                                 }
                             }
                             deliverAlarmsLocked(triggerList, nowELAPSED);
-                            reorderAlarmsBasedOnStandbyBuckets(triggerPackages);
+                            if (mConstants.USE_TARE_POLICY) {
+                                reorderAlarmsBasedOnTare(triggerPackages);
+                            } else {
+                                reorderAlarmsBasedOnStandbyBuckets(triggerPackages);
+                            }
                             rescheduleKernelAlarmsLocked();
                             updateNextAlarmClockLocked();
                             MetricsHelper.pushAlarmBatchDelivered(triggerList.size(), wakeUps);
@@ -4301,6 +4536,43 @@
         return alarm.creatorUid;
     }
 
+    @GuardedBy("mLock")
+    private boolean canAffordBillLocked(@NonNull Alarm alarm,
+            @NonNull EconomyManagerInternal.ActionBill bill) {
+        final int userId = UserHandle.getUserId(alarm.uid);
+        final String pkgName = alarm.sourcePackage;
+        ArrayMap<EconomyManagerInternal.ActionBill, Boolean> actionAffordability =
+                mAffordabilityCache.get(userId, pkgName);
+        if (actionAffordability == null) {
+            actionAffordability = new ArrayMap<>();
+            mAffordabilityCache.add(userId, pkgName, actionAffordability);
+        }
+
+        if (actionAffordability.containsKey(bill)) {
+            return actionAffordability.get(bill);
+        }
+
+        final boolean canAfford = mEconomyManagerInternal.canPayFor(userId, pkgName, bill);
+        actionAffordability.put(bill, canAfford);
+        return canAfford;
+    }
+
+    @GuardedBy("mLock")
+    private boolean hasEnoughWealthLocked(@NonNull Alarm alarm) {
+        return canAffordBillLocked(alarm, TareBill.getAppropriateBill(alarm));
+    }
+
+    private Bundle getAlarmOperationBundle(Alarm alarm) {
+        if (alarm.mIdleOptions != null) {
+            return alarm.mIdleOptions;
+        } else {
+            if (alarm.operation.isActivity()) {
+                return mActivityOptsRestrictBal.toBundle();
+            } else {
+                return mBroadcastOptsRestrictBal.toBundle();
+            }
+        }
+    }
 
     @VisibleForTesting
     class AlarmHandler extends Handler {
@@ -4315,6 +4587,7 @@
         public static final int EXACT_ALARM_DENY_LIST_PACKAGES_ADDED = 9;
         public static final int EXACT_ALARM_DENY_LIST_PACKAGES_REMOVED = 10;
         public static final int REFRESH_EXACT_ALARM_CANDIDATES = 11;
+        public static final int TARE_AFFORDABILITY_CHANGED = 12;
 
         AlarmHandler() {
             super(Looper.myLooper());
@@ -4339,7 +4612,11 @@
                     for (int i = 0; i < triggerList.size(); i++) {
                         Alarm alarm = triggerList.get(i);
                         try {
-                            alarm.operation.send();
+                            // Disallow AlarmManager to start random background activity.
+                            final Bundle bundle = getAlarmOperationBundle(alarm);
+                            alarm.operation.send(/* context */ null, /* code */0, /* intent */
+                                    null, /* onFinished */null, /* handler */
+                                    null, /* requiredPermission */ null, bundle);
                         } catch (PendingIntent.CanceledException e) {
                             if (alarm.repeatInterval > 0) {
                                 // This IntentSender is no longer valid, but this
@@ -4387,6 +4664,20 @@
                     }
                     break;
 
+                case TARE_AFFORDABILITY_CHANGED:
+                    synchronized (mLock) {
+                        final int userId = msg.arg1;
+                        final String packageName = (String) msg.obj;
+
+                        final ArraySet<Pair<String, Integer>> filterPackages = new ArraySet<>();
+                        filterPackages.add(Pair.create(packageName, userId));
+                        if (reorderAlarmsBasedOnTare(filterPackages)) {
+                            rescheduleKernelAlarmsLocked();
+                            updateNextAlarmClockLocked();
+                        }
+                    }
+                    break;
+
                 case REMOVE_FOR_CANCELED:
                     final PendingIntent operation = (PendingIntent) msg.obj;
                     synchronized (mLock) {
@@ -4641,6 +4932,31 @@
         }
     }
 
+    private final EconomyManagerInternal.AffordabilityChangeListener mAffordabilityChangeListener =
+            new EconomyManagerInternal.AffordabilityChangeListener() {
+                @Override
+                public void onAffordabilityChanged(int userId, @NonNull String packageName,
+                        @NonNull EconomyManagerInternal.ActionBill bill, boolean canAfford) {
+                    if (DEBUG_TARE) {
+                        Slog.d(TAG,
+                                userId + ":" + packageName + " affordability for "
+                                        + TareBill.getName(bill) + " changed to " + canAfford);
+                    }
+
+                    ArrayMap<EconomyManagerInternal.ActionBill, Boolean> actionAffordability =
+                            mAffordabilityCache.get(userId, packageName);
+                    if (actionAffordability == null) {
+                        actionAffordability = new ArrayMap<>();
+                        mAffordabilityCache.add(userId, packageName, actionAffordability);
+                    }
+                    actionAffordability.put(bill, canAfford);
+
+                    mHandler.obtainMessage(AlarmHandler.TARE_AFFORDABILITY_CHANGED, userId,
+                            canAfford ? 1 : 0, packageName)
+                            .sendToTarget();
+                }
+            };
+
     private final Listener mForceAppStandbyListener = new Listener() {
 
         @Override
@@ -4901,9 +5217,10 @@
                     mSendCount++;
 
                     try {
+                        final Bundle bundle = getAlarmOperationBundle(alarm);
                         alarm.operation.send(getContext(), 0,
                                 mBackgroundIntent.putExtra(Intent.EXTRA_ALARM_COUNT, alarm.count),
-                                mDeliveryTracker, mHandler, null, alarm.mIdleOptions);
+                                mDeliveryTracker, mHandler, null, bundle);
                     } catch (PendingIntent.CanceledException e) {
                         if (alarm.repeatInterval > 0) {
                             // This IntentSender is no longer valid, but this
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/TareBill.java b/apex/jobscheduler/service/java/com/android/server/alarm/TareBill.java
new file mode 100644
index 0000000..e2f5ee1
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/TareBill.java
@@ -0,0 +1,144 @@
+/*
+ * 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.alarm;
+
+import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE;
+import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
+
+import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK;
+import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_EXACT;
+import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE;
+import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_INEXACT;
+import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE;
+import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT;
+import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE;
+import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT;
+import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE;
+
+import android.annotation.NonNull;
+
+import com.android.server.tare.EconomyManagerInternal;
+import com.android.server.tare.EconomyManagerInternal.ActionBill;
+
+import java.util.List;
+
+/**
+ * Container to maintain alarm TARE {@link ActionBill}s and their related methods.
+ */
+final class TareBill {
+    /**
+     * Bill to use for AlarmClocks.
+     */
+    static final ActionBill ALARM_CLOCK = new ActionBill(List.of(
+            new EconomyManagerInternal.AnticipatedAction(ACTION_ALARM_CLOCK, 1, 0)));
+    /**
+     * Bills to use for various alarm types.
+     */
+    static final ActionBill NONWAKEUP_INEXACT_ALARM = new ActionBill(List.of(
+            new EconomyManagerInternal.AnticipatedAction(ACTION_ALARM_NONWAKEUP_INEXACT, 1, 0)));
+    static final ActionBill NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM = new ActionBill(List.of(
+            new EconomyManagerInternal.AnticipatedAction(
+                    ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE, 1, 0)));
+    static final ActionBill NONWAKEUP_EXACT_ALARM = new ActionBill(List.of(
+            new EconomyManagerInternal.AnticipatedAction(ACTION_ALARM_NONWAKEUP_EXACT, 1, 0)));
+    static final ActionBill NONWAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM = new ActionBill(List.of(
+            new EconomyManagerInternal.AnticipatedAction(
+                    ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE, 1, 0)));
+    static final ActionBill WAKEUP_INEXACT_ALARM = new ActionBill(List.of(
+            new EconomyManagerInternal.AnticipatedAction(ACTION_ALARM_WAKEUP_INEXACT, 1, 0)));
+    static final ActionBill WAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM = new ActionBill(List.of(
+            new EconomyManagerInternal.AnticipatedAction(
+                    ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE, 1, 0)));
+    static final ActionBill WAKEUP_EXACT_ALARM = new ActionBill(List.of(
+            new EconomyManagerInternal.AnticipatedAction(ACTION_ALARM_WAKEUP_EXACT, 1, 0)));
+    static final ActionBill WAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM = new ActionBill(List.of(
+            new EconomyManagerInternal.AnticipatedAction(
+                    ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE, 1, 0)));
+
+    @NonNull
+    static ActionBill getAppropriateBill(@NonNull Alarm alarm) {
+        if (alarm.alarmClock != null) {
+            return ALARM_CLOCK;
+        }
+
+        final boolean allowWhileIdle =
+                (alarm.flags & (FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED | FLAG_ALLOW_WHILE_IDLE)) != 0;
+        final boolean isExact = alarm.windowLength == 0;
+
+        if (alarm.wakeup) {
+            if (isExact) {
+                if (allowWhileIdle) {
+                    return WAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM;
+                }
+                return WAKEUP_EXACT_ALARM;
+            }
+            // Inexact
+            if (allowWhileIdle) {
+                return WAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM;
+            }
+            return WAKEUP_INEXACT_ALARM;
+        }
+
+        // Nonwakeup
+        if (isExact) {
+            if (allowWhileIdle) {
+                return NONWAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM;
+            }
+            return NONWAKEUP_EXACT_ALARM;
+
+        }
+        if (allowWhileIdle) {
+            return NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM;
+        }
+        return NONWAKEUP_INEXACT_ALARM;
+    }
+
+    @NonNull
+    static String getName(@NonNull ActionBill bill) {
+        if (bill.equals(ALARM_CLOCK)) {
+            return "ALARM_CLOCK_BILL";
+        }
+        if (bill.equals(NONWAKEUP_INEXACT_ALARM)) {
+            return "NONWAKEUP_INEXACT_ALARM_BILL";
+        }
+        if (bill.equals(NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM)) {
+            return "NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM_BILL";
+        }
+        if (bill.equals(NONWAKEUP_EXACT_ALARM)) {
+            return "NONWAKEUP_EXACT_ALARM_BILL";
+        }
+        if (bill.equals(NONWAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM)) {
+            return "NONWAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM_BILL";
+        }
+        if (bill.equals(WAKEUP_INEXACT_ALARM)) {
+            return "WAKEUP_INEXACT_ALARM_BILL";
+        }
+        if (bill.equals(WAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM)) {
+            return "WAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM_BILL";
+        }
+        if (bill.equals(WAKEUP_EXACT_ALARM)) {
+            return "WAKEUP_EXACT_ALARM_BILL";
+        }
+        if (bill.equals(WAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM)) {
+            return "WAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM_BILL";
+        }
+        return "UNKNOWN_BILL (" + bill.toString() + ")";
+    }
+
+    private TareBill() {
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 26237c4..9c4cada 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1075,13 +1075,21 @@
     }
 
     @Override
-    public void onUserUnlocked(@NonNull TargetUser user) {
+    public void onUserStarting(@NonNull TargetUser user) {
         synchronized (mLock) {
-            // Note that the user has started after its unlocked instead of when the user
-            // actually starts because the storage won't be decrypted until unlock.
             mStartedUsers = ArrayUtils.appendInt(mStartedUsers, user.getUserIdentifier());
         }
-        // Let's kick any outstanding jobs for this user.
+        // The user is starting but credential encrypted storage is still locked.
+        // Only direct-boot-aware jobs can safely run.
+        // Let's kick off any eligible jobs for this user.
+        mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
+    }
+
+    @Override
+    public void onUserUnlocked(@NonNull TargetUser user) {
+        // The user is fully unlocked and credential encrypted storage is now decrypted.
+        // Direct-boot-UNaware jobs can now safely run.
+        // Let's kick off any outstanding jobs for this user.
         mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
     }
 
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
index 8a1a07c..180424f 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
@@ -89,7 +89,6 @@
     private static final String ALARM_TAG_LEDGER_CLEANUP = "*tare.ledger_cleanup*";
 
     private final Object mLock;
-    private final CompleteEconomicPolicy mCompleteEconomicPolicy;
     private final Handler mHandler;
     private final InternalResourceService mIrs;
 
@@ -184,11 +183,9 @@
     private static final int MSG_CLEAN_LEDGER = 1;
     private static final int MSG_SET_ALARMS = 2;
 
-    Agent(@NonNull InternalResourceService irs,
-            @NonNull CompleteEconomicPolicy completeEconomicPolicy) {
+    Agent(@NonNull InternalResourceService irs) {
         mLock = irs.getLock();
         mIrs = irs;
-        mCompleteEconomicPolicy = completeEconomicPolicy;
         mHandler = new AgentHandler(TareHandlerThread.get().getLooper());
         mAppStandbyInternal = LocalServices.getService(AppStandbyInternal.class);
     }
@@ -260,19 +257,19 @@
 
         final long now = getCurrentTimeMillis();
         final Ledger ledger = getLedgerLocked(userId, pkgName);
+        final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
 
         final int eventType = getEventType(eventId);
         switch (eventType) {
             case TYPE_ACTION:
-                final long actionCost =
-                        mCompleteEconomicPolicy.getCostOfAction(eventId, userId, pkgName);
+                final long actionCost = economicPolicy.getCostOfAction(eventId, userId, pkgName);
 
                 recordTransactionLocked(userId, pkgName, ledger,
                         new Ledger.Transaction(now, now, eventId, tag, -actionCost), true);
                 break;
 
             case TYPE_REWARD:
-                final EconomicPolicy.Reward reward = mCompleteEconomicPolicy.getReward(eventId);
+                final EconomicPolicy.Reward reward = economicPolicy.getReward(eventId);
                 if (reward != null) {
                     final long rewardSum = ledger.get24HourSum(eventId, now);
                     final long rewardVal = Math.max(0,
@@ -311,11 +308,11 @@
         }
         OngoingEvent ongoingEvent = ongoingEvents.get(eventId, tag);
 
+        final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
         final int eventType = getEventType(eventId);
         switch (eventType) {
             case TYPE_ACTION:
-                final long actionCost =
-                        mCompleteEconomicPolicy.getCostOfAction(eventId, userId, pkgName);
+                final long actionCost = economicPolicy.getCostOfAction(eventId, userId, pkgName);
 
                 if (ongoingEvent == null) {
                     ongoingEvents.add(eventId, tag,
@@ -326,7 +323,7 @@
                 break;
 
             case TYPE_REWARD:
-                final EconomicPolicy.Reward reward = mCompleteEconomicPolicy.getReward(eventId);
+                final EconomicPolicy.Reward reward = economicPolicy.getReward(eventId);
                 if (reward != null) {
                     if (ongoingEvent == null) {
                         ongoingEvents.add(eventId, tag, new OngoingEvent(
@@ -348,8 +345,14 @@
 
     @GuardedBy("mLock")
     void onDeviceStateChangedLocked() {
+        onPricingChangedLocked();
+    }
+
+    @GuardedBy("mLock")
+    void onPricingChangedLocked() {
         final long now = getCurrentTimeMillis();
         final long nowElapsed = SystemClock.elapsedRealtime();
+        final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
 
         mCurrentOngoingEvents.forEach((userId, pkgName, ongoingEvents) -> {
             final ArraySet<ActionAffordabilityNote> actionAffordabilityNotes =
@@ -381,7 +384,7 @@
                 final int size = actionAffordabilityNotes.size();
                 for (int i = 0; i < size; ++i) {
                     final ActionAffordabilityNote note = actionAffordabilityNotes.valueAt(i);
-                    note.recalculateModifiedPrice(mCompleteEconomicPolicy, userId, pkgName);
+                    note.recalculateModifiedPrice(economicPolicy, userId, pkgName);
                     final long newBalance = getLedgerLocked(userId, pkgName).getCurrentBalance();
                     final boolean isAffordable = newBalance >= note.getCachedModifiedPrice();
                     if (wasAffordable[i] != isAffordable) {
@@ -398,6 +401,7 @@
     void onAppStatesChangedLocked(final int userId, @NonNull ArraySet<String> pkgNames) {
         final long now = getCurrentTimeMillis();
         final long nowElapsed = SystemClock.elapsedRealtime();
+        final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
 
         for (int i = 0; i < pkgNames.size(); ++i) {
             final String pkgName = pkgNames.valueAt(i);
@@ -433,7 +437,7 @@
                     final int size = actionAffordabilityNotes.size();
                     for (int n = 0; n < size; ++n) {
                         final ActionAffordabilityNote note = actionAffordabilityNotes.valueAt(n);
-                        note.recalculateModifiedPrice(mCompleteEconomicPolicy, userId, pkgName);
+                        note.recalculateModifiedPrice(economicPolicy, userId, pkgName);
                         final long newBalance =
                                 getLedgerLocked(userId, pkgName).getCurrentBalance();
                         final boolean isAffordable = newBalance >= note.getCachedModifiedPrice();
@@ -532,6 +536,7 @@
                     "Tried to adjust system balance for " + appToString(userId, pkgName));
             return;
         }
+        final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
         final long maxCirculationAllowed = mIrs.getMaxCirculationLocked();
         final long newArcsInCirculation = mCurrentNarcsInCirculation + transaction.delta;
         if (transaction.delta > 0 && newArcsInCirculation > maxCirculationAllowed) {
@@ -549,12 +554,11 @@
         }
         final long originalBalance = ledger.getCurrentBalance();
         if (transaction.delta > 0
-                && originalBalance + transaction.delta
-                > mCompleteEconomicPolicy.getMaxSatiatedBalance()) {
+                && originalBalance + transaction.delta > economicPolicy.getMaxSatiatedBalance()) {
             // Set lower bound at 0 so we don't accidentally take away credits when we were trying
             // to _give_ the app credits.
             final long newDelta =
-                    Math.max(0, mCompleteEconomicPolicy.getMaxSatiatedBalance() - originalBalance);
+                    Math.max(0, economicPolicy.getMaxSatiatedBalance() - originalBalance);
             Slog.i(TAG, "Would result in becoming too rich. Decreasing transaction "
                     + eventToString(transaction.eventId)
                     + (transaction.tag == null ? "" : ":" + transaction.tag)
@@ -601,6 +605,7 @@
      */
     @GuardedBy("mLock")
     void reclaimUnusedAssetsLocked(double percentage) {
+        final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
         final List<PackageInfo> pkgs = mIrs.getInstalledPackages();
         final long now = getCurrentTimeMillis();
         for (int i = 0; i < pkgs.size(); ++i) {
@@ -613,8 +618,7 @@
                     mAppStandbyInternal.getTimeSinceLastUsedByUser(pkgName, userId);
             if (timeSinceLastUsedMs >= MIN_UNUSED_TIME_MS) {
                 // Use a constant floor instead of the scaled floor from the IRS.
-                final long minBalance =
-                        mCompleteEconomicPolicy.getMinSatiatedBalance(userId, pkgName);
+                final long minBalance = economicPolicy.getMinSatiatedBalance(userId, pkgName);
                 final long curBalance = ledger.getCurrentBalance();
                 long toReclaim = (long) (curBalance * percentage);
                 if (curBalance - toReclaim < minBalance) {
@@ -1198,8 +1202,9 @@
             actionAffordabilityNotes = new ArraySet<>();
             mActionAffordabilityNotes.add(userId, pkgName, actionAffordabilityNotes);
         }
+        final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
         final ActionAffordabilityNote note =
-                new ActionAffordabilityNote(bill, listener, mCompleteEconomicPolicy);
+                new ActionAffordabilityNote(bill, listener, economicPolicy);
         if (actionAffordabilityNotes.add(note)) {
             if (!mIrs.isEnabled()) {
                 // When TARE isn't enabled, we always say something is affordable. We also don't
@@ -1208,7 +1213,7 @@
                 note.setNewAffordability(true);
                 return;
             }
-            note.recalculateModifiedPrice(mCompleteEconomicPolicy, userId, pkgName);
+            note.recalculateModifiedPrice(economicPolicy, userId, pkgName);
             note.setNewAffordability(
                     getBalanceLocked(userId, pkgName) >= note.getCachedModifiedPrice());
             mIrs.postAffordabilityChanged(userId, pkgName, note);
@@ -1224,8 +1229,9 @@
         final ArraySet<ActionAffordabilityNote> actionAffordabilityNotes =
                 mActionAffordabilityNotes.get(userId, pkgName);
         if (actionAffordabilityNotes != null) {
+            final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
             final ActionAffordabilityNote note =
-                    new ActionAffordabilityNote(bill, listener, mCompleteEconomicPolicy);
+                    new ActionAffordabilityNote(bill, listener, economicPolicy);
             if (actionAffordabilityNotes.remove(note)) {
                 // Update ongoing alarm
                 scheduleBalanceCheckLocked(userId, pkgName);
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
index fc057f7..1acb270 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
@@ -98,12 +98,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ContentResolver;
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.os.UserHandle;
 import android.provider.Settings;
-import android.util.KeyValueListParser;
 import android.util.IndentingPrintWriter;
+import android.util.KeyValueListParser;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -145,7 +142,6 @@
     private long mMaxSatiatedCirculation;
 
     private final KeyValueListParser mParser = new KeyValueListParser(',');
-    private final SettingsObserver mSettingsObserver;
     private final InternalResourceService mInternalResourceService;
 
     private final SparseArray<Action> mActions = new SparseArray<>();
@@ -154,7 +150,6 @@
     AlarmManagerEconomicPolicy(InternalResourceService irs) {
         super(irs);
         mInternalResourceService = irs;
-        mSettingsObserver = new SettingsObserver(TareHandlerThread.getHandler());
         loadConstants("");
     }
 
@@ -162,12 +157,7 @@
     void setup() {
         super.setup();
         ContentResolver resolver = mInternalResourceService.getContext().getContentResolver();
-        resolver.registerContentObserver(
-                Settings.Global.getUriFor(TARE_ALARM_MANAGER_CONSTANTS),
-                false, mSettingsObserver, UserHandle.USER_ALL);
-        loadConstants(Settings.Global.getString(
-                mInternalResourceService.getContext().getContentResolver(),
-                TARE_ALARM_MANAGER_CONSTANTS));
+        loadConstants(Settings.Global.getString(resolver, TARE_ALARM_MANAGER_CONSTANTS));
     }
 
     @Override
@@ -215,7 +205,7 @@
         }
 
         mMinSatiatedBalance = arcToNarc(mParser.getInt(KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP,
-                        DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP));
+                DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP));
         mMaxSatiatedBalance = arcToNarc(mParser.getInt(KEY_AM_MAX_SATIATED_BALANCE,
                 DEFAULT_AM_MAX_SATIATED_BALANCE));
         mMaxSatiatedCirculation = arcToNarc(mParser.getInt(KEY_AM_MAX_CIRCULATION,
@@ -312,7 +302,7 @@
                 (long) (arcToNarc(1) * mParser.getFloat(KEY_AM_REWARD_TOP_ACTIVITY_ONGOING,
                         DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING)),
                 arcToNarc(mParser.getInt(KEY_AM_REWARD_TOP_ACTIVITY_MAX,
-                                DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX))));
+                        DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX))));
         mRewards.put(REWARD_NOTIFICATION_SEEN, new Reward(REWARD_NOTIFICATION_SEEN,
                 arcToNarc(mParser.getInt(KEY_AM_REWARD_NOTIFICATION_SEEN_INSTANT,
                         DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT)),
@@ -350,19 +340,6 @@
                                 DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX))));
     }
 
-    private final class SettingsObserver extends ContentObserver {
-        SettingsObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            loadConstants(Settings.Global.getString(
-                    mInternalResourceService.getContext().getContentResolver(),
-                    TARE_ALARM_MANAGER_CONSTANTS));
-        }
-    }
-
     @Override
     void dump(IndentingPrintWriter pw) {
         pw.println("Actions:");
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
index dbc7bd6..7bf0e6d 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
@@ -75,7 +75,7 @@
     }
 
     @Override
-    public long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
+    long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
         long min = 0;
         for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
             min += mEnabledEconomicPolicies.valueAt(i).getMinSatiatedBalance(userId, pkgName);
@@ -84,24 +84,24 @@
     }
 
     @Override
-    public long getMaxSatiatedBalance() {
+    long getMaxSatiatedBalance() {
         return mMaxSatiatedBalance;
     }
 
     @Override
-    public long getMaxSatiatedCirculation() {
+     long getMaxSatiatedCirculation() {
         return mMaxSatiatedCirculation;
     }
 
     @NonNull
     @Override
-    public int[] getCostModifiers() {
+    int[] getCostModifiers() {
         return mCostModifiers == null ? EmptyArray.INT : mCostModifiers;
     }
 
     @Nullable
     @Override
-    public Action getAction(@AppAction int actionId) {
+    Action getAction(@AppAction int actionId) {
         if (mActions.contains(actionId)) {
             return mActions.get(actionId);
         }
@@ -123,7 +123,7 @@
 
     @Nullable
     @Override
-    public Reward getReward(@UtilityReward int rewardId) {
+    Reward getReward(@UtilityReward int rewardId) {
         if (mRewards.contains(rewardId)) {
             return mRewards.get(rewardId);
         }
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
index 40ab49c..b3b6f6f 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.tare;
 
+import static android.provider.Settings.Global.TARE_ALARM_MANAGER_CONSTANTS;
+import static android.provider.Settings.Global.TARE_JOB_SCHEDULER_CONSTANTS;
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 
@@ -83,6 +85,8 @@
     static final long UNUSED_RECLAMATION_PERIOD_MS = 24 * HOUR_IN_MILLIS;
     /** How much of an app's unused wealth should be reclaimed periodically. */
     private static final float DEFAULT_UNUSED_RECLAMATION_PERCENTAGE = .1f;
+    /** The amount of time to delay reclamation by after boot. */
+    private static final long RECLAMATION_STARTUP_DELAY_MS = 30_000L;
     private static final int PACKAGE_QUERY_FLAGS =
             PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                     | PackageManager.MATCH_APEX;
@@ -96,9 +100,12 @@
     private final PackageManagerInternal mPackageManagerInternal;
 
     private final Agent mAgent;
-    private final CompleteEconomicPolicy mCompleteEconomicPolicy;
     private final ConfigObserver mConfigObserver;
     private final EconomyManagerStub mEconomyManagerStub;
+    private final Scribe mScribe;
+
+    @GuardedBy("mLock")
+    private CompleteEconomicPolicy mCompleteEconomicPolicy;
 
     @NonNull
     @GuardedBy("mLock")
@@ -117,9 +124,6 @@
     // In the range [0,100] to represent 0% to 100% battery.
     @GuardedBy("mLock")
     private int mCurrentBatteryLevel;
-    // TODO: load from disk
-    @GuardedBy("mLock")
-    private long mLastUnusedReclamationTime;
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Nullable
@@ -187,7 +191,7 @@
                 public void onAlarm() {
                     synchronized (mLock) {
                         mAgent.reclaimUnusedAssetsLocked(DEFAULT_UNUSED_RECLAMATION_PERCENTAGE);
-                        mLastUnusedReclamationTime = getCurrentTimeMillis();
+                        mScribe.setLastReclamationTimeLocked(getCurrentTimeMillis());
                         scheduleUnusedWealthReclamationLocked();
                     }
                 }
@@ -216,8 +220,9 @@
         mPackageManager = context.getPackageManager();
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
         mEconomyManagerStub = new EconomyManagerStub();
+        mScribe = new Scribe(this);
         mCompleteEconomicPolicy = new CompleteEconomicPolicy(this);
-        mAgent = new Agent(this, mCompleteEconomicPolicy);
+        mAgent = new Agent(this);
 
         mConfigObserver = new ConfigObserver(mHandler, context);
 
@@ -246,6 +251,12 @@
 
     /** Returns the installed packages for all users. */
     @NonNull
+    @GuardedBy("mLock")
+    CompleteEconomicPolicy getCompleteEconomicPolicyLocked() {
+        return mCompleteEconomicPolicy;
+    }
+
+    @NonNull
     List<PackageInfo> getInstalledPackages() {
         synchronized (mLock) {
             return mPkgCache;
@@ -451,8 +462,8 @@
     @GuardedBy("mLock")
     private void scheduleUnusedWealthReclamationLocked() {
         final long now = getCurrentTimeMillis();
-        final long nextReclamationTime =
-                Math.max(mLastUnusedReclamationTime + UNUSED_RECLAMATION_PERIOD_MS, now + 30_000);
+        final long nextReclamationTime = Math.max(now + RECLAMATION_STARTUP_DELAY_MS,
+                mScribe.getLastReclamationTimeLocked() + UNUSED_RECLAMATION_PERIOD_MS);
         mHandler.post(() -> {
             // Never call out to AlarmManager with the lock held. This sits below AM.
             AlarmManager alarmManager = getContext().getSystemService(AlarmManager.class);
@@ -463,7 +474,7 @@
                         ALARM_TAG_WEALTH_RECLAMATION, mUnusedWealthReclamationListener, mHandler);
             } else {
                 mHandler.sendEmptyMessageDelayed(
-                        MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT, 30_000);
+                        MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT, RECLAMATION_STARTUP_DELAY_MS);
             }
         });
     }
@@ -531,6 +542,7 @@
             if (isFirstSetup) {
                 mAgent.grantBirthrightsLocked();
             }
+            scheduleUnusedWealthReclamationLocked();
         }
     }
 
@@ -542,7 +554,6 @@
             registerListeners();
             mCurrentBatteryLevel = getCurrentBatteryLevel();
             mHandler.post(this::setupHeavyWork);
-            scheduleUnusedWealthReclamationLocked();
             mCompleteEconomicPolicy.setup();
         }
     }
@@ -562,6 +573,7 @@
                 }
             });
             mPkgCache.clear();
+            mScribe.tearDownLocked();
             mUidToPackageCache.clear();
             getContext().unregisterReceiver(mBroadcastReceiver);
             UsageStatsManagerInternal usmi =
@@ -698,14 +710,14 @@
             long requiredBalance = 0;
             final List<EconomyManagerInternal.AnticipatedAction> projectedActions =
                     bill.getAnticipatedActions();
-            for (int i = 0; i < projectedActions.size(); ++i) {
-                AnticipatedAction action = projectedActions.get(i);
-                final long cost =
-                        mCompleteEconomicPolicy.getCostOfAction(action.actionId, userId, pkgName);
-                requiredBalance += cost * action.numInstantaneousCalls
-                        + cost * (action.ongoingDurationMs / 1000);
-            }
             synchronized (mLock) {
+                for (int i = 0; i < projectedActions.size(); ++i) {
+                    AnticipatedAction action = projectedActions.get(i);
+                    final long cost = mCompleteEconomicPolicy.getCostOfAction(
+                            action.actionId, userId, pkgName);
+                    requiredBalance += cost * action.numInstantaneousCalls
+                            + cost * (action.ongoingDurationMs / 1000);
+                }
                 return mAgent.getBalanceLocked(userId, pkgName) >= requiredBalance;
             }
         }
@@ -722,16 +734,16 @@
             long totalCostPerSecond = 0;
             final List<EconomyManagerInternal.AnticipatedAction> projectedActions =
                     bill.getAnticipatedActions();
-            for (int i = 0; i < projectedActions.size(); ++i) {
-                AnticipatedAction action = projectedActions.get(i);
-                final long cost =
-                        mCompleteEconomicPolicy.getCostOfAction(action.actionId, userId, pkgName);
-                totalCostPerSecond += cost;
-            }
-            if (totalCostPerSecond == 0) {
-                return FOREVER_MS;
-            }
             synchronized (mLock) {
+                for (int i = 0; i < projectedActions.size(); ++i) {
+                    AnticipatedAction action = projectedActions.get(i);
+                    final long cost = mCompleteEconomicPolicy.getCostOfAction(
+                            action.actionId, userId, pkgName);
+                    totalCostPerSecond += cost;
+                }
+                if (totalCostPerSecond == 0) {
+                    return FOREVER_MS;
+                }
                 return mAgent.getBalanceLocked(userId, pkgName) * 1000 / totalCostPerSecond;
             }
         }
@@ -784,15 +796,24 @@
         public void start() {
             mContentResolver.registerContentObserver(
                     Settings.Global.getUriFor(Settings.Global.ENABLE_TARE), false, this);
-            updateConfig();
+            mContentResolver.registerContentObserver(
+                    Settings.Global.getUriFor(TARE_ALARM_MANAGER_CONSTANTS), false, this);
+            mContentResolver.registerContentObserver(
+                    Settings.Global.getUriFor(TARE_JOB_SCHEDULER_CONSTANTS), false, this);
+            updateEnabledStatus();
         }
 
         @Override
-        public void onChange(boolean selfChange) {
-            updateConfig();
+        public void onChange(boolean selfChange, Uri uri) {
+            if (uri.equals(Settings.Global.getUriFor(Settings.Global.ENABLE_TARE))) {
+                updateEnabledStatus();
+            } else if (uri.equals(Settings.Global.getUriFor(TARE_ALARM_MANAGER_CONSTANTS))
+                    || uri.equals(Settings.Global.getUriFor(TARE_JOB_SCHEDULER_CONSTANTS))) {
+                updateEconomicPolicy();
+            }
         }
 
-        private void updateConfig() {
+        private void updateEnabledStatus() {
             final boolean isTareEnabled = Settings.Global.getInt(mContentResolver,
                     Settings.Global.ENABLE_TARE, Settings.Global.DEFAULT_ENABLE_TARE) == 1;
             if (mIsEnabled != isTareEnabled) {
@@ -804,6 +825,17 @@
                 }
             }
         }
+
+        private void updateEconomicPolicy() {
+            synchronized (mLock) {
+                mCompleteEconomicPolicy.tearDown();
+                mCompleteEconomicPolicy = new CompleteEconomicPolicy(InternalResourceService.this);
+                if (mIsEnabled && mBootPhase >= PHASE_SYSTEM_SERVICES_READY) {
+                    mCompleteEconomicPolicy.setup();
+                    mAgent.onPricingChangedLocked();
+                }
+            }
+        }
     }
 
     private static void dumpHelp(PrintWriter pw) {
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
index c332f2f..fa732ea 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
@@ -107,12 +107,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ContentResolver;
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.os.UserHandle;
 import android.provider.Settings;
-import android.util.KeyValueListParser;
 import android.util.IndentingPrintWriter;
+import android.util.KeyValueListParser;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -147,7 +144,6 @@
     private long mMaxSatiatedCirculation;
 
     private final KeyValueListParser mParser = new KeyValueListParser(',');
-    private final SettingsObserver mSettingsObserver;
     private final InternalResourceService mInternalResourceService;
 
     private final SparseArray<Action> mActions = new SparseArray<>();
@@ -156,7 +152,6 @@
     JobSchedulerEconomicPolicy(InternalResourceService irs) {
         super(irs);
         mInternalResourceService = irs;
-        mSettingsObserver = new SettingsObserver(TareHandlerThread.getHandler());
         loadConstants("");
     }
 
@@ -164,12 +159,7 @@
     void setup() {
         super.setup();
         ContentResolver resolver = mInternalResourceService.getContext().getContentResolver();
-        resolver.registerContentObserver(
-                Settings.Global.getUriFor(TARE_JOB_SCHEDULER_CONSTANTS),
-                false, mSettingsObserver, UserHandle.USER_ALL);
-        loadConstants(Settings.Global.getString(
-                mInternalResourceService.getContext().getContentResolver(),
-                TARE_JOB_SCHEDULER_CONSTANTS));
+        loadConstants(Settings.Global.getString(resolver, TARE_JOB_SCHEDULER_CONSTANTS));
     }
 
     @Override
@@ -324,19 +314,6 @@
                                 DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX))));
     }
 
-    private final class SettingsObserver extends ContentObserver {
-        SettingsObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            loadConstants(Settings.Global.getString(
-                    mInternalResourceService.getContext().getContentResolver(),
-                    TARE_JOB_SCHEDULER_CONSTANTS));
-        }
-    }
-
     @Override
     void dump(IndentingPrintWriter pw) {
         pw.println("Actions:");
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
new file mode 100644
index 0000000..a2c1e9a
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
@@ -0,0 +1,54 @@
+/*
+ * 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.tare;
+
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * Maintains the current TARE state and handles writing it to disk and reading it back from disk.
+ */
+public class Scribe {
+    private static final String TAG = "TARE-" + Scribe.class.getSimpleName();
+    private static final boolean DEBUG = InternalResourceService.DEBUG
+            || Log.isLoggable(TAG, Log.DEBUG);
+
+    private final InternalResourceService mIrs;
+
+    @GuardedBy("mIrs.mLock")
+    private long mLastReclamationTime;
+
+    Scribe(InternalResourceService irs) {
+        mIrs = irs;
+    }
+
+    @GuardedBy("mIrs.mLock")
+    long getLastReclamationTimeLocked() {
+        return mLastReclamationTime;
+    }
+
+    @GuardedBy("InternalResourceService.mLock")
+    void setLastReclamationTimeLocked(long time) {
+        mLastReclamationTime = time;
+    }
+
+    @GuardedBy("mIrs.mLock")
+    void tearDownLocked() {
+        mLastReclamationTime = 0;
+    }
+}
diff --git a/api/Android.bp b/api/Android.bp
index 66b6dba..dbb81a6 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -24,9 +24,8 @@
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
-python_binary_host {
-    name: "api_versions_trimmer",
-    srcs: ["api_versions_trimmer.py"],
+python_defaults {
+    name: "python3_version_defaults",
     version: {
         py2: {
             enabled: false,
@@ -38,6 +37,12 @@
     },
 }
 
+python_binary_host {
+    name: "api_versions_trimmer",
+    srcs: ["api_versions_trimmer.py"],
+    defaults: ["python3_version_defaults"],
+}
+
 python_test_host {
     name: "api_versions_trimmer_unittests",
     main: "api_versions_trimmer_unittests.py",
@@ -45,24 +50,35 @@
         "api_versions_trimmer_unittests.py",
         "api_versions_trimmer.py",
     ],
+    defaults: ["python3_version_defaults"],
     test_options: {
         unit_test: true,
     },
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-            embedded_launcher: false,
-        },
+}
+
+python_binary_host {
+    name: "merge_annotation_zips",
+    srcs: ["merge_annotation_zips.py"],
+    defaults: ["python3_version_defaults"],
+}
+
+python_test_host {
+    name: "merge_annotation_zips_test",
+    main: "merge_annotation_zips_test.py",
+    srcs: [
+        "merge_annotation_zips.py",
+        "merge_annotation_zips_test.py",
+    ],
+    defaults: ["python3_version_defaults"],
+    test_options: {
+        unit_test: true,
     },
 }
 
 metalava_cmd = "$(location metalava)"
 // Silence reflection warnings. See b/168689341
 metalava_cmd += " -J--add-opens=java.base/java.util=ALL-UNNAMED "
-metalava_cmd += " --no-banner --format=v2 "
+metalava_cmd += " --quiet --no-banner --format=v2 "
 
 genrule {
     name: "current-api-xml",
@@ -123,13 +139,13 @@
         ":android-incompatibilities.api.public.latest",
         ":frameworks-base-api-current.txt",
     ],
-    out: ["stdout.txt"],
+    out: ["updated-baseline.txt"],
     tools: ["metalava"],
     cmd: metalava_cmd +
         "--check-compatibility:api:released $(location :android.api.public.latest) " +
         "--baseline:compatibility:released $(location :android-incompatibilities.api.public.latest) " +
-        "$(location :frameworks-base-api-current.txt) " +
-        "> $(genDir)/stdout.txt",
+        "--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " +
+        "$(location :frameworks-base-api-current.txt)",
 }
 
 genrule {
@@ -251,14 +267,14 @@
         ":frameworks-base-api-current.txt",
         ":frameworks-base-api-system-current.txt",
     ],
-    out: ["stdout.txt"],
+    out: ["updated-baseline.txt"],
     tools: ["metalava"],
     cmd: metalava_cmd +
         "--check-compatibility:api:released $(location :android.api.system.latest) " +
         "--check-compatibility:base $(location :frameworks-base-api-current.txt) " +
         "--baseline:compatibility:released $(location :android-incompatibilities.api.system.latest) " +
-        "$(location :frameworks-base-api-system-current.txt) " +
-        "> $(genDir)/stdout.txt",
+        "--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " +
+        "$(location :frameworks-base-api-system-current.txt)",
 }
 
 genrule {
@@ -350,7 +366,7 @@
         ":frameworks-base-api-current.txt",
         ":frameworks-base-api-module-lib-current.txt",
     ],
-    out: ["stdout.txt"],
+    out: ["updated-baseline.txt"],
     tools: ["metalava"],
     cmd: metalava_cmd +
         "--check-compatibility:api:released $(location :android.api.module-lib.latest) " +
@@ -359,8 +375,8 @@
         // MODULE_LIBS -> public.
         "--check-compatibility:base $(location :frameworks-base-api-current.txt) " +
         "--baseline:compatibility:released $(location :android-incompatibilities.api.module-lib.latest) " +
-        "$(location :frameworks-base-api-module-lib-current.txt) " +
-        "> $(genDir)/stdout.txt",
+        "--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " +
+        "$(location :frameworks-base-api-module-lib-current.txt)",
 }
 
 genrule {
diff --git a/api/api_versions_trimmer_unittests.py b/api/api_versions_trimmer_unittests.py
index 4eb929e..d2e5b7d 100644
--- a/api/api_versions_trimmer_unittests.py
+++ b/api/api_versions_trimmer_unittests.py
@@ -304,4 +304,4 @@
 
 
 if __name__ == "__main__":
-  unittest.main()
+  unittest.main(verbosity=2)
diff --git a/api/merge_annotation_zips.py b/api/merge_annotation_zips.py
new file mode 100755
index 0000000..9c67d7b
--- /dev/null
+++ b/api/merge_annotation_zips.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python3
+#
+# 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.
+
+"""Script to merge annotation XML files (created by e.g. metalava)."""
+
+from pathlib import Path
+import sys
+import xml.etree.ElementTree as ET
+import zipfile
+
+
+def validate_xml_assumptions(root):
+  """Verify the format of the annotations XML matches expectations"""
+  prevName = ""
+  assert root.tag == 'root'
+  for child in root:
+    assert child.tag == 'item', 'unexpected tag: %s' % child.tag
+    assert list(child.attrib.keys()) == ['name'], 'unexpected attribs: %s' % child.attrib.keys()
+    assert prevName < child.get('name'), 'items unexpectedly not strictly sorted (possibly duplicate entries)'
+    prevName = child.get('name')
+
+
+def merge_xml(a, b):
+  """Merge two annotation xml files"""
+  for xml in [a, b]:
+    validate_xml_assumptions(xml)
+  a.extend(b[:])
+  a[:] = sorted(a[:], key=lambda x: x.get('name'))
+  validate_xml_assumptions(a)
+
+
+def merge_zip_file(out_dir, zip_file):
+  """Merge the content of the zip_file into out_dir"""
+  for filename in zip_file.namelist():
+    path = Path(out_dir, filename)
+    if path.exists():
+      existing_xml = ET.parse(path)
+      with zip_file.open(filename) as other_file:
+        other_xml = ET.parse(other_file)
+      merge_xml(existing_xml.getroot(), other_xml.getroot())
+      existing_xml.write(path, encoding='UTF-8', xml_declaration=True)
+    else:
+      zip_file.extract(filename, out_dir)
+
+
+def main():
+  out_dir = Path(sys.argv[1])
+  zip_filenames = sys.argv[2:]
+
+  assert not out_dir.exists()
+  out_dir.mkdir()
+  for zip_filename in zip_filenames:
+    with zipfile.ZipFile(zip_filename) as zip_file:
+      merge_zip_file(out_dir, zip_file)
+
+
+if __name__ == "__main__":
+  main()
diff --git a/api/merge_annotation_zips_test.py b/api/merge_annotation_zips_test.py
new file mode 100644
index 0000000..26795c47
--- /dev/null
+++ b/api/merge_annotation_zips_test.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python3
+#
+# 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.
+
+import io
+from pathlib import Path
+import tempfile
+import unittest
+import zipfile
+
+import merge_annotation_zips
+
+
+zip_a = {
+  'android/provider/annotations.xml':
+  """<?xml version="1.0" encoding="UTF-8"?>
+<root>
+  <item name="android.provider.BlockedNumberContract boolean isBlocked(android.content.Context, java.lang.String)">
+    <annotation name="androidx.annotation.WorkerThread"/>
+  </item>
+  <item name="android.provider.SimPhonebookContract.SimRecords android.net.Uri getItemUri(int, int, int) 2">
+    <annotation name="androidx.annotation.IntRange">
+      <val name="from" val="1" />
+    </annotation>
+  </item>
+</root>""",
+  'android/os/annotations.xml':
+  """<?xml version="1.0" encoding="UTF-8"?>
+<root>
+  <item name="android.app.ActionBar void setCustomView(int) 0">
+    <annotation name="androidx.annotation.LayoutRes"/>
+  </item>
+</root>
+"""
+}
+
+zip_b = {
+  'android/provider/annotations.xml':
+  """<?xml version="1.0" encoding="UTF-8"?>
+<root>
+  <item name="android.provider.MediaStore QUERY_ARG_MATCH_FAVORITE">
+    <annotation name="androidx.annotation.IntDef">
+      <val name="value" val="{android.provider.MediaStore.MATCH_DEFAULT, android.provider.MediaStore.MATCH_INCLUDE, android.provider.MediaStore.MATCH_EXCLUDE, android.provider.MediaStore.MATCH_ONLY}" />
+      <val name="flag" val="true" />
+    </annotation>
+  </item>
+  <item name="android.provider.MediaStore QUERY_ARG_MATCH_PENDING">
+    <annotation name="androidx.annotation.IntDef">
+      <val name="value" val="{android.provider.MediaStore.MATCH_DEFAULT, android.provider.MediaStore.MATCH_INCLUDE, android.provider.MediaStore.MATCH_EXCLUDE, android.provider.MediaStore.MATCH_ONLY}" />
+      <val name="flag" val="true" />
+    </annotation>
+  </item>
+</root>"""
+}
+
+zip_c = {
+  'android/app/annotations.xml':
+  """<?xml version="1.0" encoding="UTF-8"?>
+<root>
+  <item name="android.app.ActionBar void setCustomView(int) 0">
+    <annotation name="androidx.annotation.LayoutRes"/>
+  </item>
+</root>"""
+}
+
+merged_provider = """<?xml version='1.0' encoding='UTF-8'?>
+<root>
+  <item name="android.provider.BlockedNumberContract boolean isBlocked(android.content.Context, java.lang.String)">
+    <annotation name="androidx.annotation.WorkerThread" />
+  </item>
+  <item name="android.provider.MediaStore QUERY_ARG_MATCH_FAVORITE">
+    <annotation name="androidx.annotation.IntDef">
+      <val name="value" val="{android.provider.MediaStore.MATCH_DEFAULT, android.provider.MediaStore.MATCH_INCLUDE, android.provider.MediaStore.MATCH_EXCLUDE, android.provider.MediaStore.MATCH_ONLY}" />
+      <val name="flag" val="true" />
+    </annotation>
+  </item>
+  <item name="android.provider.MediaStore QUERY_ARG_MATCH_PENDING">
+    <annotation name="androidx.annotation.IntDef">
+      <val name="value" val="{android.provider.MediaStore.MATCH_DEFAULT, android.provider.MediaStore.MATCH_INCLUDE, android.provider.MediaStore.MATCH_EXCLUDE, android.provider.MediaStore.MATCH_ONLY}" />
+      <val name="flag" val="true" />
+    </annotation>
+  </item>
+<item name="android.provider.SimPhonebookContract.SimRecords android.net.Uri getItemUri(int, int, int) 2">
+    <annotation name="androidx.annotation.IntRange">
+      <val name="from" val="1" />
+    </annotation>
+  </item>
+</root>"""
+
+
+
+class MergeAnnotationZipsTest(unittest.TestCase):
+
+  def test_merge_zips(self):
+    with tempfile.TemporaryDirectory() as out_dir:
+      for zip_content in [zip_a, zip_b, zip_c]:
+        f = io.BytesIO()
+        with zipfile.ZipFile(f, "w") as zip_file:
+          for filename, content in zip_content.items():
+            zip_file.writestr(filename, content)
+          merge_annotation_zips.merge_zip_file(out_dir, zip_file)
+
+      # Unchanged
+      self.assertEqual(zip_a['android/os/annotations.xml'], Path(out_dir, 'android/os/annotations.xml').read_text())
+      self.assertEqual(zip_c['android/app/annotations.xml'], Path(out_dir, 'android/app/annotations.xml').read_text())
+
+      # Merged
+      self.assertEqual(merged_provider, Path(out_dir, 'android/provider/annotations.xml').read_text())
+
+
+if __name__ == "__main__":
+  unittest.main(verbosity=2)
diff --git a/core/api/current.txt b/core/api/current.txt
index 5178f3d83..7a7d191 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -79,6 +79,7 @@
     field public static final String CONTROL_LOCATION_UPDATES = "android.permission.CONTROL_LOCATION_UPDATES";
     field public static final String DELETE_CACHE_FILES = "android.permission.DELETE_CACHE_FILES";
     field public static final String DELETE_PACKAGES = "android.permission.DELETE_PACKAGES";
+    field public static final String DELIVER_COMPANION_MESSAGES = "android.permission.DELIVER_COMPANION_MESSAGES";
     field public static final String DIAGNOSTIC = "android.permission.DIAGNOSTIC";
     field public static final String DISABLE_KEYGUARD = "android.permission.DISABLE_KEYGUARD";
     field public static final String DUMP = "android.permission.DUMP";
@@ -842,7 +843,7 @@
     field @Deprecated public static final int isModifier = 16843334; // 0x1010246
     field @Deprecated public static final int isRepeatable = 16843336; // 0x1010248
     field public static final int isScrollContainer = 16843342; // 0x101024e
-    field public static final int isSplitRequired = 16844177; // 0x1010591
+    field @Deprecated public static final int isSplitRequired = 16844177; // 0x1010591
     field public static final int isStatic = 16844122; // 0x101055a
     field @Deprecated public static final int isSticky = 16843335; // 0x1010247
     field public static final int isolatedProcess = 16843689; // 0x10103a9
@@ -1300,7 +1301,7 @@
     field public static final int shortcutLongLabel = 16844074; // 0x101052a
     field public static final int shortcutShortLabel = 16844073; // 0x1010529
     field public static final int shouldDisableView = 16843246; // 0x10101ee
-    field public static final int shouldUseDefaultUnfoldTransition;
+    field public static final int shouldUseDefaultDeviceStateChangeTransition;
     field public static final int showAsAction = 16843481; // 0x10102d9
     field public static final int showDefault = 16843258; // 0x10101fa
     field public static final int showDividers = 16843561; // 0x1010329
@@ -6940,7 +6941,7 @@
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
     method public CharSequence loadLabel(android.content.pm.PackageManager);
     method public android.graphics.drawable.Drawable loadThumbnail(android.content.pm.PackageManager);
-    method public boolean shouldUseDefaultUnfoldTransition();
+    method public boolean shouldUseDefaultDeviceStateChangeTransition();
     method public boolean supportsMultipleDisplays();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.WallpaperInfo> CREATOR;
@@ -9894,9 +9895,11 @@
 
   public abstract class CompanionDeviceService extends android.app.Service {
     ctor public CompanionDeviceService();
+    method @RequiresPermission(android.Manifest.permission.DELIVER_COMPANION_MESSAGES) public final void dispatchMessage(int, int, @NonNull byte[]);
     method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
     method @MainThread public abstract void onDeviceAppeared(@NonNull String);
     method @MainThread public abstract void onDeviceDisappeared(@NonNull String);
+    method @MainThread public void onDispatchMessage(int, int, @NonNull byte[]);
     field public static final String SERVICE_INTERFACE = "android.companion.CompanionDeviceService";
   }
 
@@ -12548,6 +12551,7 @@
     method public abstract boolean addPermissionAsync(@NonNull android.content.pm.PermissionInfo);
     method @Deprecated public abstract void addPreferredActivity(@NonNull android.content.IntentFilter, int, @Nullable android.content.ComponentName[], @NonNull android.content.ComponentName);
     method @RequiresPermission(value="android.permission.WHITELIST_RESTRICTED_PERMISSIONS", conditional=true) public boolean addWhitelistedRestrictedPermission(@NonNull String, @NonNull String, int);
+    method public boolean canPackageQuery(@NonNull String, @NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract boolean canRequestPackageInstalls();
     method public abstract String[] canonicalToCurrentPackageNames(@NonNull String[]);
     method @CheckResult public abstract int checkPermission(@NonNull String, @NonNull String);
@@ -12643,7 +12647,6 @@
     method public boolean isPackageSuspended();
     method @CheckResult public abstract boolean isPermissionRevokedByPolicy(@NonNull String, @NonNull String);
     method public abstract boolean isSafeMode();
-    method public boolean mayPackageQuery(@NonNull String, @NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
     method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryActivityProperty(@NonNull String);
     method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryApplicationProperty(@NonNull String);
     method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(@NonNull android.content.Intent, int);
@@ -19634,14 +19637,22 @@
   }
 
   public final class Geocoder {
-    ctor public Geocoder(android.content.Context, java.util.Locale);
-    ctor public Geocoder(android.content.Context);
-    method public java.util.List<android.location.Address> getFromLocation(double, double, int) throws java.io.IOException;
-    method public java.util.List<android.location.Address> getFromLocationName(String, int) throws java.io.IOException;
-    method public java.util.List<android.location.Address> getFromLocationName(String, int, double, double, double, double) throws java.io.IOException;
+    ctor public Geocoder(@NonNull android.content.Context);
+    ctor public Geocoder(@NonNull android.content.Context, @NonNull java.util.Locale);
+    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange int) throws java.io.IOException;
+    method public void getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange int, @NonNull android.location.Geocoder.GeocodeListener);
+    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange int) throws java.io.IOException;
+    method public void getFromLocationName(@NonNull String, @IntRange int, @NonNull android.location.Geocoder.GeocodeListener);
+    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double) throws java.io.IOException;
+    method public void getFromLocationName(@NonNull String, @IntRange int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @NonNull android.location.Geocoder.GeocodeListener);
     method public static boolean isPresent();
   }
 
+  public static interface Geocoder.GeocodeListener {
+    method public default void onError(@Nullable String);
+    method public void onGeocode(@NonNull java.util.List<android.location.Address>);
+  }
+
   public final class GnssAntennaInfo implements android.os.Parcelable {
     method public int describeContents();
     method @FloatRange(from=0.0f) public double getCarrierFrequencyMHz();
@@ -35365,7 +35376,6 @@
     field public static final String EXTRA_INPUT_METHOD_ID = "input_method_id";
     field public static final String EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME = "android.provider.extra.NOTIFICATION_LISTENER_COMPONENT_NAME";
     field public static final String EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI = "android.provider.extra.SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI";
-    field public static final String EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_PENDING_INTENT = "android.provider.extra.SETTINGS_LARGE_SCREEN_DEEP_LINK_PENDING_INTENT";
     field public static final String EXTRA_SETTINGS_LARGE_SCREEN_HIGHLIGHT_MENU_KEY = "android.provider.extra.SETTINGS_LARGE_SCREEN_HIGHLIGHT_MENU_KEY";
     field public static final String EXTRA_SUB_ID = "android.provider.extra.SUB_ID";
     field public static final String EXTRA_WIFI_NETWORK_LIST = "android.provider.extra.WIFI_NETWORK_LIST";
@@ -42375,8 +42385,11 @@
     field public static final String MMS_CONFIG_UA_PROF_URL = "uaProfUrl";
     field public static final String MMS_CONFIG_USER_AGENT = "userAgent";
     field public static final int MMS_ERROR_CONFIGURATION_ERROR = 7; // 0x7
+    field public static final int MMS_ERROR_DATA_DISABLED = 11; // 0xb
     field public static final int MMS_ERROR_HTTP_FAILURE = 4; // 0x4
+    field public static final int MMS_ERROR_INACTIVE_SUBSCRIPTION = 10; // 0xa
     field public static final int MMS_ERROR_INVALID_APN = 2; // 0x2
+    field public static final int MMS_ERROR_INVALID_SUBSCRIPTION_ID = 9; // 0x9
     field public static final int MMS_ERROR_IO_ERROR = 5; // 0x5
     field public static final int MMS_ERROR_NO_DATA_NETWORK = 8; // 0x8
     field public static final int MMS_ERROR_RETRY = 6; // 0x6
@@ -46984,8 +46997,15 @@
   }
 
   @UiThread public interface AttachedSurfaceControl {
+    method public default void addOnSurfaceTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnSurfaceTransformHintChangedListener);
     method public boolean applyTransactionOnDraw(@NonNull android.view.SurfaceControl.Transaction);
     method @Nullable public android.view.SurfaceControl.Transaction buildReparentTransaction(@NonNull android.view.SurfaceControl);
+    method public default int getSurfaceTransformHint();
+    method public default void removeOnSurfaceTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnSurfaceTransformHintChangedListener);
+  }
+
+  @UiThread public static interface AttachedSurfaceControl.OnSurfaceTransformHintChangedListener {
+    method public void onSurfaceTransformHintChanged(int);
   }
 
   public final class Choreographer {
@@ -48490,6 +48510,7 @@
 
   public static class SurfaceControl.Transaction implements java.io.Closeable android.os.Parcelable {
     ctor public SurfaceControl.Transaction();
+    method @NonNull public android.view.SurfaceControl.Transaction addTransactionCommittedListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.TransactionCommittedListener);
     method public void apply();
     method public void close();
     method public int describeContents();
@@ -48616,6 +48637,10 @@
     field public static final int TO_RIGHT = 8; // 0x8
   }
 
+  public interface TransactionCommittedListener {
+    method public void onTransactionCommitted();
+  }
+
   public final class VelocityTracker {
     method public void addMovement(android.view.MotionEvent);
     method public void clear();
@@ -50823,6 +50848,8 @@
 
   public final class AccessibilityManager {
     method public void addAccessibilityRequestPreparer(android.view.accessibility.AccessibilityRequestPreparer);
+    method public void addAccessibilityServicesStateChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener);
+    method public void addAccessibilityServicesStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener);
     method public boolean addAccessibilityStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
     method public void addAccessibilityStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener, @Nullable android.os.Handler);
     method public boolean addTouchExplorationStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
@@ -50835,10 +50862,10 @@
     method public int getRecommendedTimeoutMillis(int, int);
     method public void interrupt();
     method public static boolean isAccessibilityButtonSupported();
-    method public boolean isAudioDescriptionEnabled();
     method public boolean isEnabled();
     method public boolean isTouchExplorationEnabled();
     method public void removeAccessibilityRequestPreparer(android.view.accessibility.AccessibilityRequestPreparer);
+    method public boolean removeAccessibilityServicesStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener);
     method public boolean removeAccessibilityStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
     method public boolean removeTouchExplorationStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
     method public void sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
@@ -50847,6 +50874,10 @@
     field public static final int FLAG_CONTENT_TEXT = 2; // 0x2
   }
 
+  public static interface AccessibilityManager.AccessibilityServicesStateChangeListener {
+    method public void onAccessibilityServicesStateChanged(@NonNull android.view.accessibility.AccessibilityManager);
+  }
+
   public static interface AccessibilityManager.AccessibilityStateChangeListener {
     method public void onAccessibilityStateChanged(boolean);
   }
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index e110341..0fc727f 100755
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -2350,7 +2350,7 @@
     field public static final String APP_PREDICTION_SERVICE = "app_prediction";
     field public static final String BACKUP_SERVICE = "backup";
     field public static final String BATTERY_STATS_SERVICE = "batterystats";
-    field public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1048576; // 0x100000
+    field @Deprecated public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1048576; // 0x100000
     field public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 262144; // 0x40000
     field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
     field public static final String CONTEXTHUB_SERVICE = "contexthub";
@@ -3320,13 +3320,17 @@
 package android.hardware.hdmi {
 
   public abstract class HdmiClient {
-    method public void deviceSelect(int, @NonNull android.hardware.hdmi.HdmiTvClient.SelectCallback);
     method public android.hardware.hdmi.HdmiDeviceInfo getActiveSource();
+    method public void selectDevice(int, @NonNull android.hardware.hdmi.HdmiClient.SelectedDeviceCallback);
     method public void sendKeyEvent(int, boolean);
     method public void sendVendorCommand(int, byte[], boolean);
     method public void setVendorCommandListener(@NonNull android.hardware.hdmi.HdmiControlManager.VendorCommandListener);
   }
 
+  public static interface HdmiClient.SelectedDeviceCallback {
+    method public void onComplete(int);
+  }
+
   public final class HdmiControlManager {
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHdmiCecEnabledChangeListener(@NonNull android.hardware.hdmi.HdmiControlManager.CecSettingChangeListener);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHdmiCecEnabledChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.hdmi.HdmiControlManager.CecSettingChangeListener);
@@ -14399,6 +14403,7 @@
     method public int getFlags();
     method @Nullable public android.view.contentcapture.ContentCaptureSessionId getParentSessionId();
     method public int getTaskId();
+    method @Nullable public android.os.IBinder getWindowToken();
     field public static final int FLAG_DISABLED_BY_APP = 1; // 0x1
     field public static final int FLAG_DISABLED_BY_FLAG_SECURE = 2; // 0x2
     field public static final int FLAG_RECONNECTED = 4; // 0x4
@@ -14406,6 +14411,7 @@
 
   public final class ContentCaptureEvent implements android.os.Parcelable {
     method public int describeContents();
+    method @Nullable public android.graphics.Rect getBounds();
     method @Nullable public android.view.contentcapture.ContentCaptureContext getContentCaptureContext();
     method public long getEventTime();
     method @Nullable public android.view.autofill.AutofillId getId();
@@ -14425,6 +14431,7 @@
     field public static final int TYPE_VIEW_TEXT_CHANGED = 3; // 0x3
     field public static final int TYPE_VIEW_TREE_APPEARED = 5; // 0x5
     field public static final int TYPE_VIEW_TREE_APPEARING = 4; // 0x4
+    field public static final int TYPE_WINDOW_BOUNDS_CHANGED = 10; // 0xa
   }
 
   public final class ContentCaptureManager {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 96fa9c4..ac28903 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2882,13 +2882,7 @@
 package android.view.accessibility {
 
   public final class AccessibilityManager {
-    method public void addAccessibilityServicesStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener, @Nullable android.os.Handler);
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public java.util.List<java.lang.String> getAccessibilityShortcutTargets(int);
-    method public void removeAccessibilityServicesStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener);
-  }
-
-  public static interface AccessibilityManager.AccessibilityServicesStateChangeListener {
-    method public void onAccessibilityServicesStateChanged(android.view.accessibility.AccessibilityManager);
   }
 
   public class AccessibilityNodeInfo implements android.os.Parcelable {
diff --git a/core/java/Android.bp b/core/java/Android.bp
index c330ff7..5f2c456 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -371,12 +371,7 @@
 filegroup {
     name: "framework-cellbroadcast-shared-srcs",
     srcs: [
-        ":modules-utils-preconditions-srcs",
-        "android/os/HandlerExecutor.java",
         "android/util/LocalLog.java",
-        "com/android/internal/util/IState.java",
-        "com/android/internal/util/State.java",
-        "com/android/internal/util/StateMachine.java",
     ],
 }
 
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index d1def7e..763a65f 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -167,6 +167,14 @@
     public static final String KEY_SPLASH_SCREEN_THEME = "android.activity.splashScreenTheme";
 
     /**
+     * PendingIntent caller allows activity start even if PendingIntent creator is in background.
+     * This only works if the PendingIntent caller is allowed to start background activities,
+     * for example if it's in the foreground, or has BAL permission.
+     * @hide
+     */
+    public static final String KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED =
+            "android.pendingIntent.backgroundActivityAllowed";
+    /**
      * Callback for when the last frame of the animation is played.
      * @hide
      */
@@ -380,6 +388,12 @@
     /** @hide */
     public static final int ANIM_REMOTE_ANIMATION = 13;
 
+    /**
+     * Default value for KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED.
+     * @hide
+     **/
+    public static final boolean PENDING_INTENT_BAL_ALLOWED_DEFAULT = true;
+
     private String mPackageName;
     private Rect mLaunchBounds;
     private int mAnimationType = ANIM_UNDEFINED;
@@ -431,6 +445,7 @@
     private String mSplashScreenThemeResName;
     @SplashScreen.SplashScreenStyle
     private int mSplashScreenStyle;
+    private boolean mPendingIntentBalAllowed = PENDING_INTENT_BAL_ALLOWED_DEFAULT;
     private boolean mRemoveWithTaskOrganizer;
     private boolean mLaunchedFromBubble;
     private boolean mTransientLaunch;
@@ -1184,6 +1199,8 @@
         mRemoteTransition = opts.getParcelable(KEY_REMOTE_TRANSITION);
         mOverrideTaskTransition = opts.getBoolean(KEY_OVERRIDE_TASK_TRANSITION);
         mSplashScreenThemeResName = opts.getString(KEY_SPLASH_SCREEN_THEME);
+        mPendingIntentBalAllowed = opts.getBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED,
+                PENDING_INTENT_BAL_ALLOWED_DEFAULT);
         mRemoveWithTaskOrganizer = opts.getBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER);
         mLaunchedFromBubble = opts.getBoolean(KEY_LAUNCHED_FROM_BUBBLE);
         mTransientLaunch = opts.getBoolean(KEY_TRANSIENT_LAUNCH);
@@ -1400,6 +1417,24 @@
     }
 
     /**
+     * Set PendingIntent activity is allowed to be started in the background if the caller
+     * can start background activities.
+     * @hide
+     */
+    public void setPendingIntentBackgroundActivityLaunchAllowed(boolean allowed) {
+        mPendingIntentBalAllowed = allowed;
+    }
+
+    /**
+     * Get PendingIntent activity is allowed to be started in the background if the caller
+     * can start background activities.
+     * @hide
+     */
+    public boolean isPendingIntentBackgroundActivityLaunchAllowed() {
+        return mPendingIntentBalAllowed;
+    }
+
+    /**
      * Sets whether the activity is to be launched into LockTask mode.
      *
      * Use this option to start an activity in LockTask mode. Note that only apps permitted by
@@ -1972,6 +2007,7 @@
         if (mSplashScreenThemeResName != null && !mSplashScreenThemeResName.isEmpty()) {
             b.putString(KEY_SPLASH_SCREEN_THEME, mSplashScreenThemeResName);
         }
+        b.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, mPendingIntentBalAllowed);
         if (mRemoveWithTaskOrganizer) {
             b.putBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER, mRemoveWithTaskOrganizer);
         }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 34023a4..f1fd8b7 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3616,6 +3616,11 @@
                 }
                 activity.mLaunchedFromBubble = r.mLaunchedFromBubble;
                 activity.mCalled = false;
+                // Assigning the activity to the record before calling onCreate() allows
+                // ActivityThread#getActivity() lookup for the callbacks triggered from
+                // ActivityLifecycleCallbacks#onActivityCreated() or
+                // ActivityLifecycleCallback#onActivityPostCreated().
+                r.activity = activity;
                 if (r.isPersistable()) {
                     mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                 } else {
@@ -3626,7 +3631,6 @@
                         "Activity " + r.intent.getComponent().toShortString() +
                         " did not call through to super.onCreate()");
                 }
-                r.activity = activity;
                 mLastReportedWindowingMode.put(activity.getActivityToken(),
                         config.windowConfiguration.getWindowingMode());
             }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 7ddc2c94d..f5dd6bd 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -3577,12 +3577,12 @@
     }
 
     @Override
-    public boolean mayPackageQuery(@NonNull String sourcePackageName,
+    public boolean canPackageQuery(@NonNull String sourcePackageName,
             @NonNull String targetPackageName) throws NameNotFoundException {
         Objects.requireNonNull(sourcePackageName);
         Objects.requireNonNull(targetPackageName);
         try {
-            return mPM.mayPackageQuery(sourcePackageName, targetPackageName, getUserId());
+            return mPM.canPackageQuery(sourcePackageName, targetPackageName, getUserId());
         } catch (ParcelableException e) {
             e.maybeRethrow(PackageManager.NameNotFoundException.class);
             throw new RuntimeException(e);
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index bd7162c..4e19abf 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -43,6 +43,7 @@
     private int mMaxManifestReceiverApiLevel = Build.VERSION_CODES.CUR_DEVELOPMENT;
     private boolean mDontSendToRestrictedApps = false;
     private boolean mAllowBackgroundActivityStarts;
+    private boolean mPendingIntentBalAllowed = ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT;
 
     /**
      * How long to temporarily put an app on the power allowlist when executing this broadcast
@@ -79,6 +80,16 @@
             "android:broadcast.dontSendToRestrictedApps";
 
     /**
+     * PendingIntent caller allows activity start even if PendingIntent creator is in background.
+     * This only works if the PendingIntent caller is allowed to start background activities,
+     * for example if it's in the foreground, or has BAL permission.
+     * TODO: Merge it with ActivityOptions.
+     * @hide
+     */
+    public static final String KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED =
+            "android.pendingIntent.backgroundActivityAllowed";
+
+    /**
      * Corresponds to {@link #setBackgroundActivityStartsAllowed}.
      */
     private static final String KEY_ALLOW_BACKGROUND_ACTIVITY_STARTS =
@@ -130,6 +141,8 @@
         mDontSendToRestrictedApps = opts.getBoolean(KEY_DONT_SEND_TO_RESTRICTED_APPS, false);
         mAllowBackgroundActivityStarts = opts.getBoolean(KEY_ALLOW_BACKGROUND_ACTIVITY_STARTS,
                 false);
+        mPendingIntentBalAllowed = opts.getBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED,
+                ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT);
     }
 
     /**
@@ -301,6 +314,26 @@
     }
 
     /**
+     * Set PendingIntent activity is allowed to be started in the background if the caller
+     * can start background activities.
+     * TODO: Merge it with ActivityOptions.
+     * @hide
+     */
+    public void setPendingIntentBackgroundActivityLaunchAllowed(boolean allowed) {
+        mPendingIntentBalAllowed = allowed;
+    }
+
+    /**
+     * Get PendingIntent activity is allowed to be started in the background if the caller
+     * can start background activities.
+     * TODO: Merge it with ActivityOptions.
+     * @hide
+     */
+    public boolean isPendingIntentBackgroundActivityLaunchAllowed() {
+        return mPendingIntentBalAllowed;
+    }
+
+    /**
      * Returns the created options as a Bundle, which can be passed to
      * {@link android.content.Context#sendBroadcast(android.content.Intent)
      * Context.sendBroadcast(Intent)} and related methods.
@@ -328,6 +361,8 @@
         if (mAllowBackgroundActivityStarts) {
             b.putBoolean(KEY_ALLOW_BACKGROUND_ACTIVITY_STARTS, true);
         }
+        // TODO: Add API for BroadcastOptions and have a shared base class with ActivityOptions.
+        b.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, mPendingIntentBalAllowed);
         return b.isEmpty() ? null : b;
     }
 }
diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java
index 4dff4e0..c552cb6 100644
--- a/core/java/android/app/WallpaperInfo.java
+++ b/core/java/android/app/WallpaperInfo.java
@@ -81,7 +81,7 @@
     final int mContextDescriptionResource;
     final boolean mShowMetadataInPreview;
     final boolean mSupportsAmbientMode;
-    final boolean mShouldUseDefaultUnfoldTransition;
+    final boolean mShouldUseDefaultDeviceStateChangeTransition;
     final String mSettingsSliceUri;
     final boolean mSupportMultipleDisplays;
 
@@ -146,9 +146,9 @@
             mSupportsAmbientMode = sa.getBoolean(
                     com.android.internal.R.styleable.Wallpaper_supportsAmbientMode,
                     false);
-            mShouldUseDefaultUnfoldTransition = sa.getBoolean(
-                    com.android.internal.R.styleable.Wallpaper_shouldUseDefaultUnfoldTransition,
-                    true);
+            mShouldUseDefaultDeviceStateChangeTransition = sa.getBoolean(
+                    com.android.internal.R.styleable
+                            .Wallpaper_shouldUseDefaultDeviceStateChangeTransition, true);
             mSettingsSliceUri = sa.getString(
                     com.android.internal.R.styleable.Wallpaper_settingsSliceUri);
             mSupportMultipleDisplays = sa.getBoolean(
@@ -175,7 +175,7 @@
         mSupportsAmbientMode = source.readInt() != 0;
         mSettingsSliceUri = source.readString();
         mSupportMultipleDisplays = source.readInt() != 0;
-        mShouldUseDefaultUnfoldTransition = source.readInt() != 0;
+        mShouldUseDefaultDeviceStateChangeTransition = source.readInt() != 0;
         mService = ResolveInfo.CREATOR.createFromParcel(source);
     }
     
@@ -399,23 +399,25 @@
     }
 
     /**
-     * Returns whether this wallpaper should receive default zooming updates when unfolding.
-     * If set to false the wallpaper will not receive zoom events when folding or unfolding
-     * a foldable device, so it can implement its own unfold transition.
+     * Returns whether this wallpaper should receive default zooming updates when the device
+     * changes its state (e.g. when folding or unfolding a foldable device).
+     * If set to false the wallpaper will not receive zoom events when changing the device state,
+     * so it can implement its own transition instead.
      * <p>
      * This corresponds to the value {@link
-     * android.R.styleable#Wallpaper_shouldUseDefaultUnfoldTransition} in the XML description
-     * of the wallpaper.
+     * android.R.styleable#Wallpaper_shouldUseDefaultDeviceStateChangeTransition} in the
+     * XML description of the wallpaper.
      * <p>
      * The default value is {@code true}.
      *
-     * @see android.R.styleable#Wallpaper_shouldUseDefaultUnfoldTransition
-     * @return {@code true} if wallpaper should receive default fold/unfold transition updates
+     * @see android.R.styleable#Wallpaper_shouldUseDefaultDeviceStateChangeTransition
+     * @return {@code true} if wallpaper should receive default device state change
+     * transition updates
      *
-     * @attr ref android.R.styleable#Wallpaper_shouldUseDefaultUnfoldTransition
+     * @attr ref android.R.styleable#Wallpaper_shouldUseDefaultDeviceStateChangeTransition
      */
-    public boolean shouldUseDefaultUnfoldTransition() {
-        return mShouldUseDefaultUnfoldTransition;
+    public boolean shouldUseDefaultDeviceStateChangeTransition() {
+        return mShouldUseDefaultDeviceStateChangeTransition;
     }
 
     public void dump(Printer pw, String prefix) {
@@ -448,7 +450,7 @@
         dest.writeInt(mSupportsAmbientMode ? 1 : 0);
         dest.writeString(mSettingsSliceUri);
         dest.writeInt(mSupportMultipleDisplays ? 1 : 0);
-        dest.writeInt(mShouldUseDefaultUnfoldTransition ? 1 : 0);
+        dest.writeInt(mShouldUseDefaultDeviceStateChangeTransition ? 1 : 0);
         mService.writeToParcel(dest, flags);
     }
 
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index e6a4656..71fae3d 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -625,17 +625,6 @@
          * Returns the standby bucket of the app, if the event is of type
          * {@link #STANDBY_BUCKET_CHANGED}, otherwise returns 0.
          * @return the standby bucket associated with the event.
-         * @hide
-         */
-        public int getStandbyBucket() {
-            return (mBucketAndReason & 0xFFFF0000) >>> 16;
-        }
-
-        /**
-         * Returns the standby bucket of the app, if the event is of type
-         * {@link #STANDBY_BUCKET_CHANGED}, otherwise returns 0.
-         * @return the standby bucket associated with the event.
-         *
          */
         public int getAppStandbyBucket() {
             return (mBucketAndReason & 0xFFFF0000) >>> 16;
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 6a527a5..15de079 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -445,6 +445,32 @@
     }
 
     /**
+     * Dispatch a message to system for processing.
+     *
+     * <p>Calling app must declare uses-permission
+     * {@link android.Manifest.permission#DELIVER_COMPANION_MESSAGES}</p>
+     *
+     * @param messageId id of the message
+     * @param associationId association id of the associated device where data is coming from
+     * @param message message received from the associated device
+     *
+     * @throws DeviceNotAssociatedException if the given device was not previously associated with
+     * this app
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.DELIVER_COMPANION_MESSAGES)
+    public void dispatchMessage(int messageId, int associationId, @NonNull byte[] message)
+            throws DeviceNotAssociatedException {
+        try {
+            mService.dispatchMessage(messageId, associationId, message);
+        } catch (RemoteException e) {
+            ExceptionUtils.propagateIfInstanceOf(e.getCause(), DeviceNotAssociatedException.class);
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Associates given device with given app for the given user directly, without UI prompt.
      *
      * @param packageName package name of the companion app
diff --git a/core/java/android/companion/CompanionDeviceService.java b/core/java/android/companion/CompanionDeviceService.java
index 56639ea..15266d6 100644
--- a/core/java/android/companion/CompanionDeviceService.java
+++ b/core/java/android/companion/CompanionDeviceService.java
@@ -20,6 +20,7 @@
 import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.app.Service;
 import android.content.Intent;
 import android.os.Handler;
@@ -86,6 +87,37 @@
     @MainThread
     public abstract void onDeviceDisappeared(@NonNull String address);
 
+    /**
+     * Called by system whenever the system dispatches a message to the app to send it to
+     * an associated device.
+     *
+     * @param messageId system assigned id of the message to be sent
+     * @param associationId association id of the associated device
+     * @param message message to be sent
+     */
+    @MainThread
+    public void onDispatchMessage(int messageId, int associationId, @NonNull byte[] message) {
+        // do nothing. Companion apps can override this function for system to send messages.
+    }
+
+    /**
+     * App calls this method when there's a message received from an associated device,
+     * which needs to be dispatched to system for processing.
+     *
+     * <p>Calling app must declare uses-permission
+     * {@link android.Manifest.permission#DELIVER_COMPANION_MESSAGES}</p>
+     *
+     * @param messageId id of the message
+     * @param associationId id of the associated device
+     * @param message messaged received from the associated device
+     */
+    @RequiresPermission(android.Manifest.permission.DELIVER_COMPANION_MESSAGES)
+    public final void dispatchMessage(int messageId, int associationId, @NonNull byte[] message) {
+        CompanionDeviceManager companionDeviceManager =
+                getSystemService(CompanionDeviceManager.class);
+        companionDeviceManager.dispatchMessage(messageId, associationId, message);
+    }
+
     @Nullable
     @Override
     public final IBinder onBind(@NonNull Intent intent) {
@@ -112,5 +144,18 @@
                     CompanionDeviceService::onDeviceDisappeared,
                     CompanionDeviceService.this, address));
         }
+
+        public void onDispatchMessage(int messageId, int associationId, @NonNull byte[] message) {
+            Handler.getMain().sendMessage(PooledLambda.obtainMessage(
+                    CompanionDeviceService::onDispatchMessage,
+                    CompanionDeviceService.this, messageId, associationId, message));
+        }
+
+        public final void dispatchMessage(int messageId, int associationId,
+                @NonNull byte[] message) {
+            Handler.getMain().sendMessage(PooledLambda.obtainMessage(
+                    CompanionDeviceService::dispatchMessage,
+                    CompanionDeviceService.this, messageId, associationId, message));
+        }
     }
 }
diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl
index d113b92..25c5cb3 100644
--- a/core/java/android/companion/ICompanionDeviceManager.aidl
+++ b/core/java/android/companion/ICompanionDeviceManager.aidl
@@ -54,4 +54,6 @@
 
     void createAssociation(in String packageName, in String macAddress, int userId,
         in byte[] certificate);
+
+    void dispatchMessage(in int messageId, in int associationId, in byte[] message);
 }
diff --git a/core/java/android/companion/ICompanionDeviceService.aidl b/core/java/android/companion/ICompanionDeviceService.aidl
index f3977ca..25212a1 100644
--- a/core/java/android/companion/ICompanionDeviceService.aidl
+++ b/core/java/android/companion/ICompanionDeviceService.aidl
@@ -16,14 +16,9 @@
 
 package android.companion;
 
-import android.app.PendingIntent;
-import android.companion.IFindDeviceCallback;
-import android.companion.Association;
-import android.companion.AssociationRequest;
-import android.content.ComponentName;
-
 /** @hide */
 oneway interface ICompanionDeviceService {
     void onDeviceAppeared(in String address);
     void onDeviceDisappeared(in String address);
+    void onDispatchMessage(in int messageId, in int associationId, in byte[] message);
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 78d83c0..3ab070f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -416,13 +416,12 @@
     public static final int BIND_SCHEDULE_LIKE_TOP_APP = 0x00080000;
 
     /**
-     * Flag for {@link #bindService}: allow background activity starts from the bound service's
-     * process.
-     * This flag is only respected if the caller is holding
-     * {@link android.Manifest.permission#START_ACTIVITIES_FROM_BACKGROUND}.
+     * This flag has never been used.
      * @hide
+     * @deprecated This flag has never been used.
      */
     @SystemApi
+    @Deprecated
     public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 0x00100000;
 
     /**
@@ -3483,9 +3482,8 @@
      * @return {@code true} if the system is in the process of bringing up a
      *         service that your client has permission to bind to; {@code false}
      *         if the system couldn't find the service or if your client doesn't
-     *         have permission to bind to it. If this value is {@code true}, you
-     *         should later call {@link #unbindService} to release the
-     *         connection.
+     *         have permission to bind to it. You should call {@link #unbindService}
+     *         to release the connection even if this method returned {@code false}.
      *
      * @throws SecurityException If the caller does not have permission to access the service
      * or the service can not be found.
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index df29249..7ac385b 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -819,5 +819,5 @@
 
     void setKeepUninstalledPackages(in List<String> packageList);
 
-    boolean mayPackageQuery(String sourcePackageName, String targetPackageName, int userId);
+    boolean canPackageQuery(String sourcePackageName, String targetPackageName, int userId);
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 6b672ff..f9d3a14 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3934,6 +3934,15 @@
     public static final String FEATURE_APP_COMPAT_OVERRIDES =
             "android.software.app_compat_overrides";
 
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
+     * supports communal mode,
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_COMMUNAL_MODE = "android.software.communal_mode";
+
     /** @hide */
     public static final boolean APP_ENUMERATION_ENABLED_BY_DEFAULT = true;
 
@@ -9348,10 +9357,10 @@
      * system, or if the caller is not able to query for details about the source or
      * target package.
      */
-    public boolean mayPackageQuery(@NonNull String sourcePackageName,
+    public boolean canPackageQuery(@NonNull String sourcePackageName,
             @NonNull String targetPackageName) throws NameNotFoundException {
         throw new UnsupportedOperationException(
-                "mayPackageQuery not implemented in subclass");
+                "canPackageQuery not implemented in subclass");
     }
 
     /**
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index 0a69413..0d8fdcc 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -7,6 +7,9 @@
       "path": "cts/hostsidetests/stagedinstall"
     },
     {
+      "path": "cts/hostsidetests/packagemanager"
+    },
+    {
       "path": "system/apex/tests"
     }
   ],
diff --git a/core/java/android/content/pm/parsing/ApkLite.java b/core/java/android/content/pm/parsing/ApkLite.java
index 49d4137..259cbf9 100644
--- a/core/java/android/content/pm/parsing/ApkLite.java
+++ b/core/java/android/content/pm/parsing/ApkLite.java
@@ -108,6 +108,16 @@
     private final boolean mOverlayIsStatic;
     /** Indicate the priority of this overlay package */
     private final int mOverlayPriority;
+    /**
+     * A comma separated list of system property names to control whether the overlay should be
+     * excluded based on the system property condition.
+     */
+    private final @Nullable String mRequiredSystemPropertyName;
+    /**
+     * A comma separated list of system property values to control whether the overlay should be
+     * excluded based on the system property condition.
+     */
+    private final @Nullable String mRequiredSystemPropertyValue;
 
     /**
      * Indicate the policy to deal with user data when rollback is committed
@@ -125,6 +135,7 @@
             boolean debuggable, boolean profileableByShell, boolean multiArch, boolean use32bitAbi,
             boolean useEmbeddedDex, boolean extractNativeLibs, boolean isolatedSplits,
             String targetPackageName, boolean overlayIsStatic, int overlayPriority,
+            String requiredSystemPropertyName, String requiredSystemPropertyValue,
             int minSdkVersion, int targetSdkVersion, int rollbackDataPolicy,
             Set<String> requiredSplitTypes, Set<String> splitTypes) {
         mPath = path;
@@ -153,6 +164,8 @@
         mTargetPackageName = targetPackageName;
         mOverlayIsStatic = overlayIsStatic;
         mOverlayPriority = overlayPriority;
+        mRequiredSystemPropertyName = requiredSystemPropertyName;
+        mRequiredSystemPropertyValue = requiredSystemPropertyValue;
         mMinSdkVersion = minSdkVersion;
         mTargetSdkVersion = targetSdkVersion;
         mRollbackDataPolicy = rollbackDataPolicy;
@@ -419,6 +432,24 @@
     }
 
     /**
+     * A comma separated list of system property names to control whether the overlay should be
+     * excluded based on the system property condition.
+     */
+    @DataClass.Generated.Member
+    public @Nullable String getRequiredSystemPropertyName() {
+        return mRequiredSystemPropertyName;
+    }
+
+    /**
+     * A comma separated list of system property values to control whether the overlay should be
+     * excluded based on the system property condition.
+     */
+    @DataClass.Generated.Member
+    public @Nullable String getRequiredSystemPropertyValue() {
+        return mRequiredSystemPropertyValue;
+    }
+
+    /**
      * Indicate the policy to deal with user data when rollback is committed
      *
      * @see {@link PackageManager#ROLLBACK_DATA_POLICY_RESTORE}
@@ -431,10 +462,10 @@
     }
 
     @DataClass.Generated(
-            time = 1628562554893L,
+            time = 1631763761543L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ApkLite.java",
-            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mRevisionCode\nprivate final  int mInstallLocation\nprivate final  int mMinSdkVersion\nprivate final  int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final  boolean mFeatureSplit\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mProfileableByShell\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final  boolean mOverlayIsStatic\nprivate final  int mOverlayPriority\nprivate final  int mRollbackDataPolicy\npublic  long getLongVersionCode()\nprivate  boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mRevisionCode\nprivate final  int mInstallLocation\nprivate final  int mMinSdkVersion\nprivate final  int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final  boolean mFeatureSplit\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mProfileableByShell\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final  boolean mOverlayIsStatic\nprivate final  int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final  int mRollbackDataPolicy\npublic  long getLongVersionCode()\nprivate  boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index d3b6f2b..82637aa 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -18,6 +18,7 @@
 
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+import static android.content.pm.parsing.ParsingPackageUtils.PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY;
 import static android.content.pm.parsing.ParsingPackageUtils.checkRequiredSystemProperties;
 import static android.content.pm.parsing.ParsingPackageUtils.parsePublicKey;
 import static android.content.pm.parsing.ParsingPackageUtils.validateName;
@@ -332,7 +333,7 @@
                 signingDetails = SigningDetails.UNKNOWN;
             }
 
-            return parseApkLite(input, apkPath, parser, signingDetails);
+            return parseApkLite(input, apkPath, parser, signingDetails, flags);
         } catch (XmlPullParserException | IOException | RuntimeException e) {
             Slog.w(TAG, "Failed to parse " + apkPath, e);
             return input.error(PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
@@ -350,7 +351,7 @@
     }
 
     private static ParseResult<ApkLite> parseApkLite(ParseInput input, String codePath,
-            XmlResourceParser parser, SigningDetails signingDetails)
+            XmlResourceParser parser, SigningDetails signingDetails, int flags)
             throws IOException, XmlPullParserException {
         ParseResult<Pair<String, String>> result = parsePackageSplitNames(input, parser);
         if (result.isError()) {
@@ -522,14 +523,14 @@
         }
 
         // Check to see if overlay should be excluded based on system property condition
-        if (!checkRequiredSystemProperties(requiredSystemPropertyName,
-                requiredSystemPropertyValue)) {
-            Slog.i(TAG, "Skipping target and overlay pair " + targetPackage + " and "
+        if ((flags & PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY) == 0
+                && !checkRequiredSystemProperties(
+                        requiredSystemPropertyName, requiredSystemPropertyValue)) {
+            String message = "Skipping target and overlay pair " + targetPackage + " and "
                     + codePath + ": overlay ignored due to required system property: "
-                    + requiredSystemPropertyName + " with value: " + requiredSystemPropertyValue);
-            targetPackage = null;
-            overlayIsStatic = false;
-            overlayPriority = 0;
+                    + requiredSystemPropertyName + " with value: " + requiredSystemPropertyValue;
+            Slog.i(TAG, message);
+            return input.skip(message);
         }
 
         return input.success(
@@ -538,7 +539,8 @@
                         versionCodeMajor, revisionCode, installLocation, verifiers, signingDetails,
                         coreApp, debuggable, profilableByShell, multiArch, use32bitAbi,
                         useEmbeddedDex, extractNativeLibs, isolatedSplits, targetPackage,
-                        overlayIsStatic, overlayPriority, minSdkVersion, targetSdkVersion,
+                        overlayIsStatic, overlayPriority, requiredSystemPropertyName,
+                        requiredSystemPropertyValue, minSdkVersion, targetSdkVersion,
                         rollbackDataPolicy, requiredSplitTypes.first, requiredSplitTypes.second));
     }
 
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 69cf32f..97af1d24 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -217,6 +217,11 @@
     public static final int PARSE_IS_SYSTEM_DIR = 1 << 4;
     public static final int PARSE_COLLECT_CERTIFICATES = 1 << 5;
     public static final int PARSE_ENFORCE_CODE = 1 << 6;
+    /**
+     * This flag is applied in the ApkLiteParser. Used by OverlayConfigParser to ignore the
+     * checks of required system property within the overlay tag.
+     */
+    public static final int PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY = 1 << 7;
     public static final int PARSE_CHATTY = 1 << 31;
 
     @IntDef(flag = true, prefix = { "PARSE_" }, value = {
@@ -227,6 +232,7 @@
             PARSE_IGNORE_PROCESSES,
             PARSE_IS_SYSTEM_DIR,
             PARSE_MUST_BE_APK,
+            PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ParseFlags {}
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index 5cfba3d..395c655 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -263,12 +263,12 @@
                     @Override
                     public void onServiceConnected(ComponentName component, IBinder binder) {
                         mProxy = ICameraExtensionsProxyService.Stub.asInterface(binder);
-                        mInitFuture.setStatus(true);
                         try {
                             mSupportsAdvancedExtensions = mProxy.advancedExtensionsSupported();
                         } catch (RemoteException e) {
                             Log.e(TAG, "Remote IPC failed!");
                         }
+                        mInitFuture.setStatus(true);
                     }
                 };
                 ctx.bindService(intent, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT |
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index eab9d8b..0276815 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -85,7 +85,7 @@
 
     /**
      * A {@code Key} is used to do capture request field lookups with
-     * {@link CaptureResult#get} or to set fields with
+     * {@link CaptureRequest#get} or to set fields with
      * {@link CaptureRequest.Builder#set(Key, Object)}.
      *
      * <p>For example, to set the crop rectangle for the next capture:
@@ -95,11 +95,11 @@
      * </pre></code>
      * </p>
      *
-     * <p>To enumerate over all possible keys for {@link CaptureResult}, see
-     * {@link CameraCharacteristics#getAvailableCaptureResultKeys}.</p>
+     * <p>To enumerate over all possible keys for {@link CaptureRequest}, see
+     * {@link CameraCharacteristics#getAvailableCaptureRequestKeys}.</p>
      *
-     * @see CaptureResult#get
-     * @see CameraCharacteristics#getAvailableCaptureResultKeys
+     * @see CaptureRequest#get
+     * @see CameraCharacteristics#getAvailableCaptureRequestKeys
      */
     public final static class Key<T> {
         private final CameraMetadataNative.Key<T> mKey;
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
index 3b1cb94..425f22c 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
@@ -58,7 +58,7 @@
 
     private static final class JpegParameters {
         public HashSet<Long> mTimeStamps = new HashSet<>();
-        public int mRotation = JPEG_DEFAULT_ROTATION; // CCW multiple of 90 degrees
+        public int mRotation = JPEG_DEFAULT_ROTATION; // CW multiple of 90 degrees
         public int mQuality = JPEG_DEFAULT_QUALITY; // [0..100]
     }
 
@@ -100,7 +100,8 @@
             Integer orientation = captureBundles.get(0).captureResult.get(
                     CaptureResult.JPEG_ORIENTATION);
             if (orientation != null) {
-                ret.mRotation = orientation / 90;
+                // The jpeg encoder expects CCW rotation, convert from CW
+                ret.mRotation = (360 - (orientation % 360)) / 90;
             } else {
                 Log.w(TAG, "No jpeg rotation set, using default: " + JPEG_DEFAULT_ROTATION);
             }
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index a25ae60..d9734b4 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -1018,7 +1018,7 @@
      * <p>The following formats will never have a stall duration:
      * <ul>
      * <li>{@link ImageFormat#YUV_420_888 YUV_420_888}
-     * <li>{@link #isOutputSupportedFor(Class) Implementation-Defined}
+     * <li>{@link ImageFormat#PRIVATE PRIVATE}
      * </ul></p>
      *
      * <p>
diff --git a/core/java/android/hardware/hdmi/HdmiClient.java b/core/java/android/hardware/hdmi/HdmiClient.java
index 1959ff8..eb4cffd 100644
--- a/core/java/android/hardware/hdmi/HdmiClient.java
+++ b/core/java/android/hardware/hdmi/HdmiClient.java
@@ -4,7 +4,6 @@
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.hardware.hdmi.HdmiControlManager.VendorCommandListener;
-import android.hardware.hdmi.HdmiTvClient.SelectCallback;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -29,13 +28,25 @@
     }
 
     /**
+     * Callback interface used to get the result of {@link #selectDevice}.
+     */
+    public interface SelectedDeviceCallback {
+        /**
+         * Called when the operation is finished.
+         * @param result the result value of {@link #selectDevice} and can have the values mentioned
+         *               in {@link HdmiControlShellCommand#getResultString}
+         */
+        void onComplete(int result);
+    }
+
+    /**
      * Selects a CEC logical device to be a new active source.
      *
      * @param logicalAddress logical address of the device to select
      * @param callback callback to get the result with
      * @throws {@link IllegalArgumentException} if the {@code callback} is null
      */
-    public void deviceSelect(int logicalAddress, @NonNull SelectCallback callback) {
+    public void selectDevice(int logicalAddress, @NonNull SelectedDeviceCallback callback) {
         if (callback == null) {
             throw new IllegalArgumentException("callback must not be null.");
         }
@@ -49,7 +60,7 @@
     /**
      * @hide
      */
-    private static IHdmiControlCallback getCallbackWrapper(final SelectCallback callback) {
+    private static IHdmiControlCallback getCallbackWrapper(final SelectedDeviceCallback callback) {
         return new IHdmiControlCallback.Stub() {
             @Override
             public void onComplete(int result) {
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java
index 74cf001..575ad83 100644
--- a/core/java/android/hardware/hdmi/HdmiTvClient.java
+++ b/core/java/android/hardware/hdmi/HdmiTvClient.java
@@ -60,7 +60,8 @@
     }
 
     /**
-     * Callback interface used to get the result of {@link #deviceSelect}.
+     * Callback interface used to get the result of {@link #portSelect} and
+     * {@link #setSystemAudioMode}.
      */
     public interface SelectCallback {
         /**
@@ -77,7 +78,7 @@
      * @param logicalAddress logical address of the device to select
      * @param callback callback to get the result with
      * @throws {@link IllegalArgumentException} if the {@code callback} is null
-     * @deprecated Please use {@link HdmiClient#deviceSelect()} instead.
+     * @deprecated Please use {@link HdmiClient#selectDevice} instead.
      */
     @Deprecated
     public void deviceSelect(int logicalAddress, @NonNull SelectCallback callback) {
@@ -91,10 +92,6 @@
         }
     }
 
-    /**
-     * @deprecated Please use {@link HdmiClient#getCallbackWrapper()} instead.
-     */
-    @Deprecated
     private static IHdmiControlCallback getCallbackWrapper(final SelectCallback callback) {
         return new IHdmiControlCallback.Stub() {
             @Override
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 4255d88..c6a365e 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -2867,7 +2867,12 @@
      * Ask the input target to execute its default action via
      * {@link InputConnection#performEditorAction
      * InputConnection.performEditorAction()}.
-     * 
+     *
+     * <p>For compatibility, this method does not execute a custom action even if {@link
+     * EditorInfo#actionLabel EditorInfo.actionLabel} is set. The implementor should directly call
+     * {@link InputConnection#performEditorAction InputConnection.performEditorAction()} with
+     * {@link EditorInfo#actionId EditorInfo.actionId} if they want to execute a custom action.</p>
+     *
      * @param fromEnterKey If true, this will be executed as if the user had
      * pressed an enter key on the keyboard, that is it will <em>not</em>
      * be done if the editor has set {@link EditorInfo#IME_FLAG_NO_ENTER_ACTION
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 6da02f5..fb21ce3 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -260,6 +260,9 @@
     /**
      * Returns the value for key {@code key}.
      *
+     * This call should always be made after {@link #unparcel()} or inside a lock after making sure
+     * {@code mMap} is not null.
+     *
      * @hide
      */
     final Object getValue(String key) {
@@ -270,15 +273,15 @@
     /**
      * Returns the value for a certain position in the array map.
      *
+     * This call should always be made after {@link #unparcel()} or inside a lock after making sure
+     * {@code mMap} is not null.
+     *
      * @hide
      */
     final Object getValueAt(int i) {
         Object object = mMap.valueAt(i);
         if (object instanceof Supplier<?>) {
-            Supplier<?> supplier = (Supplier<?>) object;
-            synchronized (this) {
-                object = supplier.get();
-            }
+            object = ((Supplier<?>) object).get();
             mMap.setValueAt(i, object);
         }
         return object;
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 3d18125..483b549 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -83,7 +83,7 @@
          * Debuggable builds will throw an BinderProxyMapSizeException if the number of
          * map entries exceeds:
          */
-        private static final int CRASH_AT_SIZE = 20_000;
+        private static final int CRASH_AT_SIZE = 25_000;
 
         /**
          * We next warn when we exceed this bucket size.
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 018bc6b..e7c3a83 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -73,3 +73,6 @@
 
 # UpdateEngine
 per-file *UpdateEngine* = file:/platform/system/update_engine:/OWNERS
+
+# VINTF
+per-file Vintf* = file:/platform/system/libvintf:/OWNERS
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index f5d8346..2be9533 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -16,6 +16,8 @@
 
 package android.os;
 
+import static java.util.Objects.requireNonNull;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
@@ -3453,12 +3455,19 @@
         private final int mLength;
         private final int mType;
         @Nullable private final ClassLoader mLoader;
-        @Nullable private Parcel mSource;
         @Nullable private Object mObject;
-        @Nullable private Parcel mValueParcel;
+        @Nullable private volatile Parcel mValueParcel;
+
+        /**
+         * This goes from non-null to null once. Always check the nullability of this object before
+         * performing any operations, either involving itself or mObject since the happens-before
+         * established by this volatile will guarantee visibility of either. We can assume this
+         * parcel won't change anymore.
+         */
+        @Nullable private volatile Parcel mSource;
 
         LazyValue(Parcel source, int position, int length, int type, @Nullable ClassLoader loader) {
-            mSource = source;
+            mSource = requireNonNull(source);
             mPosition = position;
             mLength = length;
             mType = type;
@@ -3467,38 +3476,41 @@
 
         @Override
         public Object get() {
-            if (mObject == null) {
-                int restore = mSource.dataPosition();
-                try {
-                    mSource.setDataPosition(mPosition);
-                    mObject = mSource.readValue(mLoader);
-                } finally {
-                    mSource.setDataPosition(restore);
-                }
-                mSource = null;
-                if (mValueParcel != null) {
-                    mValueParcel.recycle();
-                    mValueParcel = null;
+            Parcel source = mSource;
+            if (source != null) {
+                synchronized (source) {
+                    int restore = source.dataPosition();
+                    try {
+                        source.setDataPosition(mPosition);
+                        mObject = source.readValue(mLoader);
+                    } finally {
+                        source.setDataPosition(restore);
+                    }
+                    mSource = null;
                 }
             }
             return mObject;
         }
 
         public void writeToParcel(Parcel out) {
-            if (mObject == null) {
-                out.appendFrom(mSource, mPosition, mLength + 8);
+            Parcel source = mSource;
+            if (source != null) {
+                out.appendFrom(source, mPosition, mLength + 8);
             } else {
                 out.writeValue(mObject);
             }
         }
 
         public boolean hasFileDescriptors() {
-            return getValueParcel().hasFileDescriptors();
+            Parcel source = mSource;
+            return (source != null)
+                    ? getValueParcel(source).hasFileDescriptors()
+                    : Parcel.hasFileDescriptors(mObject);
         }
 
         @Override
         public String toString() {
-            return mObject == null
+            return (mSource != null)
                     ? "Supplier{" + valueTypeToString(mType) + "@" + mPosition + "+" + mLength + '}'
                     : "Supplier{" + mObject + "}";
         }
@@ -3517,41 +3529,49 @@
                 return false;
             }
             LazyValue value = (LazyValue) other;
-            // Check if they are either both serialized or both deserialized
-            if ((mObject == null) != (value.mObject == null)) {
+            // Check if they are either both serialized or both deserialized.
+            Parcel source = mSource;
+            Parcel otherSource = value.mSource;
+            if ((source == null) != (otherSource == null)) {
                 return false;
             }
-            // If both are deserialized, compare the live objects
-            if (mObject != null) {
-                return mObject.equals(value.mObject);
+            // If both are deserialized, compare the live objects.
+            if (source == null) {
+                // Note that here it's guaranteed that both mObject references contain valid values
+                // (possibly null) since mSource will have provided the memory barrier for those and
+                // once deserialized we never go back to serialized state.
+                return Objects.equals(mObject, value.mObject);
             }
-            // Better safely fail here since this could mean we get different objects
+            // Better safely fail here since this could mean we get different objects.
             if (!Objects.equals(mLoader, value.mLoader)) {
                 return false;
             }
-            // Otherwise compare metadata prior to comparing payload
+            // Otherwise compare metadata prior to comparing payload.
             if (mType != value.mType || mLength != value.mLength) {
                 return false;
             }
-            // Finally we compare the payload
-            return getValueParcel().compareData(value.getValueParcel()) == 0;
+            // Finally we compare the payload.
+            return getValueParcel(source).compareData(value.getValueParcel(otherSource)) == 0;
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(mObject, mLoader, mType, mLength);
+            // Accessing mSource first to provide memory barrier for mObject
+            return Objects.hash(mSource == null, mObject, mLoader, mType, mLength);
         }
 
         /** This extracts the parcel section responsible for the object and returns it. */
-        private Parcel getValueParcel() {
-            if (mValueParcel == null) {
-                mValueParcel = Parcel.obtain();
+        private Parcel getValueParcel(Parcel source) {
+            Parcel parcel = mValueParcel;
+            if (parcel == null) {
+                parcel = Parcel.obtain();
                 // mLength is the length of object representation, excluding the type and length.
                 // mPosition is the position of the entire value container, right before the type.
                 // So, we add 4 bytes for the type + 4 bytes for the length written.
-                mValueParcel.appendFrom(mSource, mPosition, mLength + 8);
+                parcel.appendFrom(source, mPosition, mLength + 8);
+                mValueParcel = parcel;
             }
-            return mValueParcel;
+            return parcel;
         }
     }
 
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 2f66a39..2e41382 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -548,6 +548,7 @@
             WAKE_REASON_HDMI,
             WAKE_REASON_DISPLAY_GROUP_ADDED,
             WAKE_REASON_DISPLAY_GROUP_TURNED_ON,
+            WAKE_REASON_UNFOLD_DEVICE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface WakeReason{}
@@ -647,6 +648,12 @@
     public static final int WAKE_REASON_DISPLAY_GROUP_TURNED_ON = 11;
 
     /**
+     * Wake up reason code: Waking the device due to unfolding of a foldable device.
+     * @hide
+     */
+    public static final int WAKE_REASON_UNFOLD_DEVICE = 12;
+
+    /**
      * Convert the wake reason to a string for debugging purposes.
      * @hide
      */
@@ -664,6 +671,7 @@
             case WAKE_REASON_LID: return "WAKE_REASON_LID";
             case WAKE_REASON_DISPLAY_GROUP_ADDED: return "WAKE_REASON_DISPLAY_GROUP_ADDED";
             case WAKE_REASON_DISPLAY_GROUP_TURNED_ON: return "WAKE_REASON_DISPLAY_GROUP_TURNED_ON";
+            case WAKE_REASON_UNFOLD_DEVICE: return "WAKE_REASON_UNFOLD_DEVICE";
             default: return Integer.toString(wakeReason);
         }
     }
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index 755c35f..3739040 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -98,6 +98,10 @@
         return mServiceManager.updatableViaApex(name);
     }
 
+    public ConnectionInfo getConnectionInfo(String name) throws RemoteException {
+        return mServiceManager.getConnectionInfo(name);
+    }
+
     public void registerClientCallback(String name, IBinder service, IClientCallback cb)
             throws RemoteException {
         throw new RemoteException();
diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java
index bf0b655..1f11197 100644
--- a/core/java/android/os/VintfObject.java
+++ b/core/java/android/os/VintfObject.java
@@ -97,8 +97,11 @@
      * ["android.hidl.manager@1.0", "android.hardware.camera.device@1.0",
      *  "android.hardware.camera.device@3.2"]. There are no duplicates.
      *
-     * For AIDL HALs, the version is stripped away
-     * (e.g. "android.hardware.light").
+     * For AIDL HALs, the version is a single number
+     * (e.g. "android.hardware.light@1"). Historically, this API strips the
+     * version number for AIDL HALs (e.g. "android.hardware.light"). Users
+     * of this API must be able to handle both for backwards compatibility.
+     *
      * @hide
      */
     @TestApi
diff --git a/core/java/android/permission/OWNERS b/core/java/android/permission/OWNERS
index 19a3a8b..b5466b6 100644
--- a/core/java/android/permission/OWNERS
+++ b/core/java/android/permission/OWNERS
@@ -1,11 +1,12 @@
 # Bug component: 137825
 
-eugenesusla@google.com
 evanseverson@google.com
 evanxinchen@google.com
 ewol@google.com
 guojing@google.com
 jaysullivan@google.com
+olekarg@google.com
+pyuli@google.com
 ntmyren@google.com
 svetoslavganov@android.com
 svetoslavganov@google.com
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 63ab74e..2d10ade 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -35,7 +35,6 @@
 import android.app.AutomaticZenRule;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
-import android.app.PendingIntent;
 import android.app.SearchManager;
 import android.app.WallpaperManager;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -7235,14 +7234,6 @@
             "enabled_accessibility_services";
 
         /**
-         * Whether select sound track with audio description by default.
-         * @hide
-         */
-        @Readable
-        public static final String ENABLE_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT =
-                "enable_accessibility_audio_description_by_default";
-
-        /**
          * List of the notified non-accessibility category accessibility services.
          *
          * @hide
@@ -9035,6 +9026,15 @@
         public static final String UNSAFE_VOLUME_MUSIC_ACTIVE_MS = "unsafe_volume_music_active_ms";
 
         /**
+         * Indicates whether the spatial audio feature was enabled for this user.
+         *
+         * Type : int (0 disabled, 1 enabled)
+         *
+         * @hide
+         */
+        public static final String SPATIAL_AUDIO_ENABLED = "spatial_audio_enabled";
+
+        /**
          * Indicates whether notification display on the lock screen is enabled.
          * <p>
          * Type: int (0 for false, 1 for true)
@@ -10253,6 +10253,13 @@
         public static final String COMMUNAL_MODE_ENABLED = "communal_mode_enabled";
 
         /**
+         * An array of all the packages which have been enabled for hub mode by the user.
+         *
+         * @hide
+         */
+        public static final String COMMUNAL_MODE_PACKAGES = "communal_mode_packages";
+
+        /**
          * These entries are considered common between the personal and the managed profile,
          * since the managed profile doesn't get to change them.
          */
@@ -10399,6 +10406,14 @@
                 "enable_accessibility_global_gesture_enabled";
 
         /**
+         * Whether select sound track with audio description by default.
+         * @hide
+         */
+        @Readable
+        public static final String ENABLE_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT =
+                "enable_accessibility_audio_description_by_default";
+
+        /**
          * Whether Airplane Mode is on.
          */
         @Readable
@@ -17755,9 +17770,6 @@
      *
      *     Input: {@link #EXTRA_SETTINGS_LARGE_SCREEN_HIGHLIGHT_MENU_KEY} must be included to
      * specify a key that indicates the menu item which will be highlighted on settings home menu.
-     *
-     *     Input: {@link #EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_PENDING_INTENT} is optional. Apps
-     * can use the {@link PendingIntent} extra to launch into its private {@link Activity}.
      * <p>
      * Output: Nothing.
      */
@@ -17785,15 +17797,6 @@
             "android.provider.extra.SETTINGS_LARGE_SCREEN_HIGHLIGHT_MENU_KEY";
 
     /**
-     * Activity Extra: Apps can use the {@link PendingIntent} extra to launch into its private
-     * {@link Activity}.
-     * <p>
-     * This is an optional extra field to {@link #ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK}.
-     */
-    public static final String EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_PENDING_INTENT =
-            "android.provider.extra.SETTINGS_LARGE_SCREEN_DEEP_LINK_PENDING_INTENT";
-
-    /**
      * Performs a strict and comprehensive check of whether a calling package is allowed to
      * write/modify system settings, as the condition differs for pre-M, M+, and
      * privileged/preinstalled apps. If the provided uid does not match the
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 491a5f9..9819648 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -920,13 +920,17 @@
 
         if (!mWaking && !mFinished) {
             mWaking = true;
-            // During wake up the activity should be translucent to allow the application underneath
-            // to start drawing. Normally, the WM animation system takes care of this, but here we
-            // give the dream application some time to perform a custom exit animation.
-            // If it uses a view animation, the WM doesn't know about it and can't make the activity
-            // translucent in the normal way. Therefore, here we ensure that the activity is
-            // translucent during wake up regardless of what animation is used in onWakeUp().
-            mActivity.convertToTranslucent(null, null);
+
+            if (mActivity != null) {
+                // During wake up the activity should be translucent to allow the application
+                // underneath to start drawing. Normally, the WM animation system takes care of
+                // this, but here we give the dream application some time to perform a custom exit
+                // animation. If it uses a view animation, the WM doesn't know about it and can't
+                // make the activity translucent in the normal way. Therefore, here we ensure that
+                // the activity is translucent during wake up regardless of what animation is used
+                // in onWakeUp().
+                mActivity.convertToTranslucent(null, null);
+            }
 
             // As a minor optimization, invoke the callback first in case it simply
             // calls finish() immediately so there wouldn't be much point in telling
diff --git a/core/java/android/service/quicksettings/TEST_MAPPING b/core/java/android/service/quicksettings/TEST_MAPPING
new file mode 100644
index 0000000..2d45c5b2
--- /dev/null
+++ b/core/java/android/service/quicksettings/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsTileServiceTestCases",
+      "options": [
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index cb5e51c..2d263a5 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -561,12 +561,16 @@
          */
         public void reportEngineShown(boolean waitForEngineShown) {
             if (mIWallpaperEngine.mShownReported) return;
-            Message message = mCaller.obtainMessage(MSG_REPORT_SHOWN);
             if (!waitForEngineShown) {
+                Message message = mCaller.obtainMessage(MSG_REPORT_SHOWN);
                 mCaller.removeMessages(MSG_REPORT_SHOWN);
                 mCaller.sendMessage(message);
             } else {
-                mCaller.sendMessageDelayed(message, TimeUnit.SECONDS.toMillis(1));
+                // if we are already waiting, no need to reset the timeout.
+                if (!mCaller.hasMessages(MSG_REPORT_SHOWN)) {
+                    Message message = mCaller.obtainMessage(MSG_REPORT_SHOWN);
+                    mCaller.sendMessageDelayed(message, TimeUnit.SECONDS.toMillis(5));
+                }
             }
         }
 
@@ -2256,6 +2260,8 @@
                 mShownReported = true;
                 try {
                     mConnection.engineShown(this);
+                    Log.d(TAG, "Wallpaper has updated the surface:"
+                            + mWallpaperManager.getWallpaperInfo());
                 } catch (RemoteException e) {
                     Log.w(TAG, "Wallpaper host disappeared", e);
                     return;
diff --git a/core/java/android/text/method/TranslationTransformationMethod.java b/core/java/android/text/method/TranslationTransformationMethod.java
index 80387aa..43d186e 100644
--- a/core/java/android/text/method/TranslationTransformationMethod.java
+++ b/core/java/android/text/method/TranslationTransformationMethod.java
@@ -62,6 +62,13 @@
         return mOriginalTranslationMethod;
     }
 
+    /**
+     * Returns the {@link TextView}'s {@link ViewTranslationResponse}.
+     */
+    public ViewTranslationResponse getViewTranslationResponse() {
+        return mTranslationResponse;
+    }
+
     @Override
     public CharSequence getTransformation(CharSequence source, View view) {
         if (!mAllowLengthChanges) {
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index b07b522..8e4e99e 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -56,6 +56,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.OptionalInt;
 
 /**
  * APK Signature Scheme v3 verifier.
@@ -70,6 +71,7 @@
     public static final int SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID = 3;
 
     private static final int APK_SIGNATURE_SCHEME_V3_BLOCK_ID = 0xf05368c0;
+    private static final int APK_SIGNATURE_SCHEME_V31_BLOCK_ID = 0x1b93ad61;
 
     /**
      * Returns {@code true} if the provided APK contains an APK Signature Scheme V3 signature.
@@ -133,8 +135,23 @@
      */
     private static VerifiedSigner verify(RandomAccessFile apk, boolean verifyIntegrity)
             throws SignatureNotFoundException, SecurityException, IOException {
-        SignatureInfo signatureInfo = findSignature(apk);
-        return verify(apk, signatureInfo, verifyIntegrity);
+        ApkSignatureSchemeV3Verifier verifier = new ApkSignatureSchemeV3Verifier(apk,
+                verifyIntegrity);
+        try {
+            SignatureInfo signatureInfo = findSignature(apk, APK_SIGNATURE_SCHEME_V31_BLOCK_ID);
+            return verifier.verify(signatureInfo, APK_SIGNATURE_SCHEME_V31_BLOCK_ID);
+        } catch (SignatureNotFoundException ignored) {
+            // This is expected if the APK is not using v3.1 to target rotation.
+        } catch (PlatformNotSupportedException ignored) {
+            // This is expected if the APK is targeting a platform version later than that of the
+            // device for rotation.
+        }
+        try {
+            SignatureInfo signatureInfo = findSignature(apk, APK_SIGNATURE_SCHEME_V3_BLOCK_ID);
+            return verifier.verify(signatureInfo, APK_SIGNATURE_SCHEME_V3_BLOCK_ID);
+        } catch (PlatformNotSupportedException e) {
+            throw new SecurityException(e);
+        }
     }
 
     /**
@@ -146,7 +163,31 @@
      */
     public static SignatureInfo findSignature(RandomAccessFile apk)
             throws IOException, SignatureNotFoundException {
-        return ApkSigningBlockUtils.findSignature(apk, APK_SIGNATURE_SCHEME_V3_BLOCK_ID);
+        return findSignature(apk, APK_SIGNATURE_SCHEME_V3_BLOCK_ID);
+    }
+
+    /*
+     * Returns the APK Signature Scheme v3 block in the provided {@code apk} file with the specified
+     * {@code blockId} and the additional information relevant for verifying the block against the
+     * file.
+     *
+     * @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v3
+     * @throws IOException                if an I/O error occurs while reading the APK file
+     **/
+    private static SignatureInfo findSignature(RandomAccessFile apk, int blockId)
+            throws IOException, SignatureNotFoundException {
+        return ApkSigningBlockUtils.findSignature(apk, blockId);
+    }
+
+    private final RandomAccessFile mApk;
+    private final boolean mVerifyIntegrity;
+    private OptionalInt mOptionalRotationMinSdkVersion = OptionalInt.empty();
+    private int mSignerMinSdkVersion;
+    private int mBlockId;
+
+    private ApkSignatureSchemeV3Verifier(RandomAccessFile apk, boolean verifyIntegrity) {
+        mApk = apk;
+        mVerifyIntegrity = verifyIntegrity;
     }
 
     /**
@@ -156,10 +197,9 @@
      * @param signatureInfo APK Signature Scheme v3 Block and information relevant for verifying it
      *                      against the APK file.
      */
-    private static VerifiedSigner verify(
-            RandomAccessFile apk,
-            SignatureInfo signatureInfo,
-            boolean doVerifyIntegrity) throws SecurityException, IOException {
+    private VerifiedSigner verify(SignatureInfo signatureInfo, int blockId)
+            throws SecurityException, IOException, PlatformNotSupportedException {
+        mBlockId = blockId;
         int signerCount = 0;
         Map<Integer, byte[]> contentDigests = new ArrayMap<>();
         Pair<X509Certificate[], ApkSigningBlockUtils.VerifiedProofOfRotation> result = null;
@@ -191,7 +231,13 @@
         }
 
         if (signerCount < 1 || result == null) {
-            throw new SecurityException("No signers found");
+            // There must always be a valid signer targeting the device SDK version for a v3.0
+            // signature.
+            if (blockId == APK_SIGNATURE_SCHEME_V3_BLOCK_ID) {
+                throw new SecurityException("No signers found");
+            }
+            throw new PlatformNotSupportedException(
+                    "None of the signers support the current platform version");
         }
 
         if (signerCount != 1) {
@@ -203,21 +249,21 @@
             throw new SecurityException("No content digests found");
         }
 
-        if (doVerifyIntegrity) {
-            ApkSigningBlockUtils.verifyIntegrity(contentDigests, apk, signatureInfo);
+        if (mVerifyIntegrity) {
+            ApkSigningBlockUtils.verifyIntegrity(contentDigests, mApk, signatureInfo);
         }
 
         byte[] verityRootHash = null;
         if (contentDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) {
             byte[] verityDigest = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256);
             verityRootHash = ApkSigningBlockUtils.parseVerityDigestAndVerifySourceLength(
-                    verityDigest, apk.getChannel().size(), signatureInfo);
+                    verityDigest, mApk.getChannel().size(), signatureInfo);
         }
 
         return new VerifiedSigner(result.first, result.second, verityRootHash, contentDigests);
     }
 
-    private static Pair<X509Certificate[], ApkSigningBlockUtils.VerifiedProofOfRotation>
+    private Pair<X509Certificate[], ApkSigningBlockUtils.VerifiedProofOfRotation>
             verifySigner(
                 ByteBuffer signerBlock,
                 Map<Integer, byte[]> contentDigests,
@@ -228,6 +274,14 @@
         int maxSdkVersion = signerBlock.getInt();
 
         if (Build.VERSION.SDK_INT < minSdkVersion || Build.VERSION.SDK_INT > maxSdkVersion) {
+            // if this is a v3.1 block then save the minimum SDK version for rotation for comparison
+            // against the v3.0 additional attribute.
+            if (mBlockId == APK_SIGNATURE_SCHEME_V31_BLOCK_ID) {
+                if (!mOptionalRotationMinSdkVersion.isPresent()
+                        || mOptionalRotationMinSdkVersion.getAsInt() > minSdkVersion) {
+                    mOptionalRotationMinSdkVersion = OptionalInt.of(minSdkVersion);
+                }
+            }
             // this signature isn't meant to be used with this platform, skip it.
             throw new PlatformNotSupportedException(
                     "Signer not supported by this platform "
@@ -370,6 +424,7 @@
             throw new SecurityException(
                     "minSdkVersion mismatch between signed and unsigned in v3 signer block.");
         }
+        mSignerMinSdkVersion = signedMinSDK;
 
         int signedMaxSDK = signedData.getInt();
         if (signedMaxSDK != maxSdkVersion) {
@@ -382,10 +437,12 @@
     }
 
     private static final int PROOF_OF_ROTATION_ATTR_ID = 0x3ba06f8c;
+    private static final int ROTATION_MIN_SDK_VERSION_ATTR_ID = 0x559f8b02;
+    private static final int ROTATION_ON_DEV_RELEASE_ATTR_ID = 0xc2a6b3ba;
 
-    private static Pair<X509Certificate[], ApkSigningBlockUtils.VerifiedProofOfRotation>
+    private Pair<X509Certificate[], ApkSigningBlockUtils.VerifiedProofOfRotation>
             verifyAdditionalAttributes(ByteBuffer attrs, List<X509Certificate> certs,
-                CertificateFactory certFactory) throws IOException {
+                CertificateFactory certFactory) throws IOException, PlatformNotSupportedException {
         X509Certificate[] certChain = certs.toArray(new X509Certificate[certs.size()]);
         ApkSigningBlockUtils.VerifiedProofOfRotation por = null;
 
@@ -418,6 +475,49 @@
                     }
 
                     break;
+                case ROTATION_MIN_SDK_VERSION_ATTR_ID:
+                    if (attr.remaining() < 4) {
+                        throw new IOException(
+                                "Remaining buffer too short to contain rotation minSdkVersion "
+                                        + "value. Remaining: "
+                                        + attr.remaining());
+                    }
+                    int attrRotationMinSdkVersion = attr.getInt();
+                    if (!mOptionalRotationMinSdkVersion.isPresent()) {
+                        throw new SecurityException(
+                                "Expected a v3.1 signing block targeting SDK version "
+                                        + attrRotationMinSdkVersion
+                                        + ", but a v3.1 block was not found");
+                    }
+                    int rotationMinSdkVersion = mOptionalRotationMinSdkVersion.getAsInt();
+                    if (rotationMinSdkVersion != attrRotationMinSdkVersion) {
+                        throw new SecurityException(
+                                "Expected a v3.1 signing block targeting SDK version "
+                                        + attrRotationMinSdkVersion
+                                        + ", but the v3.1 block was targeting "
+                                        + rotationMinSdkVersion);
+                    }
+                    break;
+                case ROTATION_ON_DEV_RELEASE_ATTR_ID:
+                    // This attribute should only be used in a v3.1 signer as it allows the v3.1
+                    // signature scheme to target a platform under development.
+                    if (mBlockId == APK_SIGNATURE_SCHEME_V31_BLOCK_ID) {
+                        // A platform under development uses the same SDK version as the most
+                        // recently released platform; if this platform's SDK version is the same as
+                        // the minimum of the signer, then only allow this signer to be used if this
+                        // is not a "REL" platform.
+                        if (Build.VERSION.SDK_INT == mSignerMinSdkVersion
+                                && "REL".equals(Build.VERSION.CODENAME)) {
+                            // Set the rotation-min-sdk-version to be verified against the stripping
+                            // attribute in the v3.0 block.
+                            mOptionalRotationMinSdkVersion = OptionalInt.of(mSignerMinSdkVersion);
+                            throw new PlatformNotSupportedException(
+                                    "The device is running a release version of "
+                                            + mSignerMinSdkVersion
+                                            + ", but the signer is targeting a dev release");
+                        }
+                    }
+                    break;
                 default:
                     // not the droid we're looking for, move along, move along.
                     break;
diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java
index bcc5b56..b2fc9a0 100644
--- a/core/java/android/view/AttachedSurfaceControl.java
+++ b/core/java/android/view/AttachedSurfaceControl.java
@@ -53,4 +53,72 @@
      * to the View hierarchy you may need to call {@link android.view.View#invalidate}
      */
     boolean applyTransactionOnDraw(@NonNull SurfaceControl.Transaction t);
+
+    /**
+     * The transform hint can be used by a buffer producer to pre-rotate the rendering such that the
+     * final transformation in the system composer is identity. This can be very useful when used in
+     * conjunction with the h/w composer HAL in situations where it cannot handle rotations or
+     * handle them with an additional power cost.
+     *
+     * The transform hint should be used with ASurfaceControl APIs when submitting buffers.
+     * Example usage:
+     *
+     * 1. After a configuration change, before dequeuing a buffer, the buffer producer queries the
+     *    function for the transform hint.
+     *
+     * 2. The desired buffer width and height is rotated by the transform hint.
+     *
+     * 3. The producer dequeues a buffer of the new pre-rotated size.
+     *
+     * 4. The producer renders to the buffer such that the image is already transformed, that is
+     *    applying the transform hint to the rendering.
+     *
+     * 5. The producer applies the inverse transform hint to the buffer it just rendered.
+     *
+     * 6. The producer queues the pre-transformed buffer with the buffer transform.
+     *
+     * 7. The composer combines the buffer transform with the display transform.  If the buffer
+     *    transform happens to cancel out the display transform then no rotation is needed and there
+     *    will be no performance penalties.
+     *
+     * Note, when using ANativeWindow APIs in conjunction with a NativeActivity Surface or
+     * SurfaceView Surface, the buffer producer will already have access to the transform hint and
+     * no additional work is needed.
+     */
+    default @Surface.Rotation int getSurfaceTransformHint() {
+        return Surface.ROTATION_0;
+    }
+
+    /**
+     * Surface transform hint change listener.
+     * @see #getSurfaceTransformHint
+     */
+    @UiThread
+    interface OnSurfaceTransformHintChangedListener {
+        /**
+         * @param hint new surface transform hint
+         * @see #getSurfaceTransformHint
+         */
+        void onSurfaceTransformHintChanged(@Surface.Rotation int hint);
+    }
+
+    /**
+     * Registers a surface transform hint changed listener to receive notifications about when
+     * the transform hint changes.
+     *
+     * @see #getSurfaceTransformHint
+     * @see #removeOnSurfaceTransformHintChangedListener
+     */
+    default void addOnSurfaceTransformHintChangedListener(
+            @NonNull OnSurfaceTransformHintChangedListener listener) {
+    }
+
+    /**
+     * Unregisters a surface transform hint changed listener.
+     *
+     * @see #addOnSurfaceTransformHintChangedListener
+     */
+    default void removeOnSurfaceTransformHintChangedListener(
+            @NonNull OnSurfaceTransformHintChangedListener listener) {
+    }
 }
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index a6abed0..9da5088 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -175,6 +175,11 @@
             float touchX, float touchY, float thumbCenterX, float thumbCenterY, in ClipData data);
 
     /**
+     * Drops the content of the current drag operation for accessibility
+     */
+    boolean dropForAccessibility(IWindow window, int x, int y);
+
+    /**
      * Report the result of a drop action targeted to the given window.
      * consumed is 'true' when the drop was accepted by a valid recipient,
      * 'false' otherwise.
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index cdf1e46..2b5e286 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -83,6 +83,7 @@
 per-file ViewRootInsetsControllerHost.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file Window*.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file Window*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
+per-file TransactionCommittedCallback.java = file:/services/core/java/com/android/server/wm/OWNERS
 
 # Scroll Capture
 per-file *ScrollCapture*.aidl = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index a563d09..1a79e4c 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -26,6 +26,7 @@
 import static android.view.SurfaceControlProto.LAYER_ID;
 import static android.view.SurfaceControlProto.NAME;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.FloatRange;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
@@ -74,6 +75,7 @@
 import java.util.Arrays;
 import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -160,6 +162,7 @@
     private static native boolean nativeGetAnimationFrameStats(WindowAnimationFrameStats outStats);
 
     private static native long[] nativeGetPhysicalDisplayIds();
+    private static native long nativeGetPrimaryPhysicalDisplayId();
     private static native IBinder nativeGetPhysicalDisplayToken(long physicalDisplayId);
     private static native IBinder nativeCreateDisplay(String name, boolean secure);
     private static native void nativeDestroyDisplay(IBinder displayToken);
@@ -243,6 +246,8 @@
     private static native void nativeSetTransformHint(long nativeObject, int transformHint);
     private static native int nativeGetTransformHint(long nativeObject);
     private static native int nativeGetLayerId(long nativeObject);
+    private static native void nativeAddTransactionCommittedListener(long nativeObject,
+            TransactionCommittedListener listener);
 
     @Nullable
     @GuardedBy("mLock")
@@ -2275,6 +2280,15 @@
     }
 
     /**
+     * Exposed to identify the correct display to apply the primary display orientation. Avoid using
+     * for any other purpose.
+     * @hide
+     */
+    public static long getPrimaryPhysicalDisplayId() {
+        return nativeGetPrimaryPhysicalDisplayId();
+    }
+
+    /**
      * @hide
      */
     public static IBinder getPhysicalDisplayToken(long physicalDisplayId) {
@@ -3509,6 +3523,31 @@
         }
 
         /**
+         * Request to add a {@link TransactionCommittedListener}.
+         *
+         * The callback is invoked when transaction is applied and the updates are ready to be
+         * presented. This callback does not mean buffers have been released! It simply means that
+         * any new transactions applied will not overwrite the transaction for which we are
+         * receiving a callback and instead will be included in the next frame. If you are trying
+         * to avoid dropping frames (overwriting transactions), and unable to use timestamps (Which
+         * provide a more efficient solution), then this method provides a method to pace your
+         * transaction application.
+         *
+         * @param executor The executor that the callback should be invoked on.
+         * @param listener The callback that will be invoked when the transaction has been
+         *                 committed.
+         */
+        @NonNull
+        public Transaction addTransactionCommittedListener(
+                @NonNull @CallbackExecutor Executor executor,
+                @NonNull TransactionCommittedListener listener) {
+            TransactionCommittedListener listenerInner =
+                    () -> executor.execute(listener::onTransactionCommitted);
+            nativeAddTransactionCommittedListener(mNativeObject, listenerInner);
+            return this;
+        }
+
+        /**
          * Writes the transaction to parcel, clearing the transaction as if it had been applied so
          * it can be used to store future transactions. It's the responsibility of the parcel
          * reader to apply the original transaction.
diff --git a/core/java/android/view/TransactionCommittedListener.java b/core/java/android/view/TransactionCommittedListener.java
new file mode 100644
index 0000000..6abded2
--- /dev/null
+++ b/core/java/android/view/TransactionCommittedListener.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Interface to handle request to
+ * {@link SurfaceControl.Transaction#addTransactionCommittedListener(Executor, TransactionCommittedListener)}
+ */
+public interface TransactionCommittedListener {
+    /**
+     * Invoked when the transaction has been committed in SurfaceFlinger.
+     */
+    void onTransactionCommitted();
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3924e9b..96a2449 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3515,6 +3515,7 @@
      *                    1             PFLAG4_ALLOW_CLICK_WHEN_DISABLED
      *                   1              PFLAG4_DETACHED
      *                  1               PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE
+     *                 1                PFLAG4_DRAG_A11Y_STARTED
      * |-------|-------|-------|-------|
      */
 
@@ -3586,6 +3587,11 @@
      */
     private static final int PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE = 0x000004000;
 
+    /**
+     * Indicates that the view has started a drag with {@link AccessibilityAction#ACTION_DRAG_START}
+     */
+    private static final int PFLAG4_DRAG_A11Y_STARTED = 0x000008000;
+
     /* End of masks for mPrivateFlags4 */
 
     /** @hide */
@@ -10395,8 +10401,17 @@
         if (mTouchDelegate != null) {
             info.setTouchDelegateInfo(mTouchDelegate.getTouchDelegateInfo());
         }
+
+        if (startedSystemDragForAccessibility()) {
+            info.addAction(AccessibilityAction.ACTION_DRAG_CANCEL);
+        }
+
+        if (canAcceptAccessibilityDrop()) {
+            info.addAction(AccessibilityAction.ACTION_DRAG_DROP);
+        }
     }
 
+
     /**
      * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the
      * additional data.
@@ -14233,9 +14248,45 @@
                 return true;
             }
         }
+
+        if (action == R.id.accessibilityActionDragDrop) {
+            if (!canAcceptAccessibilityDrop()) {
+                return false;
+            }
+            try {
+                if (mAttachInfo != null && mAttachInfo.mSession != null) {
+                    final int[] location = new int[2];
+                    getLocationInWindow(location);
+                    final int centerX = location[0] + getWidth() / 2;
+                    final int centerY = location[1] + getHeight() / 2;
+                    return mAttachInfo.mSession.dropForAccessibility(mAttachInfo.mWindow,
+                            centerX, centerY);
+                }
+            } catch (RemoteException e) {
+                Log.e(VIEW_LOG_TAG, "Unable to drop for accessibility", e);
+            }
+            return false;
+        } else if (action == R.id.accessibilityActionDragCancel) {
+            if (!startedSystemDragForAccessibility()) {
+                return false;
+            }
+            if (mAttachInfo != null && mAttachInfo.mDragToken != null) {
+                cancelDragAndDrop();
+                return true;
+            }
+            return false;
+        }
         return false;
     }
 
+    private boolean canAcceptAccessibilityDrop() {
+        if (!canAcceptDrag()) {
+            return false;
+        }
+        ListenerInfo li = mListenerInfo;
+        return (li != null) && (li.mOnDragListener != null || li.mOnReceiveContentListener != null);
+    }
+
     private boolean traverseAtGranularity(int granularity, boolean forward,
             boolean extendSelection) {
         CharSequence text = getIterableTextForAccessibility();
@@ -26681,6 +26732,37 @@
             data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0);
         }
 
+        Rect bounds = new Rect();
+        getBoundsOnScreen(bounds, true);
+
+        Point lastTouchPoint = new Point();
+        mAttachInfo.mViewRootImpl.getLastTouchPoint(lastTouchPoint);
+        final ViewRootImpl root = mAttachInfo.mViewRootImpl;
+
+        // Skip surface logic since shadows and animation are not required during the a11y drag
+        final boolean a11yEnabled = AccessibilityManager.getInstance(mContext).isEnabled();
+        if (a11yEnabled && (flags & View.DRAG_FLAG_ACCESSIBILITY_ACTION) != 0) {
+            try {
+                IBinder token = mAttachInfo.mSession.performDrag(
+                        mAttachInfo.mWindow, flags, null,
+                        mAttachInfo.mViewRootImpl.getLastTouchSource(),
+                        0f, 0f, 0f, 0f, data);
+                if (ViewDebug.DEBUG_DRAG) {
+                    Log.d(VIEW_LOG_TAG, "startDragAndDrop via a11y action returned " + token);
+                }
+                if (token != null) {
+                    root.setLocalDragState(myLocalState);
+                    mAttachInfo.mDragToken = token;
+                    mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this);
+                    setAccessibilityDragStarted(true);
+                }
+                return token != null;
+            } catch (Exception e) {
+                Log.e(VIEW_LOG_TAG, "Unable to initiate a11y drag", e);
+                return false;
+            }
+        }
+
         Point shadowSize = new Point();
         Point shadowTouchPoint = new Point();
         shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint);
@@ -26705,7 +26787,6 @@
                     + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y);
         }
 
-        final ViewRootImpl root = mAttachInfo.mViewRootImpl;
         final SurfaceSession session = new SurfaceSession();
         final SurfaceControl surfaceControl = new SurfaceControl.Builder(session)
                 .setName("drag surface")
@@ -26728,12 +26809,9 @@
                 surface.unlockCanvasAndPost(canvas);
             }
 
-            // repurpose 'shadowSize' for the last touch point
-            root.getLastTouchPoint(shadowSize);
-
-            token = mAttachInfo.mSession.performDrag(
-                    mAttachInfo.mWindow, flags, surfaceControl, root.getLastTouchSource(),
-                    shadowSize.x, shadowSize.y, shadowTouchPoint.x, shadowTouchPoint.y, data);
+            token = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, flags, surfaceControl,
+                    root.getLastTouchSource(), lastTouchPoint.x, lastTouchPoint.y,
+                    shadowTouchPoint.x, shadowTouchPoint.y, data);
             if (ViewDebug.DEBUG_DRAG) {
                 Log.d(VIEW_LOG_TAG, "performDrag returned " + token);
             }
@@ -26745,6 +26823,10 @@
                 mAttachInfo.mDragToken = token;
                 // Cache the local state object for delivery with DragEvents
                 root.setLocalDragState(myLocalState);
+                if (a11yEnabled) {
+                    // Set for AccessibilityEvents
+                    mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this);
+                }
             }
             return token != null;
         } catch (Exception e) {
@@ -26758,6 +26840,24 @@
         }
     }
 
+    void setAccessibilityDragStarted(boolean started) {
+        int pflags4 = mPrivateFlags4;
+        if (started) {
+            pflags4 |= PFLAG4_DRAG_A11Y_STARTED;
+        } else {
+            pflags4 &= ~PFLAG4_DRAG_A11Y_STARTED;
+        }
+
+        if (pflags4 != mPrivateFlags4) {
+            mPrivateFlags4 = pflags4;
+            sendWindowContentChangedAccessibilityEvent(CONTENT_CHANGE_TYPE_UNDEFINED);
+        }
+    }
+
+    private boolean startedSystemDragForAccessibility() {
+        return (mPrivateFlags4 & PFLAG4_DRAG_A11Y_STARTED) != 0;
+    }
+
     /**
      * Cancels an ongoing drag and drop operation.
      * <p>
@@ -26975,6 +27075,12 @@
         }
 
         switch (event.mAction) {
+            case DragEvent.ACTION_DRAG_STARTED: {
+                if (result && li.mOnDragListener != null) {
+                    sendWindowContentChangedAccessibilityEvent(
+                            AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+                }
+            } break;
             case DragEvent.ACTION_DRAG_ENTERED: {
                 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
                 refreshDrawableState();
@@ -26983,7 +27089,15 @@
                 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
                 refreshDrawableState();
             } break;
+            case DragEvent.ACTION_DROP: {
+                if (result && (li.mOnDragListener != null | li.mOnReceiveContentListener != null)) {
+                    sendWindowContentChangedAccessibilityEvent(
+                            AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_DROPPED);
+                }
+            } break;
             case DragEvent.ACTION_DRAG_ENDED: {
+                sendWindowContentChangedAccessibilityEvent(
+                        AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
                 mPrivateFlags2 &= ~View.DRAG_MASK;
                 refreshDrawableState();
             } break;
@@ -26996,6 +27110,15 @@
         return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0;
     }
 
+    void sendWindowContentChangedAccessibilityEvent(int changeType) {
+        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+            AccessibilityEvent event = AccessibilityEvent.obtain();
+            event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+            event.setContentChangeTypes(changeType);
+            sendAccessibilityEventUnchecked(event);
+        }
+    }
+
     /**
      * This needs to be a better API (NOT ON VIEW) before it is exposed.  If
      * it is ever exposed at all.
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 775c15e..49f5229 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -412,6 +412,9 @@
      *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_SUBTREE}
      *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_TEXT}
      *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED}
+     *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_STARTED}
+     *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_CANCELLED}
+     *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_DROPPED}
      *            </ul>
      */
     public void notifySubtreeAccessibilityStateChanged(
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0dd6e22..9710be5 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -312,6 +312,9 @@
     static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<>();
     static boolean sFirstDrawComplete = false;
 
+    private ArrayList<OnSurfaceTransformHintChangedListener> mTransformHintListeners =
+            new ArrayList<>();
+    private @Surface.Rotation int mPreviousTransformHint = Surface.ROTATION_0;
     /**
      * Callback for notifying about global configuration changes.
      */
@@ -647,6 +650,7 @@
     /* Drag/drop */
     ClipDescription mDragDescription;
     View mCurrentDragView;
+    View mStartedDragViewForA11y;
     volatile Object mLocalDragState;
     final PointF mDragPoint = new PointF();
     final PointF mLastTouchPoint = new PointF();
@@ -4269,6 +4273,14 @@
         try {
             if (!isContentCaptureEnabled()) return;
 
+            // Initial dispatch of window bounds to content capture
+            if (mAttachInfo.mContentCaptureManager != null) {
+                MainContentCaptureSession session =
+                        mAttachInfo.mContentCaptureManager.getMainContentCaptureSession();
+                session.notifyWindowBoundsChanged(session.getId(),
+                        getConfiguration().windowConfiguration.getBounds());
+            }
+
             // Content capture is a go!
             rootView.dispatchInitialProvideContentCaptureStructure();
         } finally {
@@ -7572,6 +7584,11 @@
             if (what == DragEvent.ACTION_DRAG_STARTED) {
                 mCurrentDragView = null;    // Start the current-recipient tracking
                 mDragDescription = event.mClipDescription;
+                if (mStartedDragViewForA11y != null) {
+                    // Send a drag started a11y event
+                    mStartedDragViewForA11y.sendWindowContentChangedAccessibilityEvent(
+                            AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_STARTED);
+                }
             } else {
                 if (what == DragEvent.ACTION_DRAG_ENDED) {
                     mDragDescription = null;
@@ -7646,6 +7663,16 @@
 
                 // When the drag operation ends, reset drag-related state
                 if (what == DragEvent.ACTION_DRAG_ENDED) {
+                    if (mStartedDragViewForA11y != null) {
+                        // If the drag failed, send a cancelled event from the source. Otherwise,
+                        // the View that accepted the drop sends CONTENT_CHANGE_TYPE_DRAG_DROPPED
+                        if (!event.getResult()) {
+                            mStartedDragViewForA11y.sendWindowContentChangedAccessibilityEvent(
+                                    AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_CANCELLED);
+                        }
+                        mStartedDragViewForA11y.setAccessibilityDragStarted(false);
+                    }
+                    mStartedDragViewForA11y = null;
                     mCurrentDragView = null;
                     setLocalDragState(null);
                     mAttachInfo.mDragToken = null;
@@ -7725,6 +7752,13 @@
         mCurrentDragView = newDragTarget;
     }
 
+    /** Sets the view that started drag and drop for the purpose of sending AccessibilityEvents */
+    void setDragStartedViewForAccessibility(View view) {
+        if (mStartedDragViewForA11y == null) {
+            mStartedDragViewForA11y = view;
+        }
+    }
+
     private AudioManager getAudioManager() {
         if (mView == null) {
             throw new IllegalStateException("getAudioManager called when there is no mView");
@@ -7803,6 +7837,14 @@
                 insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
                 mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
                 mTempControls, mSurfaceSize);
+
+        if (mAttachInfo.mContentCaptureManager != null) {
+            MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
+                    .getMainContentCaptureSession();
+            mainSession.notifyWindowBoundsChanged(mainSession.getId(),
+                    getConfiguration().windowConfiguration.getBounds());
+        }
+
         mPendingBackDropFrame.set(mTmpFrames.backdropFrame);
         if (mSurfaceControl.isValid()) {
             if (!useBLAST()) {
@@ -7820,6 +7862,11 @@
                 mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl);
                 mAttachInfo.mThreadedRenderer.setBlastBufferQueue(mBlastBufferQueue);
             }
+            int transformHint = mSurfaceControl.getTransformHint();
+            if (mPreviousTransformHint != transformHint) {
+                mPreviousTransformHint = transformHint;
+                dispatchTransformHintChanged(transformHint);
+            }
         } else {
             destroySurface();
         }
@@ -10442,7 +10489,39 @@
         return true;
     }
 
-    int getSurfaceTransformHint() {
+    @Override
+    public @Surface.Rotation int getSurfaceTransformHint() {
         return mSurfaceControl.getTransformHint();
     }
+
+    @Override
+    public void addOnSurfaceTransformHintChangedListener(
+            OnSurfaceTransformHintChangedListener listener) {
+        Objects.requireNonNull(listener);
+        if (mTransformHintListeners.contains(listener)) {
+            throw new IllegalArgumentException(
+                    "attempt to call addOnSurfaceTransformHintChangedListener() "
+                            + "with a previously registered listener");
+        }
+        mTransformHintListeners.add(listener);
+    }
+
+    @Override
+    public void removeOnSurfaceTransformHintChangedListener(
+            OnSurfaceTransformHintChangedListener listener) {
+        Objects.requireNonNull(listener);
+        mTransformHintListeners.remove(listener);
+    }
+
+    private void dispatchTransformHintChanged(@Surface.Rotation int hint) {
+        if (mTransformHintListeners.isEmpty()) {
+            return;
+        }
+        ArrayList<OnSurfaceTransformHintChangedListener> listeners =
+                (ArrayList<OnSurfaceTransformHintChangedListener>) mTransformHintListeners.clone();
+        for (int i = 0; i < listeners.size(); i++) {
+            OnSurfaceTransformHintChangedListener listener = listeners.get(i);
+            listener.onSurfaceTransformHintChanged(hint);
+        }
+    }
 }
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index c413a9b..ffb7efa 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -498,4 +498,9 @@
     public void generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm,
             RemoteCallback callback) {
     }
+
+    @Override
+    public boolean dropForAccessibility(IWindow window, int x, int y) {
+        return false;
+    }
 }
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 0606b5c..bb3f4e5 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -23,6 +23,7 @@
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.AccessibilityServiceInfo.FeedbackType;
 import android.accessibilityservice.AccessibilityShortcutInfo;
+import android.annotation.CallbackExecutor;
 import android.annotation.ColorInt;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -36,7 +37,6 @@
 import android.app.RemoteAction;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -47,6 +47,7 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
@@ -55,7 +56,6 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseArray;
@@ -75,6 +75,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
  * System level service that serves as an event dispatch for {@link AccessibilityEvent}s,
@@ -265,7 +266,7 @@
     private final ArrayMap<HighTextContrastChangeListener, Handler>
             mHighTextContrastStateChangeListeners = new ArrayMap<>();
 
-    private final ArrayMap<AccessibilityServicesStateChangeListener, Handler>
+    private final ArrayMap<AccessibilityServicesStateChangeListener, Executor>
             mServicesStateChangeListeners = new ArrayMap<>();
 
     /**
@@ -273,8 +274,6 @@
      */
     private SparseArray<List<AccessibilityRequestPreparer>> mRequestPreparerLists;
 
-    private ContentResolver mContentResolver;
-
     /**
      * Listener for the system accessibility state. To listen for changes to the
      * accessibility state on the device, implement this interface and register
@@ -307,13 +306,20 @@
     }
 
     /**
-     * Listener for changes to the state of accessibility services. Changes include services being
-     * enabled or disabled, or changes to the {@link AccessibilityServiceInfo} of a running service.
-     * {@see #addAccessibilityServicesStateChangeListener}.
+     * Listener for changes to the state of accessibility services.
      *
-     * @hide
+     * <p>
+     * This refers to changes to {@link AccessibilityServiceInfo}, including:
+     * <ul>
+     *     <li>Whenever a service is enabled or disabled, or its info has been set or removed.</li>
+     *     <li>Whenever a metadata attribute of any running service's info changes.</li>
+     * </ul>
+     *
+     * @see #getEnabledAccessibilityServiceList for a list of infos of the enabled accessibility
+     * services.
+     * @see #addAccessibilityServicesStateChangeListener
+     *
      */
-    @TestApi
     public interface AccessibilityServicesStateChangeListener {
 
         /**
@@ -321,7 +327,7 @@
          *
          * @param manager The manager that is calling back
          */
-        void onAccessibilityServicesStateChanged(AccessibilityManager manager);
+        void onAccessibilityServicesStateChanged(@NonNull  AccessibilityManager manager);
     }
 
     /**
@@ -413,7 +419,7 @@
         public void notifyServicesStateChanged(long updatedUiTimeout) {
             updateUiTimeout(updatedUiTimeout);
 
-            final ArrayMap<AccessibilityServicesStateChangeListener, Handler> listeners;
+            final ArrayMap<AccessibilityServicesStateChangeListener, Executor> listeners;
             synchronized (mLock) {
                 if (mServicesStateChangeListeners.isEmpty()) {
                     return;
@@ -425,7 +431,7 @@
             for (int i = 0; i < numListeners; i++) {
                 final AccessibilityServicesStateChangeListener listener =
                         mServicesStateChangeListeners.keyAt(i);
-                mServicesStateChangeListeners.valueAt(i).post(() -> listener
+                mServicesStateChangeListeners.valueAt(i).execute(() -> listener
                         .onAccessibilityServicesStateChanged(AccessibilityManager.this));
             }
         }
@@ -487,7 +493,6 @@
         mCallback = new MyCallback();
         mHandler = new Handler(context.getMainLooper(), mCallback);
         mUserId = userId;
-        mContentResolver = context.getContentResolver();
         synchronized (mLock) {
             initialFocusAppearanceLocked(context.getResources());
             tryConnectToServiceLocked(service);
@@ -512,7 +517,6 @@
         mCallback = new MyCallback();
         mHandler = handler;
         mUserId = userId;
-        mContentResolver = context.getContentResolver();
         synchronized (mLock) {
             initialFocusAppearanceLocked(context.getResources());
             if (serviceConnect) {
@@ -920,32 +924,39 @@
     /**
      * Registers a {@link AccessibilityServicesStateChangeListener}.
      *
+     * @param executor The executor.
      * @param listener The listener.
-     * @param handler The handler on which the listener should be called back, or {@code null}
-     *                for a callback on the process's main handler.
-     * @hide
      */
-    @TestApi
     public void addAccessibilityServicesStateChangeListener(
-            @NonNull AccessibilityServicesStateChangeListener listener, @Nullable Handler handler) {
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull AccessibilityServicesStateChangeListener listener) {
         synchronized (mLock) {
-            mServicesStateChangeListeners
-                    .put(listener, (handler == null) ? mHandler : handler);
+            mServicesStateChangeListeners.put(listener, executor);
         }
     }
 
     /**
+     * Registers a {@link AccessibilityServicesStateChangeListener}. This will execute a callback on
+     * the process's main handler.
+     *
+     * @param listener The listener.
+     *
+     */
+    public void addAccessibilityServicesStateChangeListener(
+            @NonNull AccessibilityServicesStateChangeListener listener) {
+        addAccessibilityServicesStateChangeListener(new HandlerExecutor(mHandler), listener);
+    }
+
+    /**
      * Unregisters a {@link AccessibilityServicesStateChangeListener}.
      *
      * @param listener The listener.
-     *
-     * @hide
+     * @return {@code true} if the listener was previously registered.
      */
-    @TestApi
-    public void removeAccessibilityServicesStateChangeListener(
+    public boolean removeAccessibilityServicesStateChangeListener(
             @NonNull AccessibilityServicesStateChangeListener listener) {
         synchronized (mLock) {
-            mServicesStateChangeListeners.remove(listener);
+            return mServicesStateChangeListeners.remove(listener) != null;
         }
     }
 
@@ -1826,25 +1837,6 @@
         return res.getBoolean(com.android.internal.R.bool.config_showNavigationBar);
     }
 
-    /**
-     * Determines if users want to select sound track with audio description by default.
-     *
-     * Audio description, also referred to as a video description, described video, or
-     * more precisely called a visual description, is a form of narration used to provide
-     * information surrounding key visual elements in a media work for the benefit of
-     * blind and visually impaired consumers.
-     *
-     * The method provides the preference value to content provider apps to select the
-     * default sound track during playing a video or movie.
-     *
-     * @return {@code true} if the audio description is enabled, {@code false} otherwise.
-     */
-    public boolean isAudioDescriptionEnabled() {
-        return Settings.Secure.getInt(
-                mContentResolver,
-                Settings.Secure.ENABLE_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT, 0) == 1;
-    }
-
     private final class MyCallback implements Handler.Callback {
         public static final int MSG_SET_STATE = 1;
 
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index b296d6f..b1d618e 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -19,7 +19,6 @@
 import android.annotation.AnimRes;
 import android.annotation.ColorInt;
 import android.annotation.InterpolatorRes;
-import android.app.ActivityThread;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
@@ -259,6 +258,8 @@
 
         setZAdjustment(a.getInt(com.android.internal.R.styleable.Animation_zAdjustment, ZORDER_NORMAL));
 
+        setBackgroundColor(a.getInt(com.android.internal.R.styleable.Animation_background, 0));
+
         setDetachWallpaper(
                 a.getBoolean(com.android.internal.R.styleable.Animation_detachWallpaper, false));
         setShowWallpaper(
@@ -270,15 +271,6 @@
 
         a.recycle();
 
-        Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
-        TypedArray uiStyledAttrs = uiContext
-                .obtainStyledAttributes(attrs, com.android.internal.R.styleable.Animation);
-
-        setBackgroundColor(
-                uiStyledAttrs.getColor(com.android.internal.R.styleable.Animation_background, 0));
-
-        uiStyledAttrs.recycle();
-
         if (resID > 0) {
             setInterpolator(context, resID);
         }
@@ -640,15 +632,16 @@
     }
 
     /**
-     * Set background behind an animation.
+     * Set background behind animation.
      *
-     * @param bg The background color. If 0, no background.
+     * @param bg The background color.  If 0, no background.  Currently must
+     * be black, with any desired alpha level.
      *
      * @deprecated None of window animations are running with background color.
      */
     @Deprecated
     public void setBackgroundColor(@ColorInt int bg) {
-        mBackgroundColor = bg;
+        // The background color is not needed any more, do nothing.
     }
 
     /**
@@ -810,7 +803,7 @@
     @Deprecated
     @ColorInt
     public int getBackgroundColor() {
-        return mBackgroundColor;
+        return 0;
     }
 
     /**
diff --git a/core/java/android/view/animation/TranslateAnimation.java b/core/java/android/view/animation/TranslateAnimation.java
index ec55a02..3365c70 100644
--- a/core/java/android/view/animation/TranslateAnimation.java
+++ b/core/java/android/view/animation/TranslateAnimation.java
@@ -57,6 +57,9 @@
     /** @hide */
     protected float mToYDelta;
 
+    private int mWidth;
+    private int mParentWidth;
+
     /**
      * Constructor used when a TranslateAnimation is loaded from a resource.
      *
@@ -179,5 +182,60 @@
         mToXDelta = resolveSize(mToXType, mToXValue, width, parentWidth);
         mFromYDelta = resolveSize(mFromYType, mFromYValue, height, parentHeight);
         mToYDelta = resolveSize(mToYType, mToYValue, height, parentHeight);
+
+        mWidth = width;
+        mParentWidth = parentWidth;
+    }
+
+    /**
+     * Checks whether or not the translation is exclusively an x axis translation.
+     *
+     * @hide
+     */
+    public boolean isXAxisTransition() {
+        return mFromXDelta - mToXDelta != 0 && mFromYDelta - mToYDelta == 0;
+    }
+
+    /**
+     * Checks whether or not the translation is a full width x axis slide in or out translation.
+     *
+     * @hide
+     */
+    public boolean isFullWidthTranslate() {
+        boolean isXAxisSlideTransition =
+                isSlideInLeft() || isSlideOutRight() || isSlideInRight() || isSlideOutLeft();
+        return mWidth == mParentWidth && isXAxisSlideTransition;
+    }
+
+    private boolean isSlideInLeft() {
+        boolean startsOutOfParentOnLeft = mFromXDelta <= -mWidth;
+        return startsOutOfParentOnLeft && endsXEnclosedWithinParent();
+    }
+
+    private boolean isSlideOutRight() {
+        boolean endOutOfParentOnRight = mToXDelta >= mParentWidth;
+        return startsXEnclosedWithinParent() && endOutOfParentOnRight;
+    }
+
+    private boolean isSlideInRight() {
+        boolean startsOutOfParentOnRight = mFromXDelta >= mParentWidth;
+        return startsOutOfParentOnRight && endsXEnclosedWithinParent();
+    }
+
+    private boolean isSlideOutLeft() {
+        boolean endOutOfParentOnLeft = mToXDelta <= -mWidth;
+        return startsXEnclosedWithinParent() && endOutOfParentOnLeft;
+    }
+
+    private boolean endsXEnclosedWithinParent() {
+        return mWidth <= mParentWidth
+                && mToXDelta + mWidth <= mParentWidth
+                && mToXDelta >= 0;
+    }
+
+    private boolean startsXEnclosedWithinParent() {
+        return mWidth <= mParentWidth
+                && mFromXDelta + mWidth <= mParentWidth
+                && mFromXDelta >= 0;
     }
 }
diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index 71b8003..3bc9a96 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.content.LocusId;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.view.Display;
@@ -105,6 +106,7 @@
     private final int mFlags;
     private final int mDisplayId;
     private final ActivityId mActivityId;
+    private final IBinder mWindowToken;
 
     // Fields below are set by the service upon "delivery" and are not marshalled in the parcel
     private int mParentSessionId = NO_SESSION_ID;
@@ -112,7 +114,7 @@
     /** @hide */
     public ContentCaptureContext(@Nullable ContentCaptureContext clientContext,
             @NonNull ActivityId activityId, @NonNull ComponentName componentName, int displayId,
-            int flags) {
+            IBinder windowToken, int flags) {
         if (clientContext != null) {
             mHasClientContext = true;
             mExtras = clientContext.mExtras;
@@ -126,6 +128,7 @@
         mFlags = flags;
         mDisplayId = displayId;
         mActivityId = activityId;
+        mWindowToken = windowToken;
     }
 
     private ContentCaptureContext(@NonNull Builder builder) {
@@ -137,6 +140,7 @@
         mFlags = 0;
         mDisplayId = Display.INVALID_DISPLAY;
         mActivityId = null;
+        mWindowToken = null;
     }
 
     /** @hide */
@@ -148,6 +152,7 @@
         mFlags = original.mFlags | extraFlags;
         mDisplayId = original.mDisplayId;
         mActivityId = original.mActivityId;
+        mWindowToken = original.mWindowToken;
     }
 
     /**
@@ -230,6 +235,20 @@
     }
 
     /**
+     * Gets the window token of the activity associated with this context.
+     *
+     * <p>The token can be used to attach relevant overlay views to the activity's window. This can
+     * be done through {@link android.view.WindowManager.LayoutParams#token}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public IBinder getWindowToken() {
+        return mWindowToken;
+    }
+
+    /**
      * Gets the flags associated with this context.
      *
      * @return any combination of {@link #FLAG_DISABLED_BY_FLAG_SECURE},
@@ -328,6 +347,7 @@
         }
         pw.print(", activityId="); pw.print(mActivityId);
         pw.print(", displayId="); pw.print(mDisplayId);
+        pw.print(", windowToken="); pw.print(mWindowToken);
         if (mParentSessionId != NO_SESSION_ID) {
             pw.print(", parentId="); pw.print(mParentSessionId);
         }
@@ -352,6 +372,7 @@
             builder.append("act=").append(ComponentName.flattenToShortString(mComponentName))
                 .append(", activityId=").append(mActivityId)
                 .append(", displayId=").append(mDisplayId)
+                .append(", windowToken=").append(mWindowToken)
                 .append(", flags=").append(mFlags);
         } else {
             builder.append("id=").append(mId);
@@ -381,6 +402,7 @@
         parcel.writeParcelable(mComponentName, flags);
         if (fromServer()) {
             parcel.writeInt(mDisplayId);
+            parcel.writeStrongBinder(mWindowToken);
             parcel.writeInt(mFlags);
             mActivityId.writeToParcel(parcel, flags);
         }
@@ -411,11 +433,12 @@
                 return clientContext;
             } else {
                 final int displayId = parcel.readInt();
+                final IBinder windowToken = parcel.readStrongBinder();
                 final int flags = parcel.readInt();
                 final ActivityId activityId = new ActivityId(parcel);
 
                 return new ContentCaptureContext(clientContext, activityId, componentName,
-                        displayId, flags);
+                        displayId, windowToken, flags);
             }
         }
 
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index ae45c6e..0f4bc19 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -24,6 +24,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.graphics.Insets;
+import android.graphics.Rect;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.Selection;
@@ -121,6 +122,12 @@
      */
     public static final int TYPE_VIEW_INSETS_CHANGED = 9;
 
+    /**
+     * Called before {@link #TYPE_VIEW_TREE_APPEARING}, or after the size of the window containing
+     * the views changed.
+     */
+    public static final int TYPE_WINDOW_BOUNDS_CHANGED = 10;
+
     /** @hide */
     @IntDef(prefix = { "TYPE_" }, value = {
             TYPE_VIEW_APPEARED,
@@ -131,7 +138,8 @@
             TYPE_CONTEXT_UPDATED,
             TYPE_SESSION_PAUSED,
             TYPE_SESSION_RESUMED,
-            TYPE_VIEW_INSETS_CHANGED
+            TYPE_VIEW_INSETS_CHANGED,
+            TYPE_WINDOW_BOUNDS_CHANGED,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EventType{}
@@ -149,6 +157,7 @@
     private int mParentSessionId = NO_SESSION_ID;
     private @Nullable ContentCaptureContext mClientContext;
     private @Nullable Insets mInsets;
+    private @Nullable Rect mBounds;
 
     private int mComposingStart = MAX_INVALID_VALUE;
     private int mComposingEnd = MAX_INVALID_VALUE;
@@ -345,6 +354,13 @@
         return this;
     }
 
+    /** @hide */
+    @NonNull
+    public ContentCaptureEvent setBounds(@NonNull Rect bounds) {
+        mBounds = bounds;
+        return this;
+    }
+
     /**
      * Gets the type of the event.
      *
@@ -418,6 +434,16 @@
     }
 
     /**
+     * Gets the {@link Rect} bounds of the window associated with the event. Valid bounds will only
+     * be returned if the type of the event is {@link #TYPE_WINDOW_BOUNDS_CHANGED}, otherwise they
+     * will be null.
+     */
+    @Nullable
+    public Rect getBounds() {
+        return mBounds;
+    }
+
+    /**
      * Merges event of the same type, either {@link #TYPE_VIEW_TEXT_CHANGED}
      * or {@link #TYPE_VIEW_DISAPPEARED}.
      *
@@ -488,6 +514,9 @@
         if (mInsets != null) {
             pw.print(", insets="); pw.println(mInsets);
         }
+        if (mBounds != null) {
+            pw.print(", bounds="); pw.println(mBounds);
+        }
         if (mComposingStart > MAX_INVALID_VALUE) {
             pw.print(", composing("); pw.print(mComposingStart);
             pw.print(", "); pw.print(mComposingEnd); pw.print(")");
@@ -532,6 +561,9 @@
         if (mInsets != null) {
             string.append(", insets=").append(mInsets);
         }
+        if (mBounds != null) {
+            string.append(", bounds=").append(mBounds);
+        }
         if (mComposingStart > MAX_INVALID_VALUE) {
             string.append(", composing=[")
                     .append(mComposingStart).append(",").append(mComposingEnd).append("]");
@@ -567,6 +599,9 @@
         if (mType == TYPE_VIEW_INSETS_CHANGED) {
             parcel.writeParcelable(mInsets, flags);
         }
+        if (mType == TYPE_WINDOW_BOUNDS_CHANGED) {
+            parcel.writeParcelable(mBounds, flags);
+        }
         if (mType == TYPE_VIEW_TEXT_CHANGED) {
             parcel.writeInt(mComposingStart);
             parcel.writeInt(mComposingEnd);
@@ -607,6 +642,9 @@
             if (type == TYPE_VIEW_INSETS_CHANGED) {
                 event.setInsets(parcel.readParcelable(null));
             }
+            if (type == TYPE_WINDOW_BOUNDS_CHANGED) {
+                event.setBounds(parcel.readParcelable(null));
+            }
             if (type == TYPE_VIEW_TEXT_CHANGED) {
                 event.setComposingIndex(parcel.readInt(), parcel.readInt());
                 event.restoreComposingSpan();
@@ -648,6 +686,8 @@
                 return "CONTEXT_UPDATED";
             case TYPE_VIEW_INSETS_CHANGED:
                 return "VIEW_INSETS_CHANGED";
+            case TYPE_WINDOW_BOUNDS_CHANGED:
+                return "TYPE_WINDOW_BOUNDS_CHANGED";
             default:
                 return "UKNOWN_TYPE: " + type;
         }
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 4cf5532..98ef4e7 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -26,6 +26,7 @@
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TREE_APPEARED;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TREE_APPEARING;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_WINDOW_BOUNDS_CHANGED;
 import static android.view.contentcapture.ContentCaptureHelper.getSanitizedString;
 import static android.view.contentcapture.ContentCaptureHelper.sDebug;
 import static android.view.contentcapture.ContentCaptureHelper.sVerbose;
@@ -38,6 +39,7 @@
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
 import android.graphics.Insets;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -776,6 +778,14 @@
                 .setClientContext(context), FORCE_FLUSH));
     }
 
+    /** public because is also used by ViewRootImpl */
+    public void notifyWindowBoundsChanged(int sessionId, @NonNull Rect bounds) {
+        mHandler.post(() -> sendEvent(
+                new ContentCaptureEvent(sessionId, TYPE_WINDOW_BOUNDS_CHANGED)
+                .setBounds(bounds)
+        ));
+    }
+
     @Override
     void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
         super.dump(prefix, pw);
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index aa28a92..fdcc208 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -726,8 +726,9 @@
      * associated with the action.</p>
      *
      * @param editorAction This must be one of the action constants for
-     * {@link EditorInfo#imeOptions EditorInfo.editorType}, such as
-     * {@link EditorInfo#IME_ACTION_GO EditorInfo.EDITOR_ACTION_GO}.
+     * {@link EditorInfo#imeOptions EditorInfo.imeOptions}, such as
+     * {@link EditorInfo#IME_ACTION_GO EditorInfo.EDITOR_ACTION_GO}, or the value of
+     * {@link EditorInfo#actionId EditorInfo.actionId} if a custom action is available.
      * @return true on success, false if the input connection is no longer
      * valid.
      */
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index b571560..f58a07f 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -592,9 +592,8 @@
             final View rootView = roots.get(rootNum).getView();
             if (rootView instanceof ViewGroup) {
                 findViewsTraversalByAutofillIds((ViewGroup) rootView, sourceViewIds);
-            } else {
-                addViewIfNeeded(sourceViewIds, rootView);
             }
+            addViewIfNeeded(sourceViewIds, rootView);
         }
     }
 
@@ -605,9 +604,8 @@
             final View child = viewGroup.getChildAt(i);
             if (child instanceof ViewGroup) {
                 findViewsTraversalByAutofillIds((ViewGroup) child, sourceViewIds);
-            } else {
-                addViewIfNeeded(sourceViewIds, child);
             }
+            addViewIfNeeded(sourceViewIds, child);
         }
     }
 
diff --git a/core/java/android/view/translation/ViewTranslationCallback.java b/core/java/android/view/translation/ViewTranslationCallback.java
index a075662..66c028b 100644
--- a/core/java/android/view/translation/ViewTranslationCallback.java
+++ b/core/java/android/view/translation/ViewTranslationCallback.java
@@ -41,6 +41,11 @@
      * method will not be called before {@link View#onViewTranslationResponse} or
      * {@link View#onVirtualViewTranslationResponses}.
      *
+     * <p> NOTE: It is possible the user changes text that causes a new
+     * {@link ViewTranslationResponse} returns to show the new translation. If you cache the
+     * {@link ViewTranslationResponse} here, you should remember to keep the cached value up
+     * to date.
+     *
      * <p> NOTE: For TextView implementation, {@link ContentCaptureSession#notifyViewTextChanged}
      * shouldn't be called with the translated text, simply calling setText() here will trigger the
      * method. You should either override {@code View#onProvideContentCaptureStructure()} to report
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index ea39f6d..fcaeeff 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -396,8 +396,9 @@
                 // Prompt user to add this person to contacts
                 final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, createUri);
                 if (extras != null) {
-                    extras.remove(EXTRA_URI_CONTENT);
-                    intent.putExtras(extras);
+                    Bundle bundle = new Bundle(extras);
+                    bundle.remove(EXTRA_URI_CONTENT);
+                    intent.putExtras(bundle);
                 }
                 getContext().startActivity(intent);
             }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 69a5e39..3eaf852 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -13822,9 +13822,9 @@
             TextView.this.handleTextChanged(buffer, start, before, after);
 
             if (AccessibilityManager.getInstance(mContext).isEnabled()
-                    && (isFocused() || isSelected() && isShown())) {
+                    && (isFocused() || (isSelected() && isShown()))) {
                 sendAccessibilityEventTypeViewTextChanged(mBeforeText, start, before, after);
-                mBeforeText = null;
+                mBeforeText = TextUtils.stringOrSpannedString(mTransformed);
             }
         }
 
@@ -13852,6 +13852,54 @@
                 Log.v(LOG_TAG, "onSpanAdded s=" + s + " e=" + e + " what=" + what + ": " + buf);
             }
             TextView.this.spanChange(buf, what, -1, s, -1, e);
+            // Note we don't update mBeforeText here. We look for SuggestionSpans added after the
+            // text content changes.
+            if (AccessibilityManager.getInstance(mContext).isEnabled()
+                    && (isFocused() || (isSelected() && isShown()))
+                    && (what instanceof SuggestionSpan)) {
+                // When the user types a new word, and SuggestionSpans on the existing words will be
+                // removed and added again. We don't need to send out events for existing
+                // SuggestionSpans. Multiple spans can be placed on the range.
+                if (mBeforeText instanceof SpannedString) {
+                    final SpannedString beforeSpannedString = (SpannedString) mBeforeText;
+                    if ((beforeSpannedString.getSpanStart(what) == s)
+                            && (beforeSpannedString.getSpanEnd(what) == e)) {
+                        // Exactly same span is found.
+                        return;
+                    }
+                    // Suggestion span couldn't be found. Try to find a suggestion span that has the
+                    // same contents.
+                    SuggestionSpan[] suggestionSpans = beforeSpannedString.getSpans(s, e,
+                            SuggestionSpan.class);
+                    for (final SuggestionSpan suggestionSpan : suggestionSpans) {
+                        final int start = beforeSpannedString.getSpanStart(suggestionSpan);
+                        if (start != s) {
+                            continue;
+                        }
+                        final int end = beforeSpannedString.getSpanEnd(suggestionSpan);
+                        if (end != e) {
+                            continue;
+                        }
+                        if (equalSuggestionSpan(suggestionSpan, (SuggestionSpan) what)) {
+                            return;
+                        }
+                    }
+                }
+                AccessibilityEvent event =
+                        AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
+                event.setFromIndex(s);
+                event.setToIndex(e);
+                event.setBeforeText(mBeforeText);
+                sendAccessibilityEventUnchecked(event);
+            }
+        }
+
+        private boolean equalSuggestionSpan(SuggestionSpan span1, SuggestionSpan span2) {
+            // We compare flags because flags will determine the underline color.
+            return Arrays.equals(span1.getSuggestions(), span2.getSuggestions())
+                    && Objects.equals(span1.getLocaleObject(), span2.getLocaleObject())
+                    && span1.getLocale().equals(span2.getLocale())
+                    && (span1.getFlags() == span2.getFlags());
         }
 
         public void onSpanRemoved(Spannable buf, Object what, int s, int e) {
diff --git a/core/java/android/widget/TextViewTranslationCallback.java b/core/java/android/widget/TextViewTranslationCallback.java
index 9d60009..152405b 100644
--- a/core/java/android/widget/TextViewTranslationCallback.java
+++ b/core/java/android/widget/TextViewTranslationCallback.java
@@ -70,7 +70,12 @@
                     + "onViewTranslationResponse().");
             return false;
         }
-        if (mTranslationTransformation == null) {
+        // It is possible user changes text and new translation response returns, system should
+        // update the translation response to keep the result up to date.
+        // Because TextView.setTransformationMethod() will skip the same TransformationMethod
+        // instance, we should create a new one to let new translation can work.
+        if (mTranslationTransformation == null
+                || !response.equals(mTranslationTransformation.getViewTranslationResponse())) {
             TransformationMethod originalTranslationMethod =
                     ((TextView) view).getTransformationMethod();
             mTranslationTransformation = new TranslationTransformationMethod(response,
diff --git a/core/java/com/android/internal/app/AbstractResolverComparator.java b/core/java/com/android/internal/app/AbstractResolverComparator.java
index c00d16c..42fc7bd 100644
--- a/core/java/com/android/internal/app/AbstractResolverComparator.java
+++ b/core/java/com/android/internal/app/AbstractResolverComparator.java
@@ -161,6 +161,11 @@
         final ResolveInfo lhs = lhsp.getResolveInfoAt(0);
         final ResolveInfo rhs = rhsp.getResolveInfoAt(0);
 
+        final boolean lFixedAtTop = lhsp.isFixedAtTop();
+        final boolean rFixedAtTop = rhsp.isFixedAtTop();
+        if (lFixedAtTop && !rFixedAtTop) return -1;
+        if (!lFixedAtTop && rFixedAtTop) return 1;
+
         // We want to put the one targeted to another user at the end of the dialog.
         if (lhs.targetUserId != UserHandle.USER_CURRENT) {
             return rhs.targetUserId != UserHandle.USER_CURRENT ? 0 : 1;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index a727b34..6ff74e4 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -240,6 +240,12 @@
             SystemUiDeviceConfigFlags.HASH_SALT_MAX_DAYS,
             DEFAULT_SALT_EXPIRATION_DAYS);
 
+    private static final boolean DEFAULT_IS_NEARBY_SHARE_FIRST_TARGET_IN_RANKED_APP = false;
+    private boolean mIsNearbyShareFirstTargetInRankedApp =
+            DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
+                    SystemUiDeviceConfigFlags.IS_NEARBY_SHARE_FIRST_TARGET_IN_RANKED_APP,
+                    DEFAULT_IS_NEARBY_SHARE_FIRST_TARGET_IN_RANKED_APP);
+
     private Bundle mReplacementExtras;
     private IntentSender mChosenComponentSender;
     private IntentSender mRefinementIntentSender;
@@ -600,10 +606,11 @@
 
         // Exclude out Nearby from main list if chip is present, to avoid duplication
         ComponentName nearbySharingComponent = getNearbySharingComponent();
-        boolean hasNearby = nearbySharingComponent != null;
+        boolean shouldFilterNearby = !shouldNearbyShareBeFirstInRankedRow()
+                && nearbySharingComponent != null;
 
         if (pa != null) {
-            ComponentName[] names = new ComponentName[pa.length + (hasNearby ? 1 : 0)];
+            ComponentName[] names = new ComponentName[pa.length + (shouldFilterNearby ? 1 : 0)];
             for (int i = 0; i < pa.length; i++) {
                 if (!(pa[i] instanceof ComponentName)) {
                     Log.w(TAG, "Filtered component #" + i + " not a ComponentName: " + pa[i]);
@@ -612,12 +619,12 @@
                 }
                 names[i] = (ComponentName) pa[i];
             }
-            if (hasNearby) {
+            if (shouldFilterNearby) {
                 names[names.length - 1] = nearbySharingComponent;
             }
 
             mFilteredComponentNames = names;
-        } else if (hasNearby) {
+        } else if (shouldFilterNearby) {
             mFilteredComponentNames = new ComponentName[1];
             mFilteredComponentNames[0] = nearbySharingComponent;
         }
@@ -1240,7 +1247,9 @@
         final ViewGroup actionRow =
                 (ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row);
         addActionButton(actionRow, createCopyButton());
-        addActionButton(actionRow, createNearbyButton(targetIntent));
+        if (shouldNearbyShareBeIncludedAsActionButton()) {
+            addActionButton(actionRow, createNearbyButton(targetIntent));
+        }
 
         CharSequence sharingText = targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT);
         if (sharingText == null) {
@@ -1291,7 +1300,9 @@
         final ViewGroup actionRow =
                 (ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row);
         //TODO: addActionButton(actionRow, createCopyButton());
-        addActionButton(actionRow, createNearbyButton(targetIntent));
+        if (shouldNearbyShareBeIncludedAsActionButton()) {
+            addActionButton(actionRow, createNearbyButton(targetIntent));
+        }
         addActionButton(actionRow, createEditButton(targetIntent));
 
         mPreviewCoord = new ContentPreviewCoordinator(contentPreviewLayout, false);
@@ -1411,8 +1422,9 @@
         final ViewGroup actionRow =
                 (ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row);
         //TODO(b/120417119): addActionButton(actionRow, createCopyButton());
-        addActionButton(actionRow, createNearbyButton(targetIntent));
-
+        if (shouldNearbyShareBeIncludedAsActionButton()) {
+            addActionButton(actionRow, createNearbyButton(targetIntent));
+        }
 
         String action = targetIntent.getAction();
         if (Intent.ACTION_SEND.equals(action)) {
@@ -1713,7 +1725,6 @@
 
         super.startSelected(which, always, filtered);
 
-
         if (currentListAdapter.getCount() > 0) {
             // Log the index of which type of target the user picked.
             // Lower values mean the ranking was better.
@@ -2303,6 +2314,12 @@
         public boolean isComponentPinned(ComponentName name) {
             return mPinnedSharedPrefs.getBoolean(name.flattenToString(), false);
         }
+
+        @Override
+        public boolean isFixedAtTop(ComponentName name) {
+            return name != null && name.equals(getNearbySharingComponent())
+                    && shouldNearbyShareBeFirstInRankedRow();
+        }
     }
 
     @VisibleForTesting
@@ -2838,7 +2855,7 @@
                             .targetInfoForPosition(mListPosition, /* filtered */ true);
 
                     // This should always be the case for ItemViewHolder, check for validity
-                    if (ti instanceof DisplayResolveInfo) {
+                    if (ti instanceof DisplayResolveInfo && shouldShowTargetDetails(ti)) {
                         showTargetDetails((DisplayResolveInfo) ti);
                     }
                     return true;
@@ -2847,6 +2864,13 @@
         }
     }
 
+    private boolean shouldShowTargetDetails(TargetInfo ti) {
+        ComponentName nearbyShare = getNearbySharingComponent();
+        //  Suppress target details for nearby share to hide pin/unpin action
+        return !(nearbyShare != null && nearbyShare.equals(ti.getResolvedComponentName())
+                && shouldNearbyShareBeFirstInRankedRow());
+    }
+
     /**
      * Add a footer to the list, to support scrolling behavior below the navbar.
      */
@@ -3212,7 +3236,7 @@
                         final TargetInfo ti = mChooserListAdapter.targetInfoForPosition(
                                 holder.getItemIndex(column), true);
                         // This should always be the case for non-DS targets, check for validity
-                        if (ti instanceof DisplayResolveInfo) {
+                        if (ti instanceof DisplayResolveInfo && shouldShowTargetDetails(ti)) {
                             showTargetDetails((DisplayResolveInfo) ti);
                         }
                         return true;
@@ -3861,4 +3885,12 @@
     protected void maybeLogProfileChange() {
         getChooserActivityLogger().logShareheetProfileChanged();
     }
+
+    private boolean shouldNearbyShareBeFirstInRankedRow() {
+        return ActivityManager.isLowRamDeviceStatic() && mIsNearbyShareFirstTargetInRankedApp;
+    }
+
+    private boolean shouldNearbyShareBeIncludedAsActionButton() {
+        return !shouldNearbyShareBeFirstInRankedRow();
+    }
 }
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 85d27a1..91b4b7f 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -2035,6 +2035,7 @@
         private final List<Intent> mIntents = new ArrayList<>();
         private final List<ResolveInfo> mResolveInfos = new ArrayList<>();
         private boolean mPinned;
+        private boolean mFixedAtTop;
 
         public ResolvedComponentInfo(ComponentName name, Intent intent, ResolveInfo info) {
             this.name = name;
@@ -2083,6 +2084,14 @@
         public void setPinned(boolean pinned) {
             mPinned = pinned;
         }
+
+        public boolean isFixedAtTop() {
+            return mFixedAtTop;
+        }
+
+        public void setFixedAtTop(boolean isFixedAtTop) {
+            mFixedAtTop = isFixedAtTop;
+        }
     }
 
     class ItemClickListener implements AdapterView.OnItemClickListener,
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index 10ac1bc..9a95e64 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -181,6 +181,7 @@
                 final ResolverActivity.ResolvedComponentInfo rci =
                         new ResolverActivity.ResolvedComponentInfo(name, intent, newInfo);
                 rci.setPinned(isComponentPinned(name));
+                rci.setFixedAtTop(isFixedAtTop(name));
                 into.add(rci);
             }
         }
@@ -195,6 +196,14 @@
         return false;
     }
 
+    /**
+     * Whether this component is fixed at top in the ranked apps list. Always false for Resolver;
+     * overridden in Chooser.
+     */
+    public boolean isFixedAtTop(ComponentName name) {
+        return false;
+    }
+
     // Filter out any activities that the launched uid does not have permission for.
     // To preserve the inputList, optionally will return the original list if any modification has
     // been made.
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 06f68e8..1b3fd7b 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -495,6 +495,12 @@
     public static final String SHORTCUT_APPSEARCH_INTEGRATION =
             "shortcut_appsearch_integration";
 
+    /**
+     * (boolean) Whether nearby share should be the first target in ranked apps.
+     */
+    public static final String IS_NEARBY_SHARE_FIRST_TARGET_IN_RANKED_APP =
+            "is_nearby_share_first_target_in_ranked_app";
+
     private SystemUiDeviceConfigFlags() {
     }
 }
diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java
index 3f3c9bd..6c73e70 100644
--- a/core/java/com/android/internal/content/om/OverlayConfig.java
+++ b/core/java/com/android/internal/content/om/OverlayConfig.java
@@ -23,6 +23,7 @@
 import android.os.Build;
 import android.os.Trace;
 import android.util.ArrayMap;
+import android.util.IndentingPrintWriter;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -32,9 +33,12 @@
 import com.android.internal.util.Preconditions;
 
 import java.io.File;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.function.BiConsumer;
 import java.util.function.Supplier;
 
@@ -116,14 +120,16 @@
         }
 
         boolean foundConfigFile = false;
-        ArrayList<ParsedOverlayInfo> packageManagerOverlayInfos = null;
+        final Map<String, ParsedOverlayInfo> packageManagerOverlayInfos =
+                packageProvider == null ? null : getOverlayPackageInfos(packageProvider);
 
         final ArrayList<ParsedConfiguration> overlays = new ArrayList<>();
         for (int i = 0, n = partitions.size(); i < n; i++) {
             final OverlayPartition partition = partitions.get(i);
             final OverlayScanner scanner = (scannerFactory == null) ? null : scannerFactory.get();
             final ArrayList<ParsedConfiguration> partitionOverlays =
-                    OverlayConfigParser.getConfigurations(partition, scanner);
+                    OverlayConfigParser.getConfigurations(partition, scanner,
+                            packageManagerOverlayInfos);
             if (partitionOverlays != null) {
                 foundConfigFile = true;
                 overlays.addAll(partitionOverlays);
@@ -138,12 +144,8 @@
             if (scannerFactory != null) {
                 partitionOverlayInfos = new ArrayList<>(scanner.getAllParsedInfos());
             } else {
-                if (packageManagerOverlayInfos == null) {
-                    packageManagerOverlayInfos = getOverlayPackageInfos(packageProvider);
-                }
-
                 // Filter out overlays not present in the partition.
-                partitionOverlayInfos = new ArrayList<>(packageManagerOverlayInfos);
+                partitionOverlayInfos = new ArrayList<>(packageManagerOverlayInfos.values());
                 for (int j = partitionOverlayInfos.size() - 1; j >= 0; j--) {
                     if (!partition.containsFile(partitionOverlayInfos.get(j).path)) {
                         partitionOverlayInfos.remove(j);
@@ -289,14 +291,14 @@
     }
 
     @NonNull
-    private static ArrayList<ParsedOverlayInfo> getOverlayPackageInfos(
+    private static Map<String, ParsedOverlayInfo> getOverlayPackageInfos(
             @NonNull PackageProvider packageManager) {
-        final ArrayList<ParsedOverlayInfo> overlays = new ArrayList<>();
+        final HashMap<String, ParsedOverlayInfo> overlays = new HashMap<>();
         packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem) -> {
             if (p.getOverlayTarget() != null && isSystem) {
-                overlays.add(new ParsedOverlayInfo(p.getPackageName(), p.getOverlayTarget(),
-                        p.getTargetSdkVersion(), p.isOverlayIsStatic(), p.getOverlayPriority(),
-                        new File(p.getBaseApkPath())));
+                overlays.put(p.getPackageName(), new ParsedOverlayInfo(p.getPackageName(),
+                        p.getOverlayTarget(), p.getTargetSdkVersion(), p.isOverlayIsStatic(),
+                        p.getOverlayPriority(), new File(p.getBaseApkPath())));
             }
         });
         return overlays;
@@ -397,6 +399,25 @@
         return idmapPaths.toArray(new String[0]);
     }
 
+    /** Dump all overlay configurations to the Printer. */
+    public void dump(@NonNull PrintWriter writer) {
+        final IndentingPrintWriter ipw = new IndentingPrintWriter(writer);
+        ipw.println("Overlay configurations:");
+        ipw.increaseIndent();
+
+        final ArrayList<Configuration> configurations = new ArrayList<>(mConfigurations.values());
+        configurations.sort(Comparator.comparingInt(o -> o.configIndex));
+        for (int i = 0; i < configurations.size(); i++) {
+            final Configuration configuration = configurations.get(i);
+            ipw.print(configuration.configIndex);
+            ipw.print(", ");
+            ipw.print(configuration.parsedConfig);
+            ipw.println();
+        }
+        ipw.decreaseIndent();
+        ipw.println();
+    }
+
     /**
      * For each overlay APK, this creates the idmap file that allows the overlay to override the
      * target package.
diff --git a/core/java/com/android/internal/content/om/OverlayConfigParser.java b/core/java/com/android/internal/content/om/OverlayConfigParser.java
index a86e595..053a341 100644
--- a/core/java/com/android/internal/content/om/OverlayConfigParser.java
+++ b/core/java/com/android/internal/content/om/OverlayConfigParser.java
@@ -28,6 +28,7 @@
 import android.util.Xml;
 
 import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo;
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 
 import libcore.io.IoUtils;
@@ -40,6 +41,7 @@
 import java.io.FileReader;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Map;
 
 /**
  * Responsible for parsing configurations of Runtime Resource Overlays that control mutability,
@@ -192,7 +194,8 @@
      */
     @Nullable
     static ArrayList<ParsedConfiguration> getConfigurations(
-            @NonNull OverlayPartition partition, @Nullable OverlayScanner scanner) {
+            @NonNull OverlayPartition partition, @Nullable OverlayScanner scanner,
+            @Nullable Map<String, ParsedOverlayInfo> packageManagerOverlayInfos) {
         if (partition.getOverlayFolder() == null) {
             return null;
         }
@@ -207,11 +210,12 @@
         }
 
         final ParsingContext parsingContext = new ParsingContext(partition);
-        readConfigFile(configFile, scanner, parsingContext);
+        readConfigFile(configFile, scanner, packageManagerOverlayInfos, parsingContext);
         return parsingContext.mOrderedConfigurations;
     }
 
     private static void readConfigFile(@NonNull File configFile, @Nullable OverlayScanner scanner,
+            @Nullable Map<String, ParsedOverlayInfo> packageManagerOverlayInfos,
             @NonNull ParsingContext parsingContext) {
         FileReader configReader;
         try {
@@ -231,10 +235,12 @@
                 final String name = parser.getName();
                 switch (name) {
                     case "merge":
-                        parseMerge(configFile, parser, scanner, parsingContext);
+                        parseMerge(configFile, parser, scanner, packageManagerOverlayInfos,
+                                parsingContext);
                         break;
                     case "overlay":
-                        parseOverlay(configFile, parser, scanner, parsingContext);
+                        parseOverlay(configFile, parser, scanner, packageManagerOverlayInfos,
+                                parsingContext);
                         break;
                     default:
                         Log.w(TAG, String.format("Tag %s is unknown in %s at %s",
@@ -258,7 +264,9 @@
      * configuration files.
      */
     private static void parseMerge(@NonNull File configFile, @NonNull XmlPullParser parser,
-            @Nullable OverlayScanner scanner, @NonNull ParsingContext parsingContext) {
+            @Nullable OverlayScanner scanner,
+            @Nullable Map<String, ParsedOverlayInfo> packageManagerOverlayInfos,
+            @NonNull ParsingContext parsingContext) {
         final String path = parser.getAttributeValue(null, "path");
         if (path == null) {
             throw new IllegalStateException(String.format("<merge> without path in %s at %s"
@@ -304,7 +312,7 @@
                             parser.getPositionDescription()));
         }
 
-        readConfigFile(includedConfigFile, scanner, parsingContext);
+        readConfigFile(includedConfigFile, scanner, packageManagerOverlayInfos, parsingContext);
         parsingContext.mMergeDepth--;
     }
 
@@ -330,7 +338,12 @@
      * order of non-configured overlays when enabled by the OverlayManagerService is undefined.
      */
     private static void parseOverlay(@NonNull File configFile, @NonNull XmlPullParser parser,
-            @Nullable OverlayScanner scanner, @NonNull ParsingContext parsingContext) {
+            @Nullable OverlayScanner scanner,
+            @Nullable Map<String, ParsedOverlayInfo> packageManagerOverlayInfos,
+            @NonNull ParsingContext parsingContext) {
+        Preconditions.checkArgument((scanner == null) != (packageManagerOverlayInfos == null),
+                "scanner and packageManagerOverlayInfos cannot be both null or both non-null");
+
         final String packageName = parser.getAttributeValue(null, "package");
         if (packageName == null) {
             throw new IllegalStateException(String.format("\"<overlay> without package in %s at %s",
@@ -338,16 +351,30 @@
         }
 
         // Ensure the overlay being configured is present in the partition during zygote
-        // initialization.
+        // initialization, unless the package is an excluded overlay package.
         ParsedOverlayInfo info = null;
         if (scanner != null) {
             info = scanner.getParsedInfo(packageName);
-            if (info == null|| !parsingContext.mPartition.containsOverlay(info.path)) {
+            if (info == null
+                    && scanner.isExcludedOverlayPackage(packageName, parsingContext.mPartition)) {
+                Log.d(TAG, "overlay " + packageName + " in partition "
+                        + parsingContext.mPartition.getOverlayFolder() + " is ignored.");
+                return;
+            } else if (info == null || !parsingContext.mPartition.containsOverlay(info.path)) {
                 throw new IllegalStateException(
                         String.format("overlay %s not present in partition %s in %s at %s",
                                 packageName, parsingContext.mPartition.getOverlayFolder(),
                                 configFile, parser.getPositionDescription()));
             }
+        } else {
+            // Zygote shall have crashed itself, if there's an overlay apk not present in the
+            // partition. For the overlay package not found in the package manager, we can assume
+            // that it's an excluded overlay package.
+            if (packageManagerOverlayInfos.get(packageName) == null) {
+                Log.d(TAG, "overlay " + packageName + " in partition "
+                        + parsingContext.mPartition.getOverlayFolder() + " is ignored.");
+                return;
+            }
         }
 
         if (parsingContext.mConfiguredOverlays.contains(packageName)) {
diff --git a/core/java/com/android/internal/content/om/OverlayScanner.java b/core/java/com/android/internal/content/om/OverlayScanner.java
index 6b5cb8d..4387d1b 100644
--- a/core/java/com/android/internal/content/om/OverlayScanner.java
+++ b/core/java/com/android/internal/content/om/OverlayScanner.java
@@ -16,6 +16,9 @@
 
 package com.android.internal.content.om;
 
+import static android.content.pm.parsing.ParsingPackageUtils.PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY;
+import static android.content.pm.parsing.ParsingPackageUtils.checkRequiredSystemProperties;
+
 import static com.android.internal.content.om.OverlayConfig.TAG;
 
 import android.annotation.NonNull;
@@ -24,13 +27,17 @@
 import android.content.pm.parsing.ApkLiteParseUtils;
 import android.content.pm.parsing.result.ParseResult;
 import android.content.pm.parsing.result.ParseTypeImpl;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 
 /**
  * This class scans a directory containing overlay APKs and extracts information from the overlay
@@ -73,6 +80,14 @@
      */
     private final ArrayMap<String, ParsedOverlayInfo> mParsedOverlayInfos = new ArrayMap<>();
 
+    /**
+     * A list of pair<packageName, apkFile> which is excluded from the system based on the
+     * system property condition.
+     *
+     * @see #isExcludedOverlayPackage(String, OverlayConfigParser.OverlayPartition)
+     */
+    private final List<Pair<String, File>> mExcludedOverlayPackages = new ArrayList<>();
+
     /** Retrieves information parsed from the overlay with the package name. */
     @Nullable
     public final ParsedOverlayInfo getParsedInfo(String packageName) {
@@ -86,6 +101,25 @@
     }
 
     /**
+     * Returns {@code true} if the given package name on the given overlay partition is an
+     * excluded overlay package.
+     * <p>
+     * An excluded overlay package declares overlay attributes of required system property in its
+     * manifest that do not match the corresponding values on the device.
+     */
+    final boolean isExcludedOverlayPackage(@NonNull String packageName,
+            @NonNull OverlayConfigParser.OverlayPartition overlayPartition) {
+        for (int i = 0; i < mExcludedOverlayPackages.size(); i++) {
+            final Pair<String, File> pair = mExcludedOverlayPackages.get(i);
+            if (pair.first.equals(packageName)
+                    && overlayPartition.containsOverlay(pair.second)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Recursively searches the directory for overlay APKs. If an overlay is found with the same
      * package name as a previously scanned overlay, the info of the new overlay will replace the
      * info of the previously scanned overlay.
@@ -115,7 +149,7 @@
                 continue;
             }
 
-            final ParsedOverlayInfo info = parseOverlayManifest(f);
+            final ParsedOverlayInfo info = parseOverlayManifest(f, mExcludedOverlayPackages);
             if (info == null) {
                 continue;
             }
@@ -124,20 +158,37 @@
         }
     }
 
-    /** Extracts information about the overlay from its manifest. */
+    /**
+     * Extracts information about the overlay from its manifest. Adds the package name and apk file
+     * into the {@code outExcludedOverlayPackages} if the apk is excluded from the system based
+     * on the system property condition.
+     */
     @VisibleForTesting
-    public ParsedOverlayInfo parseOverlayManifest(File overlayApk) {
+    public ParsedOverlayInfo parseOverlayManifest(File overlayApk,
+            List<Pair<String, File>> outExcludedOverlayPackages) {
         final ParseTypeImpl input = ParseTypeImpl.forParsingWithoutPlatformCompat();
         final ParseResult<ApkLite> ret = ApkLiteParseUtils.parseApkLite(input.reset(),
-                overlayApk, /* flags */ 0);
+                overlayApk, PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY);
         if (ret.isError()) {
             Log.w(TAG, "Got exception loading overlay.", ret.getException());
             return null;
         }
         final ApkLite apkLite = ret.getResult();
-        return apkLite.getTargetPackageName() == null ? null :
-                new ParsedOverlayInfo(apkLite.getPackageName(), apkLite.getTargetPackageName(),
-                        apkLite.getTargetSdkVersion(), apkLite.isOverlayIsStatic(),
-                        apkLite.getOverlayPriority(), new File(apkLite.getPath()));
+        if (apkLite.getTargetPackageName() == null) {
+            // Not an overlay package
+            return null;
+        }
+        final String propName = apkLite.getRequiredSystemPropertyName();
+        final String propValue = apkLite.getRequiredSystemPropertyValue();
+        if ((!TextUtils.isEmpty(propName) || !TextUtils.isEmpty(propValue))
+                && !checkRequiredSystemProperties(propName, propValue)) {
+            // The overlay package should be excluded. Adds it into the outExcludedOverlayPackages
+            // for overlay configuration parser to ignore it.
+            outExcludedOverlayPackages.add(Pair.create(apkLite.getPackageName(), overlayApk));
+            return null;
+        }
+        return new ParsedOverlayInfo(apkLite.getPackageName(), apkLite.getTargetPackageName(),
+                apkLite.getTargetSdkVersion(), apkLite.isOverlayIsStatic(),
+                apkLite.getOverlayPriority(), new File(apkLite.getPath()));
     }
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 7c4de82..94a1efe 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -77,7 +77,6 @@
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.IndentingPrintWriter;
-import android.util.IntArray;
 import android.util.KeyValueListParser;
 import android.util.Log;
 import android.util.LongSparseArray;
@@ -161,7 +160,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    static final int VERSION = 200;
+    static final int VERSION = 201;
 
     // The maximum number of names wakelocks we will keep track of
     // per uid; once the limit is reached, we batch the remaining wakelocks
@@ -464,10 +463,12 @@
             uidStates = mPendingUids.clone();
             mPendingUids.clear();
         }
+        final long timestampMs = mClock.elapsedRealtime();
         for (int i = uidStates.size() - 1; i >= 0; --i) {
             final int uid = uidStates.keyAt(i);
             final int procState = uidStates.valueAt(i);
             final int[] isolatedUids;
+            final LongArrayMultiStateCounter[] isolatedUidTimeInFreqCounters;
             final Uid u;
             synchronized (BatteryStatsImpl.this) {
                 // It's possible that uid no longer exists and any internal references have
@@ -479,26 +480,44 @@
                 }
                 if (u.mChildUids == null) {
                     isolatedUids = null;
+                    isolatedUidTimeInFreqCounters = null;
                 } else {
-                    isolatedUids = u.mChildUids.toArray();
-                    for (int j = isolatedUids.length - 1; j >= 0; --j) {
-                        isolatedUids[j] = u.mChildUids.get(j);
+                    int childUidCount = u.mChildUids.size();
+                    isolatedUids = new int[childUidCount];
+                    isolatedUidTimeInFreqCounters = new LongArrayMultiStateCounter[childUidCount];
+                    for (int j = childUidCount - 1; j >= 0; --j) {
+                        isolatedUids[j] = u.mChildUids.keyAt(j);
+                        isolatedUidTimeInFreqCounters[j] = u.mChildUids.valueAt(j);
                     }
                 }
             }
-            long[] cpuTimesMs = mKernelSingleUidTimeReader.readDeltaMs(uid);
+
+            LongArrayMultiStateCounter onBatteryCounter =
+                    u.getProcStateTimeCounter().getCounter();
+            LongArrayMultiStateCounter onBatteryScreenOffCounter =
+                    u.getProcStateScreenOffTimeCounter().getCounter();
+
+            onBatteryCounter.setState(procState, timestampMs);
+            mKernelSingleUidTimeReader.addDelta(uid, onBatteryCounter, timestampMs);
+
+            onBatteryScreenOffCounter.setState(procState, timestampMs);
+            mKernelSingleUidTimeReader.addDelta(uid, onBatteryScreenOffCounter, timestampMs);
+
             if (isolatedUids != null) {
+                LongArrayMultiStateCounter.LongArrayContainer deltaContainer =
+                        new LongArrayMultiStateCounter.LongArrayContainer(getCpuFreqCount());
                 for (int j = isolatedUids.length - 1; j >= 0; --j) {
-                    cpuTimesMs = addCpuTimes(cpuTimesMs,
-                            mKernelSingleUidTimeReader.readDeltaMs(isolatedUids[j]));
+                    if (isolatedUidTimeInFreqCounters[j] != null) {
+                        mKernelSingleUidTimeReader.addDelta(isolatedUids[j],
+                                isolatedUidTimeInFreqCounters[j], timestampMs, deltaContainer);
+                        onBatteryCounter.addCounts(deltaContainer);
+                        onBatteryScreenOffCounter.addCounts(deltaContainer);
+                    }
                 }
             }
-            if (onBattery && cpuTimesMs != null) {
-                synchronized (BatteryStatsImpl.this) {
-                    u.addProcStateTimesMs(procState, cpuTimesMs, onBattery);
-                    u.addProcStateScreenOffTimesMs(procState, cpuTimesMs, onBatteryScreenOff);
-                }
-            }
+
+            onBatteryCounter.setState(u.mProcessState, timestampMs);
+            onBatteryScreenOffCounter.setState(u.mProcessState, timestampMs);
         }
     }
 
@@ -537,6 +556,7 @@
                 return;
             }
 
+            // TODO(b/197162116): just get a list of UIDs
             final SparseArray<long[]> allUidCpuFreqTimesMs =
                     mCpuUidFreqTimeReader.getAllUidCpuFreqTimeMs();
             // If the KernelSingleUidTimeReader has stale cpu times, then we shouldn't try to
@@ -553,24 +573,40 @@
                 if (u == null) {
                     continue;
                 }
-                final long[] cpuTimesMs = allUidCpuFreqTimesMs.valueAt(i);
-                if (cpuTimesMs == null) {
-                    continue;
+
+                final int procState;
+                final int idx = mPendingUids.indexOfKey(uid);
+                if (idx >= 0) {
+                    procState = mPendingUids.valueAt(idx);
+                    mPendingUids.removeAt(idx);
+                } else {
+                    procState = u.mProcessState;
                 }
-                final long[] deltaTimesMs = mKernelSingleUidTimeReader.computeDelta(
-                        uid, cpuTimesMs.clone());
-                if (onBattery && deltaTimesMs != null) {
-                    final int procState;
-                    final int idx = mPendingUids.indexOfKey(uid);
-                    if (idx >= 0) {
-                        procState = mPendingUids.valueAt(idx);
-                        mPendingUids.removeAt(idx);
-                    } else {
-                        procState = u.mProcessState;
-                    }
-                    if (procState >= 0 && procState < Uid.NUM_PROCESS_STATE) {
-                        u.addProcStateTimesMs(procState, deltaTimesMs, onBattery);
-                        u.addProcStateScreenOffTimesMs(procState, deltaTimesMs, onBatteryScreenOff);
+
+                final long timestampMs = mClock.elapsedRealtime();
+                final LongArrayMultiStateCounter onBatteryCounter =
+                        u.getProcStateTimeCounter().getCounter();
+                final LongArrayMultiStateCounter onBatteryScreenOffCounter =
+                        u.getProcStateScreenOffTimeCounter().getCounter();
+
+                onBatteryCounter.setState(procState, timestampMs);
+                mKernelSingleUidTimeReader.addDelta(uid, onBatteryCounter, timestampMs);
+
+                onBatteryScreenOffCounter.setState(procState, timestampMs);
+                mKernelSingleUidTimeReader.addDelta(uid, onBatteryScreenOffCounter, timestampMs);
+
+                if (u.mChildUids != null) {
+                    final LongArrayMultiStateCounter.LongArrayContainer deltaContainer =
+                            new LongArrayMultiStateCounter.LongArrayContainer(getCpuFreqCount());
+                    for (int j = u.mChildUids.size() - 1; j >= 0; --j) {
+                        final LongArrayMultiStateCounter counter = u.mChildUids.valueAt(j);
+                        if (counter != null) {
+                            final int isolatedUid = u.mChildUids.keyAt(j);
+                            mKernelSingleUidTimeReader.addDelta(isolatedUid,
+                                    counter, timestampMs, deltaContainer);
+                            onBatteryCounter.addCounts(deltaContainer);
+                            onBatteryScreenOffCounter.addCounts(deltaContainer);
+                        }
                     }
                 }
             }
@@ -1653,6 +1689,97 @@
         }
     }
 
+    private static class TimeInFreqMultiStateCounter implements TimeBaseObs {
+        private final TimeBase mTimeBase;
+        private final LongArrayMultiStateCounter mCounter;
+
+        private TimeInFreqMultiStateCounter(TimeBase timeBase, Parcel in, long timestampMs) {
+            mTimeBase = timeBase;
+            mCounter = LongArrayMultiStateCounter.CREATOR.createFromParcel(in);
+            mCounter.setEnabled(mTimeBase.isRunning(), timestampMs);
+            timeBase.add(this);
+        }
+
+        private TimeInFreqMultiStateCounter(TimeBase timeBase, int stateCount, int cpuFreqCount,
+                long timestampMs) {
+            mTimeBase = timeBase;
+            mCounter = new LongArrayMultiStateCounter(stateCount, cpuFreqCount);
+            mCounter.setEnabled(mTimeBase.isRunning(), timestampMs);
+            timeBase.add(this);
+        }
+
+        private void writeToParcel(Parcel out) {
+            mCounter.writeToParcel(out, 0);
+        }
+
+        @Override
+        public void onTimeStarted(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
+            mCounter.setEnabled(true, elapsedRealtimeUs / 1000);
+        }
+
+        @Override
+        public void onTimeStopped(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
+            mCounter.setEnabled(false, elapsedRealtimeUs / 1000);
+        }
+
+        public LongArrayMultiStateCounter getCounter() {
+            return mCounter;
+        }
+
+        public int getStateCount() {
+            return mCounter.getStateCount();
+        }
+
+        public void setTrackingEnabled(boolean enabled, long timestampMs) {
+            mCounter.setEnabled(enabled && mTimeBase.isRunning(), timestampMs);
+        }
+
+        private void setState(int uidRunningState, long elapsedRealtimeMs) {
+            mCounter.setState(uidRunningState, elapsedRealtimeMs);
+        }
+
+        /**
+         * Returns accumulated counts for the specified state, or null if all counts are zero.
+         */
+        @Nullable
+        public long[] getCountsLocked(int which, int procState) {
+            LongArrayMultiStateCounter.LongArrayContainer longArrayContainer =
+                    new LongArrayMultiStateCounter.LongArrayContainer(mCounter.getArrayLength());
+            mCounter.getCounts(longArrayContainer, procState);
+            final long[] counts = new long[mCounter.getArrayLength()];
+            longArrayContainer.getValues(counts);
+
+            // Return counts only if at least one of the elements is non-zero.
+            for (int i = counts.length - 1; i >= 0; --i) {
+                if (counts[i] != 0) {
+                    return counts;
+                }
+            }
+            return null;
+        }
+
+        public void logState(Printer pw, String prefix) {
+            pw.println(prefix + "mCounter=" + mCounter);
+        }
+
+        /**
+         * Clears state of this counter.
+         */
+        @Override
+        public boolean reset(boolean detachIfReset, long elapsedRealtimeUs /* unused */) {
+            mCounter.reset();
+            if (detachIfReset) {
+                detach();
+            }
+            return true;
+        }
+
+        @Override
+        public void detach() {
+            mTimeBase.remove(this);
+        }
+    }
+
     @VisibleForTesting
     public static class LongSamplingCounter extends LongCounter implements TimeBaseObs {
         final TimeBase mTimeBase;
@@ -7300,10 +7427,10 @@
         LongSamplingCounterArray mScreenOffCpuFreqTimeMs;
         LongSamplingCounterArray mCpuClusterTimesMs;
 
-        LongSamplingCounterArray[] mProcStateTimeMs;
-        LongSamplingCounterArray[] mProcStateScreenOffTimeMs;
+        TimeInFreqMultiStateCounter mProcStateTimeMs;
+        TimeInFreqMultiStateCounter mProcStateScreenOffTimeMs;
 
-        IntArray mChildUids;
+        SparseArray<LongArrayMultiStateCounter> mChildUids;
 
         /**
          * The statistics we have collected for this uid's wake locks.
@@ -7455,8 +7582,10 @@
         }
 
         @VisibleForTesting
-        public void setProcessStateForTest(int procState) {
+        public void setProcessStateForTest(int procState, long elapsedTimeMs) {
             mProcessState = procState;
+            getProcStateTimeCounter().setState(procState, elapsedTimeMs);
+            getProcStateScreenOffTimeCounter().setState(procState, elapsedTimeMs);
         }
 
         @Override
@@ -7481,7 +7610,7 @@
 
         @Override
         public long[] getCpuFreqTimes(int which, int procState) {
-            if (which < 0 || which >= NUM_PROCESS_STATE) {
+            if (procState < 0 || procState >= NUM_PROCESS_STATE) {
                 return null;
             }
             if (mProcStateTimeMs == null) {
@@ -7491,12 +7620,13 @@
                 mProcStateTimeMs = null;
                 return null;
             }
-            return nullIfAllZeros(mProcStateTimeMs[procState], which);
+
+            return mProcStateTimeMs.getCountsLocked(which, procState);
         }
 
         @Override
         public long[] getScreenOffCpuFreqTimes(int which, int procState) {
-            if (which < 0 || which >= NUM_PROCESS_STATE) {
+            if (procState < 0 || procState >= NUM_PROCESS_STATE) {
                 return null;
             }
             if (mProcStateScreenOffTimeMs == null) {
@@ -7506,7 +7636,7 @@
                 mProcStateScreenOffTimeMs = null;
                 return null;
             }
-            return nullIfAllZeros(mProcStateScreenOffTimeMs[procState], which);
+            return mProcStateScreenOffTimeMs.getCountsLocked(which, procState);
         }
 
         public long getBinderCallCount() {
@@ -7525,15 +7655,26 @@
 
         public void addIsolatedUid(int isolatedUid) {
             if (mChildUids == null) {
-                mChildUids = new IntArray();
-            } else if (mChildUids.indexOf(isolatedUid) >= 0) {
+                mChildUids = new SparseArray<>();
+            } else if (mChildUids.indexOfKey(isolatedUid) >= 0) {
                 return;
             }
-            mChildUids.add(isolatedUid);
+            if (mBsi.trackPerProcStateCpuTimes()) {
+                LongArrayMultiStateCounter counter =
+                        new LongArrayMultiStateCounter(1, mBsi.getCpuFreqCount());
+                // Set initial values to all 0. This is a child UID and we want to include
+                // the entirety of its CPU time-in-freq stats into the parent's stats.
+                counter.updateValues(
+                        new LongArrayMultiStateCounter.LongArrayContainer(mBsi.getCpuFreqCount()),
+                        mBsi.mClock.elapsedRealtime());
+                mChildUids.put(isolatedUid, counter);
+            } else {
+                mChildUids.put(isolatedUid, null);
+            }
         }
 
         public void removeIsolatedUid(int isolatedUid) {
-            final int idx = mChildUids == null ? -1 : mChildUids.indexOf(isolatedUid);
+            final int idx = mChildUids == null ? -1 : mChildUids.indexOfKey(isolatedUid);
             if (idx < 0) {
                 return;
             }
@@ -7557,31 +7698,37 @@
             return null;
         }
 
-        private void addProcStateTimesMs(int procState, long[] cpuTimesMs, boolean onBattery) {
-            if (mProcStateTimeMs == null) {
-                mProcStateTimeMs = new LongSamplingCounterArray[NUM_PROCESS_STATE];
+        private void ensureMultiStateCounters() {
+            if (mProcStateTimeMs != null) {
+                return;
             }
-            if (mProcStateTimeMs[procState] == null
-                    || mProcStateTimeMs[procState].getSize() != cpuTimesMs.length) {
-                detachIfNotNull(mProcStateTimeMs[procState]);
-                mProcStateTimeMs[procState] = new LongSamplingCounterArray(
-                        mBsi.mOnBatteryTimeBase);
-            }
-            mProcStateTimeMs[procState].addCountLocked(cpuTimesMs, onBattery);
+
+            final long timestampMs = mBsi.mClock.elapsedRealtime();
+            mProcStateTimeMs =
+                    new TimeInFreqMultiStateCounter(mBsi.mOnBatteryTimeBase,
+                            NUM_PROCESS_STATE, mBsi.getCpuFreqCount(), timestampMs);
+            mProcStateScreenOffTimeMs =
+                    new TimeInFreqMultiStateCounter(mBsi.mOnBatteryScreenOffTimeBase,
+                            NUM_PROCESS_STATE, mBsi.getCpuFreqCount(), timestampMs);
         }
 
-        private void addProcStateScreenOffTimesMs(int procState, long[] cpuTimesMs,
-                boolean onBatteryScreenOff) {
-            if (mProcStateScreenOffTimeMs == null) {
-                mProcStateScreenOffTimeMs = new LongSamplingCounterArray[NUM_PROCESS_STATE];
+        private TimeInFreqMultiStateCounter getProcStateTimeCounter() {
+            ensureMultiStateCounters();
+            return mProcStateTimeMs;
+        }
+
+        private TimeInFreqMultiStateCounter getProcStateScreenOffTimeCounter() {
+            ensureMultiStateCounters();
+            return mProcStateScreenOffTimeMs;
+        }
+
+        private void setProcStateTimesTrackingEnabled(boolean enabled, long timestampMs) {
+            if (mProcStateTimeMs != null) {
+                mProcStateTimeMs.setTrackingEnabled(enabled, timestampMs);
             }
-            if (mProcStateScreenOffTimeMs[procState] == null
-                    || mProcStateScreenOffTimeMs[procState].getSize() != cpuTimesMs.length) {
-                detachIfNotNull(mProcStateScreenOffTimeMs[procState]);
-                mProcStateScreenOffTimeMs[procState] = new LongSamplingCounterArray(
-                        mBsi.mOnBatteryScreenOffTimeBase);
+            if (mProcStateScreenOffTimeMs != null) {
+                mProcStateScreenOffTimeMs.setTrackingEnabled(enabled, timestampMs);
             }
-            mProcStateScreenOffTimeMs[procState].addCountLocked(cpuTimesMs, onBatteryScreenOff);
         }
 
         @Override
@@ -9112,18 +9259,14 @@
             mCpuClusterTimesMs.writeToParcel(out);
 
             if (mProcStateTimeMs != null) {
-                out.writeInt(mProcStateTimeMs.length);
-                for (LongSamplingCounterArray counters : mProcStateTimeMs) {
-                    LongSamplingCounterArray.writeToParcel(out, counters);
-                }
+                out.writeInt(mProcStateTimeMs.getStateCount());
+                mProcStateTimeMs.writeToParcel(out);
             } else {
                 out.writeInt(0);
             }
             if (mProcStateScreenOffTimeMs != null) {
-                out.writeInt(mProcStateScreenOffTimeMs.length);
-                for (LongSamplingCounterArray counters : mProcStateScreenOffTimeMs) {
-                    LongSamplingCounterArray.writeToParcel(out, counters);
-                }
+                out.writeInt(mProcStateScreenOffTimeMs.getStateCount());
+                mProcStateScreenOffTimeMs.writeToParcel(out);
             } else {
                 out.writeInt(0);
             }
@@ -9416,22 +9559,27 @@
             mCpuActiveTimeMs = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
             mCpuClusterTimesMs = new LongSamplingCounterArray(mBsi.mOnBatteryTimeBase, in);
 
-            int length = in.readInt();
-            if (length == NUM_PROCESS_STATE) {
-                mProcStateTimeMs = new LongSamplingCounterArray[length];
-                for (int procState = 0; procState < length; ++procState) {
-                    mProcStateTimeMs[procState] = LongSamplingCounterArray.readFromParcel(
-                            in, mBsi.mOnBatteryTimeBase);
+            final long timestampMs = mBsi.mClock.elapsedRealtime();
+            int stateCount = in.readInt();
+            if (stateCount != 0) {
+                // Read the object from the Parcel, whether it's usable or not
+                TimeInFreqMultiStateCounter counter = new TimeInFreqMultiStateCounter(
+                        mBsi.mOnBatteryTimeBase, in, timestampMs);
+                if (stateCount == NUM_PROCESS_STATE) {
+                    mProcStateTimeMs = counter;
                 }
             } else {
                 mProcStateTimeMs = null;
             }
-            length = in.readInt();
-            if (length == NUM_PROCESS_STATE) {
-                mProcStateScreenOffTimeMs = new LongSamplingCounterArray[length];
-                for (int procState = 0; procState < length; ++procState) {
-                    mProcStateScreenOffTimeMs[procState] = LongSamplingCounterArray.readFromParcel(
-                            in, mBsi.mOnBatteryScreenOffTimeBase);
+
+            stateCount = in.readInt();
+            if (stateCount != 0) {
+                // Read the object from the Parcel, whether it's usable or not
+                TimeInFreqMultiStateCounter counter =
+                        new TimeInFreqMultiStateCounter(
+                                mBsi.mOnBatteryScreenOffTimeBase, in, timestampMs);
+                if (stateCount == NUM_PROCESS_STATE) {
+                    mProcStateScreenOffTimeMs = counter;
                 }
             } else {
                 mProcStateScreenOffTimeMs = null;
@@ -10607,6 +10755,16 @@
         return mCpuFreqs;
     }
 
+    /**
+     * Returns the total number of frequencies across all CPU clusters.
+     */
+    private int getCpuFreqCount() {
+        if (mCpuFreqs == null) {
+            mCpuFreqs = mCpuUidFreqTimeReader.readFreqs(mPowerProfile);
+        }
+        return mCpuFreqs != null ? mCpuFreqs.length : 0;
+    }
+
     public BatteryStatsImpl(File systemDir, Handler handler, PlatformIdleStateCallback cb,
             MeasuredEnergyRetriever energyStatsCb, UserInfoProvider userInfoProvider) {
         this(Clock.SYSTEM_CLOCK, systemDir, handler, cb, energyStatsCb, userInfoProvider);
@@ -14751,6 +14909,7 @@
                     DEFAULT_BATTERY_CHARGED_DELAY_MS);
         }
 
+        @GuardedBy("BatteryStatsImpl.this")
         private void updateTrackCpuTimesByProcStateLocked(boolean wasEnabled, boolean isEnabled) {
             TRACK_CPU_TIMES_BY_PROC_STATE = isEnabled;
             if (isEnabled && !wasEnabled) {
@@ -14761,6 +14920,10 @@
                 mNumBatchedSingleUidCpuTimeReads = 0;
                 mCpuTimeReadsTrackingStartTimeMs = mClock.uptimeMillis();
             }
+            final long timestampMs = mClock.elapsedRealtime();
+            for (int i = mUidStats.size() - 1; i >= 0; i--) {
+                mUidStats.valueAt(i).setProcStateTimesTrackingEnabled(isEnabled, timestampMs);
+            }
         }
 
         private void updateProcStateCpuTimesReadDelayMs(long oldDelayMillis, long newDelayMillis) {
@@ -15535,31 +15698,32 @@
             u.mCpuActiveTimeMs.readSummaryFromParcelLocked(in);
             u.mCpuClusterTimesMs.readSummaryFromParcelLocked(in);
 
-            int length = in.readInt();
-            if (length == Uid.NUM_PROCESS_STATE) {
-                detachIfNotNull(u.mProcStateTimeMs);
-                u.mProcStateTimeMs = new LongSamplingCounterArray[length];
-                for (int procState = 0; procState < length; ++procState) {
-                    u.mProcStateTimeMs[procState]
-                            = LongSamplingCounterArray.readSummaryFromParcelLocked(
-                                    in, mOnBatteryTimeBase);
+            detachIfNotNull(u.mProcStateTimeMs);
+            u.mProcStateTimeMs = null;
+
+            int stateCount = in.readInt();
+            if (stateCount != 0) {
+                // Read the object from the Parcel, whether it's usable or not
+                TimeInFreqMultiStateCounter counter = new TimeInFreqMultiStateCounter(
+                        mOnBatteryTimeBase, in, mClock.elapsedRealtime());
+                if (stateCount == Uid.NUM_PROCESS_STATE) {
+                    u.mProcStateTimeMs = counter;
                 }
-            } else {
-                detachIfNotNull(u.mProcStateTimeMs);
-                u.mProcStateTimeMs = null;
             }
-            length = in.readInt();
-            if (length == Uid.NUM_PROCESS_STATE) {
+
+            detachIfNotNull(u.mProcStateScreenOffTimeMs);
+            u.mProcStateScreenOffTimeMs = null;
+
+            stateCount = in.readInt();
+            if (stateCount != 0) {
                 detachIfNotNull(u.mProcStateScreenOffTimeMs);
-                u.mProcStateScreenOffTimeMs = new LongSamplingCounterArray[length];
-                for (int procState = 0; procState < length; ++procState) {
-                    u.mProcStateScreenOffTimeMs[procState]
-                            = LongSamplingCounterArray.readSummaryFromParcelLocked(
-                                    in, mOnBatteryScreenOffTimeBase);
+                // Read the object from the Parcel, whether it's usable or not
+                TimeInFreqMultiStateCounter counter =
+                        new TimeInFreqMultiStateCounter(
+                                mOnBatteryScreenOffTimeBase, in, mClock.elapsedRealtime());
+                if (stateCount == Uid.NUM_PROCESS_STATE) {
+                    u.mProcStateScreenOffTimeMs = counter;
                 }
-            } else {
-                detachIfNotNull(u.mProcStateScreenOffTimeMs);
-                u.mProcStateScreenOffTimeMs = null;
             }
 
             if (in.readInt() != 0) {
@@ -16062,18 +16226,15 @@
             u.mCpuClusterTimesMs.writeSummaryToParcelLocked(out);
 
             if (u.mProcStateTimeMs != null) {
-                out.writeInt(u.mProcStateTimeMs.length);
-                for (LongSamplingCounterArray counters : u.mProcStateTimeMs) {
-                    LongSamplingCounterArray.writeSummaryToParcelLocked(out, counters);
-                }
+                out.writeInt(u.mProcStateTimeMs.getStateCount());
+                u.mProcStateTimeMs.writeToParcel(out);
             } else {
                 out.writeInt(0);
             }
+
             if (u.mProcStateScreenOffTimeMs != null) {
-                out.writeInt(u.mProcStateScreenOffTimeMs.length);
-                for (LongSamplingCounterArray counters : u.mProcStateScreenOffTimeMs) {
-                    LongSamplingCounterArray.writeSummaryToParcelLocked(out, counters);
-                }
+                out.writeInt(u.mProcStateScreenOffTimeMs.getStateCount());
+                u.mProcStateScreenOffTimeMs.writeToParcel(out);
             } else {
                 out.writeInt(0);
             }
diff --git a/core/java/com/android/internal/os/KernelSingleUidTimeReader.java b/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
index 31952eb..9052644 100644
--- a/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
+++ b/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
@@ -243,6 +243,23 @@
         }
     }
 
+    /**
+     * Retrieves CPU time-in-state data for the specified UID and adds the accumulated
+     * delta to the supplied counter.
+     */
+    public void addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs) {
+        mInjector.addDelta(uid, counter, timestampMs, null);
+    }
+
+    /**
+     * Same as {@link #addDelta(int, LongArrayMultiStateCounter, long)}, also returning
+     * the delta in the supplied array container.
+     */
+    public void addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs,
+            LongArrayMultiStateCounter.LongArrayContainer deltaContainer) {
+        mInjector.addDelta(uid, counter, timestampMs, deltaContainer);
+    }
+
     @VisibleForTesting
     public static class Injector {
         public byte[] readData(String procFile) throws IOException {
@@ -254,14 +271,19 @@
         /**
          * Reads CPU time-in-state data for the specified UID and adds the delta since the
          * previous call to the current state stats in the LongArrayMultiStateCounter.
+         *
+         * The delta is also returned via the optional deltaOut parameter.
          */
-        public boolean addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs) {
-            return addDeltaFromBpf(uid, counter.mNativeObject, timestampMs);
+        public boolean addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs,
+                LongArrayMultiStateCounter.LongArrayContainer deltaOut) {
+            return addDeltaFromBpf(uid, counter.mNativeObject, timestampMs,
+                    deltaOut != null ? deltaOut.mNativeObject : 0);
         }
 
         @CriticalNative
         private static native boolean addDeltaFromBpf(int uid,
-                long longArrayMultiStateCounterNativePointer, long timestampMs);
+                long longArrayMultiStateCounterNativePointer, long timestampMs,
+                long longArrayContainerNativePointer);
 
         /**
          * Used for testing.
@@ -269,13 +291,15 @@
          * Takes mock cpu-time-in-frequency data and uses it the same way eBPF data would be used.
          */
         public boolean addDeltaForTest(int uid, LongArrayMultiStateCounter counter,
-                long timestampMs, long[][] timeInFreqDataNanos) {
-            return addDeltaForTest(uid, counter.mNativeObject, timestampMs, timeInFreqDataNanos);
+                long timestampMs, long[][] timeInFreqDataNanos,
+                LongArrayMultiStateCounter.LongArrayContainer deltaOut) {
+            return addDeltaForTest(uid, counter.mNativeObject, timestampMs, timeInFreqDataNanos,
+                    deltaOut != null ? deltaOut.mNativeObject : 0);
         }
 
         private static native boolean addDeltaForTest(int uid,
                 long longArrayMultiStateCounterNativePointer, long timestampMs,
-                long[][] timeInFreqDataNanos);
+                long[][] timeInFreqDataNanos, long longArrayContainerNativePointer);
     }
 
     @VisibleForTesting
diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
index aecab3d..d98b73f 100644
--- a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
+++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
@@ -26,6 +26,8 @@
 
 import libcore.util.NativeAllocationRegistry;
 
+import java.util.Arrays;
+
 /**
  * Performs per-state counting of multi-element values over time. The class' behavior is illustrated
  * by this example:
@@ -62,7 +64,9 @@
                 NativeAllocationRegistry.createMalloced(
                         LongArrayContainer.class.getClassLoader(), native_getReleaseFunc());
 
-        private final long mNativeObject;
+        // Visible to other objects in this package so that it can be passed to @CriticalNative
+        // methods.
+        final long mNativeObject;
         private final int mLength;
 
         public LongArrayContainer(int length) {
@@ -93,6 +97,13 @@
             native_getValues(mNativeObject, array);
         }
 
+        @Override
+        public String toString() {
+            final long[] array = new long[mLength];
+            getValues(array);
+            return Arrays.toString(array);
+        }
+
         @CriticalNative
         private static native long native_init(int length);
 
@@ -133,6 +144,14 @@
         mLength = native_getArrayLength(mNativeObject);
     }
 
+    public int getStateCount() {
+        return mStateCount;
+    }
+
+    public int getArrayLength() {
+        return mLength;
+    }
+
     /**
      * Enables or disables the counter.  When the counter is disabled, it does not
      * accumulate counts supplied by the {@link #updateValues} method.
@@ -147,7 +166,7 @@
     public void setState(int state, long timestampMs) {
         if (state < 0 || state >= mStateCount) {
             throw new IllegalArgumentException(
-                    "State: " + state + ", outside the range: [0-" + mStateCount + "]");
+                    "State: " + state + ", outside the range: [0-" + (mStateCount - 1) + "]");
         }
         native_setState(mNativeObject, state, timestampMs);
     }
@@ -167,6 +186,17 @@
     }
 
     /**
+     * Adds the supplied values to the current accumulated values in the counter.
+     */
+    public void addCounts(LongArrayContainer counts) {
+        if (counts.mLength != mLength) {
+            throw new IllegalArgumentException(
+                    "Invalid array length: " + counts.mLength + ", expected: " + mLength);
+        }
+        native_addCounts(mNativeObject, counts.mNativeObject);
+    }
+
+    /**
      * Resets the accumulated counts to 0.
      */
     public void reset() {
@@ -231,6 +261,10 @@
             long longArrayContainerNativeObject, long timestampMs);
 
     @CriticalNative
+    private static native void native_addCounts(long nativeObject,
+            long longArrayContainerNativeObject);
+
+    @CriticalNative
     private static native void native_reset(long nativeObject);
 
     @CriticalNative
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
index 776a705..3915b0e 100644
--- a/core/java/com/android/internal/os/WifiPowerCalculator.java
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -215,6 +215,9 @@
                             + "ms tx=" + txTime + "ms power=" + formatCharge(
                             powerDurationAndTraffic.powerMah));
                 }
+            } else {
+                powerDurationAndTraffic.durationMs = 0;
+                powerDurationAndTraffic.powerMah = 0;
             }
         } else {
             final long wifiRunningTime = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000;
diff --git a/core/java/com/android/internal/view/ListViewCaptureHelper.java b/core/java/com/android/internal/view/ListViewCaptureHelper.java
index c25b4b5..f4a5b71 100644
--- a/core/java/com/android/internal/view/ListViewCaptureHelper.java
+++ b/core/java/com/android/internal/view/ListViewCaptureHelper.java
@@ -39,6 +39,12 @@
     private int mOverScrollMode;
 
     @Override
+    public boolean onAcceptSession(@NonNull ListView view) {
+        return view.isVisibleToUser()
+                && (view.canScrollVertically(UP) || view.canScrollVertically(DOWN));
+    }
+
+    @Override
     public void onPrepareForStart(@NonNull ListView view, Rect scrollBounds) {
         mScrollDelta = 0;
 
@@ -114,7 +120,6 @@
         return result;
     }
 
-
     @Override
     public void onPrepareForEnd(@NonNull ListView listView) {
         // Restore original position and state
diff --git a/core/java/com/android/internal/view/RecyclerViewCaptureHelper.java b/core/java/com/android/internal/view/RecyclerViewCaptureHelper.java
index d14adf6..64622f0 100644
--- a/core/java/com/android/internal/view/RecyclerViewCaptureHelper.java
+++ b/core/java/com/android/internal/view/RecyclerViewCaptureHelper.java
@@ -44,6 +44,12 @@
     private int mOverScrollMode;
 
     @Override
+    public boolean onAcceptSession(@NonNull ViewGroup view) {
+        return view.isVisibleToUser()
+                && (view.canScrollVertically(UP) || view.canScrollVertically(DOWN));
+    }
+
+    @Override
     public void onPrepareForStart(@NonNull ViewGroup view, Rect scrollBounds) {
         mScrollDelta = 0;
 
diff --git a/core/java/com/android/internal/view/ScrollCaptureViewHelper.java b/core/java/com/android/internal/view/ScrollCaptureViewHelper.java
index 356cd6b..baf725d 100644
--- a/core/java/com/android/internal/view/ScrollCaptureViewHelper.java
+++ b/core/java/com/android/internal/view/ScrollCaptureViewHelper.java
@@ -67,10 +67,7 @@
      * @param view the view being captured
      * @return true if the callback should respond to a request with scroll bounds
      */
-    default boolean onAcceptSession(@NonNull V view) {
-        return view.isVisibleToUser()
-                && (view.canScrollVertically(UP) || view.canScrollVertically(DOWN));
-    }
+    boolean onAcceptSession(@NonNull V view);
 
     /**
      * Given a scroll capture request for a view, adjust the provided rect to cover the scrollable
diff --git a/core/java/com/android/internal/view/ScrollViewCaptureHelper.java b/core/java/com/android/internal/view/ScrollViewCaptureHelper.java
index a360f63..db7881f 100644
--- a/core/java/com/android/internal/view/ScrollViewCaptureHelper.java
+++ b/core/java/com/android/internal/view/ScrollViewCaptureHelper.java
@@ -43,6 +43,11 @@
     private boolean mScrollBarEnabled;
     private int mOverScrollMode;
 
+    public boolean onAcceptSession(@NonNull ViewGroup view) {
+        return view.isVisibleToUser()
+                && (view.canScrollVertically(UP) || view.canScrollVertically(DOWN));
+    }
+
     public void onPrepareForStart(@NonNull ViewGroup view, Rect scrollBounds) {
         mStartScrollY = view.getScrollY();
         mOverScrollMode = view.getOverScrollMode();
diff --git a/core/java/com/android/internal/view/WebViewCaptureHelper.java b/core/java/com/android/internal/view/WebViewCaptureHelper.java
index e6a311c..37ce782 100644
--- a/core/java/com/android/internal/view/WebViewCaptureHelper.java
+++ b/core/java/com/android/internal/view/WebViewCaptureHelper.java
@@ -28,7 +28,7 @@
 /**
  * ScrollCapture for WebView.
  */
-class WebViewCaptureHelper implements ScrollCaptureViewHelper<WebView> {
+public class WebViewCaptureHelper implements ScrollCaptureViewHelper<WebView> {
     private static final String TAG = "WebViewScrollCapture";
 
     private final Rect mRequestWebViewLocal = new Rect();
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index b0cf5dc..d7eef0d 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -488,12 +488,14 @@
     }
 
     private void readAllPermissions() {
+        final XmlPullParser parser = Xml.newPullParser();
+
         // Read configuration from system
-        readPermissions(Environment.buildPath(
+        readPermissions(parser, Environment.buildPath(
                 Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
 
         // Read configuration from the old permissions dir
-        readPermissions(Environment.buildPath(
+        readPermissions(parser, Environment.buildPath(
                 Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
 
         // Vendors are only allowed to customize these
@@ -503,18 +505,18 @@
             // For backward compatibility
             vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS);
         }
-        readPermissions(Environment.buildPath(
+        readPermissions(parser, Environment.buildPath(
                 Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
-        readPermissions(Environment.buildPath(
+        readPermissions(parser, Environment.buildPath(
                 Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
 
         String vendorSkuProperty = SystemProperties.get(VENDOR_SKU_PROPERTY, "");
         if (!vendorSkuProperty.isEmpty()) {
             String vendorSkuDir = "sku_" + vendorSkuProperty;
-            readPermissions(Environment.buildPath(
+            readPermissions(parser, Environment.buildPath(
                     Environment.getVendorDirectory(), "etc", "sysconfig", vendorSkuDir),
                     vendorPermissionFlag);
-            readPermissions(Environment.buildPath(
+            readPermissions(parser, Environment.buildPath(
                     Environment.getVendorDirectory(), "etc", "permissions", vendorSkuDir),
                     vendorPermissionFlag);
         }
@@ -522,18 +524,18 @@
         // Allow ODM to customize system configs as much as Vendor, because /odm is another
         // vendor partition other than /vendor.
         int odmPermissionFlag = vendorPermissionFlag;
-        readPermissions(Environment.buildPath(
+        readPermissions(parser, Environment.buildPath(
                 Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
-        readPermissions(Environment.buildPath(
+        readPermissions(parser, Environment.buildPath(
                 Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
 
         String skuProperty = SystemProperties.get(SKU_PROPERTY, "");
         if (!skuProperty.isEmpty()) {
             String skuDir = "sku_" + skuProperty;
 
-            readPermissions(Environment.buildPath(
+            readPermissions(parser, Environment.buildPath(
                     Environment.getOdmDirectory(), "etc", "sysconfig", skuDir), odmPermissionFlag);
-            readPermissions(Environment.buildPath(
+            readPermissions(parser, Environment.buildPath(
                     Environment.getOdmDirectory(), "etc", "permissions", skuDir),
                     odmPermissionFlag);
         }
@@ -541,9 +543,9 @@
         // Allow OEM to customize these
         int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS
                 | ALLOW_VENDOR_APEX;
-        readPermissions(Environment.buildPath(
+        readPermissions(parser, Environment.buildPath(
                 Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag);
-        readPermissions(Environment.buildPath(
+        readPermissions(parser, Environment.buildPath(
                 Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);
 
         // Allow Product to customize these configs
@@ -558,15 +560,15 @@
             // DEVICE_INITIAL_SDK_INT for the devices without product interface enforcement.
             productPermissionFlag = ALLOW_ALL;
         }
-        readPermissions(Environment.buildPath(
+        readPermissions(parser, Environment.buildPath(
                 Environment.getProductDirectory(), "etc", "sysconfig"), productPermissionFlag);
-        readPermissions(Environment.buildPath(
+        readPermissions(parser, Environment.buildPath(
                 Environment.getProductDirectory(), "etc", "permissions"), productPermissionFlag);
 
         // Allow /system_ext to customize all system configs
-        readPermissions(Environment.buildPath(
+        readPermissions(parser, Environment.buildPath(
                 Environment.getSystemExtDirectory(), "etc", "sysconfig"), ALLOW_ALL);
-        readPermissions(Environment.buildPath(
+        readPermissions(parser, Environment.buildPath(
                 Environment.getSystemExtDirectory(), "etc", "permissions"), ALLOW_ALL);
 
         // Skip loading configuration from apex if it is not a system process.
@@ -580,12 +582,13 @@
             if (f.isFile() || f.getPath().contains("@")) {
                 continue;
             }
-            readPermissions(Environment.buildPath(f, "etc", "permissions"), apexPermissionFlag);
+            readPermissions(parser, Environment.buildPath(f, "etc", "permissions"),
+                    apexPermissionFlag);
         }
     }
 
     @VisibleForTesting
-    public void readPermissions(File libraryDir, int permissionFlag) {
+    public void readPermissions(final XmlPullParser parser, File libraryDir, int permissionFlag) {
         // Read permissions from given directory.
         if (!libraryDir.exists() || !libraryDir.isDirectory()) {
             if (permissionFlag == ALLOW_ALL) {
@@ -620,12 +623,12 @@
                 continue;
             }
 
-            readPermissionsFromXml(f, permissionFlag);
+            readPermissionsFromXml(parser, f, permissionFlag);
         }
 
         // Read platform permissions last so it will take precedence
         if (platformFile != null) {
-            readPermissionsFromXml(platformFile, permissionFlag);
+            readPermissionsFromXml(parser, platformFile, permissionFlag);
         }
     }
 
@@ -634,8 +637,9 @@
                 + permFile + " at " + parser.getPositionDescription());
     }
 
-    private void readPermissionsFromXml(File permFile, int permissionFlag) {
-        FileReader permReader = null;
+    private void readPermissionsFromXml(final XmlPullParser parser, File permFile,
+            int permissionFlag) {
+        final FileReader permReader;
         try {
             permReader = new FileReader(permFile);
         } catch (FileNotFoundException e) {
@@ -647,7 +651,6 @@
         final boolean lowRam = ActivityManager.isLowRamDeviceStatic();
 
         try {
-            XmlPullParser parser = Xml.newPullParser();
             parser.setInput(permReader);
 
             int type;
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 7b79b38..67ab30b 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -621,6 +621,8 @@
                              "(Z)V");
     gInputEventReceiverClassInfo.onDragEvent =
             GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onDragEvent", "(ZFF)V");
+    gInputEventReceiverClassInfo.onTouchModeChanged =
+            GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onTouchModeChanged", "(Z)V");
     gInputEventReceiverClassInfo.onBatchedInputEventPending =
             GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onBatchedInputEventPending",
                              "(I)V");
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 5c096dd..dae844f 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -238,6 +238,11 @@
     jmethodID ctor;
 } gJankDataClassInfo;
 
+static struct {
+    jclass clazz;
+    jmethodID onTransactionCommitted;
+} gTransactionCommittedListenerClassInfo;
+
 class JNamedColorSpace {
 public:
     // ColorSpace.Named.SRGB.ordinal() = 0;
@@ -329,6 +334,44 @@
     }
 };
 
+class TransactionCommittedListenerWrapper {
+public:
+    explicit TransactionCommittedListenerWrapper(JNIEnv* env, jobject object) {
+        env->GetJavaVM(&mVm);
+        mTransactionCommittedListenerObject = env->NewGlobalRef(object);
+        LOG_ALWAYS_FATAL_IF(!mTransactionCommittedListenerObject, "Failed to make global ref");
+    }
+
+    ~TransactionCommittedListenerWrapper() {
+        getenv()->DeleteGlobalRef(mTransactionCommittedListenerObject);
+    }
+
+    void callback() {
+        JNIEnv* env = getenv();
+        env->CallVoidMethod(mTransactionCommittedListenerObject,
+                            gTransactionCommittedListenerClassInfo.onTransactionCommitted);
+    }
+
+    static void transactionCallbackThunk(void* context, nsecs_t /*latchTime*/,
+                                         const sp<Fence>& /*presentFence*/,
+                                         const std::vector<SurfaceControlStats>& /*stats*/) {
+        TransactionCommittedListenerWrapper* listener =
+                reinterpret_cast<TransactionCommittedListenerWrapper*>(context);
+        listener->callback();
+        delete listener;
+    }
+
+private:
+    jobject mTransactionCommittedListenerObject;
+    JavaVM* mVm;
+
+    JNIEnv* getenv() {
+        JNIEnv* env;
+        mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+        return env;
+    }
+};
+
 // ----------------------------------------------------------------------------
 
 static jlong nativeCreateTransaction(JNIEnv* env, jclass clazz) {
@@ -898,6 +941,12 @@
     return array;
 }
 
+static jlong nativeGetPrimaryPhysicalDisplayId(JNIEnv* env, jclass clazz) {
+    PhysicalDisplayId displayId;
+    SurfaceComposerClient::getPrimaryPhysicalDisplayId(&displayId);
+    return static_cast<jlong>(displayId.value);
+}
+
 static jobject nativeGetPhysicalDisplayToken(JNIEnv* env, jclass clazz, jlong physicalDisplayId) {
     const auto id = DisplayId::fromValue<PhysicalDisplayId>(physicalDisplayId);
     if (!id) return nullptr;
@@ -1730,6 +1779,17 @@
             {frameTimelineVsyncId, android::os::IInputConstants::INVALID_INPUT_EVENT_ID});
 }
 
+static void nativeAddTransactionCommittedListener(JNIEnv* env, jclass clazz, jlong transactionObj,
+                                                  jobject transactionCommittedListenerObject) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+    void* context =
+            new TransactionCommittedListenerWrapper(env, transactionCommittedListenerObject);
+    transaction->addTransactionCommittedCallback(TransactionCommittedListenerWrapper::
+                                                         transactionCallbackThunk,
+                                                 context);
+}
+
 class JankDataListenerWrapper : public JankDataListener {
 public:
     JankDataListenerWrapper(JNIEnv* env, jobject onJankDataListenerObject) {
@@ -1906,6 +1966,8 @@
             (void*)nativeReleaseFrameRateFlexibilityToken },
     {"nativeGetPhysicalDisplayIds", "()[J",
             (void*)nativeGetPhysicalDisplayIds },
+    {"nativeGetPrimaryPhysicalDisplayId", "()J",
+            (void*)nativeGetPrimaryPhysicalDisplayId },
     {"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;",
             (void*)nativeGetPhysicalDisplayToken },
     {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
@@ -2027,6 +2089,8 @@
             (void*)nativeGetLayerId },
     {"nativeSetDropInputMode", "(JJI)V",
              (void*)nativeSetDropInputMode },
+    {"nativeAddTransactionCommittedListener", "(JLandroid/view/TransactionCommittedListener;)V",
+            (void*) nativeAddTransactionCommittedListener },
         // clang-format on
 };
 
@@ -2242,6 +2306,14 @@
     gJankDataListenerClassInfo.onJankDataAvailable =
             GetMethodIDOrDie(env, onJankDataListenerClazz, "onJankDataAvailable",
                              "([Landroid/view/SurfaceControl$JankData;)V");
+
+    jclass transactionCommittedListenerClazz =
+            FindClassOrDie(env, "android/view/TransactionCommittedListener");
+    gTransactionCommittedListenerClassInfo.clazz =
+            MakeGlobalRefOrDie(env, transactionCommittedListenerClazz);
+    gTransactionCommittedListenerClassInfo.onTransactionCommitted =
+            GetMethodIDOrDie(env, transactionCommittedListenerClazz, "onTransactionCommitted",
+                             "()V");
     return err;
 }
 
diff --git a/core/jni/com_android_internal_os_KernelSingleUidTimeReader.cpp b/core/jni/com_android_internal_os_KernelSingleUidTimeReader.cpp
index 689b259..bea5ffe 100644
--- a/core/jni/com_android_internal_os_KernelSingleUidTimeReader.cpp
+++ b/core/jni/com_android_internal_os_KernelSingleUidTimeReader.cpp
@@ -50,7 +50,8 @@
  */
 static jboolean addCpuTimeInFreqDelta(
         jint uid, jlong counterNativePtr, jlong timestampMs,
-        std::optional<std::vector<std::vector<uint64_t>>> timeInFreqDataNanos) {
+        std::optional<std::vector<std::vector<uint64_t>>> timeInFreqDataNanos,
+        jlong deltaOutContainerNativePtr) {
     if (!timeInFreqDataNanos) {
         return false;
     }
@@ -70,20 +71,35 @@
     for (size_t i = 0; i < s; ++i) {
         flattened[i] /= NSEC_PER_MSEC;
     }
-    counter->updateValue(flattened, timestampMs);
+    if (s != counter->getCount(0).size()) { // Counter has at least one state
+        ALOGE("Mismatch between eBPF data size (%d) and the counter size (%d)", (int)s,
+              (int)counter->getCount(0).size());
+        return false;
+    }
+
+    const std::vector<uint64_t> &delta = counter->updateValue(flattened, timestampMs);
+    if (deltaOutContainerNativePtr) {
+        std::vector<uint64_t> *vector =
+                reinterpret_cast<std::vector<uint64_t> *>(deltaOutContainerNativePtr);
+        *vector = delta;
+    }
+
     return true;
 }
 
-static jboolean addDeltaFromBpf(jint uid, jlong counterNativePtr, jlong timestampMs) {
+static jboolean addDeltaFromBpf(jint uid, jlong counterNativePtr, jlong timestampMs,
+                                jlong deltaOutContainerNativePtr) {
     return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs,
-                                 android::bpf::getUidCpuFreqTimes(uid));
+                                 android::bpf::getUidCpuFreqTimes(uid), deltaOutContainerNativePtr);
 }
 
 static jboolean addDeltaForTest(JNIEnv *env, jclass, jint uid, jlong counterNativePtr,
-                                jlong timestampMs, jobjectArray timeInFreqDataNanos) {
+                                jlong timestampMs, jobjectArray timeInFreqDataNanos,
+                                jlong deltaOutContainerNativePtr) {
     if (!timeInFreqDataNanos) {
         return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs,
-                                     std::optional<std::vector<std::vector<uint64_t>>>());
+                                     std::optional<std::vector<std::vector<uint64_t>>>(),
+                                     deltaOutContainerNativePtr);
     }
 
     std::vector<std::vector<uint64_t>> timeInFreqData;
@@ -97,17 +113,18 @@
         }
         timeInFreqData.push_back(cluster);
     }
-    return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs, std::optional(timeInFreqData));
+    return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs, std::optional(timeInFreqData),
+                                 deltaOutContainerNativePtr);
 }
 
 static const JNINativeMethod g_single_methods[] = {
         {"readBpfData", "(I)[J", (void *)getUidCpuFreqTimeMs},
 
         // @CriticalNative
-        {"addDeltaFromBpf", "(IJJ)Z", (void *)addDeltaFromBpf},
+        {"addDeltaFromBpf", "(IJJJ)Z", (void *)addDeltaFromBpf},
 
         // Used for testing
-        {"addDeltaForTest", "(IJJ[[J)Z", (void *)addDeltaForTest},
+        {"addDeltaForTest", "(IJJ[[JJ)Z", (void *)addDeltaForTest},
 };
 
 int register_com_android_internal_os_KernelSingleUidTimeReader(JNIEnv *env) {
diff --git a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
index 8326de2..6e7ebda 100644
--- a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
+++ b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
@@ -65,6 +65,14 @@
     counter->updateValue(*vector, timestamp);
 }
 
+static void native_addCounts(jlong nativePtr, jlong longArrayContainerNativePtr) {
+    battery::LongArrayMultiStateCounter *counter =
+            reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
+    std::vector<uint64_t> *vector =
+            reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
+    counter->addValue(*vector);
+}
+
 static void native_reset(jlong nativePtr) {
     battery::LongArrayMultiStateCounter *counter =
             reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
@@ -184,6 +192,8 @@
         // @CriticalNative
         {"native_updateValues", "(JJJ)V", (void *)native_updateValues},
         // @CriticalNative
+        {"native_addCounts", "(JJ)V", (void *)native_addCounts},
+        // @CriticalNative
         {"native_reset", "(J)V", (void *)native_reset},
         // @CriticalNative
         {"native_getCounts", "(JJI)V", (void *)native_getCounts},
diff --git a/core/proto/android/app/window_configuration.proto b/core/proto/android/app/window_configuration.proto
index b158b31..a3757ad 100644
--- a/core/proto/android/app/window_configuration.proto
+++ b/core/proto/android/app/window_configuration.proto
@@ -21,14 +21,15 @@
 
 import "frameworks/base/core/proto/android/graphics/rect.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/base/core/proto/android/typedef.proto";
 
 /** Proto representation for WindowConfiguration.java class. */
 message WindowConfigurationProto {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional .android.graphics.RectProto app_bounds = 1;
-    optional int32 windowing_mode = 2;
-    optional int32 activity_type = 3;
+    optional int32 windowing_mode = 2 [(.android.typedef) = "android.app.WindowConfiguration.WindowingMode"];
+    optional int32 activity_type = 3 [(.android.typedef) = "android.app.WindowConfiguration.ActivityType"];
     optional .android.graphics.RectProto bounds = 4;
     optional .android.graphics.RectProto max_bounds = 5;
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 20beaf7..c2c8239 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2950,13 +2950,11 @@
                 android:protectionLevel="signature" />
 
     <!-- Allows an app to set and release automotive projection.
-         <p>Once permissions can be granted via role-only, this needs to be changed to
-          protectionLevel="role" and added to the SYSTEM_AUTOMOTIVE_PROJECTION role.
          @hide
          @SystemApi
     -->
     <permission android:name="android.permission.TOGGLE_AUTOMOTIVE_PROJECTION"
-                android:protectionLevel="signature|privileged" />
+                android:protectionLevel="internal|role" />
 
     <!-- Allows an app to prevent non-system-overlay windows from being drawn on top of it -->
     <permission android:name="android.permission.HIDE_OVERLAY_WINDOWS"
@@ -4335,6 +4333,11 @@
     <permission android:name="android.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE"
                 android:protectionLevel="normal" />
 
+    <!-- Allows an application to deliver companion messages to system
+         -->
+    <permission android:name="android.permission.DELIVER_COMPANION_MESSAGES"
+                android:protectionLevel="normal" />
+
     <!-- Allows an application to create new companion device associations.
          @SystemApi
          @hide -->
diff --git a/core/res/res/anim-ldrtl/cross_profile_apps_thumbnail_enter.xml b/core/res/res/anim-ldrtl/cross_profile_apps_thumbnail_enter.xml
index 5add19b..aa38000 100644
--- a/core/res/res/anim-ldrtl/cross_profile_apps_thumbnail_enter.xml
+++ b/core/res/res/anim-ldrtl/cross_profile_apps_thumbnail_enter.xml
@@ -18,19 +18,9 @@
 -->
 <!-- This should be kept in sync with task_open_enter.xml -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-     android:hasRoundedCorners="true"
      android:shareInterpolator="false"
-     android:zAdjustment="top">
-
-    <alpha
-        android:fromAlpha="1"
-        android:toAlpha="1.0"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/linear"
-        android:startOffset="67"
-        android:duration="217"/>
+     android:zAdjustment="top"
+     android:hasRoundedCorners="true">
 
     <translate
         android:fromXDelta="-105%"
@@ -38,36 +28,9 @@
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
-        android:interpolator="@interpolator/aggressive_ease"
-        android:startOffset="50"
-        android:duration="383"/>
-
-    <scale
-        android:fromXScale="1.0526"
-        android:toXScale="1"
-        android:fromYScale="1.0526"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="283"/>
-
-    <scale
-        android:fromXScale="0.95"
-        android:toXScale="1"
-        android:fromYScale="0.95"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:startOffset="283"
-        android:duration="317"/>
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:startOffset="0"
+        android:duration="500"/>
 
     <!-- To keep the thumbnail around longer and fade out the thumbnail -->
     <alpha android:fromAlpha="1.0" android:toAlpha="0"
diff --git a/core/res/res/anim-ldrtl/task_close_enter.xml b/core/res/res/anim-ldrtl/task_close_enter.xml
index e00141a..5ace46d 100644
--- a/core/res/res/anim-ldrtl/task_close_enter.xml
+++ b/core/res/res/anim-ldrtl/task_close_enter.xml
@@ -14,20 +14,9 @@
   ~ limitations under the License
   -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false"
-    android:zAdjustment="top"
-    android:hasRoundedCorners="true"
-    android:showWallpaper="true">
-
-    <alpha
-        android:fromAlpha="1"
-        android:toAlpha="1.0"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/linear"
-        android:startOffset="67"
-        android:duration="217"/>
+     android:shareInterpolator="false"
+     android:zAdjustment="top"
+     android:hasRoundedCorners="true">
 
     <translate
         android:fromXDelta="105%"
@@ -35,34 +24,7 @@
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
-        android:interpolator="@interpolator/aggressive_ease"
-        android:startOffset="50"
-        android:duration="383"/>
-
-    <scale
-        android:fromXScale="1.0526"
-        android:toXScale="1"
-        android:fromYScale="1.0526"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="283"/>
-
-    <scale
-        android:fromXScale="0.95"
-        android:toXScale="1"
-        android:fromYScale="0.95"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:startOffset="283"
-        android:duration="317"/>
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:startOffset="0"
+        android:duration="500"/>
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim-ldrtl/task_close_exit.xml b/core/res/res/anim-ldrtl/task_close_exit.xml
index 71a44ae..76fbdff 100644
--- a/core/res/res/anim-ldrtl/task_close_exit.xml
+++ b/core/res/res/anim-ldrtl/task_close_exit.xml
@@ -15,19 +15,8 @@
   -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false"
-    android:hasRoundedCorners="true"
-    android:showWallpaper="true">
-
-    <alpha
-        android:fromAlpha="1.0"
-        android:toAlpha="1"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/linear"
-        android:startOffset="67"
-        android:duration="283"/>
+     android:shareInterpolator="false"
+     android:hasRoundedCorners="true">
 
     <translate
         android:fromXDelta="0"
@@ -35,22 +24,9 @@
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
-        android:interpolator="@interpolator/aggressive_ease"
-        android:startOffset="50"
-        android:duration="383"/>
-
-    <scale
-        android:fromXScale="1.0"
-        android:toXScale="0.95"
-        android:fromYScale="1.0"
-        android:toYScale="0.95"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="283"/>
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:startOffset="0"
+        android:duration="500"/>
 
     <!-- This is needed to keep the animation running while task_open_enter completes -->
     <alpha
diff --git a/core/res/res/anim-ldrtl/task_open_enter.xml b/core/res/res/anim-ldrtl/task_open_enter.xml
index 7815f7d..52c74a6 100644
--- a/core/res/res/anim-ldrtl/task_open_enter.xml
+++ b/core/res/res/anim-ldrtl/task_open_enter.xml
@@ -16,20 +16,9 @@
 <!-- This should in sync with task_open_enter_cross_profile_apps.xml -->
 <!-- This should in sync with cross_profile_apps_thumbnail_enter.xml -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false"
-    android:zAdjustment="top"
-    android:hasRoundedCorners="true"
-    android:showWallpaper="true">
-
-    <alpha
-        android:fromAlpha="1"
-        android:toAlpha="1.0"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/linear"
-        android:startOffset="67"
-        android:duration="217"/>
+     android:shareInterpolator="false"
+     android:zAdjustment="top"
+     android:hasRoundedCorners="true">
 
     <translate
         android:fromXDelta="-105%"
@@ -37,34 +26,7 @@
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
-        android:interpolator="@interpolator/aggressive_ease"
-        android:startOffset="50"
-        android:duration="383"/>
-
-    <scale
-        android:fromXScale="1.0526"
-        android:toXScale="1"
-        android:fromYScale="1.0526"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="283"/>
-
-    <scale
-        android:fromXScale="0.95"
-        android:toXScale="1"
-        android:fromYScale="0.95"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:startOffset="283"
-        android:duration="317"/>
-</set>
\ No newline at end of file
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:startOffset="0"
+        android:duration="500"/>
+</set>
diff --git a/core/res/res/anim-ldrtl/task_open_enter_cross_profile_apps.xml b/core/res/res/anim-ldrtl/task_open_enter_cross_profile_apps.xml
index 5fccd6df..90ec071 100644
--- a/core/res/res/anim-ldrtl/task_open_enter_cross_profile_apps.xml
+++ b/core/res/res/anim-ldrtl/task_open_enter_cross_profile_apps.xml
@@ -16,20 +16,9 @@
   -->
 <!-- This should in sync with task_open_enter.xml -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false"
-    android:zAdjustment="top"
-    android:hasRoundedCorners="true"
-    android:showWallpaper="true">
-
-    <alpha
-        android:fromAlpha="1"
-        android:toAlpha="1.0"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/linear"
-        android:startOffset="67"
-        android:duration="217"/>
+     android:shareInterpolator="false"
+     android:zAdjustment="top"
+     android:hasRoundedCorners="true">
 
     <translate
         android:fromXDelta="-105%"
@@ -37,36 +26,9 @@
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
-        android:interpolator="@interpolator/aggressive_ease"
-        android:startOffset="50"
-        android:duration="383"/>
-
-    <scale
-        android:fromXScale="1.0526"
-        android:toXScale="1"
-        android:fromYScale="1.0526"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="283"/>
-
-    <scale
-        android:fromXScale="0.95"
-        android:toXScale="1"
-        android:fromYScale="0.95"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:startOffset="283"
-        android:duration="317"/>
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:startOffset="0"
+        android:duration="500"/>
 
     <!-- To keep the transition around longer for the thumbnail, should be kept in sync with
          cross_profile_apps_thumbmail.xml -->
@@ -75,4 +37,4 @@
         android:toAlpha="1.0"
         android:startOffset="717"
         android:duration="200"/>
-</set>
\ No newline at end of file
+</set>
diff --git a/core/res/res/anim-ldrtl/task_open_exit.xml b/core/res/res/anim-ldrtl/task_open_exit.xml
index 025e1bd..beb6fca 100644
--- a/core/res/res/anim-ldrtl/task_open_exit.xml
+++ b/core/res/res/anim-ldrtl/task_open_exit.xml
@@ -15,19 +15,8 @@
   -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false"
-    android:hasRoundedCorners="true"
-    android:showWallpaper="true">
-
-    <alpha
-        android:fromAlpha="1.0"
-        android:toAlpha="1"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/linear"
-        android:startOffset="67"
-        android:duration="283"/>
+     android:shareInterpolator="false"
+     android:hasRoundedCorners="true">
 
     <translate
         android:fromXDelta="0"
@@ -35,22 +24,9 @@
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
-        android:interpolator="@interpolator/aggressive_ease"
-        android:startOffset="50"
-        android:duration="383"/>
-
-    <scale
-        android:fromXScale="1.0"
-        android:toXScale="0.95"
-        android:fromYScale="1.0"
-        android:toYScale="0.95"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="283"/>
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:startOffset="0"
+        android:duration="500"/>
 
     <!-- This is needed to keep the animation running while task_open_enter completes -->
     <alpha
diff --git a/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml
index 2cfeecf..f6d7b72 100644
--- a/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml
+++ b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml
@@ -19,18 +19,8 @@
 <!-- This should be kept in sync with task_open_enter.xml -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
      android:shareInterpolator="false"
-     android:hasRoundedCorners="true"
-     android:zAdjustment="top">
-
-    <alpha
-        android:fromAlpha="1"
-        android:toAlpha="1.0"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/linear"
-        android:startOffset="67"
-        android:duration="217"/>
+     android:zAdjustment="top"
+     android:hasRoundedCorners="true">
 
     <translate
         android:fromXDelta="105%"
@@ -38,36 +28,9 @@
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
-        android:interpolator="@interpolator/aggressive_ease"
-        android:startOffset="50"
-        android:duration="383"/>
-
-    <scale
-        android:fromXScale="1.0526"
-        android:toXScale="1"
-        android:fromYScale="1.0526"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="283"/>
-
-    <scale
-        android:fromXScale="0.95"
-        android:toXScale="1"
-        android:fromYScale="0.95"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:startOffset="283"
-        android:duration="317"/>
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:startOffset="0"
+        android:duration="500"/>
 
     <!-- To keep the thumbnail around longer and fade out the thumbnail -->
     <alpha android:fromAlpha="1.0" android:toAlpha="0"
diff --git a/core/res/res/anim/task_close_enter.xml b/core/res/res/anim/task_close_enter.xml
index 487ff5c..52017b1 100644
--- a/core/res/res/anim/task_close_enter.xml
+++ b/core/res/res/anim/task_close_enter.xml
@@ -16,20 +16,9 @@
 */
 -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false"
-    android:zAdjustment="top"
-    android:hasRoundedCorners="true"
-    android:showWallpaper="true">
-
-    <alpha
-        android:fromAlpha="1"
-        android:toAlpha="1.0"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/linear"
-        android:startOffset="67"
-        android:duration="217"/>
+     android:shareInterpolator="false"
+     android:zAdjustment="top"
+     android:hasRoundedCorners="true">
 
     <translate
         android:fromXDelta="-105%"
@@ -37,34 +26,7 @@
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
-        android:interpolator="@interpolator/aggressive_ease"
-        android:startOffset="50"
-        android:duration="383"/>
-
-    <scale
-        android:fromXScale="1.0526"
-        android:toXScale="1"
-        android:fromYScale="1.0526"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="283"/>
-
-    <scale
-        android:fromXScale="0.95"
-        android:toXScale="1"
-        android:fromYScale="0.95"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:startOffset="283"
-        android:duration="317"/>
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:startOffset="0"
+        android:duration="500"/>
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml
index afc3256c..736f3f2 100644
--- a/core/res/res/anim/task_close_exit.xml
+++ b/core/res/res/anim/task_close_exit.xml
@@ -17,19 +17,8 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false"
-    android:hasRoundedCorners="true"
-    android:showWallpaper="true">
-
-    <alpha
-        android:fromAlpha="1.0"
-        android:toAlpha="1"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/linear"
-        android:startOffset="67"
-        android:duration="283"/>
+     android:shareInterpolator="false"
+     android:hasRoundedCorners="true">
 
     <translate
         android:fromXDelta="0"
@@ -37,22 +26,9 @@
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
-        android:interpolator="@interpolator/aggressive_ease"
-        android:startOffset="50"
-        android:duration="383"/>
-
-    <scale
-        android:fromXScale="1.0"
-        android:toXScale="0.95"
-        android:fromYScale="1.0"
-        android:toYScale="0.95"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="283"/>
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:startOffset="0"
+        android:duration="500"/>
 
     <!-- This is needed to keep the animation running while task_open_enter completes -->
     <alpha
diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml
index 0aafc1c..3c93438 100644
--- a/core/res/res/anim/task_open_enter.xml
+++ b/core/res/res/anim/task_open_enter.xml
@@ -15,23 +15,12 @@
 ** limitations under the License.
 */
 -->
-<!-- This should in sync with task_open_enter_cross_profile_apps.xml -->
-<!-- This should in sync with cross_profile_apps_thumbnail_enter.xml -->
+<!-- This should be kept in sync with task_open_enter_cross_profile_apps.xml -->
+<!-- This should be kept in sync with cross_profile_apps_thumbnail_enter.xml -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false"
-    android:zAdjustment="top"
-    android:hasRoundedCorners="true"
-    android:showWallpaper="true">
-
-    <alpha
-        android:fromAlpha="1"
-        android:toAlpha="1.0"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/linear"
-        android:startOffset="67"
-        android:duration="217"/>
+     android:shareInterpolator="false"
+     android:zAdjustment="top"
+     android:hasRoundedCorners="true">
 
     <translate
         android:fromXDelta="105%"
@@ -39,34 +28,7 @@
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
-        android:interpolator="@interpolator/aggressive_ease"
-        android:startOffset="50"
-        android:duration="383"/>
-
-    <scale
-        android:fromXScale="1.0526"
-        android:toXScale="1"
-        android:fromYScale="1.0526"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="283"/>
-
-    <scale
-        android:fromXScale="0.95"
-        android:toXScale="1"
-        android:fromYScale="0.95"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:startOffset="283"
-        android:duration="317"/>
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:startOffset="0"
+        android:duration="500"/>
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/task_open_enter_cross_profile_apps.xml b/core/res/res/anim/task_open_enter_cross_profile_apps.xml
index 702f7ba..16249d1 100644
--- a/core/res/res/anim/task_open_enter_cross_profile_apps.xml
+++ b/core/res/res/anim/task_open_enter_cross_profile_apps.xml
@@ -18,20 +18,9 @@
 -->
 <!-- This should in sync with task_open_enter.xml -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false"
-    android:zAdjustment="top"
-    android:hasRoundedCorners="true"
-    android:showWallpaper="true">
-
-    <alpha
-        android:fromAlpha="1"
-        android:toAlpha="1.0"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/linear"
-        android:startOffset="67"
-        android:duration="217"/>
+     android:shareInterpolator="false"
+     android:zAdjustment="top"
+     android:hasRoundedCorners="true">
 
     <translate
         android:fromXDelta="105%"
@@ -39,36 +28,9 @@
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
-        android:interpolator="@interpolator/aggressive_ease"
-        android:startOffset="50"
-        android:duration="383"/>
-
-    <scale
-        android:fromXScale="1.0526"
-        android:toXScale="1"
-        android:fromYScale="1.0526"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="283"/>
-
-    <scale
-        android:fromXScale="0.95"
-        android:toXScale="1"
-        android:fromYScale="0.95"
-        android:toYScale="1"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:startOffset="283"
-        android:duration="317"/>
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:startOffset="0"
+        android:duration="500"/>
 
     <!-- To keep the transition around longer for the thumbnail, should be kept in sync with
          cross_profile_apps_thumbmail.xml -->
diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml
index 691317d..d170317 100644
--- a/core/res/res/anim/task_open_exit.xml
+++ b/core/res/res/anim/task_open_exit.xml
@@ -17,19 +17,8 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false"
-    android:hasRoundedCorners="true"
-    android:showWallpaper="true">
-
-    <alpha
-        android:fromAlpha="1.0"
-        android:toAlpha="1"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:interpolator="@interpolator/linear"
-        android:startOffset="67"
-        android:duration="283"/>
+     android:shareInterpolator="false"
+     android:hasRoundedCorners="true">
 
     <translate
         android:fromXDelta="0"
@@ -37,22 +26,9 @@
         android:fillEnabled="true"
         android:fillBefore="true"
         android:fillAfter="true"
-        android:interpolator="@interpolator/aggressive_ease"
-        android:startOffset="50"
-        android:duration="383"/>
-
-    <scale
-        android:fromXScale="1.0"
-        android:toXScale="0.95"
-        android:fromYScale="1.0"
-        android:toYScale="0.95"
-        android:fillEnabled="true"
-        android:fillBefore="true"
-        android:fillAfter="true"
-        android:pivotX="50%"
-        android:pivotY="50%"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="283"/>
+        android:interpolator="@interpolator/fast_out_extra_slow_in"
+        android:startOffset="0"
+        android:duration="500"/>
 
     <!-- This is needed to keep the animation running while task_open_enter completes -->
     <alpha
diff --git a/core/res/res/color/overview_background.xml b/core/res/res/color/overview_background.xml
new file mode 100644
index 0000000..45c6c25
--- /dev/null
+++ b/core/res/res/color/overview_background.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral2_500" android:lStar="87" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/color/overview_background_dark.xml b/core/res/res/color/overview_background_dark.xml
new file mode 100644
index 0000000..84f4fdf
--- /dev/null
+++ b/core/res/res/color/overview_background_dark.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral2_500" android:lStar="35" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/drawable-nodpi/default_wallpaper.png b/core/res/res/drawable-nodpi/default_wallpaper.png
index 490ebee..5152972 100644
--- a/core/res/res/drawable-nodpi/default_wallpaper.png
+++ b/core/res/res/drawable-nodpi/default_wallpaper.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png
new file mode 100644
index 0000000..26376fb
--- /dev/null
+++ b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png
Binary files differ
diff --git a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png
new file mode 100644
index 0000000..490ebee
--- /dev/null
+++ b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png
Binary files differ
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 456bcf7..95aed93 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -34,7 +34,7 @@
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"সংযোগৰ সমস্যা বা MMI ক\'ড মান্য নহয়।"</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"কেৱল ফিক্সড ডায়েলিং নম্বৰৰ বাবে কার্য সীমাবদ্ধ কৰা হৈছে।"</string>
-    <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"আপুনি ৰ\'মিঙত থকাৰ সময়ত কল ফৰৱাৰ্ডিঙৰ ছেটিংসমূহ সলনি কৰিব নোৱাৰি।"</string>
+    <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"আপুনি ৰ\'মিঙত থকাৰ সময়ত কল ফৰৱাৰ্ডিঙৰ ছেটিং সলনি কৰিব নোৱাৰি।"</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"সেৱা সক্ষম কৰা হ’ল।"</string>
     <string name="serviceEnabledFor" msgid="1463104778656711613">"সেৱা সক্ষম কৰা হ’ল:"</string>
     <string name="serviceDisabled" msgid="641878791205871379">"সেৱা অক্ষম কৰা হ’ল।"</string>
@@ -124,7 +124,7 @@
     <string name="roamingTextSearching" msgid="5323235489657753486">"সেৱাৰ বাবে অনুসন্ধান কৰি থকা হৈছে"</string>
     <string name="wfcRegErrorTitle" msgid="3193072971584858020">"ৱাই-ফাই কলিং ছেট আপ কৰিব পৰা নগ\'ল"</string>
   <string-array name="wfcOperatorErrorAlertMessages">
-    <item msgid="468830943567116703">"ৱাই-ফাইৰ জৰিয়তে কল কৰিবলৈ আৰু বাৰ্তা পঠাবলৈ, প্ৰথমে আপোনাৰ বাহকক আপোনাৰ ডিভাইচটো ছেট আপ কৰিব দিবলৈ কওক। তাৰ পিচত, ছেটিংসমূহলৈ গৈ আকৌ ৱাই-ফাই কলিং অন কৰক। (ত্ৰুটি ক\'ড: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+    <item msgid="468830943567116703">"ৱাই-ফাইৰ জৰিয়তে কল কৰিবলৈ আৰু বাৰ্তা পঠাবলৈ, প্ৰথমে আপোনাৰ বাহকক আপোনাৰ ডিভাইচটো ছেট আপ কৰিবলৈ কওক। তাৰ পাছত, ছেটিঙলৈ গৈ আকৌ ৱাই-ফাই কলিং অন কৰক। (ত্ৰুটি ক\'ড: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
   </string-array>
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="4795145070505729156">"আপোনাৰ বাহকৰ ওচৰত ৱাই-ফাই কলিং সুবিধা পঞ্জীয়ন কৰাত সমস্যাৰ উদ্ভৱ হৈছে: <xliff:g id="CODE">%1$s</xliff:g>"</item>
@@ -218,7 +218,7 @@
     <string name="silent_mode" msgid="8796112363642579333">"নিঃশব্দ ম\'ড"</string>
     <string name="turn_on_radio" msgid="2961717788170634233">"ৱায়াৰলেছ অন কৰক"</string>
     <string name="turn_off_radio" msgid="7222573978109933360">"ৱায়াৰলেছ অফ কৰক"</string>
-    <string name="screen_lock" msgid="2072642720826409809">"স্ক্ৰীণ লক"</string>
+    <string name="screen_lock" msgid="2072642720826409809">"স্ক্ৰীন লক"</string>
     <string name="power_off" msgid="4111692782492232778">"পাৱাৰ অফ"</string>
     <string name="silent_mode_silent" msgid="5079789070221150912">"ৰিংগাৰ অফ আছে"</string>
     <string name="silent_mode_vibrate" msgid="8821830448369552678">"ৰিংগাৰ কম্পন অৱস্থাত আছে"</string>
@@ -268,7 +268,7 @@
     <string name="global_actions_toggle_airplane_mode" msgid="6911684460146916206">"এয়াৰপ্লেইন ম\'ড"</string>
     <string name="global_actions_airplane_mode_on_status" msgid="5508025516695361936">"এয়াৰপ্লেইন ম\'ড অন কৰা আছে"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="8522219771500505475">"এয়াৰপ্লেইন ম\'ড অফ কৰা আছে"</string>
-    <string name="global_action_settings" msgid="4671878836947494217">"ছেটিংসমূহ"</string>
+    <string name="global_action_settings" msgid="4671878836947494217">"ছেটিং"</string>
     <string name="global_action_assist" msgid="2517047220311505805">"সহায়"</string>
     <string name="global_action_voice_assist" msgid="6655788068555086695">"কণ্ঠধ্বনিৰে সহায়"</string>
     <string name="global_action_lockdown" msgid="2475471405907902963">"লকডাউন"</string>
@@ -400,8 +400,8 @@
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"এপটোক অগ্ৰভূমি সেৱাসমূহ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে।"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"এপৰ সঞ্চয়াগাৰৰ খালী ঠাই হিচাপ কৰক"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"এপটোক ইয়াৰ ক\'ড, ডেটা আৰু কেশ্বৰ আকাৰ বিচাৰি উলিয়াবলৈ অনুমতি দিয়ে"</string>
-    <string name="permlab_writeSettings" msgid="8057285063719277394">"ছিষ্টেম ছেটিংসমূহ সংশোধন কৰক"</string>
-    <string name="permdesc_writeSettings" msgid="8293047411196067188">"এপটোক ছিষ্টেমৰ ছেটিংসমূহৰ ডেটা সংশোধন কৰিবলৈ অনুমতি দিয়ে৷ ক্ষতিকাৰক এপসমূহে আপোনাৰ ছিষ্টেম কনফিগাৰেশ্বনক ক্ষতিগ্ৰস্ত কৰিব পাৰে৷"</string>
+    <string name="permlab_writeSettings" msgid="8057285063719277394">"ছিষ্টেম ছেটিংহ সংশোধন কৰক"</string>
+    <string name="permdesc_writeSettings" msgid="8293047411196067188">"এপ্‌টোক ছিষ্টেমৰ ছেটিঙৰ ডেটা সংশোধন কৰিবলৈ অনুমতি দিয়ে৷ ক্ষতিকাৰক এপ্‌সমূহে আপোনাৰ ছিষ্টেম কনফিগাৰেশ্বনক ক্ষতিগ্ৰস্ত কৰিব পাৰে৷"</string>
     <string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"আৰম্ভ হোৱাৰ সময়ত চলাওক"</string>
     <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"ছিষ্টেমে বুট কৰা কাৰ্য সমাপ্ত কৰাৰ লগে লগে এপটোক নিজে নিজে আৰম্ভ হ\'বলৈ অনুমতি দিয়ে। ইয়াৰ ফলত ফ\'নটো ষ্টাৰ্ট হওতে বেছি সময়ৰ প্ৰয়োজন হ\'ব পাৰে, আৰু এপটো সদায় চলি থকাৰ কাৰণে ফ\'নটো সামগ্ৰিকভাৱে লেহেমীয়া হ\'ব পাৰে।"</string>
     <string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"ছিষ্টেমে বুটিং সমাপ্ত কৰাৰ লগে লগে এই এপ্‌টোক নিজে নিজে আৰম্ভ হ’বলৈ অনুমতি দিয়ে। এই কাৰ্যৰ বাবে আপোনাৰ Android TV ডিভাইচটো আৰম্ভ হ’বলৈ দীঘলীয়া সময়ৰ প্ৰয়োজন হ’ব পাৰে আৰু সকলো সময়তে চলি থাকি এপ্‌টোক সামগ্ৰিকভাৱে ডিভাইচটো লেহেমীয়া কৰিবলৈ দিয়ে।"</string>
@@ -442,8 +442,8 @@
     <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"এই এপ্‌টো ব্যৱহাৰ হৈ থকা অৱস্থাত ই অৱস্থান সেৱাসমূহৰ পৰা আপোনাৰ আনুমানিক অৱস্থান লাভ কৰিব পাৰে। এপ্‌টোৱে অৱস্থান লাভ কৰিবলৈ হ’লে আপোনাৰ ডিভাইচৰ অৱস্থান সেৱাসমূহ অন কৰি ৰাখিবই লাগিব।"</string>
     <string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"নেপথ্যত চলি থকা সময়ত অৱস্থানৰ এক্সেছ"</string>
     <string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"এই এপ্‌টোৱে যিকোনো সময়তে অৱস্থান এক্সেছ কৰিব পাৰে, আনকি এপ্‌টো ব্যৱহাৰ হৈ নথকা অৱস্থাতো।"</string>
-    <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"আপোনাৰ অডিঅ\' ছেটিংসমূহ সলনি কৰক"</string>
-    <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"এপটোক ভলিউমৰ দৰে গ্ল\'বেল অডিঅ\' ছেটিংসমূহ যাৰ স্পীকাৰক আউটপুটৰ বাবে ব্যৱহাৰ হয় তাক সলনি কৰিবলৈ অনুমতি দিয়ে৷"</string>
+    <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"আপোনাৰ অডিঅ\' ছেটিং সলনি কৰক"</string>
+    <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"এপ্‌টোক ভলিউমৰ দৰে গ্ল\'বেল অডিঅ\' ছেটিং আৰু আউটপুটৰ বাবে কোনটো স্পীকাৰ ব্যৱহাৰ হয় তাক সলনি কৰিবলৈ অনুমতি দিয়ে৷"</string>
     <string name="permlab_recordAudio" msgid="1208457423054219147">"অডিঅ\' ৰেকর্ড কৰক"</string>
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"এই এপ্‌টোৱে ইয়াক ব্যৱহাৰ কৰি থাকোঁতে মাইক্ৰ’ফ’ন ব্যৱহাৰ কৰি অডিঅ’ ৰেকর্ড কৰিব পাৰে।"</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"নেপথ্যত অডিঅ’ ৰেকৰ্ড কৰক"</string>
@@ -519,7 +519,7 @@
     <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"আপোনাৰ টেবলেটৰ লগতে মাল্টিকাষ্ট ঠিকনাবোৰ ও ব্যৱহাৰ কৰি এপক ৱাই-ফাই নেটৱর্কত থকা সকলো ডিভাইচলৈ পঠোৱা পেকেট প্ৰাপ্ত কৰিবলৈ অনুমতি দিয়ে। এই কার্যই ন\'ন মাল্টিকাষ্ট ম\'ডতকৈ বেটাৰিৰ অধিক চ্চাৰ্জ ব্যৱহাৰ কৰে।"</string>
     <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"কেৱল আপোনাৰ Android TV ডিভাইচটোৱেই নহয়, মাল্টিকাষ্ট ঠিকনাবোৰ ব্যৱহাৰ কৰি এটা ৱাই-ফাই নেটৱর্কত থকা সকলো ডিভাইচলৈ পঠোৱা পেকেটবোৰ লাভ কৰিবলৈ এপ্‌টোক অনুমতি দিয়ে। এই কার্যই ন’ন-মাল্টিকাষ্ট ম’ডতকৈ অধিক পাৱাৰ ব্যৱহাৰ কৰে।"</string>
     <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"আপোনাৰ ফ\'নৰ লগতে মাল্টিকাষ্ট ঠিকনাবোৰ ও ব্যৱহাৰ কৰি এপক ৱাই-ফাই নেটৱর্কত থকা সকলো ডিভাইচলৈ পঠোৱা পেকেট প্ৰাপ্ত কৰিবলৈ অনুমতি দিয়ে। এই কার্যই ন\'ন মাল্টিকাষ্ট ম\'ডতকৈ বেটাৰিৰ অধিক চ্চাৰ্জ ব্যৱহাৰ কৰে।"</string>
-    <string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"ব্লুটুথ ছেটিংসমূহ ব্যৱহাৰ কৰক"</string>
+    <string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"ব্লুটুথ ছেটিং এক্সেছ কৰক"</string>
     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"স্থানীয় ব্লুটুথ টে\'বলেট কনফিগাৰ কৰিবলৈ আৰু দূৰৱৰ্তী ডিভাইচসমূহৰ সৈতে যোৰা লগাবলৈ আৰু বিচাৰি উলিয়াবলৈ এপটোক অনুমতি দিয়ে।"</string>
     <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"এপ্‌টোক আপোনাৰ Android TV ডিভাইচটোত ব্লুটুথ কনফিগাৰ কৰিবলৈ আৰু ৰিম’ট ডিভাইচসমূহ বিচাৰি উলিয়াবলৈ আৰু পেয়াৰ কৰিবলৈ অনুমতি দিয়ে।"</string>
     <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"স্থানীয় ব্লুটুথ ফ\'ন কনফিগাৰ কৰিবলৈ আৰু দূৰৱৰ্তী ডিভাইচসমূহৰ সৈতে যোৰা লগাবলৈ আৰু বিচাৰি উলিয়াবলৈ এপটোক অনুমতি দিয়ে।"</string>
@@ -547,7 +547,7 @@
     <string name="permdesc_nfc" msgid="8352737680695296741">"এপটোক নিয়েৰ ফিল্ড কমিউনিকেশ্বন (NFC) টেগ, কাৰ্ড আৰু ৰিডাৰসমূহৰ সৈতে যোগাযোগ কৰিবলৈ অনুমতি দিয়ে।"</string>
     <string name="permlab_disableKeyguard" msgid="3605253559020928505">"আপোনাৰ স্ক্ৰীন লক অক্ষম কৰক"</string>
     <string name="permdesc_disableKeyguard" msgid="3223710003098573038">"এপটোক কী ল\'ক আৰু জড়িত হোৱা যিকোনো পাছৱৰ্ডৰ সুৰক্ষা অক্ষম কৰিব দিয়ে৷ উদাহৰণস্বৰূপে, কোনো অন্তৰ্গামী ফ\'ন কল উঠোৱাৰ সময়ত ফ\'নটোৱে কী-লকটো অক্ষম কৰে, তাৰ পিছত কল শেষ হ\'লেই কী লকটো পুনৰ সক্ষম কৰে৷"</string>
-    <string name="permlab_requestPasswordComplexity" msgid="1808977190557794109">"স্ক্ৰীণ লকৰ জটিলতাৰ অনুৰোধ"</string>
+    <string name="permlab_requestPasswordComplexity" msgid="1808977190557794109">"স্ক্ৰীন লকৰ জটিলতাৰ অনুৰোধ"</string>
     <string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"এপ্‌টোক স্ক্ৰীন লকৰ জটিলতাৰ স্তৰ (উচ্চ, মধ্যম, নিম্ন বা একেবাৰে নাই)ৰ বিষয়ে জানিবলৈ অনুমতি দিয়ে, যিয়ে স্ক্ৰীন লকৰ সম্ভাব্য দৈৰ্ঘ্য বা স্ক্ৰীন লকৰ প্ৰকাৰ দৰ্শায়। লগতে এপ্‌টোৱে ব্যৱহাৰকাৰীক স্ক্ৰীন লকটো এটা নিৰ্দিষ্ট স্তৰলৈ আপডে’ট কৰিবলৈ পৰামৰ্শ দিব পাৰে যিটো ব্যৱহাৰকাৰীয়ে অৱজ্ঞা কৰি পৰৱর্তী পৃষ্ঠালৈ যাব পাৰে। মনত ৰাখিব যে স্ক্ৰীন লকটো সাধাৰণ পাঠ হিচাপে ষ্ট\'ৰ কৰা নহয়; সেয়েহে, এপ্‌টোৱে সঠিক পাছৱৰ্ডটো জানিব নোৱাৰে।"</string>
     <string name="permlab_useBiometric" msgid="6314741124749633786">"বায়োমেট্ৰিক হাৰ্ডৱেৰ ব্য়ৱহাৰ কৰক"</string>
     <string name="permdesc_useBiometric" msgid="7502858732677143410">"বিশ্বাসযোগ্য়তা প্ৰমাণীকৰণৰ বাবে এপক বায়োমেট্ৰিক হাৰ্ডৱেৰ ব্য়ৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string>
@@ -640,7 +640,7 @@
     <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"আপোনাৰ মূৰটো অলপ কমকৈ হেলনীয়া কৰক।"</string>
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"আপোনাৰ মূৰটো সামান্য কমকৈ ঘূৰাওক।"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"আপোনাৰ মুখখন ঢাকি ৰখা বস্তুবোৰ আঁতৰাওক।"</string>
-    <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ক’লা বাৰডালকে ধৰি আপোনাৰ স্ক্রীণৰ ওপৰৰ অংশ চাফা কৰক"</string>
+    <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ক’লা বাৰডালকে ধৰি আপোনাৰ স্ক্রীনৰ ওপৰৰ অংশ চাফা কৰক"</string>
   <string-array name="face_acquired_vendor">
   </string-array>
     <string name="face_error_hw_not_available" msgid="5085202213036026288">"মুখমণ্ডল সত্যাপন কৰিব পৰা নগ’ল। হাৰ্ডৱেৰ নাই।"</string>
@@ -664,8 +664,8 @@
   </string-array>
     <string name="face_error_vendor_unknown" msgid="7387005932083302070">"কিবা ভুল হ’ল। পুনৰ চেষ্টা কৰক।"</string>
     <string name="face_icon_content_description" msgid="465030547475916280">"মুখমণ্ডলৰ আইকন"</string>
-    <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ছিংকৰ ছেটিংসমূহ পঢ়ক"</string>
-    <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"একাউণ্টৰ ছিংক ছেটিংবোৰ পঢ়িবলৈ এপক অনুমতি দিয়ে। যেনে, People এপ কোনো একাউণ্টত ছিংক কৰা হৈছে নে নাই সেয়া নির্ধাৰণ কৰিব পাৰে।"</string>
+    <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ছিংকৰ ছেটিং পঢ়ক"</string>
+    <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"একাউণ্টৰ ছিংক ছেটিংবোৰ পঢ়িবলৈ এপক অনুমতি দিয়ে। যেনে, People এপ্‌টো কোনো একাউণ্টৰ সৈতে ছিংক কৰা হৈছে নে নাই সেয়া নির্ধাৰণ কৰিব পাৰে।"</string>
     <string name="permlab_writeSyncSettings" msgid="6583154300780427399">"ছিংকক অন আৰু অফ ট\'গল কৰক"</string>
     <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"এপটোক কোনো একাউণ্টৰ ছিংক সম্পৰ্কীয় ছেটিংসমূহ সংশোধন কৰিবলৈ অনুমতি দিয়ে৷ উদাহৰণস্বৰূপে, এই কাৰ্যক কোনো একাউণ্টৰ জৰিয়তে People এপটোৰ ছিংক সক্ষম কৰিবলৈ ব্যৱহাৰ কৰিব পাৰি৷"</string>
     <string name="permlab_readSyncStats" msgid="3747407238320105332">"ছিংকৰ পৰিসংখ্যা পঢ়ক"</string>
@@ -727,9 +727,9 @@
     <string name="policylab_limitPassword" msgid="4851829918814422199">"পাছৱর্ডৰ নিয়ম ছেট কৰক"</string>
     <string name="policydesc_limitPassword" msgid="4105491021115793793">"স্ক্ৰীন লক পাছৱৰ্ড আৰু পিনত অনুমোদিত দৈৰ্ঘ্য আৰু বৰ্ণবোৰ নিয়ন্ত্ৰণ কৰক।।"</string>
     <string name="policylab_watchLogin" msgid="7599669460083719504">"স্ক্ৰীন আনলক কৰা প্ৰয়াসবোৰ নিৰীক্ষণ কৰক"</string>
-    <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"স্ক্ৰীণ আনলক কৰোতে লিখা অশুদ্ধ পাছৱৰ্ডৰ হিচাপ ৰাখক, আৰু যদিহে অত্যধিকবাৰ অশুদ্ধ পাছৱৰ্ড লিখা হয় তেন্তে টে\'বলেটটো লক কৰক বা টে\'বলেটটোৰ সকলো ডেটা মোহাৰক।"</string>
-    <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"স্ক্ৰীণ আনলক কৰোঁতে দিয়া ভুল পাছৱৰ্ডবোৰৰ সংখ্যা নিৰীক্ষণ কৰক আৰু যদিহে অত্যধিকবাৰ ভুল পাছৱৰ্ড দিয়া হয় তেন্তে Android TV ডিভাইচটো লক কৰক অথবা আপোনাৰ Android TV ডিভাইচৰ সকলো ডেটা মচক।"</string>
-    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"স্ক্ৰীণ আনলক কৰোতে লিখা অশুদ্ধ পাছৱৰ্ডৰ হিচাপ ৰাখক, আৰু যদিহে অত্যধিকবাৰ অশুদ্ধ পাছৱৰ্ড লিখা হয় তেন্তে ফ\'নটো লক কৰক বা ফ\'নটোৰ সকলো ডেটা মোহাৰক।"</string>
+    <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"স্ক্ৰীন আনলক কৰোঁতে টাইপ কৰা অশুদ্ধ পাছৱৰ্ডৰ সংখ্যা নিৰীক্ষণ কৰক আৰু যদিহে অত্যাধিকবাৰ অশুদ্ধ পাছৱৰ্ড টাইপ কৰা হয়, তেন্তে টেবলেটটো লক কৰক বা টেবলেটটোৰ আটাইখিনি ডেটা মচক।"</string>
+    <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"স্ক্ৰীন আনলক কৰোঁতে টাইপ কৰা ভুল পাছৱৰ্ডবোৰৰ সংখ্যা নিৰীক্ষণ কৰক আৰু যদিহে অত্যাধিকবাৰ ভুল পাছৱৰ্ড টাইপ কৰা হয়, তেন্তে Android TV ডিভাইচটো লক কৰক অথবা আপোনাৰ Android TV ডিভাইচৰ আটাইখিনি ডেটা মচক।"</string>
+    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"স্ক্ৰীন আনলক কৰোঁতে টাইপ কৰা অশুদ্ধ পাছৱৰ্ডৰ সংখ্যা নিৰীক্ষণ কৰক আৰু যদিহে অত্যাধিকবাৰ অশুদ্ধ পাছৱৰ্ড টাইপ কৰা হয়, তেন্তে ফ\'নটো লক কৰক বা ফ\'নটোৰ আটাইখিনি ডেটা মচক।"</string>
     <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"স্ক্ৰীন আনলক কৰোঁতে টাইপ কৰা অশুদ্ধ পাছৱৰ্ডৰ সংখ্যা নিৰীক্ষণ কৰক আৰু যদিহে অত্যধিকবাৰ অশুদ্ধ পাছৱৰ্ড টাইপ কৰা হয়, তেন্তে টেবলেটটো লক কৰক বা এই ব্যৱহাৰকাৰীৰ আটাইখিনি ডেটা মচক।"</string>
     <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"স্ক্ৰীনখন আনলক কৰোঁতে টাইপ কৰা ভুল পাছৱৰ্ডবোৰৰ সংখ্যা নিৰীক্ষণ কৰক আৰু যদিহে অত্যধিকবাৰ ভুল পাছৱৰ্ড টাইপ কৰা হয়, তেন্তে Android TV ডিভাইচটো লক কৰক অথবা এই ব্যৱহাৰকাৰীৰ আটাইখিনি ডেটা মচক।"</string>
     <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"স্ক্ৰীনখন আনলক কৰোঁতে টাইপ কৰা ভুল পাছৱৰ্ডবোৰৰ সংখ্যা নিৰীক্ষণ কৰক আৰু যদিহে অত্যধিকবাৰ ভুল পাছৱৰ্ড টাইপ কৰা হয়, তেন্তে ফ\'নটো লক কৰক অথবা এই ব্যৱহাৰকাৰীৰ আটাইখিনি ডেটা মচক।"</string>
@@ -754,7 +754,7 @@
     <string name="policylab_disableCamera" msgid="5749486347810162018">"কেমেৰাবোৰ অক্ষম কৰক"</string>
     <string name="policydesc_disableCamera" msgid="3204405908799676104">"সকলো ডিভাইচৰ কেমেৰাবোৰ ব্যৱহাৰ কৰাত বাধা দিয়ক।"</string>
     <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"স্ক্ৰীন লকৰ কিছুমান সুবিধা অক্ষম কৰক"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"স্ক্ৰীণ লকৰ কিছুমান সুবিধা ব্যৱহাৰ হোৱাত বাধা দিয়ক।"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"স্ক্ৰীন লকৰ কিছুমান সুবিধা ব্যৱহাৰ হোৱাত বাধা দিয়ক।"</string>
   <string-array name="phoneTypes">
     <item msgid="8996339953292723951">"ঘৰ"</item>
     <item msgid="7740243458912727194">"ম’বাইল"</item>
@@ -1213,7 +1213,7 @@
     <string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"প্ৰতিচ্ছবি তোলক"</string>
     <string name="alwaysUse" msgid="3153558199076112903">"এই কার্যৰ বাবে পূর্বনির্ধাৰিত ধৰণে ব্যৱহাৰ কৰক।"</string>
     <string name="use_a_different_app" msgid="4987790276170972776">"এটা পৃথক এপ্ ব্যৱহাৰ কৰক"</string>
-    <string name="clearDefaultHintMsg" msgid="1325866337702524936">"ছিষ্টেমৰ ছেটিংসমূহ &gt; এপসমূহ &gt; ডাউনল’ড কৰা সমল-লৈ গৈ ডিফ\'ল্ট মচক৷"</string>
+    <string name="clearDefaultHintMsg" msgid="1325866337702524936">"ছিষ্টেমৰ ছেটিং &gt; এপ্‌ &gt; ডাউনল’ড কৰা সমল-লৈ গৈ ডিফ\'ল্ট মচক৷"</string>
     <string name="chooseActivity" msgid="8563390197659779956">"কোনো কার্য বাছনি কৰক"</string>
     <string name="chooseUsbActivity" msgid="2096269989990986612">"ইউএছবি ডিভাইচৰ বাবে এটা এপ্ বাছনি কৰক"</string>
     <string name="noApplications" msgid="1186909265235544019">"কোনো এপে এই কাৰ্য কৰিব নোৱাৰে।"</string>
@@ -1241,7 +1241,7 @@
     <string name="launch_warning_original" msgid="3332206576800169626">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক পূৰ্বতে লঞ্চ কৰা হৈছিল৷"</string>
     <string name="screen_compat_mode_scale" msgid="8627359598437527726">"স্কেল"</string>
     <string name="screen_compat_mode_show" msgid="5080361367584709857">"সদায় দেখুৱাওক"</string>
-    <string name="screen_compat_mode_hint" msgid="4032272159093750908">"ছিষ্টেমৰ ছেটিংসমূহ &gt; এপসমূহ &gt; ডাউনল’ড কৰা সমল-লৈ গৈ ইয়াক আকৌ সক্ষম কৰক।"</string>
+    <string name="screen_compat_mode_hint" msgid="4032272159093750908">"ছিষ্টেমৰ ছেটিং &gt; এপ্‌ &gt; ডাউনল’ড কৰা সমল-লৈ গৈ ইয়াক আকৌ সক্ষম কৰক।"</string>
     <string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বর্তমানৰ ডিছপ্লে’ৰ আকাৰ ছেটিং ব্যৱহাৰ কৰিব নোৱাৰে আৰু ই সঠিকভাৱে নচলিবও পাৰে।"</string>
     <string name="unsupported_display_size_show" msgid="980129850974919375">"সদায় দেখুৱাওক"</string>
     <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক এটা খাপ নোখোৱা Android OS সংস্কৰণৰ বাবে তৈয়াৰ কৰা হৈছিল, যাৰ ফলত ই অস্বাভাৱিকধৰণে আচৰণ কৰিব পাৰে। এপটোৰ শেহতীয়া সংস্কৰণ উপলব্ধ হ\'ব পাৰে।"</string>
@@ -1338,7 +1338,7 @@
     <string name="sms_short_code_confirm_allow" msgid="920477594325526691">"পঠিয়াওক"</string>
     <string name="sms_short_code_confirm_deny" msgid="1356917469323768230">"বাতিল কৰক"</string>
     <string name="sms_short_code_remember_choice" msgid="1374526438647744862">"মোৰ পচন্দ মনত ৰাখিব"</string>
-    <string name="sms_short_code_remember_undo_instruction" msgid="2620984439143080410">"আপুনি ইয়াক পিছত ছেটিং &gt; এপ্‌-ত সলনি কৰিব পাৰে"</string>
+    <string name="sms_short_code_remember_undo_instruction" msgid="2620984439143080410">"আপুনি ইয়াক পিছত ছেটিং &gt; এপত সলনি কৰিব পাৰে"</string>
     <string name="sms_short_code_confirm_always_allow" msgid="2223014893129755950">"যিকোনো সময়ত অনুমতি দিয়ক"</string>
     <string name="sms_short_code_confirm_never_allow" msgid="2688828813521652079">"কেতিয়াও অনুমতি নিদিব"</string>
     <string name="sim_removed_title" msgid="5387212933992546283">"ছিম কাৰ্ড আঁতৰোৱা হ’ল"</string>
@@ -1403,7 +1403,7 @@
     <string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"অন্য এপৰ ওপৰত দেখুৱায়"</string>
     <string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> অন্য এপসমূহৰ ওপৰত প্ৰদৰ্শিত হৈ আছে"</string>
     <string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g>এ অইন এপবোৰৰ ওপৰত প্ৰদৰ্শিত হৈ আছে"</string>
-    <string name="alert_windows_notification_message" msgid="6538171456970725333">"আপুনি যদি <xliff:g id="NAME">%s</xliff:g>এ এই সুবিধাটো ব্যৱহাৰ কৰাটো নিবিচাৰে তেন্তে টিপি ছেটিংসমূহ খোলক আৰু ইয়াক অফ কৰক।"</string>
+    <string name="alert_windows_notification_message" msgid="6538171456970725333">"আপুনি যদি <xliff:g id="NAME">%s</xliff:g>এ এই সুবিধাটো ব্যৱহাৰ কৰাটো নিবিচাৰে তেন্তে ছেটিং খুলিবলৈ টিপক আৰু ইয়াক অফ কৰক।"</string>
     <string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"অফ কৰক"</string>
     <string name="ext_media_checking_notification_title" msgid="8299199995416510094">"<xliff:g id="NAME">%s</xliff:g> পৰীক্ষা কৰি থকা হৈছে…"</string>
     <string name="ext_media_checking_notification_message" msgid="2231566971425375542">"বৰ্তমানৰ সমলৰ সমীক্ষা কৰি থকা হৈছে"</string>
@@ -1505,7 +1505,7 @@
     <string name="vpn_lockdown_connected" msgid="2853127976590658469">"সদা-সক্ৰিয় ভিপিএন সংযোগ কৰা হ’ল"</string>
     <string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"সদা-সক্ৰিয় ভিপিএনৰ লগত সংযোগ বিচ্ছিন্ন কৰা হৈছে"</string>
     <string name="vpn_lockdown_error" msgid="4453048646854247947">"সদা-সক্ৰিয় ভিপিএনৰ লগত সংযোগ কৰিব পৰা নাই"</string>
-    <string name="vpn_lockdown_config" msgid="8331697329868252169">"নেটৱৰ্ক বা ভিপিএন ছেটিংসমূহ সলনি কৰক"</string>
+    <string name="vpn_lockdown_config" msgid="8331697329868252169">"নেটৱৰ্ক বা VPN ছেটিং সলনি কৰক"</string>
     <string name="upload_file" msgid="8651942222301634271">"ফাইল বাছনি কৰক"</string>
     <string name="no_file_chosen" msgid="4146295695162318057">"কোনো ফাইল বাছনি কৰা হোৱা নাই"</string>
     <string name="reset" msgid="3865826612628171429">"ৰিছেট কৰক"</string>
@@ -1693,10 +1693,10 @@
     <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"দিব্যাংগসকলৰ সুবিধাৰ শ্বৰ্টকাট ব্যৱহাৰ কৰেনে?"</string>
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"শ্বৰ্টকাটটো অন হৈ থকাৰ সময়ত দুয়োটা ভলিউম বুটাম ৩ ছেকেণ্ডৰ বাবে হেঁচি ধৰি ৰাখিলে এটা সাধ্য সুবিধা আৰম্ভ হ’ব।"</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"সাধ্য সুবিধাসমূহৰ বাবে শ্বৰ্টকাট অন কৰিবনে?"</string>
-    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"দুয়োটা ভলিউম কী কিছুসময়ৰ বাবে ধৰি থাকিলে সাধ্য-সুবিধাসমূহ অন কৰে। এইটোৱে আপোনাৰ ডিভাইচটোৱে কাম কৰাৰ ধৰণ সলনি কৰিব পাৰে।\n\nবর্তমানৰ সুবিধাসমূহ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nআপুনি ছেটিংসমূহ &gt; সাধ্য-সুবিধাত কিছুমান নিৰ্দিষ্ট সুবিধা সলনি কৰিব পাৰে।"</string>
+    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"দুয়োটা ভলিউম কী কিছুসময়ৰ বাবে ধৰি থাকিলে সাধ্য-সুবিধাসমূহ অন কৰে। এইটোৱে আপোনাৰ ডিভাইচটোৱে কাম কৰাৰ ধৰণ সলনি কৰিব পাৰে।\n\nবর্তমানৰ সুবিধাসমূহ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nআপুনি ছেটিং &gt; সাধ্য-সুবিধাত কিছুমান নিৰ্দিষ্ট সুবিধা সলনি কৰিব পাৰে।"</string>
     <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g>ৰ শ্বৰ্টকাট অন কৰিবনে?"</string>
-    <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"দুয়োটা ভলিউম কী কিছুসময়ৰ বাবে ধৰি থাকিলে এটা সাধ্য- সুবিধা <xliff:g id="SERVICE">%1$s</xliff:g> অন কৰে। এইটোৱে আপোনাৰ ডিভাইচটোৱে কাম কৰাৰ ধৰণ সলনি কৰিব পাৰে।\n\nআপুনি ছেটিংসমূহ &gt; সাধ্য-সুবিধাসমূহত এই শ্বৰ্টকাটটো অন্য এটা সুবিধালৈ সলনি কৰিব পাৰে।"</string>
+    <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"দুয়োটা ভলিউম কী কিছুসময়ৰ বাবে ধৰি থাকিলে এটা সাধ্য- সুবিধা <xliff:g id="SERVICE">%1$s</xliff:g> অন কৰে। এইটোৱে আপোনাৰ ডিভাইচটোৱে কাম কৰাৰ ধৰণ সলনি কৰিব পাৰে।\n\nআপুনি ছেটিং &gt; সাধ্য-সুবিধাসমূহত এই শ্বৰ্টকাটটো অন্য এটা সুবিধালৈ সলনি কৰিব পাৰে।"</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"অন কৰক"</string>
     <string name="accessibility_shortcut_off" msgid="3651336255403648739">"অন নকৰিব"</string>
     <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"অন কৰা আছে"</string>
@@ -1704,8 +1704,8 @@
     <string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g>ক আপোনাৰ ডিভাইচটোৰ সম্পূর্ণ নিয়ন্ত্ৰণ দিবনে?"</string>
     <string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"যদি আপুনি <xliff:g id="SERVICE">%1$s</xliff:g> অন কৰে, তেন্তে আপোনাৰ ডিভাইচটোৱে ডেটা এনক্ৰিপশ্বনৰ গুণগত মান উন্নত কৰিবলৈ স্ক্ৰীন লক ব্যৱহাৰ নকৰে।"</string>
     <string name="accessibility_service_warning_description" msgid="291674995220940133">"আপোনাক সাধ্য সুবিধাৰ প্ৰয়োজনসমূহৰ জৰিয়তে সহায় কৰা এপ্‌সমূহৰ বাবে সম্পূর্ণ নিয়ন্ত্ৰণৰ সুবিধাটো সঠিক যদিও অধিকাংশ এপৰ বাবে এয়া সঠিক নহয়।"</string>
-    <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"চাওক আৰু স্ক্ৰীণ নিয়ন্ত্ৰণ কৰক"</string>
-    <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"ই স্ক্ৰীণৰ সকলো সমল পঢ়িব পাৰে আৰু অন্য এপ্‌সমূহৰ ওপৰত সমল প্ৰদর্শন কৰিব পাৰে।"</string>
+    <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"চাওক আৰু স্ক্ৰীন নিয়ন্ত্ৰণ কৰক"</string>
+    <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"ই স্ক্ৰীনত থকা আটাইখিনি সমল পঢ়িব পাৰে আৰু অন্য এপ্‌সমূহৰ ওপৰত সমল প্ৰদর্শন কৰিব পাৰে।"</string>
     <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"কার্যসমূহ চাওক আৰু কৰক"</string>
     <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"ই আপুনি কোনো এপ্ বা হার্ডৱেৰ ছেন্সৰৰ সৈতে কৰা ভাব-বিনিময় আৰু আপোনাৰ হৈ অন্য কোনো লোকে এপৰ সৈতে কৰা ভাব-বিনিময় ট্ৰেক কৰিব পাৰে।"</string>
     <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"অনুমতি দিয়ক"</string>
@@ -1855,7 +1855,7 @@
       <item quantity="other"> <xliff:g id="COUNT">%d</xliff:g> ছেকেণ্ডত আকৌ চেষ্টা কৰক</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="5897719962541636727">"পিছত আকৌ চেষ্টা কৰক"</string>
-    <string name="immersive_cling_title" msgid="2307034298721541791">"স্ক্ৰীণ পূৰ্ণৰূপত চাই আছে"</string>
+    <string name="immersive_cling_title" msgid="2307034298721541791">"স্ক্ৰীন পূৰ্ণৰূপত চাই আছে"</string>
     <string name="immersive_cling_description" msgid="7092737175345204832">"বাহিৰ হ\'বলৈ ওপৰৰপৰা তললৈ ছোৱাইপ কৰক।"</string>
     <string name="immersive_cling_positive" msgid="7047498036346489883">"বুজি পালোঁ"</string>
     <string name="done_label" msgid="7283767013231718521">"সম্পন্ন কৰা হ’ল"</string>
@@ -2088,7 +2088,7 @@
     <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"অসুবিধা নিদিব সলনি হৈছে"</string>
     <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"কি কি অৱৰোধ কৰা হৈছে জানিবলৈ টিপক।"</string>
     <string name="notification_app_name_system" msgid="3045196791746735601">"ছিষ্টেম"</string>
-    <string name="notification_app_name_settings" msgid="9088548800899952531">"ছেটিংসমূহ"</string>
+    <string name="notification_app_name_settings" msgid="9088548800899952531">"ছেটিং"</string>
     <string name="notification_appops_camera_active" msgid="8177643089272352083">"কেমেৰা"</string>
     <string name="notification_appops_microphone_active" msgid="581333393214739332">"মাইক্ৰ\'ফ\'ন"</string>
     <string name="notification_appops_overlay_active" msgid="5571732753262836481">"আপোনাৰ স্ক্ৰীনত থকা অন্য় এপৰ ওপৰত প্ৰদৰ্শিত হৈ আছে"</string>
@@ -2142,7 +2142,7 @@
     <string name="accessibility_system_action_back_label" msgid="4205361367345537608">"উভতি যাওক"</string>
     <string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"শেহতীয়া এপ্‌সমূহ"</string>
     <string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"জাননীসমূহ"</string>
-    <string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"ক্ষিপ্ৰ ছেটিংসমূহ"</string>
+    <string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"ক্ষিপ্ৰ ছেটিং"</string>
     <string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"পাৱাৰ ডায়লগ"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"লক স্ক্ৰীন"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"স্ক্ৰীণশ্বট"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 168b066..df98f93 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -325,7 +325,7 @@
     <string name="permgrouplab_phone" msgid="570318944091926620">"Telèfon"</string>
     <string name="permgroupdesc_phone" msgid="270048070781478204">"fer i gestionar trucades telefòniques"</string>
     <string name="permgrouplab_sensors" msgid="9134046949784064495">"Sensors corporals"</string>
-    <string name="permgroupdesc_sensors" msgid="2610631290633747752">"accedir a les dades del sensor sobre els signes vitals"</string>
+    <string name="permgroupdesc_sensors" msgid="2610631290633747752">"accedir a les dades del sensor sobre les constants vitals"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Recuperar el contingut de la finestra"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspecciona el contingut d\'una finestra amb què estàs interaccionant."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Activar Exploració tàctil"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 68e90f1..c4b1a0d 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1058,7 +1058,7 @@
     </plurals>
     <string name="last_month" msgid="1528906781083518683">"El mes pasado"</string>
     <string name="older" msgid="1645159827884647400">"Anterior"</string>
-    <string name="preposition_for_date" msgid="2780767868832729599">"el <xliff:g id="DATE">%s</xliff:g>"</string>
+    <string name="preposition_for_date" msgid="2780767868832729599">"<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="4336835286453822053">"a las <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="3149809685340130039">"en <xliff:g id="YEAR">%s</xliff:g>"</string>
     <string name="day" msgid="8394717255950176156">"día"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index a3ea558..2ccf9ed 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -601,7 +601,7 @@
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Aucune empreinte digitale enregistrée."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Cet appareil ne possède pas de capteur d\'empreintes digitales."</string>
     <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Le capteur a été désactivé temporairement."</string>
-    <string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"Impossible utiliser capteur empreinte digitale. Consultez un fournisseur de services de réparation"</string>
+    <string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"Impossible d\'utiliser le capteur d\'empreintes digitales. Consultez un fournisseur de services de réparation"</string>
     <string name="fingerprint_name_template" msgid="8941662088160289778">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string>
     <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utiliser l\'empreinte digitale"</string>
     <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utiliser l\'empreinte digitale ou le verrouillage de l\'écran"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index b4df01b..fb8afe4 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -747,10 +747,10 @@
     <string name="policydesc_wipeData_secondaryUser" product="default" msgid="2788325512167208654">"इस फ़ोन पर मौजूद इस उपयोगकर्ता का डेटा बिना चेतावनी के मिटा दें."</string>
     <string name="policylab_setGlobalProxy" msgid="215332221188670221">"डिवाइस वैश्विक प्रॉक्‍सी सेट करें"</string>
     <string name="policydesc_setGlobalProxy" msgid="7149665222705519604">"नीति चालू होने के दौरान इस्तेमाल करने के लिए डिवाइस ग्लोबल प्रॉक्‍सी सेट करें. केवल डिवाइस का मालिक ही ग्लोबल प्रॉक्‍सी सेट कर सकता है."</string>
-    <string name="policylab_expirePassword" msgid="6015404400532459169">"स्‍क्रीन लॉक पासवर्ड समाप्‍ति सेट करें"</string>
+    <string name="policylab_expirePassword" msgid="6015404400532459169">"स्‍क्रीन लॉक पासवर्ड के खत्म होने की अवधि सेट करें"</string>
     <string name="policydesc_expirePassword" msgid="9136524319325960675">"यह बदलें कि स्‍क्रीन लॉक पासवर्ड, पिन या पैटर्न को कितने समय में बदला जाना चाहिए."</string>
     <string name="policylab_encryptedStorage" msgid="9012936958126670110">"मेमोरी को सुरक्षित करने का तरीका सेट करें"</string>
-    <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"संग्रहित ऐप्स डेटा को एन्क्रिप्ट किया जाना आवश्‍यक है."</string>
+    <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"स्टोर किए गए ऐप डेटा को एन्क्रिप्ट किया जाना ज़रूरी है."</string>
     <string name="policylab_disableCamera" msgid="5749486347810162018">"कैमरों को अक्षम करें"</string>
     <string name="policydesc_disableCamera" msgid="3204405908799676104">"सभी डिवाइस कैमरों का उपयोग रोकें."</string>
     <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"स्‍क्रीन लॉक की कुछ सुविधाएं बंद करना"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 6493c18..8eb1069 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -916,7 +916,7 @@
     <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"Құпия сөзді <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате тердіңіз. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> секундтан кейін қайталаңыз."</string>
     <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"PIN кодын <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате тердіңіз. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> секундтан кейін қайталаңыз."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"Бекітпесін ашу өрнегін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате салдыңыз. Тағы <xliff:g id="NUMBER_1">%2$d</xliff:g> сәтсіз әрекеттен кейін сізден Google жүйесіне кіріп планшет бекітпесін ашу сұралады.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"Құлыпты ашу өрнегін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет дұрыс сызбадыңыз. Енді тағы <xliff:g id="NUMBER_1">%2$d</xliff:g> рет қателессеңіз, Android TV құрылғыңыздың құлпын ашу үшін Google есептік жазбаңызға кіру керек болады.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін қайталап көріңіз."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"Құлыпты ашу өрнегін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет дұрыс сызбадыңыз. Енді тағы <xliff:g id="NUMBER_1">%2$d</xliff:g> рет қателессеңіз, Android TV құрылғыңыздың құлпын ашу үшін Google аккаунтыңызға кіру керек болады.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін қайталап көріңіз."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"Бекітпесін ашу өрнегін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате салдыңыз. Тағы <xliff:g id="NUMBER_1">%2$d</xliff:g> сәтсіз әрекеттен кейін сізден Google жүйесіне кіріп телефон бекітпесін ашу сұралады.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"Планшеттің бекітпесін ашуға <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате әрекеттендіңіз. <xliff:g id="NUMBER_1">%2$d</xliff:g> сәтсіз әрекеттен кейін, телефон зауыттың бастапқы параметрлеріне қайта реттеледі және пайдаланушы деректері жоғалады."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"Android TV құрылғыңыздың құлпын <xliff:g id="NUMBER_0">%1$d</xliff:g> рет дұрыс ашпадыңыз. Енді тағы <xliff:g id="NUMBER_1">%2$d</xliff:g> рет қателессеңіз, Android TV құрылғыңыздың зауыттық әдепкі параметрлері қайтарылады және одан барлық пайдаланушы деректері өшіп қалады."</string>
@@ -928,7 +928,7 @@
     <string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"Кескінді ұмытып қалдыңыз ба?"</string>
     <string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"Аккаунттың бекітпесін ашу"</string>
     <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"Тым көп кескін әрекеттері"</string>
-    <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Ашу үшін Google есептік жазбаңызбен кіріңіз."</string>
+    <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Ашу үшін Google аккаунтыңызбен кіріңіз."</string>
     <string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"Пайдаланушы атауы (эл. пошта)"</string>
     <string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"Құпия сөз"</string>
     <string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"Кіру"</string>
@@ -1333,8 +1333,8 @@
     <string name="sms_control_yes" msgid="4858845109269524622">"Рұқсат беру"</string>
     <string name="sms_control_no" msgid="4845717880040355570">"Өшіру"</string>
     <string name="sms_short_code_confirm_message" msgid="1385416688897538724">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасы &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt; мекенжайына хабар жіберуді қалайды."</string>
-    <string name="sms_short_code_details" msgid="2723725738333388351">"Бұл мобильді есептік жазбаңызда "<b>"өзгерістер"</b>" тудыруы мүмкін."</string>
-    <string name="sms_premium_short_code_details" msgid="1400296309866638111"><b>"Бұл мобильді есептік жазбаңызда өзгерістерді тудырады."</b></string>
+    <string name="sms_short_code_details" msgid="2723725738333388351">"Бұл мобильді аккаунтыңызда "<b>"өзгерістер"</b>" тудыруы мүмкін."</string>
+    <string name="sms_premium_short_code_details" msgid="1400296309866638111"><b>"Бұл мобильді аккаунтыңызда өзгерістерді тудырады."</b></string>
     <string name="sms_short_code_confirm_allow" msgid="920477594325526691">"Жіберу"</string>
     <string name="sms_short_code_confirm_deny" msgid="1356917469323768230">"Бас тарту"</string>
     <string name="sms_short_code_remember_choice" msgid="1374526438647744862">"Менің таңдауым есте сақталсын"</string>
@@ -1478,7 +1478,7 @@
     <string name="ime_action_default" msgid="8265027027659800121">"Орындау"</string>
     <string name="dial_number_using" msgid="6060769078933953531">"Нөмірді\n <xliff:g id="NUMBER">%s</xliff:g> қолданып теріңіз"</string>
     <string name="create_contact_using" msgid="6200708808003692594">"Байланысты\n <xliff:g id="NUMBER">%s</xliff:g> нөмірі арқылы орнату"</string>
-    <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"Келесі бір немесе бірнеше қолданба қазір және болашақта есептік жазбаңызға қатынасуға рұқсатты сұрап жатыр."</string>
+    <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"Келесі бір немесе бірнеше қолданба қазір және болашақта аккаунтыңызға қатынасуға рұқсатты сұрап жатыр."</string>
     <string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"Бұл өтініштің орындалуын қалайсыз ба?"</string>
     <string name="grant_permissions_header_text" msgid="3420736827804657201">"Кіру өтініші"</string>
     <string name="allow" msgid="6195617008611933762">"Рұқсат беру"</string>
@@ -1685,7 +1685,7 @@
     <string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"Android TV құрылғыңыздың құлпын <xliff:g id="NUMBER">%d</xliff:g> рет дұрыс ашпадыңыз. Енді Android TV құрылғыңыздың зауыттық әдепкі параметрлері қайтарылады."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"Телефонды ашуға <xliff:g id="NUMBER">%d</xliff:g> рет қате әрекеттендіңіз. Телефон бастапқы зауыттық параметрлеріне қайта реттеледі."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате сыздыңыз. After <xliff:g id="NUMBER_1">%2$d</xliff:g> сәтсіз әрекеттен кейін планшетіңізді аккаунт арқылы ашу өтінішін аласыз.\n\n  <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"Құлыпты ашу өрнегін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет дұрыс сызбадыңыз. Енді тағы <xliff:g id="NUMBER_1">%2$d</xliff:g> рет қателессеңіз, Android TV құрылғыңыздың құлпын ашу үшін есептік жазбаңызға кіру керек болады.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін қайталап көріңіз."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"Құлыпты ашу өрнегін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет дұрыс сызбадыңыз. Енді тағы <xliff:g id="NUMBER_1">%2$d</xliff:g> рет қателессеңіз, Android TV құрылғыңыздың құлпын ашу үшін аккаунтыңызға кіру керек болады.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін қайталап көріңіз."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате сыздыңыз. <xliff:g id="NUMBER_1">%2$d</xliff:g> сәтсіз әрекеттен кейін телефоныңызды аккаунт арқылы ашу өтінішін аласыз. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string>
     <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Жою"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index d988a6b..dac2104 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -321,7 +321,7 @@
     <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"piekļūt jūsu fiziskajām aktivitātēm"</string>
     <string name="permgrouplab_camera" msgid="9090413408963547706">"Kamera"</string>
     <string name="permgroupdesc_camera" msgid="7585150538459320326">"uzņemt attēlus un ierakstīt videoklipus"</string>
-    <string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"Tuvējās ierīces"</string>
+    <string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"Tuvumā esošas ierīces"</string>
     <string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"tuvumā esošu ierīču meklēšana un savienojuma izveide ar tām"</string>
     <string name="permgrouplab_calllog" msgid="7926834372073550288">"Zvanu žurnāli"</string>
     <string name="permgroupdesc_calllog" msgid="2026996642917801803">"lasīt un rakstīt tālruņa zvanu žurnālu"</string>
@@ -542,7 +542,7 @@
     <string name="permdesc_bluetooth_connect" product="default" msgid="4546016548795544617">"Ļauj lietotnei piekļūt pārī savienotām Bluetooth ierīcēm."</string>
     <string name="permlab_bluetooth_advertise" msgid="2781147747928853177">"reklamēšana tuvumā esošās Bluetooth ierīcēs"</string>
     <string name="permdesc_bluetooth_advertise" product="default" msgid="6085174451034210183">"Atļauj lietotnei veikt reklamēšanu tuvumā esošās Bluetooth ierīcēs"</string>
-    <string name="permlab_uwb_ranging" msgid="8141915781475770665">"novietojuma noteikšana starp tuvu esošām ultraplatjoslas ierīcēm"</string>
+    <string name="permlab_uwb_ranging" msgid="8141915781475770665">"novietojums starp tuvējām ultraplatjoslas ierīcēm"</string>
     <string name="permdesc_uwb_ranging" msgid="2519723069604307055">"Atļaut lietotnei noteikt relatīvo atrašanās vietu starp tuvumā esošām ultraplatjoslas ierīcēm"</string>
     <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Informācija par vēlamo NFC maksājumu pakalpojumu"</string>
     <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Ļauj lietotnei iegūt informāciju par vēlamo NFC maksājumu pakalpojumu, piemēram, par reģistrētajiem lietojumprogrammu ID un maršruta galamērķi."</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index ed35ce4..5301a88 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -850,7 +850,7 @@
     <string name="orgTypeOther" msgid="5450675258408005553">"മറ്റുള്ളവ"</string>
     <string name="orgTypeCustom" msgid="1126322047677329218">"ഇഷ്‌ടാനുസൃതം"</string>
     <string name="relationTypeCustom" msgid="282938315217441351">"ഇഷ്‌ടാനുസൃതം"</string>
-    <string name="relationTypeAssistant" msgid="4057605157116589315">"Assistant"</string>
+    <string name="relationTypeAssistant" msgid="4057605157116589315">"അസിസ്റ്റന്റ്"</string>
     <string name="relationTypeBrother" msgid="7141662427379247820">"സഹോദരന്‍‌"</string>
     <string name="relationTypeChild" msgid="9076258911292693601">"കുട്ടി"</string>
     <string name="relationTypeDomesticPartner" msgid="7825306887697559238">"ഗാര്‍‌ഹിക പങ്കാളി"</string>
@@ -2011,7 +2011,7 @@
     <string name="app_category_image" msgid="7307840291864213007">"ഫോട്ടോകളും ചിത്രങ്ങളും"</string>
     <string name="app_category_social" msgid="2278269325488344054">"സാമൂഹിക ആപ്സുകളും ആശയവിനിമയവും"</string>
     <string name="app_category_news" msgid="1172762719574964544">"വാർത്തകളും മാസികകളും"</string>
-    <string name="app_category_maps" msgid="6395725487922533156">"Maps &amp; Navigation"</string>
+    <string name="app_category_maps" msgid="6395725487922533156">"മാപ്പുകളും നാവിഗേഷനും"</string>
     <string name="app_category_productivity" msgid="1844422703029557883">"ഉല്‍‌പ്പാദനക്ഷമത"</string>
     <string name="app_category_accessibility" msgid="6643521607848547683">"ഉപയോഗസഹായി"</string>
     <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ഉപകരണ സ്റ്റോറേജ്"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 0a8f94f..b42a310 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -408,7 +408,7 @@
     <string name="permdesc_receiveBootCompleted" product="default" msgid="7912677044558690092">"जसे सिस्टम बूट करणे समाप्त करते तसे अ‍ॅप ला स्वतः सुरू करण्यास अनुमती देते. यामुळे फोन सुरू करण्यास वेळ लागू शकतो आणि नेहमी सुरू राहून एकंदर फोनला धीमे करण्यास अ‍ॅप ला अनुमती देते."</string>
     <string name="permlab_broadcastSticky" msgid="4552241916400572230">"रोचक प्रसारण पाठवा"</string>
     <string name="permdesc_broadcastSticky" product="tablet" msgid="5058486069846384013">"रोचक प्रसारणे पाठविण्यासाठी अ‍ॅप ला अनुमती देते, जे प्रसारण समाप्त झाल्यानंतर देखील तसेच राहते. अत्याधिक वापरामुळे बरीच मेमरी वापरली जाऊन तो टॅब्लेटला धीमा किंवा अस्थिर करू शकतो."</string>
-    <string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"चिकट प्रसारणे पाठविण्यासाठी ॲपला अनुमती देते, जे प्रसारण समाप्त झाल्यानंतर देखील तसेच राहते. अत्याधिक वापरामुळे बरीच मेमरी वापरली जाऊन तो तुमच्या Android TV डिव्हाइसला धीमा किंवा अस्थिर करू शकतो."</string>
+    <string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"रोचक प्रसारणे पाठविण्यासाठी अ‍ॅपला अनुमती देते, जे प्रसारण समाप्त झाल्यानंतर देखील तसेच राहते. अत्याधिक वापरामुळे बरीच मेमरी वापरली जाऊन तो तुमच्या Android TV डिव्हाइसला धिमा किंवा अस्थिर करू शकतो."</string>
     <string name="permdesc_broadcastSticky" product="default" msgid="134529339678913453">"रोचक प्रसारणे पाठविण्यासाठी अ‍ॅप ला अनुमती देते, जे प्रसारण समाप्त झाल्यानंतर देखील तसेच राहते. अत्याधिक वापरामुळे बरीच मेमरी वापरली जाऊन तो फोनला धीमा किंवा अस्थिर करू शकतो."</string>
     <string name="permlab_readContacts" msgid="8776395111787429099">"तुमचे संपर्क वाचा"</string>
     <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"तुमच्या टॅबलेटवर स्टोअर केलेल्‍या तुमच्या संपर्कांविषयीचा डेटा वाचण्याची ॲपला अनुमती देते. अ‍ॅप्सना संपर्क तयार केलेल्या तुमच्या टॅबलेटवरील खात्याचा अ‍ॅक्सेसदेखील असेल. यामध्ये तुम्ही इंस्टॉल केलेल्या ॲप्सने तयार केलेल्या खात्यांचा समावेश असू शकतात. ही परवानगी ॲप्सना तुमचा संपर्क डेटा सेव्ह करण्याची अनुमती देते आणि दुर्भावनापूर्ण ॲप्स तुम्हाला न कळवता संपर्क डेटा शेअर करू शकतात."</string>
@@ -985,7 +985,7 @@
     <string name="js_dialog_before_unload_negative_button" msgid="3873765747622415310">"या पेजवर रहा"</string>
     <string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nआपल्‍याला खात्री आहे की तुम्ही या पृष्‍ठावरून नेव्‍हिगेट करू इच्‍छिता?"</string>
     <string name="save_password_label" msgid="9161712335355510035">"पुष्टी करा"</string>
-    <string name="double_tap_toast" msgid="7065519579174882778">"टीप: झूम कमी करण्यासाठी आणि वाढवण्यासाठी दोनदा-टॅप करा."</string>
+    <string name="double_tap_toast" msgid="7065519579174882778">"टीप: झूम कमी करण्यासाठी आणि वाढवण्यासाठी दोनदा टॅप करा."</string>
     <string name="autofill_this_form" msgid="3187132440451621492">"स्वयं-भरण"</string>
     <string name="setup_autofill" msgid="5431369130866618567">"स्वयं-भरण सेट करा"</string>
     <string name="autofill_window_title" msgid="4379134104008111961">"<xliff:g id="SERVICENAME">%1$s</xliff:g> सह ऑटोफील करा"</string>
diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml
index 2e4578c..783fabe 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -33,4 +33,6 @@
     <color name="call_notification_answer_color">#5DBA80</color>
 
     <color name="personal_apps_suspension_notification_color">#8AB4F8</color>
+
+    <color name="overview_background">@color/overview_background_dark</color>
 </resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index d6107d7..eb250cf 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -2040,7 +2040,7 @@
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Atualizar <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> em "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_3types" msgid="1312232153076212291">"Atualizar estes itens em "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> e <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Salvar"</string>
-    <string name="autofill_save_no" msgid="9212826374207023544">"Não, obrigado"</string>
+    <string name="autofill_save_no" msgid="9212826374207023544">"Agora não"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Agora não"</string>
     <string name="autofill_save_never" msgid="6821841919831402526">"Nunca"</string>
     <string name="autofill_update_yes" msgid="4608662968996874445">"Atualizar"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index d6107d7..eb250cf 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -2040,7 +2040,7 @@
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Atualizar <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> em "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_3types" msgid="1312232153076212291">"Atualizar estes itens em "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> e <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Salvar"</string>
-    <string name="autofill_save_no" msgid="9212826374207023544">"Não, obrigado"</string>
+    <string name="autofill_save_no" msgid="9212826374207023544">"Agora não"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Agora não"</string>
     <string name="autofill_save_never" msgid="6821841919831402526">"Nunca"</string>
     <string name="autofill_update_yes" msgid="4608662968996874445">"Atualizar"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 920a0b8..5e81c60 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -2111,7 +2111,7 @@
     <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"மொபைலில் போதுமான சார்ஜ் உள்ளது. அம்சங்கள் இனி தடையின்றி இயங்கும்."</string>
     <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"டேப்லெட்டில் போதுமான சார்ஜ் உள்ளது. அம்சங்கள் இனி தடையின்றி இயங்கும்."</string>
     <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"சாதனத்தில் போதுமான சார்ஜ் உள்ளது. அம்சங்கள் இனி தடையின்றி இயங்கும்."</string>
-    <string name="mime_type_folder" msgid="2203536499348787650">"கோப்புறை"</string>
+    <string name="mime_type_folder" msgid="2203536499348787650">"ஃபோல்டர்"</string>
     <string name="mime_type_apk" msgid="3168784749499623902">"Android ஆப்ஸ்"</string>
     <string name="mime_type_generic" msgid="4606589110116560228">"ஃபைல்"</string>
     <string name="mime_type_generic_ext" msgid="9220220924380909486">"<xliff:g id="EXTENSION">%1$s</xliff:g> ஃபைல்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 50fa752..4ba4c6f 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -79,8 +79,8 @@
     <string name="CLIRPermanent" msgid="166443681876381118">"మీరు కాలర్ ID సెట్టింగ్‌ను మార్చలేరు."</string>
     <string name="RestrictedOnDataTitle" msgid="1500576417268169774">"మొబైల్ డేటా సేవ లేదు"</string>
     <string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"అత్యవసర కాలింగ్ అందుబాటులో లేదు"</string>
-    <string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"వాయిస్ సేవ లేదు"</string>
-    <string name="RestrictedOnAllVoiceTitle" msgid="3982069078579103087">"వాయిస్ సేవ లేదా అత్యవసర కాలింగ్ లేదు"</string>
+    <string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"వాయిస్ సర్వీస్ లేదు"</string>
+    <string name="RestrictedOnAllVoiceTitle" msgid="3982069078579103087">"వాయిస్ సర్వీస్ లేదా ఎమర్జెన్సీ కాలింగ్ లేదు"</string>
     <string name="RestrictedStateContent" msgid="7693575344608618926">"మీ క్యారియర్ తాత్కాలికంగా ఆఫ్ చేయబడింది"</string>
     <string name="RestrictedStateContentMsimTemplate" msgid="5228235722511044687">"SIM <xliff:g id="SIMNUMBER">%d</xliff:g> కోసం మీ క్యారియర్ తాత్కాలికంగా ఆఫ్ చేశారు"</string>
     <string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"మొబైల్ నెట్‌వర్క్ అందుబాటులో లేదు"</string>
@@ -306,7 +306,7 @@
     <string name="permgroupdesc_contacts" msgid="9163927941244182567">"మీ కాంటాక్ట్‌లను యాక్సెస్ చేయడానికి"</string>
     <string name="permgrouplab_location" msgid="1858277002233964394">"లొకేషన్"</string>
     <string name="permgroupdesc_location" msgid="1995955142118450685">"ఈ పరికర లొకేషన్‌ను యాక్సెస్ చేయడానికి"</string>
-    <string name="permgrouplab_calendar" msgid="6426860926123033230">"క్యాలెండర్"</string>
+    <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string>
     <string name="permgroupdesc_calendar" msgid="6762751063361489379">"మీ క్యాలెండర్‌ను యాక్సెస్ చేయడానికి"</string>
     <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
     <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS మెసేజ్‌లను పంపడం మరియు వీక్షించడం"</string>
@@ -453,9 +453,9 @@
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"భౌతిక కార్యాకలాపాన్ని గుర్తించండి"</string>
     <string name="permdesc_activityRecognition" msgid="8667484762991357519">"ఈ యాప్ మీ భౌతిక కార్యాకలాపాన్ని గుర్తించగలదు."</string>
     <string name="permlab_camera" msgid="6320282492904119413">"చిత్రాలు మరియు వీడియోలు తీయడం"</string>
-    <string name="permdesc_camera" msgid="5240801376168647151">"యాప్ ఉపయోగంలో ఉన్నపుడు కెమెరాను ఉపయోగించి ఈ యాప్ ఎప్పుడైనా ఫోటోలను తీయగలదు, వీడియోలను రికార్డ్ చేయగలదు."</string>
+    <string name="permdesc_camera" msgid="5240801376168647151">"యాప్ ఉపయోగంలో ఉన్నపుడు కెమెరాను ఉపయోగించి ఎప్పుడు కావాలంటే అప్పుడు ఈ యాప్ ఫోటోలు తీయగలదు, వీడియోలు రికార్డ్ చేయగలదు."</string>
     <string name="permlab_backgroundCamera" msgid="7549917926079731681">"బ్యాక్‌గ్రౌండ్‌లో ఫోటోలు, వీడియోలను తీయగలదు"</string>
-    <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"కెమెరాను ఉపయోగించి ఈ యాప్ ఎప్పుడైనా ఫోటోలను తీయగలదు, వీడియోలను రికార్డ్ చేయగలదు."</string>
+    <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"ఈ యాప్, కెమెరాను ఉపయోగించి ఎప్పుడు కావాలంటే అప్పుడు ఫోటోలు తీయగలదు, వీడియోలు రికార్డ్ చేయగలదు."</string>
     <string name="permlab_systemCamera" msgid="3642917457796210580">"ఫోటోలు, వీడియోలు తీయడానికి సిస్టమ్ కెమెరాలకు యాప్, లేదా సేవా యాక్సెస్‌ను అనుమతించండి"</string>
     <string name="permdesc_systemCamera" msgid="5938360914419175986">"ఈ విశేష లేదా సిస్టమ్ యాప్ ఎప్పుడైనా సిస్టమ్ కెమెరాను ఉపయోగించి ఫోటోలు తీయగలదు, వీడియోలను రికార్డ్ చేయగలదు. యాప్‌కు android.permission.CAMERA అనుమతి ఇవ్వడం కూడా అవసరం"</string>
     <string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"కెమెరా పరికరాలు తెరుచుకుంటున్నప్పుడు లేదా మూసుకుంటున్నప్పుడు కాల్‌బ్యాక్‌లను స్వీకరించడానికి యాప్‌ను లేదా సర్వీస్‌ను అనుమతించండి."</string>
@@ -817,7 +817,7 @@
     <string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string>
     <string name="phoneTypeWorkMobile" msgid="7522314392003565121">"కార్యాలయ మొబైల్"</string>
     <string name="phoneTypeWorkPager" msgid="3748332310638505234">"కార్యాలయ పేజర్"</string>
-    <string name="phoneTypeAssistant" msgid="757550783842231039">"అసిస్టెంట్"</string>
+    <string name="phoneTypeAssistant" msgid="757550783842231039">"Assistant"</string>
     <string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string>
     <string name="eventTypeCustom" msgid="3257367158986466481">"అనుకూలం"</string>
     <string name="eventTypeBirthday" msgid="7770026752793912283">"పుట్టినరోజు"</string>
@@ -850,7 +850,7 @@
     <string name="orgTypeOther" msgid="5450675258408005553">"ఇతరం"</string>
     <string name="orgTypeCustom" msgid="1126322047677329218">"అనుకూలం"</string>
     <string name="relationTypeCustom" msgid="282938315217441351">"అనుకూలం"</string>
-    <string name="relationTypeAssistant" msgid="4057605157116589315">"అసిస్టెంట్"</string>
+    <string name="relationTypeAssistant" msgid="4057605157116589315">"Assistant"</string>
     <string name="relationTypeBrother" msgid="7141662427379247820">"సోదరుడు"</string>
     <string name="relationTypeChild" msgid="9076258911292693601">"బిడ్డ"</string>
     <string name="relationTypeDomesticPartner" msgid="7825306887697559238">"జీవిత భాగస్వామి"</string>
@@ -1046,7 +1046,7 @@
     <string name="searchview_description_query" msgid="7430242366971716338">"ప్రశ్నను వెతకండి"</string>
     <string name="searchview_description_clear" msgid="1989371719192982900">"ప్రశ్నను క్లియర్ చేయి"</string>
     <string name="searchview_description_submit" msgid="6771060386117334686">"ప్రశ్నని సమర్పించండి"</string>
-    <string name="searchview_description_voice" msgid="42360159504884679">"వాయిస్ శోధన"</string>
+    <string name="searchview_description_voice" msgid="42360159504884679">"వాయిస్ సెర్చ్"</string>
     <string name="enable_explore_by_touch_warning_title" msgid="5095399706284943314">"తాకడం ద్వారా విశ్లేషణను ప్రారంభించాలా?"</string>
     <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="1037295476738940824">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> తాకడం ద్వారా విశ్లేషణను ప్రారంభించాలనుకుంటోంది. తాకడం ద్వారా విశ్లేషణను ఆన్ చేసినప్పుడు, మీరు మీ వేలి కింద ఉన్నవాటి యొక్క వివరణలను వినవచ్చు లేదా చూడవచ్చు లేదా టాబ్లెట్‌తో పరస్పర చర్య చేయడానికి సంజ్ఞలు చేయవచ్చు."</string>
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> తాకడం ద్వారా విశ్లేషణను ప్రారంభించాలనుకుంటోంది. తాకడం ద్వారా విశ్లేషణ ఆన్ చేయబడినప్పుడు, మీరు మీ వేలి కింద ఉన్నవాటి యొక్క వివరణలను వినవచ్చు లేదా చూడవచ్చు లేదా ఫోన్‌తో పరస్పర చర్య చేయడానికి సంజ్ఞలు చేయవచ్చు."</string>
@@ -1878,7 +1878,7 @@
     <string name="confirm_battery_saver" msgid="5247976246208245754">"సరే"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"బ్యాటరీ సేవర్ ముదురు రంగు రూపాన్ని ఆన్ చేసి, బ్యాక్‌గ్రౌండ్ యాక్టివిటీ, కొన్ని విజువల్ ఎఫెక్ట్‌లు, నిర్దిష్ట ఫీచర్‌లు, ఇంకా కొన్ని నెట్‌వర్క్ కనెక్షన్‌లను పరిమితం చేస్తుంది లేదా ఆఫ్ చేస్తుంది."</string>
     <string name="battery_saver_description" msgid="8518809702138617167">"బ్యాటరీ సేవర్ ముదురు రంగు రూపాన్ని ఆన్ చేసి, బ్యాక్‌గ్రౌండ్ యాక్టివిటీ, కొన్ని విజువల్ ఎఫెక్ట్‌లు, నిర్దిష్ట ఫీచర్‌లు, ఇంకా కొన్ని నెట్‌వర్క్ కనెక్షన్‌లను పరిమితం చేస్తుంది లేదా ఆఫ్ చేస్తుంది."</string>
-    <string name="data_saver_description" msgid="4995164271550590517">"డేటా వినియోగాన్ని తగ్గించడంలో డేటా సేవర్ సహాయకరంగా ఉంటుంది. బ్యాక్‌గ్రౌండ్‌లో కొన్ని యాప్‌లు డేటాను పంపకుండా లేదా స్వీకరించకుండా నిరోధిస్తుంది. మీరు ప్రస్తుతం ఉపయోగిస్తోన్న యాప్‌, డేటాను యాక్సెస్ చేయగలదు. కానీ త‌క్కువ సార్లు మాత్ర‌మే అలా చేయవచ్చు. ఉదాహరణకు, మీరు నొక్కే వరకు ఫోటోలు ప్రదర్శించబడవు."</string>
+    <string name="data_saver_description" msgid="4995164271550590517">"డేటా వినియోగాన్ని తగ్గించడంలో డేటా సేవర్ సహాయకరంగా ఉంటుంది. బ్యాక్‌గ్రౌండ్‌లో కొన్ని యాప్‌లు డేటాను పంపకుండా లేదా స్వీకరించకుండా నిరోధిస్తుంది. మీరు ప్రస్తుతం ఉపయోగిస్తోన్న యాప్‌, డేటాను యాక్సెస్ చేయగలదు. కానీ త‌క్కువ సార్లు మాత్ర‌మే అలా చేయవచ్చు. ఉదాహరణకు, మీరు నొక్కే వరకు ఇమేజ్‌లు ప్రదర్శించబడవు."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"డేటా సేవర్‌ను ఆన్ చేయాలా?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"ఆన్ చేయి"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
@@ -2008,7 +2008,7 @@
     <string name="app_category_game" msgid="4534216074910244790">"గేమ్‌లు"</string>
     <string name="app_category_audio" msgid="8296029904794676222">"సంగీతం &amp; ఆడియో"</string>
     <string name="app_category_video" msgid="2590183854839565814">"చలనచిత్రాలు &amp; వీడియో"</string>
-    <string name="app_category_image" msgid="7307840291864213007">"ఫోటోలు &amp; చిత్రాలు"</string>
+    <string name="app_category_image" msgid="7307840291864213007">"ఫోటోలు, ఇమేజ్‌లు"</string>
     <string name="app_category_social" msgid="2278269325488344054">"సామాజికం &amp; కమ్యూనికేషన్"</string>
     <string name="app_category_news" msgid="1172762719574964544">"వార్తలు &amp; వార్తాపత్రికలు"</string>
     <string name="app_category_maps" msgid="6395725487922533156">"Maps &amp; నావిగేషన్"</string>
@@ -2291,7 +2291,7 @@
     <string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"సెట్టింగ్‌లలో ఆన్ చేయండి"</string>
     <string name="dismiss_action" msgid="1728820550388704784">"విస్మరించు"</string>
     <string name="sensor_privacy_start_use_mic_notification_content_title" msgid="2420858361276370367">"పరికరం మైక్రోఫోన్‌ను అన్‌బ్లాక్ చేయండి"</string>
-    <string name="sensor_privacy_start_use_camera_notification_content_title" msgid="7287720213963466672">"పరికరం కెమెరాను అన్‌బ్లాక్ చేయండి"</string>
+    <string name="sensor_privacy_start_use_camera_notification_content_title" msgid="7287720213963466672">"పరికరంలోని కెమెరాను అన్‌బ్లాక్ చేయండి"</string>
     <string name="sensor_privacy_start_use_notification_content_text" msgid="7595608891015777346">"&lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; యాప్, ఇతర యాప్‌లు, సర్వీస్‌ల కోసం"</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7089318886628390827">"అన్‌బ్లాక్ చేయండి"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"సెన్సార్ గోప్యత"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index a503272..c92aa08 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1758,7 +1758,7 @@
     <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Виберіть функції для кнопки спеціальних можливостей"</string>
     <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Виберіть функції для комбінації з клавішами гучності"</string>
     <string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Сервіс <xliff:g id="SERVICE_NAME">%s</xliff:g> вимкнено"</string>
-    <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Редагувати засоби"</string>
+    <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Змінити"</string>
     <string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Готово"</string>
     <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Вимкнути ярлик"</string>
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Використовувати ярлик"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index ab13dba..178713a 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1073,7 +1073,7 @@
     <string name="weeks" msgid="3516247214269821391">"tuần"</string>
     <string name="year" msgid="5182610307741238982">"năm"</string>
     <string name="years" msgid="5797714729103773425">"năm"</string>
-    <string name="now_string_shortest" msgid="3684914126941650330">"ngay lúc này"</string>
+    <string name="now_string_shortest" msgid="3684914126941650330">"vừa xong"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="7519574894537185135">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ph</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>ph</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0ef71f1..077e568 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -6822,8 +6822,9 @@
                  content for the duration of the animation. -->
             <enum name="bottom" value="-1" />
         </attr>
-        <!-- Special background behind animation. Only for use with task animations.
-             If 0, the default, there is no background. -->
+        <!-- Special background behind animation.  Only for use with window
+             animations.  Can only be a color, and only black.  If 0, the
+             default, there is no background. -->
         <attr name="background" />
         <!-- Special option for window animations: if this window is on top
              of a wallpaper, don't animate the wallpaper with it. -->
@@ -7736,7 +7737,7 @@
 
         <!-- Name of a method on the Context used to inflate the menu that will be
              called when the item is clicked.
-             {@deprecated Menu actually traverses the Context hierarchy looking for the
+             {@deprecated Menu actually traverses the Context hierarchy looking for the 
              relevant method, which is fragile (an intermediate ContextWrapper adding a
              same-named method would change behavior) and restricts bytecode optimizers
              such as R8. Instead, use MenuItem.setOnMenuItemClickListener.} -->
@@ -8370,16 +8371,18 @@
              @hide @SystemApi -->
         <attr name="supportsAmbientMode" format="boolean" />
 
-        <!-- Indicates that this wallpaper service should receive zoom updates when unfolding.
+        <!-- Indicates that this wallpaper service should receive zoom transition updates when
+             changing the device state (e.g. when folding or unfolding a foldable device).
              When this value is set to true
              {@link android.service.wallpaper.WallpaperService.Engine} could receive zoom updates
-             when folding or unfolding a foldable device. Wallpapers receive zoom updates using
+             before or after changing the device state. Wallpapers receive zoom updates using
              {@link android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float)} and
-             zoom rendering should be handled manually. Default value is true.
-             When set to false wallpapers can implement custom folding/unfolding behavior
-             by listening to {@link android.hardware.Sensor#TYPE_HINGE_ANGLE}.
-             Corresponds to {@link android.app.WallpaperInfo#shouldUseDefaultUnfoldTransition()} -->
-        <attr name="shouldUseDefaultUnfoldTransition" format="boolean" />
+             zoom rendering should be handled manually. Zoom updates are delivered only when
+             {@link android.service.wallpaper.WallpaperService.Engine} is created and not destroyed.
+             Default value is true.
+             Corresponds to
+             {@link android.app.WallpaperInfo#shouldUseDefaultDeviceStateChangeTransition()} -->
+        <attr name="shouldUseDefaultDeviceStateChangeTransition" format="boolean" />
 
         <!-- Uri that specifies a settings Slice for this wallpaper. -->
         <attr name="settingsSliceUri" format="string"/>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index fc9b55f..755938e 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1221,7 +1221,8 @@
     <attr name="isFeatureSplit" format="boolean" />
 
     <!-- Flag to specify if this APK requires at least one split [either feature or
-         resource] to be present in order to function. Default value is false. -->
+         resource] to be present in order to function. Default value is false.
+         @deprecated Use {@link android.R.attr#requiredSplitTypes} instead. -->
     <attr name="isSplitRequired" format="boolean" />
 
     <!-- List of split types required by this APK to be present in order to function properly,
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 48d4b5b..7e87baa 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -654,6 +654,11 @@
         -->
     </integer-array>
 
+    <!-- When entering this device state (defined in device_state_configuration.xml),
+         we should wake the device. -1 to disable the feature (do not wake on any device-state
+         transition). -->
+    <integer name="config_deviceStateOnWhichToWakeUp">-1</integer>
+
     <!-- Indicate the display area rect for foldable devices in folded state. -->
     <string name="config_foldedArea"></string>
 
@@ -4866,8 +4871,8 @@
     <item name="config_fixedOrientationLetterboxAspectRatio" format="float" type="dimen">0.0</item>
 
     <!-- Corners radius for activity presented the letterbox mode. Values < 0 will be ignored and
-         corners of the activity won't be rounded. -->
-    <integer name="config_letterboxActivityCornersRadius">0</integer>
+         min between device bottom corner radii will be used instead. -->
+    <integer name="config_letterboxActivityCornersRadius">-1</integer>
 
     <!-- Blur radius for the Option 3 in R.integer.config_letterboxBackgroundType. Values < 0 are
         ignored and 0 is used. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7e6ea7a..cf03916 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2905,6 +2905,7 @@
     <public type="attr" name="usesNonSdkApi" id="0x0101058e" />
     <public type="attr" name="nonInteractiveUiTimeout" id="0x0101058f" />
     <public type="attr" name="isLightTheme" id="0x01010590" />
+    <!-- {@deprecated Use requiredSplitTypes instead.} -->
     <public type="attr" name="isSplitRequired" id="0x01010591" />
     <public type="attr" name="textLocale" id="0x01010592" />
     <public type="attr" name="settingsSliceUri" id="0x01010593" />
@@ -3221,7 +3222,7 @@
   <eat-comment />
 
   <staging-public-group type="attr" first-id="0x01ff0000">
-    <public name="shouldUseDefaultUnfoldTransition" />
+    <public name="shouldUseDefaultDeviceStateChangeTransition" />
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01fe0000">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 34e4ce8..f9d150e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3847,6 +3847,7 @@
 
   <!-- For Foldables -->
   <java-symbol type="array" name="config_foldedDeviceStates" />
+  <java-symbol type="integer" name="config_deviceStateOnWhichToWakeUp" />
   <java-symbol type="string" name="config_foldedArea" />
   <java-symbol type="bool" name="config_supportsConcurrentInternalDisplays" />
   <java-symbol type="bool" name="config_unfoldTransitionEnabled" />
@@ -4458,6 +4459,8 @@
 
   <java-symbol type="integer" name="config_customizedMaxCachedProcesses" />
 
+  <java-symbol type="color" name="overview_background"/>
+
   <java-symbol type="bool" name="config_disableTaskSnapshots" />
 
   <java-symbol type="string" name="config_secondaryBuiltInDisplayCutout" />
diff --git a/core/tests/coretests/assets/scroll_capture_test.html b/core/tests/coretests/assets/scroll_capture_test.html
new file mode 100644
index 0000000..5523887
--- /dev/null
+++ b/core/tests/coretests/assets/scroll_capture_test.html
@@ -0,0 +1,51 @@
+<!--
+  ~ 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.
+  -->
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <title>Sample Content</title>
+    <meta charset="UTF-8">
+    <style>
+       body { margin: 0px; }
+       div {
+         display: block;
+         width: 800px;
+         height: 300px;
+         color: white;
+         font-size: 20px;
+       }
+       #a { background-color: #ef476f; }
+       #b { background-color: #ffd166; }
+       #c { background-color: #06d6a0; }
+       #d { background-color: #118ab2; }
+       #e { background-color: #073b4c; }
+    </style>
+</head>
+<body>
+<div id="a">Item #1</div>
+<div id="b">Item #2</div>
+<div id="c">Item #3</div>
+<div id="d">Item #4</div>
+<div id="e">Item #5</div>
+<div id="a">Item #6</div>
+<div id="b">Item #7</div>
+<div id="c">Item #8</div>
+<div id="d">Item #9</div>
+<div id="e">Item #10</div>
+<div id="a">Item #11</div>
+<div id="b">Item #12</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java
index ddb6729..4b19391 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java
@@ -39,9 +39,10 @@
     public void testConstructorAdditionalFlags() {
         final ComponentName componentName = new ComponentName("component", "name");
         final IBinder token = new Binder();
+        final IBinder windowToken = new Binder();
         final ContentCaptureContext ctx = new ContentCaptureContext(/* clientContext= */ null,
                 new ActivityId(/* taskId= */ 666, token), componentName, /* displayId= */
-                42, /* flags= */ 1);
+                42, windowToken, /* flags= */ 1);
         final ContentCaptureContext newCtx = new ContentCaptureContext(ctx, /* extraFlags= */ 2);
         assertThat(newCtx.getFlags()).isEqualTo(3);
         assertThat(newCtx.getActivityComponent()).isEqualTo(componentName);
@@ -50,6 +51,7 @@
         assertThat(activityId.getTaskId()).isEqualTo(666);
         assertThat(activityId.getToken()).isEqualTo(token);
         assertThat(newCtx.getDisplayId()).isEqualTo(42);
+        assertThat(newCtx.getWindowToken()).isEqualTo(windowToken);
         assertThat(newCtx.getExtras()).isNull();
         assertThat(newCtx.getLocusId()).isNull();
         assertThat(newCtx.getParentSessionId()).isNull();
diff --git a/core/tests/coretests/src/com/android/internal/app/AbstractResolverComparatorTest.java b/core/tests/coretests/src/com/android/internal/app/AbstractResolverComparatorTest.java
index 03ed68c..04b8886 100644
--- a/core/tests/coretests/src/com/android/internal/app/AbstractResolverComparatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/AbstractResolverComparatorTest.java
@@ -34,6 +34,23 @@
 public class AbstractResolverComparatorTest {
 
     @Test
+    public void testPositionFixed() {
+        ResolverActivity.ResolvedComponentInfo r1 = new ResolverActivity.ResolvedComponentInfo(
+                new ComponentName("package", "class"), new Intent(), new ResolveInfo()
+        );
+        r1.setFixedAtTop(true);
+
+        ResolverActivity.ResolvedComponentInfo r2 = new ResolverActivity.ResolvedComponentInfo(
+                new ComponentName("zackage", "zlass"), new Intent(), new ResolveInfo()
+        );
+        r2.setPinned(true);
+        Context context = InstrumentationRegistry.getTargetContext();
+        AbstractResolverComparator comparator = getTestComparator(context);
+        assertEquals("FixedAtTop ranks over pinned", -1, comparator.compare(r1, r2));
+        assertEquals("Pinned ranks under fixedAtTop", 1, comparator.compare(r2, r1));
+    }
+
+    @Test
     public void testPinned() {
         ResolverActivity.ResolvedComponentInfo r1 = new ResolverActivity.ResolvedComponentInfo(
                 new ComponentName("package", "class"), new Intent(), new ResolveInfo()
diff --git a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java
index c50c818..3c093d8 100644
--- a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java
+++ b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java
@@ -18,12 +18,14 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.when;
 
 import android.content.pm.parsing.ParsingPackageRead;
+import android.content.pm.parsing.ParsingPackageUtils;
 import android.os.Build;
+import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.Pair;
 
 import com.android.internal.content.om.OverlayConfig.PackageProvider;
 import com.android.internal.content.om.OverlayScanner;
@@ -38,6 +40,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.List;
 import java.util.Map;
 import java.util.function.BiConsumer;
 import java.util.function.Supplier;
@@ -58,22 +61,42 @@
         SYSTEM_SERVER,
     }
 
-    private final ArrayMap<File, ParsedOverlayInfo> mOverlayStubResults = new ArrayMap<>();
+    private final ArrayMap<File, TestOverlayInfo> mTestOverlayInfos = new ArrayMap<>();
     private Supplier<OverlayScanner> mOverlayScanner;
     private PackageProvider mPkgProvider;
     private Iteration mIteration;
 
+    /** Represents information parsed from the manifest of an overlay for test. */
+    private static class TestOverlayInfo extends ParsedOverlayInfo {
+        public final String requiredSystemPropertyName;
+        public final String requiredSystemPropertyValue;
+
+        TestOverlayInfo(String packageName, String targetPackageName,
+                int targetSdkVersion, boolean isStatic, int priority, File path,
+                String requiredSystemPropertyName, String requiredSystemPropertyValue) {
+            super(packageName, targetPackageName, targetSdkVersion, isStatic, priority, path);
+            this.requiredSystemPropertyName = requiredSystemPropertyName;
+            this.requiredSystemPropertyValue = requiredSystemPropertyValue;
+        }
+
+        public boolean isMatchRequiredSystemProperty() {
+            return ParsingPackageUtils.checkRequiredSystemProperties(
+                    requiredSystemPropertyName, requiredSystemPropertyValue);
+        }
+    }
+
     /**
      * Mocks the parsing of the file to make it appear to the scanner that the file is a valid
      * overlay APK.
      **/
     void addOverlay(File path, String packageName, String targetPackage, int targetSdkVersion,
-            boolean isStatic, int priority) {
+            boolean isStatic, int priority, String requiredSystemPropertyName,
+            String requiredSystemPropertyValue) {
         try {
             final File canonicalPath = new File(path.getCanonicalPath());
-            mOverlayStubResults.put(canonicalPath, new ParsedOverlayInfo(
+            mTestOverlayInfos.put(canonicalPath, new TestOverlayInfo(
                     packageName, targetPackage, targetSdkVersion, isStatic, priority,
-                    canonicalPath));
+                    canonicalPath, requiredSystemPropertyName, requiredSystemPropertyValue));
         } catch (IOException e) {
             Assert.fail("Failed to add overlay " + e);
         }
@@ -91,6 +114,12 @@
         addOverlay(path, packageName, targetPackage, targetSdkVersion, false, 0);
     }
 
+    void addOverlay(File path, String packageName, String targetPackage, int targetSdkVersion,
+            boolean isStatic, int priority) {
+        addOverlay(path, packageName, targetPackage, targetSdkVersion, isStatic, priority,
+                null /* requiredSystemPropertyName */, null /* requiredSystemPropertyValue */);
+    }
+
     /** Retrieves the {@link OverlayScanner} for the current run of the test. */
     Supplier<OverlayScanner> getScannerFactory() {
         return mOverlayScanner;
@@ -116,11 +145,21 @@
                 // and parsing configuration files.
                 mOverlayScanner = () -> {
                     OverlayScanner scanner = Mockito.spy(new OverlayScanner());
-                    for (Map.Entry<File, ParsedOverlayInfo> overlay :
-                            mOverlayStubResults.entrySet()) {
-                        doReturn(overlay.getValue()).when(scanner)
-                                .parseOverlayManifest(overlay.getKey());
-                    }
+                    doAnswer((InvocationOnMock invocation) -> {
+                        final Object[] args = invocation.getArguments();
+                        final File overlayApk = (File) args[0];
+                        final List<Pair<String, File>> outExcludedOverlayPackages =
+                                (List<Pair<String, File>>) args[1];
+                        final TestOverlayInfo overlayInfo = mTestOverlayInfos.get(overlayApk);
+                        if ((!TextUtils.isEmpty(overlayInfo.requiredSystemPropertyName)
+                                || !TextUtils.isEmpty(overlayInfo.requiredSystemPropertyValue))
+                                && !overlayInfo.isMatchRequiredSystemProperty()) {
+                            outExcludedOverlayPackages.add(
+                                    Pair.create(overlayInfo.packageName, overlayApk));
+                            return null;
+                        }
+                        return overlayInfo;
+                    }).when(scanner).parseOverlayManifest(any(), any());
                     return scanner;
                 };
                 mPkgProvider = null;
@@ -137,10 +176,15 @@
                     final Object[] args = invocation.getArguments();
                     final BiConsumer<ParsingPackageRead, Boolean> f =
                             (BiConsumer<ParsingPackageRead, Boolean>) args[0];
-                    for (Map.Entry<File, ParsedOverlayInfo> overlay :
-                            mOverlayStubResults.entrySet()) {
+                    for (Map.Entry<File, TestOverlayInfo> overlay :
+                            mTestOverlayInfos.entrySet()) {
                         final ParsingPackageRead a = Mockito.mock(ParsingPackageRead.class);
-                        final ParsedOverlayInfo info = overlay.getValue();
+                        final TestOverlayInfo info = overlay.getValue();
+                        if ((!TextUtils.isEmpty(info.requiredSystemPropertyName)
+                                || !TextUtils.isEmpty(info.requiredSystemPropertyValue))
+                                && !info.isMatchRequiredSystemProperty()) {
+                            continue;
+                        }
                         when(a.getPackageName()).thenReturn(info.packageName);
                         when(a.getOverlayTarget()).thenReturn(info.targetPackageName);
                         when(a.getTargetSdkVersion()).thenReturn(info.targetSdkVersion);
diff --git a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
index 178c2dd..aea453e 100644
--- a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
+++ b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
@@ -19,9 +19,11 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import android.os.FileUtils;
+import android.os.SystemProperties;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
@@ -600,4 +602,65 @@
         assertEquals(testApk.getPath(), info.path.getPath());
         assertEquals(21, info.targetSdkVersion);
     }
+
+    @Test
+    public void testOverlayManifest_withRequiredSystemPropertyAndValueNotMatched()
+            throws IOException {
+        final String systemPropertyName = "foo.name";
+        final String systemPropertyValue = "foo.value";
+
+        createFile("/product/overlay/config/config.xml",
+                "<config>"
+                        + "  <overlay package=\"one\" />"
+                        + "  <overlay package=\"two\" />"
+                        + "  <overlay package=\"three\" />"
+                        + "</config>");
+
+        mScannerRule.addOverlay(createFile("/product/overlay/one.apk"), "one", "android", 0,
+                true, 1, systemPropertyName, systemPropertyValue);
+        mScannerRule.addOverlay(createFile("/product/overlay/two.apk"), "two", "android", 0,
+                true, 1, systemPropertyName, systemPropertyValue);
+        mScannerRule.addOverlay(createFile("/product/overlay/three.apk"), "three");
+
+        final OverlayConfig overlayConfig = createConfigImpl();
+        OverlayConfig.Configuration o1 = overlayConfig.getConfiguration("one");
+        assertNull(o1);
+
+        OverlayConfig.Configuration o2 = overlayConfig.getConfiguration("two");
+        assertNull(o2);
+
+        OverlayConfig.Configuration o3 = overlayConfig.getConfiguration("three");
+        assertNotNull(o3);
+    }
+
+    @Test
+    public void testOverlayManifest_withRequiredSystemPropertyAndValueMatched()
+            throws IOException {
+        final String systemPropertyName = "ro.build.version.sdk";
+        final String systemPropertyValue = SystemProperties.get(systemPropertyName, null);
+        assertNotNull(systemPropertyValue);
+
+        createFile("/product/overlay/config/config.xml",
+                "<config>"
+                        + "  <overlay package=\"one\" />"
+                        + "  <overlay package=\"two\" />"
+                        + "  <overlay package=\"three\" />"
+                        + "</config>");
+
+        mScannerRule.addOverlay(createFile("/product/overlay/one.apk"), "one", "android", 0,
+                true, 1, systemPropertyName, systemPropertyValue);
+        mScannerRule.addOverlay(createFile("/product/overlay/two.apk"), "two", "android", 0,
+                true, 1, systemPropertyName, systemPropertyValue);
+        mScannerRule.addOverlay(createFile("/product/overlay/three.apk"), "three");
+
+        final OverlayConfig overlayConfig = createConfigImpl();
+        OverlayConfig.Configuration o1 = overlayConfig.getConfiguration("one");
+        assertNotNull(o1);
+
+        OverlayConfig.Configuration o2 = overlayConfig.getConfiguration("two");
+        assertNotNull(o2);
+
+        OverlayConfig.Configuration o3 = overlayConfig.getConfiguration("three");
+        assertNotNull(o3);
+    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
index cca6642..8b060ff 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
@@ -27,10 +27,13 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
-import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.when;
 
+import android.app.ActivityManager;
 import android.os.BatteryStats;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -40,20 +43,19 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
-import com.android.internal.util.ArrayUtils;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import java.util.Arrays;
-
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class BatteryStatsImplTest {
+    private static final long[] CPU_FREQS = {1, 2, 3, 4, 5};
+    private static final int NUM_CPU_FREQS = CPU_FREQS.length;
+
     @Mock
     private KernelCpuUidFreqTimeReader mKernelUidCpuFreqTimeReader;
     @Mock
@@ -61,13 +63,16 @@
 
     private MockBatteryStatsImpl mBatteryStatsImpl;
 
+    private MockClock mMockClock = new MockClock();
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
+        when(mKernelUidCpuFreqTimeReader.readFreqs(any())).thenReturn(CPU_FREQS);
         when(mKernelUidCpuFreqTimeReader.allUidTimesAvailable()).thenReturn(true);
         when(mKernelSingleUidTimeReader.singleUidCpuTimesAvailable()).thenReturn(true);
-        mBatteryStatsImpl = new MockBatteryStatsImpl()
+        mBatteryStatsImpl = new MockBatteryStatsImpl(mMockClock)
                 .setKernelCpuUidFreqTimeReader(mKernelUidCpuFreqTimeReader)
                 .setKernelSingleUidTimeReader(mKernelSingleUidTimeReader)
                 .setTrackingCpuByProcStateEnabled(true);
@@ -76,9 +81,17 @@
     @Test
     public void testUpdateProcStateCpuTimes() {
         mBatteryStatsImpl.setOnBatteryInternal(true);
-        mBatteryStatsImpl.updateTimeBasesLocked(false, Display.STATE_ON, 0, 0);
+        synchronized (mBatteryStatsImpl) {
+            mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
+        }
 
         final int[] testUids = {10032, 10048, 10145, 10139};
+        final int[] activityManagerProcStates = {
+                ActivityManager.PROCESS_STATE_RECEIVER,
+                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
+                ActivityManager.PROCESS_STATE_TOP,
+                ActivityManager.PROCESS_STATE_CACHED_EMPTY
+        };
         final int[] testProcStates = {
                 PROCESS_STATE_BACKGROUND,
                 PROCESS_STATE_FOREGROUND_SERVICE,
@@ -86,14 +99,24 @@
                 PROCESS_STATE_CACHED
         };
         addPendingUids(testUids, testProcStates);
+
+        // Initialize time-in-freq counters
+        mMockClock.realtime = 1000;
+        for (int i = 0; i < testUids.length; ++i) {
+            mBatteryStatsImpl.noteUidProcessStateLocked(testUids[i], activityManagerProcStates[i]);
+            mockKernelSingleUidTimeReader(testUids[i], new long[5]);
+        }
+        mBatteryStatsImpl.updateProcStateCpuTimes(true, false);
+
+        // Obtain initial CPU time-in-freq counts
         final long[][] cpuTimes = {
-                {349734983, 394982394832l, 909834, 348934, 9838},
+                {349734983, 394982394832L, 909834, 348934, 9838},
                 {7498, 1239890, 988, 13298, 98980},
                 {989834, 384098, 98483, 23809, 4984},
                 {4859048, 348903, 4578967, 5973894, 298549}
         };
         for (int i = 0; i < testUids.length; ++i) {
-            when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(cpuTimes[i]);
+            mockKernelSingleUidTimeReader(testUids[i], cpuTimes[i]);
 
             // Verify there are no cpu times initially.
             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUids[i]);
@@ -102,7 +125,9 @@
                 assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState));
             }
         }
+        addPendingUids(testUids, testProcStates);
 
+        mMockClock.realtime += 1000;
         mBatteryStatsImpl.updateProcStateCpuTimes(true, false);
 
         verifyNoPendingUids();
@@ -119,6 +144,7 @@
             }
         }
 
+        // Accumulate CPU time-in-freq deltas
         final long[][] delta1 = {
                 {9589, 148934, 309894, 3098493, 98754},
                 {21983, 94983, 4983, 9878493, 84854},
@@ -126,10 +152,15 @@
                 {843895, 43948, 949582, 99, 384}
         };
         for (int i = 0; i < testUids.length; ++i) {
-            when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(delta1[i]);
+            long[] newCpuTimes = new long[cpuTimes[i].length];
+            for (int j = 0; j < cpuTimes[i].length; j++) {
+                newCpuTimes[j] = cpuTimes[i][j] + delta1[i][j];
+            }
+            mockKernelSingleUidTimeReader(testUids[i], newCpuTimes);
         }
         addPendingUids(testUids, testProcStates);
 
+        mMockClock.realtime += 1000;
         mBatteryStatsImpl.updateProcStateCpuTimes(true, false);
 
         verifyNoPendingUids();
@@ -150,7 +181,12 @@
             }
         }
 
-        mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        // Validate the on-battery-screen-off counter
+        synchronized (mBatteryStatsImpl) {
+            mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0,
+                    mMockClock.realtime * 1000);
+        }
+
         final long[][] delta2 = {
                 {95932, 2943, 49834, 89034, 139},
                 {349, 89605, 5896, 845, 98444},
@@ -158,10 +194,15 @@
                 {488, 998, 8498, 394, 574}
         };
         for (int i = 0; i < testUids.length; ++i) {
-            when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(delta2[i]);
+            long[] newCpuTimes = new long[cpuTimes[i].length];
+            for (int j = 0; j < cpuTimes[i].length; j++) {
+                newCpuTimes[j] = cpuTimes[i][j] + delta1[i][j] + delta2[i][j];
+            }
+            mockKernelSingleUidTimeReader(testUids[i], newCpuTimes);
         }
         addPendingUids(testUids, testProcStates);
 
+        mMockClock.realtime += 1000;
         mBatteryStatsImpl.updateProcStateCpuTimes(true, true);
 
         verifyNoPendingUids();
@@ -184,6 +225,10 @@
             }
         }
 
+        // Verify handling of isolated UIDs - their time-in-freq must be directly
+        // added to that of the parent UID's.  The proc state of the isolated UID is
+        // assumed to be the same as that of the parent UID, so there is no per-state
+        // data for isolated UIDs.
         final long[][] delta3 = {
                 {98545, 95768795, 76586, 548945, 57846},
                 {788876, 586, 578459, 8776984, 9578923},
@@ -191,16 +236,20 @@
                 {9493, 784, 99895, 8974893, 9879843}
         };
         for (int i = 0; i < testUids.length; ++i) {
-            when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(
-                    delta3[i].clone());
+            long[] newCpuTimes = new long[cpuTimes[i].length];
+            for (int j = 0; j < cpuTimes[i].length; j++) {
+                newCpuTimes[j] = cpuTimes[i][j] + delta1[i][j] + delta2[i][j] + delta3[i][j];
+            }
+            mockKernelSingleUidTimeReader(testUids[i], newCpuTimes);
         }
         addPendingUids(testUids, testProcStates);
         final int parentUid = testUids[1];
         final int childUid = 99099;
         addIsolatedUid(parentUid, childUid);
         final long[] isolatedUidCpuTimes = {495784, 398473, 4895, 4905, 30984093};
-        when(mKernelSingleUidTimeReader.readDeltaMs(childUid)).thenReturn(isolatedUidCpuTimes);
+        mockKernelSingleUidTimeReader(childUid, isolatedUidCpuTimes, isolatedUidCpuTimes);
 
+        mMockClock.realtime += 1000;
         mBatteryStatsImpl.updateProcStateCpuTimes(true, true);
 
         verifyNoPendingUids();
@@ -233,7 +282,11 @@
     @Test
     public void testCopyFromAllUidsCpuTimes() {
         mBatteryStatsImpl.setOnBatteryInternal(false);
-        mBatteryStatsImpl.updateTimeBasesLocked(false, Display.STATE_ON, 0, 0);
+        synchronized (mBatteryStatsImpl) {
+            mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
+        }
+
+        mMockClock.realtime = 1000;
 
         final int[] testUids = {10032, 10048, 10145, 10139};
         final int[] testProcStates = {
@@ -242,8 +295,14 @@
                 PROCESS_STATE_TOP,
                 PROCESS_STATE_CACHED
         };
-        final int[] pendingUidIdx = {1, 2};
-        updateProcessStates(testUids, testProcStates, pendingUidIdx);
+        addPendingUids(testUids, testProcStates);
+
+        for (int i = 0; i < testUids.length; ++i) {
+            BatteryStatsImpl.Uid uid = mBatteryStatsImpl.getUidStatsLocked(testUids[i]);
+            uid.setProcessStateForTest(testProcStates[i], mMockClock.elapsedRealtime());
+            mockKernelSingleUidTimeReader(testUids[i], new long[NUM_CPU_FREQS]);
+        }
+        mBatteryStatsImpl.updateProcStateCpuTimes(true, false);
 
         final SparseArray<long[]> allUidCpuTimes = new SparseArray<>();
         long[][] allCpuTimes = {
@@ -257,18 +316,16 @@
         }
         when(mKernelUidCpuFreqTimeReader.getAllUidCpuFreqTimeMs()).thenReturn(allUidCpuTimes);
         long[][] expectedCpuTimes = {
-                {843598745, 397843, 32749, 99854},
-                {9834, 5885, 487589, 394},
-                {203984, 439, 9859, 30948},
-                {9389, 858, 239, 349}
+                {843598745, 397843, 32749, 99854, 23454},
+                {9834, 5885, 487589, 394, 93933},
+                {203984, 439, 9859, 30948, 49494},
+                {9389, 858, 239, 349, 50505}
         };
         for (int i = 0; i < testUids.length; ++i) {
-            final int idx = i;
-            final ArgumentMatcher<long[]> matcher = times -> Arrays.equals(times, allCpuTimes[idx]);
-            when(mKernelSingleUidTimeReader.computeDelta(eq(testUids[i]), argThat(matcher)))
-                    .thenReturn(expectedCpuTimes[i]);
+            mockKernelSingleUidTimeReader(testUids[i], expectedCpuTimes[i]);
         }
 
+        mMockClock.realtime += 1000;
         mBatteryStatsImpl.copyFromAllUidsCpuTimes(true, false);
 
         verifyNoPendingUids();
@@ -286,6 +343,39 @@
         }
     }
 
+    private void mockKernelSingleUidTimeReader(int testUid, long[] cpuTimes) {
+        doAnswer(invocation -> {
+            LongArrayMultiStateCounter counter = invocation.getArgument(1);
+            long timestampMs = invocation.getArgument(2);
+            LongArrayMultiStateCounter.LongArrayContainer container =
+                    new LongArrayMultiStateCounter.LongArrayContainer(NUM_CPU_FREQS);
+            container.setValues(cpuTimes);
+            counter.updateValues(container, timestampMs);
+            return null;
+        }).when(mKernelSingleUidTimeReader).addDelta(eq(testUid),
+                any(LongArrayMultiStateCounter.class), anyLong());
+    }
+
+    private void mockKernelSingleUidTimeReader(int testUid, long[] cpuTimes, long[] delta) {
+        doAnswer(invocation -> {
+            LongArrayMultiStateCounter counter = invocation.getArgument(1);
+            long timestampMs = invocation.getArgument(2);
+            LongArrayMultiStateCounter.LongArrayContainer deltaContainer =
+                    invocation.getArgument(3);
+
+            LongArrayMultiStateCounter.LongArrayContainer container =
+                    new LongArrayMultiStateCounter.LongArrayContainer(NUM_CPU_FREQS);
+            container.setValues(cpuTimes);
+            counter.updateValues(container, timestampMs);
+            if (deltaContainer != null) {
+                deltaContainer.setValues(delta);
+            }
+            return null;
+        }).when(mKernelSingleUidTimeReader).addDelta(eq(testUid),
+                any(LongArrayMultiStateCounter.class), anyLong(),
+                any(LongArrayMultiStateCounter.LongArrayContainer.class));
+    }
+
     @Test
     public void testAddCpuTimes() {
         long[] timesA = null;
@@ -314,7 +404,9 @@
         final int releaseTimeMs = 1005;
         final int currentTimeMs = 1011;
 
-        mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        synchronized (mBatteryStatsImpl) {
+            mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        }
 
         // Create a Uid Object
         final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid);
@@ -325,7 +417,7 @@
         u.noteWifiMulticastDisabledLocked(releaseTimeMs);
 
         // Get the total acquisition time
-        long totalTime = u.getWifiMulticastTime(currentTimeMs*1000,
+        long totalTime = u.getWifiMulticastTime(currentTimeMs * 1000,
                 BatteryStats.STATS_SINCE_CHARGED);
         assertEquals("Miscalculations of Multicast wakelock acquisition time",
                 (releaseTimeMs - acquireTimeMs) * 1000, totalTime);
@@ -337,7 +429,9 @@
         final int acquireTimeMs = 1000;
         final int currentTimeMs = 1011;
 
-        mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        synchronized (mBatteryStatsImpl) {
+            mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        }
 
         // Create a Uid Object
         final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid);
@@ -347,7 +441,7 @@
         u.noteWifiMulticastEnabledLocked(acquireTimeMs);
 
         // Get the total acquisition time
-        long totalTime =  u.getWifiMulticastTime(currentTimeMs*1000,
+        long totalTime = u.getWifiMulticastTime(currentTimeMs * 1000,
                 BatteryStats.STATS_SINCE_CHARGED);
         assertEquals("Miscalculations of Multicast wakelock acquisition time",
                 (currentTimeMs - acquireTimeMs) * 1000, totalTime);
@@ -363,7 +457,9 @@
         final int releaseTimeMs_2 = 1009;
         final int currentTimeMs = 1011;
 
-        mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        synchronized (mBatteryStatsImpl) {
+            mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        }
 
         // Create a Uid Object
         final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid);
@@ -377,7 +473,7 @@
         u.noteWifiMulticastDisabledLocked(releaseTimeMs_2);
 
         // Get the total acquisition time
-        long totalTime =  u.getWifiMulticastTime(currentTimeMs*1000,
+        long totalTime = u.getWifiMulticastTime(currentTimeMs * 1000,
                 BatteryStats.STATS_SINCE_CHARGED);
         assertEquals("Miscalculations of Multicast wakelock acquisition time",
                 (releaseTimeMs_2 - acquireTimeMs_1) * 1000, totalTime);
@@ -393,7 +489,9 @@
         final int releaseTimeMs_2 = 1009;
         final int currentTimeMs = 1011;
 
-        mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        synchronized (mBatteryStatsImpl) {
+            mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        }
 
         // Create a Uid Object
         final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid);
@@ -407,11 +505,11 @@
         u.noteWifiMulticastDisabledLocked(releaseTimeMs_2);
 
         // Get the total acquisition time
-        long totalTime =  u.getWifiMulticastTime(currentTimeMs*1000,
+        long totalTime = u.getWifiMulticastTime(currentTimeMs * 1000,
                 BatteryStats.STATS_SINCE_CHARGED);
         assertEquals("Miscalculations of Multicast wakelock acquisition time",
                 ((releaseTimeMs_1 - acquireTimeMs_1) + (releaseTimeMs_2 - acquireTimeMs_2))
-                * 1000, totalTime);
+                        * 1000, totalTime);
     }
 
     private void addIsolatedUid(int parentUid, int childUid) {
@@ -426,20 +524,6 @@
         }
     }
 
-    private void updateProcessStates(int[] uids, int[] procStates,
-            int[] pendingUidsIdx) {
-        final SparseIntArray pendingUids = mBatteryStatsImpl.getPendingUids();
-        for (int i = 0; i < uids.length; ++i) {
-            final BatteryStatsImpl.Uid u = mBatteryStatsImpl.getUidStatsLocked(uids[i]);
-            if (ArrayUtils.contains(pendingUidsIdx, i)) {
-                u.setProcessStateForTest(PROCESS_STATE_TOP);
-                pendingUids.put(uids[i], procStates[i]);
-            } else {
-                u.setProcessStateForTest(procStates[i]);
-            }
-        }
-    }
-
     private void verifyNoPendingUids() {
         final SparseIntArray pendingUids = mBatteryStatsImpl.getPendingUids();
         assertEquals("There shouldn't be any pending uids left: " + pendingUids,
diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
index 63e13fd..441e85d 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -183,7 +183,9 @@
         sCpuFreqTimesAvailable = totalCpuTimes != null;
         final long[] fgCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID,
                 PROCESS_STATE_FOREGROUND);
-        sPerProcStateTimesAvailable = fgCpuTimes != null;
+        final long[] topCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID,
+                PROCESS_STATE_TOP);
+        sPerProcStateTimesAvailable = fgCpuTimes != null || topCpuTimes != null;
     }
 
     @Test
@@ -563,7 +565,7 @@
 
             final long[] cpuTimesMs3 = getAllCpuFreqTimes(sTestPkgUid, PROCESS_STATE_TOP);
             assertCpuTimesValid(cpuTimesMs3);
-            assertCpuTimesEqual(cpuTimesMs3, cpuTimesMs, 20,
+            assertCpuTimesEqual(cpuTimesMs3, cpuTimesMs, 500,
                     "Unexpected cpu times after turning on tracking");
 
             doSomeWork(PROCESS_STATE_TOP);
@@ -588,7 +590,8 @@
     private void assertCpuTimesEqual(long[] actual, long[] expected, long delta, String errMsg) {
         for (int i = actual.length - 1; i >= 0; --i) {
             if (actual[i] > expected[i] + delta || actual[i] < expected[i]) {
-                fail(errMsg + ", actual=" + actual + ", expected=" + expected + ", delta=" + delta);
+                fail(errMsg + ", actual=" + Arrays.toString(actual)
+                        + ", expected=" + Arrays.toString(expected) + ", delta=" + delta);
             }
         }
     }
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
index 4182574..74ab644 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
@@ -285,7 +285,7 @@
         LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 5);
         counter.setState(0, 0);
         mInjector.setCpuTimeInStatePerClusterNs(new long[][]{{0, 0, 0}, {0, 0}});
-        boolean success = mInjector.addDelta(TEST_UID, counter, 0);
+        boolean success = mInjector.addDelta(TEST_UID, counter, 0, null);
         assertThat(success).isTrue();
 
         // Nanoseconds
@@ -294,13 +294,16 @@
                         {1_000_000, 2_000_000, 3_000_000},
                         {4_000_000, 5_000_000}});
 
-        success = mInjector.addDelta(TEST_UID, counter, 2000);
-        assertThat(success).isTrue();
-
         LongArrayMultiStateCounter.LongArrayContainer array =
                 new LongArrayMultiStateCounter.LongArrayContainer(5);
         long[] out = new long[5];
 
+        success = mInjector.addDelta(TEST_UID, counter, 2000, array);
+        assertThat(success).isTrue();
+
+        array.getValues(out);
+        assertThat(out).isEqualTo(new long[]{1, 2, 3, 4, 5});
+
         counter.getCounts(array, 0);
         array.getValues(out);
         assertThat(out).isEqualTo(new long[]{1, 2, 3, 4, 5});
@@ -312,9 +315,12 @@
                         {11_000_000, 22_000_000, 33_000_000},
                         {44_000_000, 55_000_000}});
 
-        success = mInjector.addDelta(TEST_UID, counter, 4000);
+        success = mInjector.addDelta(TEST_UID, counter, 4000, array);
         assertThat(success).isTrue();
 
+        array.getValues(out);
+        assertThat(out).isEqualTo(new long[]{10, 20, 30, 40, 50});
+
         counter.getCounts(array, 0);
         array.getValues(out);
         assertThat(out).isEqualTo(new long[]{1 + 5, 2 + 10, 3 + 15, 4 + 20, 5 + 25});
@@ -371,8 +377,10 @@
         }
 
         @Override
-        public boolean addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs) {
-            return addDeltaForTest(uid, counter, timestampMs, mCpuTimeInStatePerClusterNs);
+        public boolean addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs,
+                LongArrayMultiStateCounter.LongArrayContainer deltaOut) {
+            return addDeltaForTest(uid, counter, timestampMs, mCpuTimeInStatePerClusterNs,
+                    deltaOut);
         }
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/view/AbsCaptureHelperTest.java b/core/tests/coretests/src/com/android/internal/view/AbsCaptureHelperTest.java
new file mode 100644
index 0000000..42b2b16
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/view/AbsCaptureHelperTest.java
@@ -0,0 +1,339 @@
+/*
+ * 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.internal.view;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.annotation.NonNull;
+import android.annotation.UiThread;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.view.ScrollCaptureViewHelper.ScrollResult;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * This test contains a set of operations designed to verify the behavior of a
+ * ScrollCaptureViewHelper implementation. Subclasses define and initialize
+ * the View hierarchy by overriding {@link #createScrollableContent} and provide the
+ * helper instance by overriding {@link #createHelper()}.
+ *
+ * @param <T> The concrete View subclass handled by the helper
+ * @param <H> The helper being tested
+ */
+public abstract class AbsCaptureHelperTest<T extends View, H extends ScrollCaptureViewHelper<T>> {
+
+    private static final String TAG = "AbsCaptureHelperTest";
+
+    static final int WINDOW_WIDTH = 800;
+    static final int WINDOW_HEIGHT = 1200;
+
+    static final int CAPTURE_HEIGHT = WINDOW_HEIGHT / 2;
+    static final int CONTENT_HEIGHT = WINDOW_HEIGHT * 3;
+
+    public static final int[] ITEM_COLORS = {
+            0xef476f,
+            0xffd166,
+            0x06d6a0,
+            0x118ab2,
+            0x073b4c
+    };
+
+    enum ScrollPosition {
+        /** Scroll to top edge */
+        TOP,
+        /** Scroll middle of content to the top edge of the window */
+        MIDDLE,
+        /** Scroll bottom edge of content to the bottom edge of the window. */
+        BOTTOM
+    }
+
+    private WindowManager mWm;
+    private FrameLayout mContentRoot;
+    private T mTarget;
+    private Rect mScrollBounds;
+    private H mHelper;
+
+    private Instrumentation mInstrumentation;
+
+    @Before
+    public final void createWindow() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        Context context = mInstrumentation.getTargetContext();
+        mWm = context.getSystemService(WindowManager.class);
+
+        // Instantiate parent view on the main thread
+        mInstrumentation.runOnMainSync(() -> mContentRoot = new FrameLayout(context));
+
+        // Called this directly on the test thread so it can block until loaded if needed
+        mTarget = createScrollableContent(mContentRoot);
+
+        // Finish constructing the window on the UI thread
+        mInstrumentation.runOnMainSync(() -> {
+            mContentRoot.addView(mTarget, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+            WindowManager.LayoutParams windowLayoutParams = new WindowManager.LayoutParams(
+                    WINDOW_WIDTH,
+                    WINDOW_HEIGHT,
+                    TYPE_APPLICATION_OVERLAY,
+                    FLAG_NOT_TOUCHABLE,
+                    PixelFormat.OPAQUE);
+
+            windowLayoutParams.setTitle("ScrollCaptureHelperTest");
+            windowLayoutParams.gravity = Gravity.CENTER;
+            mWm.addView(mContentRoot, windowLayoutParams);
+        });
+    }
+
+    /**
+     * Create and prepare the instance of the helper under test.
+     *
+     * @return a new instance of ScrollCaptureViewHelper
+     */
+    protected abstract H createHelper();
+
+    /**
+     * Create a view/hierarchy containing a scrollable view to control. There should be zero
+     * padding or margins, and the test cases expect the scrollable content to be
+     * {@link #CONTENT_HEIGHT} px tall.
+     *
+     * @param parent the parent viewgroup holding the view to test
+     * @return an instance of T to test
+     */
+    @UiThread
+    protected abstract T createScrollableContent(ViewGroup parent);
+
+    /**
+     * Manually adjust the position of the scrollable view as setup for test scenarios.
+     *
+     * @param target the view target to adjust scroll position
+     * @param position the position to scroll to
+     */
+    @UiThread
+    protected void setInitialScrollPosition(T target, ScrollPosition position) {
+        Log.d(TAG, "scrollToPosition: " + position);
+        switch (position) {
+            case MIDDLE:
+                target.scrollBy(0, WINDOW_HEIGHT);
+                break;
+            case BOTTOM:
+                target.scrollBy(0, WINDOW_HEIGHT * 2);
+                break;
+        }
+    }
+
+    @Test
+    @UiThreadTest
+    public void onScrollRequested_up_fromTop() {
+        initHelper(ScrollPosition.TOP);
+
+        Rect request = new Rect(0, -CAPTURE_HEIGHT, WINDOW_WIDTH, 0);
+        ScrollResult result = requestScrollSync(mHelper, mScrollBounds, request);
+
+        assertEmpty(result.availableArea);
+    }
+
+    @Test
+    @UiThreadTest
+    public void onScrollRequested_down_fromTop() {
+        initHelper(ScrollPosition.TOP);
+        Rect request = new Rect(0, WINDOW_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT + CAPTURE_HEIGHT);
+        ScrollResult scrollResult = requestScrollSync(mHelper, mScrollBounds, request);
+
+        assertThat(scrollResult.requestedArea).isEqualTo(request);
+        assertThat(scrollResult.availableArea).isEqualTo(request);
+        // Capture height centered in the window
+        assertThat(scrollResult.scrollDelta).isEqualTo((WINDOW_HEIGHT / 2) + (CAPTURE_HEIGHT / 2));
+        assertAvailableAreaCompletelyVisible(scrollResult, mTarget);
+    }
+
+    @Test
+    @UiThreadTest
+    public void onScrollRequested_up_fromMiddle() {
+        initHelper(ScrollPosition.MIDDLE);
+
+        Rect request = new Rect(0, -CAPTURE_HEIGHT, WINDOW_WIDTH, 0);
+        ScrollResult scrollResult = requestScrollSync(mHelper, mScrollBounds, request);
+
+        assertThat(scrollResult.requestedArea).isEqualTo(request);
+        assertThat(scrollResult.availableArea).isEqualTo(request);
+        assertThat(scrollResult.scrollDelta).isEqualTo(
+                -CAPTURE_HEIGHT - (WINDOW_HEIGHT - CAPTURE_HEIGHT) / 2);
+        assertAvailableAreaCompletelyVisible(scrollResult, mTarget);
+    }
+
+    @Test
+    @UiThreadTest
+    public void onScrollRequested_down_fromMiddle() {
+        initHelper(ScrollPosition.MIDDLE);
+
+        Rect request = new Rect(0, WINDOW_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT + CAPTURE_HEIGHT);
+        ScrollResult scrollResult = requestScrollSync(mHelper, mScrollBounds, request);
+
+        assertThat(scrollResult.requestedArea).isEqualTo(request);
+        assertThat(scrollResult.availableArea).isEqualTo(request);
+        assertThat(scrollResult.scrollDelta).isEqualTo(
+                CAPTURE_HEIGHT + (WINDOW_HEIGHT - CAPTURE_HEIGHT) / 2);
+        assertAvailableAreaCompletelyVisible(scrollResult, mTarget);
+    }
+
+    @Test
+    @UiThreadTest
+    public void onScrollRequested_up_fromBottom() {
+        initHelper(ScrollPosition.BOTTOM);
+
+        Rect request = new Rect(0, -CAPTURE_HEIGHT, WINDOW_WIDTH, 0);
+        ScrollResult scrollResult = requestScrollSync(mHelper, mScrollBounds, request);
+
+        assertThat(scrollResult.requestedArea).isEqualTo(request);
+        assertThat(scrollResult.availableArea).isEqualTo(request);
+        assertThat(scrollResult.scrollDelta).isEqualTo(
+                -CAPTURE_HEIGHT - (WINDOW_HEIGHT - CAPTURE_HEIGHT) / 2);
+        assertAvailableAreaCompletelyVisible(scrollResult, mTarget);
+    }
+
+    @Test
+    @UiThreadTest
+    public void onScrollRequested_down_fromBottom() {
+        initHelper(ScrollPosition.BOTTOM);
+
+        Rect request = new Rect(0, WINDOW_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT + CAPTURE_HEIGHT);
+        ScrollResult scrollResult = requestScrollSync(mHelper, mScrollBounds, request);
+
+        assertThat(scrollResult.requestedArea).isEqualTo(request);
+        // The result is an empty rectangle and no scrolling, since it
+        // is not possible to physically scroll further down to make the
+        // requested area visible at all (it doesn't exist).
+        assertEmpty(scrollResult.availableArea);
+    }
+
+    @Test
+    @UiThreadTest
+    public void onScrollRequested_offTopEdge() {
+        initHelper(ScrollPosition.TOP);
+
+        int top = 0;
+        Rect request =
+                new Rect(0, top - (CAPTURE_HEIGHT / 2), WINDOW_WIDTH, top + (CAPTURE_HEIGHT / 2));
+
+        ScrollResult scrollResult = requestScrollSync(mHelper, mScrollBounds, request);
+
+        // The result is a partial result
+        Rect expectedResult = new Rect(request);
+        expectedResult.top += (CAPTURE_HEIGHT / 2); // top half clipped
+        assertThat(scrollResult.requestedArea).isEqualTo(request);
+        assertThat(scrollResult.availableArea).isEqualTo(expectedResult);
+        assertThat(scrollResult.scrollDelta).isEqualTo(0);
+        assertAvailableAreaPartiallyVisible(scrollResult, mTarget);
+    }
+
+    @Test
+    @UiThreadTest
+    public void onScrollRequested_offBottomEdge() {
+        initHelper(ScrollPosition.BOTTOM);
+
+        Rect request = new Rect(0, WINDOW_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT + CAPTURE_HEIGHT);
+        request.offset(0, -(CAPTURE_HEIGHT / 2));
+
+        ScrollResult scrollResult = requestScrollSync(mHelper, mScrollBounds, request);
+
+        Rect expectedResult = new Rect(request);
+        expectedResult.bottom -= 300; // bottom half clipped
+        assertThat(scrollResult.availableArea).isEqualTo(expectedResult);
+        assertThat(scrollResult.scrollDelta).isEqualTo(0);
+        assertAvailableAreaPartiallyVisible(scrollResult, mTarget);
+    }
+
+    @After
+    public final void removeWindow() throws InterruptedException {
+        mInstrumentation.runOnMainSync(() -> {
+            if (mContentRoot != null && mContentRoot.isAttachedToWindow()) {
+                mWm.removeViewImmediate(mContentRoot);
+            }
+        });
+    }
+
+    private void initHelper(ScrollPosition position) {
+        setInitialScrollPosition(mTarget, position);
+        mHelper = createHelper();
+        mScrollBounds = mHelper.onComputeScrollBounds(mTarget);
+        mHelper.onPrepareForStart(mTarget, mScrollBounds);
+    }
+
+    @NonNull
+    private ScrollResult requestScrollSync(H helper, Rect scrollBounds, Rect request) {
+        helper.onPrepareForStart(mTarget, scrollBounds);
+        ScrollResult result = helper.onScrollRequested(mTarget, scrollBounds, request);
+
+        assertNotNull(result);
+        return result;
+    }
+
+    static void assertEmpty(Rect r) {
+        if (r != null && !r.isEmpty()) {
+            fail("Not true that " + r + " is empty");
+        }
+    }
+
+    /**
+     * Returns the bounds of the view which are visible (not clipped).
+     */
+    static Rect getVisibleBounds(View v) {
+        Rect r = new Rect(0, 0, v.getWidth(), v.getHeight());
+        v.getLocalVisibleRect(r);
+        r.offset(-v.getScrollX(), -v.getScrollY());
+        return r;
+    }
+
+    static void assertAvailableAreaCompletelyVisible(ScrollResult result, View container) {
+        Rect localAvailable = new Rect(result.availableArea);
+        localAvailable.offset(0, -result.scrollDelta); // make relative to view top
+        Rect visibleBounds = getVisibleBounds(container);
+        if (!visibleBounds.contains(localAvailable)) {
+            fail("Not true that all of " + localAvailable + " is contained by " + visibleBounds);
+        }
+    }
+
+    static void assertAvailableAreaPartiallyVisible(ScrollResult result, View container) {
+        Rect requested = new Rect(result.availableArea);
+        requested.offset(0, -result.scrollDelta); // make relative
+        Rect localVisible = getVisibleBounds(container);
+        if (!Rect.intersects(localVisible, requested)) {
+            fail("Not true that any of " + requested + " is contained by " + localVisible);
+        }
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/view/ListViewCaptureHelperTest.java b/core/tests/coretests/src/com/android/internal/view/ListViewCaptureHelperTest.java
new file mode 100644
index 0000000..191574a
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/view/ListViewCaptureHelperTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view;
+
+import android.annotation.UiThread;
+import android.graphics.Color;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+public class ListViewCaptureHelperTest
+        extends AbsCaptureHelperTest<ListView, ListViewCaptureHelper> {
+
+    static final int CHILD_VIEW_HEIGHT = 300;
+    static final int CHILD_VIEW_COUNT = CONTENT_HEIGHT / CHILD_VIEW_HEIGHT;
+
+    @Override
+    protected ListViewCaptureHelper createHelper() {
+        return new ListViewCaptureHelper();
+    }
+
+    @Override
+    protected ListView createScrollableContent(ViewGroup parent) {
+        ListView listView = new ListView(parent.getContext());
+        listView.setDivider(null);
+        listView.setAdapter(new TestAdapter());
+        return listView;
+    }
+
+    @UiThread
+    protected void setInitialScrollPosition(ListView target, ScrollPosition position) {
+        int offset = 0;
+        switch (position) {
+            case MIDDLE:
+                offset = WINDOW_HEIGHT;
+                break;
+            case BOTTOM:
+                offset = WINDOW_HEIGHT * 2;
+                break;
+        }
+        int verticalPadding = target.getPaddingTop() + target.getPaddingBottom();
+        int step = (target.getHeight() - verticalPadding) / 2;
+        // ListView#scrollListBy will not scroll more than one screen height per call
+        while (offset > step) {
+            target.scrollListBy(step);
+            offset -= step;
+        }
+        target.scrollListBy(offset);
+    }
+
+    static final class TestAdapter extends BaseAdapter {
+
+        @Override
+        public int getCount() {
+            return CHILD_VIEW_COUNT;
+        }
+
+        @Override
+        public Object getItem(int position) {
+            return position;
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return 0;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            TextView view = (convertView != null)
+                    ? (TextView) convertView : new TextView(parent.getContext());
+            view.setText("Item #" + position);
+            view.setTextColor(Color.WHITE);
+            view.setTextSize(20f);
+            view.setBackgroundColor(ITEM_COLORS[position % ITEM_COLORS.length]);
+            view.setMinHeight(CHILD_VIEW_HEIGHT);
+            return view;
+        }
+    }
+
+}
diff --git a/core/tests/coretests/src/com/android/internal/view/RecyclerViewCaptureHelperTest.java b/core/tests/coretests/src/com/android/internal/view/RecyclerViewCaptureHelperTest.java
index a6b26be..1df3168 100644
--- a/core/tests/coretests/src/com/android/internal/view/RecyclerViewCaptureHelperTest.java
+++ b/core/tests/coretests/src/com/android/internal/view/RecyclerViewCaptureHelperTest.java
@@ -16,273 +16,52 @@
 
 package com.android.internal.view;
 
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.fail;
-
-import android.app.Instrumentation;
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.view.Gravity;
+import android.annotation.UiThread;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
 import android.widget.TextView;
 
-import androidx.test.annotation.UiThreadTest;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.platform.app.InstrumentationRegistry;
 
-import com.android.internal.view.ScrollCaptureViewHelper.ScrollResult;
 import com.android.internal.widget.LinearLayoutManager;
 import com.android.internal.widget.RecyclerView;
 
-import com.google.common.truth.Truth;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.util.Random;
 
 @RunWith(AndroidJUnit4.class)
-public class RecyclerViewCaptureHelperTest {
-    private static final int CHILD_VIEWS = 12;
+public class RecyclerViewCaptureHelperTest
+        extends AbsCaptureHelperTest<ViewGroup, RecyclerViewCaptureHelper> {
+
     private static final int CHILD_VIEW_HEIGHT = 300;
-    private static final int WINDOW_WIDTH = 800;
-    private static final int WINDOW_HEIGHT = 1200;
-    private static final int CAPTURE_HEIGHT = 600;
+    private static final int CHILD_VIEWS = CONTENT_HEIGHT / CHILD_VIEW_HEIGHT;
 
-    private FrameLayout mParent;
-    private RecyclerView mTarget;
-    private WindowManager mWm;
-
-    private WindowManager.LayoutParams mWindowLayoutParams;
-
-    private Context mContext;
-    private float mDensity;
-    private LinearLayoutManager mLinearLayoutManager;
-    private Instrumentation mInstrumentation;
-
-    @Before
-    @UiThreadTest
-    public void setUp() {
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
-        mContext = mInstrumentation.getContext();
-        mDensity = mContext.getResources().getDisplayMetrics().density;
-
-        mParent = new FrameLayout(mContext);
-
-        mTarget = new RecyclerView(mContext);
-        mParent.addView(mTarget, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
-
-        mTarget.setAdapter(new TestAdapter());
-        mLinearLayoutManager =
-                new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false);
-        mTarget.setLayoutManager(mLinearLayoutManager);
-        mWm = mContext.getSystemService(WindowManager.class);
-
-        // Setup the window that we are going to use
-        mWindowLayoutParams = new WindowManager.LayoutParams(WINDOW_WIDTH, WINDOW_HEIGHT,
-                TYPE_APPLICATION_OVERLAY, FLAG_NOT_TOUCHABLE, PixelFormat.OPAQUE);
-        mWindowLayoutParams.setTitle("ScrollViewCaptureHelper");
-        mWindowLayoutParams.gravity = Gravity.CENTER;
-        mWm.addView(mParent, mWindowLayoutParams);
+    @Override
+    protected RecyclerViewCaptureHelper createHelper() {
+        return new RecyclerViewCaptureHelper();
     }
 
-    @After
-    @UiThreadTest
-    public void tearDown() {
-        mWm.removeViewImmediate(mParent);
+    @Override
+    protected RecyclerView createScrollableContent(ViewGroup parent) {
+        RecyclerView recyclerView = new RecyclerView(parent.getContext());
+        recyclerView.setAdapter(new TestAdapter());
+        LinearLayoutManager layoutManager =
+                new LinearLayoutManager(parent.getContext(), LinearLayoutManager.VERTICAL, false);
+        recyclerView.setLayoutManager(layoutManager);
+        return recyclerView;
     }
 
-    @Test
-    @UiThreadTest
-    public void onScrollRequested_up_fromTop() {
-        mTarget.scrollBy(0, -(WINDOW_HEIGHT * 3));
-        // mTarget.createSnapshot(new ViewDebug.HardwareCanvasProvider(), false);
-
-        RecyclerViewCaptureHelper rvc = new RecyclerViewCaptureHelper();
-        Rect scrollBounds = rvc.onComputeScrollBounds(mTarget);
-        rvc.onPrepareForStart(mTarget, scrollBounds);
-
-        assertThat(scrollBounds.height()).isGreaterThan(CAPTURE_HEIGHT);
-
-        Rect request = new Rect(0, -CAPTURE_HEIGHT, scrollBounds.width(), 0);
-
-        ScrollResult scrollResult = rvc.onScrollRequested(mTarget,
-                scrollBounds, request);
-
-        // The result is an empty rectangle and no scrolling, since it
-        // is not possible to physically scroll further up to make the
-        // requested area visible at all (it doesn't exist).
-        assertEmpty(scrollResult.availableArea);
-    }
-
-    @Test
-    @UiThreadTest
-    public void onScrollRequested_down_fromTop() {
-        mTarget.scrollBy(0, -(WINDOW_HEIGHT * 3));
-
-        RecyclerViewCaptureHelper rvc = new RecyclerViewCaptureHelper();
-        Rect scrollBounds = rvc.onComputeScrollBounds(mTarget);
-        rvc.onPrepareForStart(mTarget, scrollBounds);
-
-        assertThat(scrollBounds.height()).isGreaterThan(CAPTURE_HEIGHT);
-
-        // Capture between y = +1200 to +1800 pixels BELOW current top
-        Rect request = new Rect(0, WINDOW_HEIGHT, scrollBounds.width(),
-                WINDOW_HEIGHT + CAPTURE_HEIGHT);
-
-        ScrollResult scrollResult = rvc.onScrollRequested(mTarget, scrollBounds, request);
-        assertThat(request).isEqualTo(scrollResult.requestedArea);
-        assertThat(request).isEqualTo(scrollResult.availableArea);
-        // Capture height centered in the window
-        assertThat(scrollResult.scrollDelta).isEqualTo(
-                CAPTURE_HEIGHT + (WINDOW_HEIGHT - CAPTURE_HEIGHT) / 2);
-        assertAvailableAreaCompletelyVisible(scrollResult, mTarget);
-    }
-
-    @Test
-    @UiThreadTest
-    public void onScrollRequested_up_fromMiddle() {
-        mTarget.scrollBy(0, WINDOW_HEIGHT);
-
-        RecyclerViewCaptureHelper helper = new RecyclerViewCaptureHelper();
-        Rect scrollBounds = helper.onComputeScrollBounds(mTarget);
-        helper.onPrepareForStart(mTarget, scrollBounds);
-
-        Rect request = new Rect(0, -CAPTURE_HEIGHT, scrollBounds.width(), 0);
-
-        ScrollResult scrollResult = helper.onScrollRequested(mTarget, scrollBounds, request);
-        assertThat(request).isEqualTo(scrollResult.requestedArea);
-        assertThat(request).isEqualTo(scrollResult.availableArea);
-        assertThat(scrollResult.scrollDelta).isEqualTo(
-                -CAPTURE_HEIGHT - (WINDOW_HEIGHT - CAPTURE_HEIGHT) / 2);
-        assertAvailableAreaCompletelyVisible(scrollResult, mTarget);
-    }
-
-    @Test
-    @UiThreadTest
-    public void onScrollRequested_down_fromMiddle() {
-        mTarget.scrollBy(0, WINDOW_HEIGHT);
-
-        RecyclerViewCaptureHelper helper = new RecyclerViewCaptureHelper();
-        Rect scrollBounds = helper.onComputeScrollBounds(mTarget);
-        helper.onPrepareForStart(mTarget, scrollBounds);
-
-        Rect request = new Rect(0, WINDOW_HEIGHT, scrollBounds.width(),
-                WINDOW_HEIGHT + CAPTURE_HEIGHT);
-
-        ScrollResult scrollResult = helper.onScrollRequested(mTarget, scrollBounds, request);
-        assertThat(request).isEqualTo(scrollResult.requestedArea);
-        assertThat(request).isEqualTo(scrollResult.availableArea);
-        assertThat(scrollResult.scrollDelta).isEqualTo(
-                CAPTURE_HEIGHT + (WINDOW_HEIGHT - CAPTURE_HEIGHT) / 2);
-        assertAvailableAreaCompletelyVisible(scrollResult, mTarget);
-    }
-
-    @Test
-    @UiThreadTest
-    public void onScrollRequested_up_fromBottom() {
-        mTarget.scrollBy(0, WINDOW_HEIGHT * 2);
-
-        RecyclerViewCaptureHelper helper = new RecyclerViewCaptureHelper();
-        Rect scrollBounds = helper.onComputeScrollBounds(mTarget);
-        helper.onPrepareForStart(mTarget, scrollBounds);
-
-        Rect request = new Rect(0, -CAPTURE_HEIGHT, scrollBounds.width(), 0);
-
-        ScrollResult scrollResult = helper.onScrollRequested(mTarget, scrollBounds, request);
-        assertThat(request).isEqualTo(scrollResult.requestedArea);
-        assertThat(request).isEqualTo(scrollResult.availableArea);
-        assertThat(scrollResult.scrollDelta).isEqualTo(
-                -CAPTURE_HEIGHT - (WINDOW_HEIGHT - CAPTURE_HEIGHT) / 2);
-        assertAvailableAreaCompletelyVisible(scrollResult, mTarget);
-    }
-
-    @Test
-    @UiThreadTest
-    public void onScrollRequested_down_fromBottom() {
-        mTarget.scrollBy(0, WINDOW_HEIGHT * 3);
-
-        RecyclerViewCaptureHelper rvc = new RecyclerViewCaptureHelper();
-        Rect scrollBounds = rvc.onComputeScrollBounds(mTarget);
-        rvc.onPrepareForStart(mTarget, scrollBounds);
-
-        Rect request = new Rect(0, WINDOW_HEIGHT, scrollBounds.width(),
-                WINDOW_HEIGHT + CAPTURE_HEIGHT);
-
-        ScrollResult scrollResult = rvc.onScrollRequested(mTarget,
-                scrollBounds, request);
-        Truth.assertThat(request).isEqualTo(scrollResult.requestedArea);
-
-        // The result is an empty rectangle and no scrolling, since it
-        // is not possible to physically scroll further down to make the
-        // requested area visible at all (it doesn't exist).
-        assertEmpty(scrollResult.availableArea);
-    }
-
-    @Test
-    @UiThreadTest
-    public void onScrollRequested_offTopEdge() {
-        mTarget.scrollBy(0, -(WINDOW_HEIGHT * 3));
-
-        RecyclerViewCaptureHelper helper = new RecyclerViewCaptureHelper();
-        Rect scrollBounds = helper.onComputeScrollBounds(mTarget);
-        helper.onPrepareForStart(mTarget, scrollBounds);
-
-        // Create a request which lands halfway off the top of the content
-        //from -1500 to -900, (starting at 1200 = -300 to +300 within the content)
-        int top = 0;
-        Rect request = new Rect(
-                0, top - (CAPTURE_HEIGHT / 2),
-                scrollBounds.width(), top + (CAPTURE_HEIGHT / 2));
-
-        ScrollResult scrollResult = helper.onScrollRequested(mTarget, scrollBounds, request);
-        assertThat(request).isEqualTo(scrollResult.requestedArea);
-
-        ScrollResult result = helper.onScrollRequested(mTarget, scrollBounds, request);
-        // The result is a partial result
-        Rect expectedResult = new Rect(request);
-        expectedResult.top += (CAPTURE_HEIGHT / 2); // top half clipped
-        assertThat(expectedResult).isEqualTo(result.availableArea);
-        assertThat(scrollResult.scrollDelta).isEqualTo(0);
-        assertAvailableAreaPartiallyVisible(scrollResult, mTarget);
-    }
-
-    @Test
-    @UiThreadTest
-    public void onScrollRequested_offBottomEdge() {
-        mTarget.scrollBy(0, WINDOW_HEIGHT * 2);
-
-        RecyclerViewCaptureHelper helper = new RecyclerViewCaptureHelper();
-        Rect scrollBounds = helper.onComputeScrollBounds(mTarget);
-        helper.onPrepareForStart(mTarget, scrollBounds);
-
-        // Create a request which lands halfway off the bottom of the content
-        //from 600 to to 1200, (starting at 2400 = 3000 to  3600 within the content)
-
-        int bottom = WINDOW_HEIGHT;
-        Rect request = new Rect(
-                0, bottom - (CAPTURE_HEIGHT / 2),
-                scrollBounds.width(), bottom + (CAPTURE_HEIGHT / 2));
-
-        ScrollResult result = helper.onScrollRequested(mTarget, scrollBounds, request);
-
-        Rect expectedResult = new Rect(request);
-        expectedResult.bottom -= 300; // bottom half clipped
-        assertThat(expectedResult).isEqualTo(result.availableArea);
-        assertThat(result.scrollDelta).isEqualTo(0);
-        assertAvailableAreaPartiallyVisible(result, mTarget);
+    @UiThread
+    protected void setInitialScrollPosition(ViewGroup target, ScrollPosition position) {
+        switch (position) {
+            case MIDDLE:
+                target.scrollBy(0, WINDOW_HEIGHT);
+                break;
+            case BOTTOM:
+                target.scrollBy(0, WINDOW_HEIGHT * 2);
+                break;
+        }
     }
 
     static final class TestViewHolder extends RecyclerView.ViewHolder {
@@ -302,11 +81,9 @@
         @Override
         public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
             TextView view = (TextView) holder.itemView;
-            view.setText("Child #" + position);
-            view.setTextColor(Color.WHITE);
+            view.setText("Item #" + position);
             view.setTextSize(30f);
-            view.setBackgroundColor(Color.rgb(mRandom.nextFloat(), mRandom.nextFloat(),
-                    mRandom.nextFloat()));
+            view.setBackgroundColor(ITEM_COLORS[position % ITEM_COLORS.length]);
             view.setMinHeight(CHILD_VIEW_HEIGHT);
         }
 
@@ -315,34 +92,4 @@
             return CHILD_VIEWS;
         }
     }
-
-    static void assertEmpty(Rect r) {
-        if (r != null && !r.isEmpty()) {
-            fail("Not true that " + r + " is empty");
-        }
-    }
-
-    static Rect getVisibleRect(View v) {
-        Rect r = new Rect(0, 0, v.getWidth(), v.getHeight());
-        v.getLocalVisibleRect(r);
-        return r;
-    }
-
-    static void assertAvailableAreaCompletelyVisible(ScrollResult result, View container) {
-        Rect requested = new Rect(result.availableArea);
-        requested.offset(0, -result.scrollDelta); // make relative
-        Rect localVisible = getVisibleRect(container);
-        if (!localVisible.contains(requested)) {
-            fail("Not true that all of " + requested + " is contained by " + localVisible);
-        }
-    }
-
-    static void assertAvailableAreaPartiallyVisible(ScrollResult result, View container) {
-        Rect requested = new Rect(result.availableArea);
-        requested.offset(0, -result.scrollDelta); // make relative
-        Rect localVisible = getVisibleRect(container);
-        if (!Rect.intersects(localVisible, requested)) {
-            fail("Not true that any of " + requested + " is contained by " + localVisible);
-        }
-    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/view/ScrollCaptureViewSupportTest.java b/core/tests/coretests/src/com/android/internal/view/ScrollCaptureViewSupportTest.java
index cb72b2d..699008b 100644
--- a/core/tests/coretests/src/com/android/internal/view/ScrollCaptureViewSupportTest.java
+++ b/core/tests/coretests/src/com/android/internal/view/ScrollCaptureViewSupportTest.java
@@ -32,6 +32,11 @@
 
     ScrollCaptureViewHelper<View> mViewHelper = new ScrollCaptureViewHelper<View>() {
         @Override
+        public boolean onAcceptSession(@NonNull View view) {
+            return true;
+        }
+
+        @Override
         public void onPrepareForStart(@NonNull View view, @NonNull Rect scrollBounds) {
         }
 
diff --git a/core/tests/coretests/src/com/android/internal/view/ScrollViewCaptureHelperTest.java b/core/tests/coretests/src/com/android/internal/view/ScrollViewCaptureHelperTest.java
index fc02ea9..9b9c69b 100644
--- a/core/tests/coretests/src/com/android/internal/view/ScrollViewCaptureHelperTest.java
+++ b/core/tests/coretests/src/com/android/internal/view/ScrollViewCaptureHelperTest.java
@@ -18,347 +18,44 @@
 
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 import android.content.Context;
 import android.graphics.Color;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.view.Gravity;
-import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
 import android.widget.TextView;
 
-import androidx.test.annotation.UiThreadTest;
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import com.android.internal.view.ScrollCaptureViewHelper.ScrollResult;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
 import java.util.Random;
 
-public class ScrollViewCaptureHelperTest {
+public class ScrollViewCaptureHelperTest
+        extends AbsCaptureHelperTest<ViewGroup, ScrollViewCaptureHelper> {
 
-    private FrameLayout mParent;
-    private ScrollView mTarget;
-    private LinearLayout mContent;
-    private WindowManager mWm;
+    private static final int CHILD_VIEW_HEIGHT = 300;
+    private static final int CHILD_VIEW_COUNT = CONTENT_HEIGHT / CHILD_VIEW_HEIGHT;
 
-    private WindowManager.LayoutParams mWindowLayoutParams;
+    private Random mRandom = new Random(0L);
 
-    private static final int CHILD_VIEWS = 12;
-    public static final int CHILD_VIEW_HEIGHT = 300;
+    @Override
+    protected ScrollViewCaptureHelper createHelper() {
+        return new ScrollViewCaptureHelper();
+    }
 
-    private static final int WINDOW_WIDTH = 800;
-    private static final int WINDOW_HEIGHT = 1200;
-
-    private static final int CAPTURE_HEIGHT = 600;
-
-    private Random mRandom;
-
-    private Context mContext;
-    private float mDensity;
-
-    @Before
-    @UiThreadTest
-    public void setUp() {
-        mContext = InstrumentationRegistry.getInstrumentation().getContext();
-        mDensity = mContext.getResources().getDisplayMetrics().density;
-
-        mRandom = new Random();
-        mParent = new FrameLayout(mContext);
-
-        mTarget = new ScrollView(mContext);
-        mParent.addView(mTarget, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
-
-        mContent = new LinearLayout(mContext);
-        mContent.setOrientation(LinearLayout.VERTICAL);
-        mTarget.addView(mContent, new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
-
-        for (int i = 0; i < CHILD_VIEWS; i++) {
+    @Override
+    protected ScrollView createScrollableContent(ViewGroup parent) {
+        Context mContext = parent.getContext();
+        ScrollView scrollView = new ScrollView(mContext);
+        LinearLayout content = new LinearLayout(mContext);
+        content.setOrientation(LinearLayout.VERTICAL);
+        scrollView.addView(content, new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+        for (int i = 0; i < CHILD_VIEW_COUNT; i++) {
             TextView view = new TextView(mContext);
-            view.setText("Child #" + i);
+            view.setText("Item #" + i);
             view.setTextColor(Color.WHITE);
             view.setTextSize(30f);
-            view.setBackgroundColor(Color.rgb(mRandom.nextFloat(), mRandom.nextFloat(),
-                    mRandom.nextFloat()));
-            mContent.addView(view, new ViewGroup.LayoutParams(MATCH_PARENT, CHILD_VIEW_HEIGHT));
+            view.setBackgroundColor(ITEM_COLORS[i % ITEM_COLORS.length]);
+            content.addView(view, new ViewGroup.LayoutParams(MATCH_PARENT, CHILD_VIEW_HEIGHT));
         }
-
-        // Window -> Parent -> Target -> Content
-
-        mWm = mContext.getSystemService(WindowManager.class);
-
-        // Setup the window that we are going to use
-        mWindowLayoutParams = new WindowManager.LayoutParams(WINDOW_WIDTH, WINDOW_HEIGHT,
-                TYPE_APPLICATION_OVERLAY, FLAG_NOT_TOUCHABLE, PixelFormat.OPAQUE);
-        mWindowLayoutParams.setTitle("ScrollViewCaptureHelper");
-        mWindowLayoutParams.gravity = Gravity.CENTER;
-        mWm.addView(mParent, mWindowLayoutParams);
-    }
-
-    @After
-    @UiThreadTest
-    public void tearDown() {
-        mWm.removeViewImmediate(mParent);
-    }
-
-    @Test
-    @UiThreadTest
-    public void onPrepareForStart() {
-        ScrollViewCaptureHelper svc = new ScrollViewCaptureHelper();
-        Rect scrollBounds = svc.onComputeScrollBounds(mTarget);
-        svc.onPrepareForStart(mTarget, scrollBounds);
-    }
-
-    @Test
-    @UiThreadTest
-    public void onScrollRequested_up_fromTop() {
-        final int startScrollY = assertScrollToY(mTarget, 0);
-
-        ScrollViewCaptureHelper svc = new ScrollViewCaptureHelper();
-        Rect scrollBounds = svc.onComputeScrollBounds(mTarget);
-        svc.onPrepareForStart(mTarget, scrollBounds);
-
-        assertTrue(scrollBounds.height() > CAPTURE_HEIGHT);
-
-        Rect request = new Rect(0, -CAPTURE_HEIGHT, scrollBounds.width(), 0);
-
-        ScrollResult scrollResult = svc.onScrollRequested(mTarget,
-                scrollBounds, request);
-
-        // The result is an empty rectangle and no scrolling, since it
-        // is not possible to physically scroll further up to make the
-        // requested area visible at all (it doesn't exist).
-        assertEmpty(scrollResult.availableArea);
-    }
-
-    @Test
-    @UiThreadTest
-    public void onScrollRequested_down_fromTop() {
-        final int startScrollY = assertScrollToY(mTarget, 0);
-
-        ScrollViewCaptureHelper svc = new ScrollViewCaptureHelper();
-        Rect scrollBounds = svc.onComputeScrollBounds(mTarget);
-        svc.onPrepareForStart(mTarget, scrollBounds);
-
-        assertTrue(scrollBounds.height() > CAPTURE_HEIGHT);
-
-        // Capture between y = +1200 to +1500 pixels BELOW current top
-        Rect request = new Rect(0, WINDOW_HEIGHT, scrollBounds.width(),
-                WINDOW_HEIGHT + CAPTURE_HEIGHT);
-
-        ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request);
-        assertRectEquals(request, scrollResult.requestedArea);
-        assertRectEquals(request, scrollResult.availableArea);
-        assertRequestedRectCompletelyVisible(startScrollY, request, getVisibleRect(mContent));
-        assertEquals(CAPTURE_HEIGHT + (WINDOW_HEIGHT - CAPTURE_HEIGHT) / 2,
-                scrollResult.scrollDelta);
-    }
-
-    @Test
-    @UiThreadTest
-    public void onScrollRequested_up_fromMiddle() {
-        final int startScrollY = assertScrollToY(mTarget, WINDOW_HEIGHT);
-
-        ScrollViewCaptureHelper svc = new ScrollViewCaptureHelper();
-        Rect scrollBounds = svc.onComputeScrollBounds(mTarget);
-        svc.onPrepareForStart(mTarget, scrollBounds);
-
-        Rect request = new Rect(0, -CAPTURE_HEIGHT, scrollBounds.width(), 0);
-
-        ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request);
-        assertRectEquals(request, scrollResult.requestedArea);
-        assertRectEquals(request, scrollResult.availableArea);
-        assertRequestedRectCompletelyVisible(startScrollY, request, getVisibleRect(mContent));
-        assertEquals(-CAPTURE_HEIGHT - (WINDOW_HEIGHT - CAPTURE_HEIGHT) / 2,
-                scrollResult.scrollDelta);
-    }
-
-    @Test
-    @UiThreadTest
-    public void onScrollRequested_down_fromMiddle() {
-        final int startScrollY = assertScrollToY(mTarget, WINDOW_HEIGHT);
-
-        ScrollViewCaptureHelper svc = new ScrollViewCaptureHelper();
-        Rect scrollBounds = svc.onComputeScrollBounds(mTarget);
-        svc.onPrepareForStart(mTarget, scrollBounds);
-
-        Rect request = new Rect(0, WINDOW_HEIGHT, scrollBounds.width(),
-                WINDOW_HEIGHT + CAPTURE_HEIGHT);
-
-        ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request);
-        assertRectEquals(request, scrollResult.requestedArea);
-        assertRectEquals(request, scrollResult.availableArea);
-        assertRequestedRectCompletelyVisible(startScrollY, request, getVisibleRect(mContent));
-        assertEquals(CAPTURE_HEIGHT + (WINDOW_HEIGHT - CAPTURE_HEIGHT) / 2,
-                scrollResult.scrollDelta);
-
-    }
-
-    @Test
-    @UiThreadTest
-    public void onScrollRequested_up_fromBottom() {
-        final int startScrollY = assertScrollToY(mTarget, WINDOW_HEIGHT * 2);
-
-        ScrollViewCaptureHelper svc = new ScrollViewCaptureHelper();
-        Rect scrollBounds = svc.onComputeScrollBounds(mTarget);
-        svc.onPrepareForStart(mTarget, scrollBounds);
-
-        Rect request = new Rect(0, -CAPTURE_HEIGHT, scrollBounds.width(), 0);
-
-        ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request);
-        assertRectEquals(request, scrollResult.requestedArea);
-        assertRectEquals(request, scrollResult.availableArea);
-        assertRequestedRectCompletelyVisible(startScrollY, request, getVisibleRect(mContent));
-        assertEquals(-CAPTURE_HEIGHT - (WINDOW_HEIGHT - CAPTURE_HEIGHT) / 2,
-                scrollResult.scrollDelta);
-    }
-
-    @Test
-    @UiThreadTest
-    public void onScrollRequested_down_fromBottom() {
-        final int startScrollY = assertScrollToY(mTarget, WINDOW_HEIGHT * 2);
-
-        ScrollViewCaptureHelper svc = new ScrollViewCaptureHelper();
-        Rect scrollBounds = svc.onComputeScrollBounds(mTarget);
-        svc.onPrepareForStart(mTarget, scrollBounds);
-
-        Rect request = new Rect(0, WINDOW_HEIGHT, scrollBounds.width(),
-                WINDOW_HEIGHT + CAPTURE_HEIGHT);
-
-        ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request);
-        assertRectEquals(request, scrollResult.requestedArea);
-
-        // The result is an empty rectangle and no scrolling, since it
-        // is not possible to physically scroll further down to make the
-        // requested area visible at all (it doesn't exist).
-        assertEmpty(scrollResult.availableArea);
-        assertEquals(0, scrollResult.scrollDelta);
-    }
-
-    @Test
-    @UiThreadTest
-    public void onScrollRequested_offTopEdge() {
-        final int startScrollY = assertScrollToY(mTarget, 0);
-
-        ScrollViewCaptureHelper svc = new ScrollViewCaptureHelper();
-        Rect scrollBounds = svc.onComputeScrollBounds(mTarget);
-        svc.onPrepareForStart(mTarget, scrollBounds);
-
-        // Create a request which lands halfway off the top of the content
-        //from -1500 to -900, (starting at 1200 = -300 to +300 within the content)
-        int top = 0;
-        Rect request = new Rect(
-                0, top - (CAPTURE_HEIGHT / 2),
-                scrollBounds.width(), top + (CAPTURE_HEIGHT / 2));
-
-        ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request);
-        assertRectEquals(request, scrollResult.requestedArea);
-
-        ScrollResult result = svc.onScrollRequested(mTarget, scrollBounds, request);
-        // The result is a partial result
-        Rect expectedResult = new Rect(request);
-        expectedResult.top += 300; // top half clipped
-        assertRectEquals(expectedResult, result.availableArea);
-        assertRequestedRectPartiallyVisible(startScrollY, request, getVisibleRect(mContent));
-        assertEquals(0, scrollResult.scrollDelta);
-    }
-
-    @Test
-    @UiThreadTest
-    public void onScrollRequested_offBottomEdge() {
-        final int startScrollY = assertScrollToY(mTarget, WINDOW_HEIGHT * 2); // 2400
-
-        ScrollViewCaptureHelper svc = new ScrollViewCaptureHelper();
-        Rect scrollBounds = svc.onComputeScrollBounds(mTarget);
-        svc.onPrepareForStart(mTarget, scrollBounds);
-
-        // Create a request which lands halfway off the bottom of the content
-        //from 600 to to 1200, (starting at 2400 = 3000 to  3600 within the content)
-
-        int bottom = WINDOW_HEIGHT;
-        Rect request = new Rect(
-                0, bottom - (CAPTURE_HEIGHT / 2),
-                scrollBounds.width(), bottom + (CAPTURE_HEIGHT / 2));
-
-        ScrollResult result = svc.onScrollRequested(mTarget, scrollBounds, request);
-
-        Rect expectedResult = new Rect(request);
-        expectedResult.bottom -= 300; // bottom half clipped
-        assertRectEquals(expectedResult, result.availableArea);
-        assertRequestedRectPartiallyVisible(startScrollY, request, getVisibleRect(mContent));
-        assertEquals(0, result.scrollDelta);
-    }
-
-    @Test
-    @UiThreadTest
-    public void onPrepareForEnd() {
-        ScrollViewCaptureHelper svc = new ScrollViewCaptureHelper();
-        svc.onPrepareForEnd(mTarget);
-    }
-
-
-    static void assertEmpty(Rect r) {
-        if (r != null && !r.isEmpty()) {
-            fail("Not true that " + r + " is empty");
-        }
-    }
-
-    static void assertContains(Rect parent, Rect child) {
-        if (!parent.contains(child)) {
-            fail("Not true that " + parent + " contains " + child);
-        }
-    }
-
-    static void assertRectEquals(Rect parent, Rect child) {
-        if (!parent.equals(child)) {
-            fail("Not true that " + parent + " is equal to " + child);
-        }
-    }
-
-    static Rect getVisibleRect(View v) {
-        Rect r = new Rect(0, 0, v.getWidth(), v.getHeight());
-        v.getLocalVisibleRect(r);
-        return r;
-    }
-
-
-    static int assertScrollToY(View v, int scrollY) {
-        v.scrollTo(0, scrollY);
-        int dest = v.getScrollY();
-        assertEquals(scrollY, dest);
-        return scrollY;
-    }
-
-    static void assertRequestedRectCompletelyVisible(int startScrollY, Rect requestRect,
-            Rect localVisibleNow) {
-        Rect captured = new Rect(localVisibleNow);
-        captured.offset(0, -startScrollY); // make relative
-
-        if (!captured.contains(requestRect)) {
-            fail("Not true that all of " + requestRect + " is contained by " + captured);
-        }
-    }
-    static void assertRequestedRectPartiallyVisible(int startScrollY, Rect requestRect,
-            Rect localVisibleNow) {
-        Rect captured = new Rect(localVisibleNow);
-        captured.offset(0, -startScrollY); // make relative
-
-        if (!Rect.intersects(captured, requestRect)) {
-            fail("Not true that any of " + requestRect + " intersects " + captured);
-        }
+        return scrollView;
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/view/WebViewCaptureHelperTest.java b/core/tests/coretests/src/com/android/internal/view/WebViewCaptureHelperTest.java
new file mode 100644
index 0000000..f38e21a
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/view/WebViewCaptureHelperTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view;
+
+import android.annotation.UiThread;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.util.Log;
+import android.view.ViewGroup;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebView.VisualStateCallback;
+import android.webkit.WebViewClient;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class WebViewCaptureHelperTest
+        extends AbsCaptureHelperTest<WebView, WebViewCaptureHelper> {
+
+    private static final String TAG = "WebViewCaptureHelperTest";
+
+    private WebView mWebView;
+
+    @Override
+    protected WebViewCaptureHelper createHelper() {
+        return new WebViewCaptureHelper();
+    }
+
+    @UiThread
+    protected void setInitialScrollPosition(WebView target, ScrollPosition position) {
+        int contentHeight = (int) (target.getContentHeight() * target.getScale());
+        int scrollBy = 0;
+        switch (position) {
+            case MIDDLE:
+                scrollBy =  WINDOW_HEIGHT;
+                break;
+            case BOTTOM:
+                scrollBy = WINDOW_HEIGHT * 2;
+                break;
+        }
+        Log.d(TAG, "scrollToPosition: position=" + position + " contentHeight=" + contentHeight
+                + " scrollBy=" + scrollBy);
+        target.scrollBy(0, scrollBy);
+    }
+
+    @Override
+    protected WebView createScrollableContent(ViewGroup parent) {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        CountDownLatch loaded = new CountDownLatch(1);
+        CountDownLatch scaleAdjusted = new CountDownLatch(1);
+        instrumentation.runOnMainSync(() -> {
+            Context mContext = parent.getContext();
+            mWebView = new WebView(mContext);
+            mWebView.setWebViewClient(new WebViewClient() {
+                @Override
+                public void onPageFinished(WebView view, String url) {
+                    Log.d(TAG, "onPageFinished: " + url);
+                }
+
+                @Override
+                public void onScaleChanged(WebView view, float oldScale, float newScale) {
+                    Log.d(TAG, "onScaleChanged: oldScale=" + oldScale + " newScale=" + newScale);
+                    // WebView reports 1.00125 when 1.0 is requested!?
+                    if (newScale > 0.99f && newScale < 1.01f) {
+                        scaleAdjusted.countDown();
+                    }
+                    Log.d(TAG, "scaleAdjusted: " + scaleAdjusted.getCount());
+                }
+
+                @Override
+                public void onLoadResource(WebView view, String url) {
+                    Log.d(TAG, "onLoadResource: " + url);
+                }
+
+                @Override
+                public void onPageCommitVisible(WebView view, String url) {
+                    Log.d(TAG, "onPageCommitVisible: " + url);
+                }
+            });
+
+            WebSettings webSettings = mWebView.getSettings();
+            webSettings.setAllowFileAccessFromFileURLs(true);
+            webSettings.setAllowUniversalAccessFromFileURLs(true);
+
+            mWebView.loadUrl("file:///android_asset/scroll_capture_test.html");
+            mWebView.postVisualStateCallback(1L, new VisualStateCallback() {
+                @Override
+                public void onComplete(long requestId) {
+                    Log.d(TAG, "VisualStateCallback::complete");
+                    loaded.countDown();
+                }
+            });
+        });
+
+        waitFor(loaded, 5, TimeUnit.SECONDS);
+
+        // Request a 1.0 zoom factor.
+        instrumentation.runOnMainSync(() -> mWebView.zoomBy(1.0f / mWebView.getScale()));
+        try {
+            // Wait for the scale factor to adjust.
+            //
+            // WebViewClient#onScaleChanged occasionally fails to fire causing a false
+            // negative test failure. WebView#getScale is not consistent across threads.
+            // So no attempt can be made here to wait for or verify the scale value directly,
+            // we just must wait and trust it changes to 1.0. :-(
+            //
+            Thread.sleep(300);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+        return mWebView;
+    }
+
+    private static boolean waitFor(CountDownLatch latch, long time, TimeUnit unit) {
+        try {
+            return latch.await(time, unit);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/core/tests/overlaytests/host/Android.bp b/core/tests/overlaytests/host/Android.bp
index e4c3fbe..08761f6 100644
--- a/core/tests/overlaytests/host/Android.bp
+++ b/core/tests/overlaytests/host/Android.bp
@@ -25,7 +25,10 @@
     name: "OverlayHostTests",
     srcs: ["src/**/*.java"],
     libs: ["tradefed"],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "device-tests",
+        "general-tests",
+    ],
     target_required: [
         "OverlayHostTests_NonPlatformSignatureOverlay",
         "OverlayHostTests_PlatformSignatureStaticOverlay",
diff --git a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk
index b453cde9..15fb76d 100644
--- a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk
+++ b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_LICENSE_CONDITIONS := notice
 LOCAL_NOTICE_FILE  := $(LOCAL_PATH)/../../../../../../NOTICE
 LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_COMPATIBILITY_SUITE := device-tests general-tests
 LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_bad
 include $(BUILD_PACKAGE)
 
@@ -34,7 +34,7 @@
 LOCAL_LICENSE_CONDITIONS := notice
 LOCAL_NOTICE_FILE  := $(LOCAL_PATH)/../../../../../../NOTICE
 LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_COMPATIBILITY_SUITE := device-tests general-tests
 LOCAL_CERTIFICATE := platform
 LOCAL_MANIFEST_FILE := static/AndroidManifest.xml
 LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_static
@@ -47,7 +47,7 @@
 LOCAL_LICENSE_CONDITIONS := notice
 LOCAL_NOTICE_FILE  := $(LOCAL_PATH)/../../../../../../NOTICE
 LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_COMPATIBILITY_SUITE := device-tests general-tests
 LOCAL_CERTIFICATE := platform
 LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
 LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
index 77fc887..3921251 100644
--- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_LICENSE_CONDITIONS := notice
 LOCAL_NOTICE_FILE  := $(LOCAL_PATH)/../../../../../../NOTICE
 LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_COMPATIBILITY_SUITE := device-tests general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
 LOCAL_USE_AAPT2 := true
 LOCAL_AAPT_FLAGS := --no-resource-removal
@@ -37,7 +37,7 @@
 LOCAL_LICENSE_CONDITIONS := notice
 LOCAL_NOTICE_FILE  := $(LOCAL_PATH)/../../../../../../NOTICE
 LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_COMPATIBILITY_SUITE := device-tests general-tests
 LOCAL_CERTIFICATE := platform
 LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
 LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
@@ -52,7 +52,7 @@
 LOCAL_LICENSE_CONDITIONS := notice
 LOCAL_NOTICE_FILE  := $(LOCAL_PATH)/../../../../../../NOTICE
 LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_COMPATIBILITY_SUITE := device-tests general-tests
 LOCAL_CERTIFICATE := platform
 LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2
 LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2
@@ -69,7 +69,7 @@
 LOCAL_LICENSE_CONDITIONS := notice
 LOCAL_NOTICE_FILE  := $(LOCAL_PATH)/../../../../../../NOTICE
 LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_COMPATIBILITY_SUITE := device-tests general-tests
 LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
 LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v1/res
@@ -83,7 +83,7 @@
 LOCAL_LICENSE_CONDITIONS := notice
 LOCAL_NOTICE_FILE  := $(LOCAL_PATH)/../../../../../../NOTICE
 LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_COMPATIBILITY_SUITE := device-tests general-tests
 LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2
 LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v2/res
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 07389b2..c250039 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -374,8 +374,6 @@
         <permission name="android.permission.STOP_APP_SWITCHES"/>
         <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
         <permission name="android.permission.SUSPEND_APPS" />
-        <!-- Permission required for UiModeManager and Telecom car mode CTS tests -->
-        <permission name="android.permission.TOGGLE_AUTOMOTIVE_PROJECTION" />
         <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
         <permission name="android.permission.USE_RESERVED_DISK"/>
         <permission name="android.permission.UWB_PRIVILEGED"/>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 119c9391..791aeb7 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -103,12 +103,6 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/TaskFragment.java"
     },
-    "-2006946193": {
-      "message": "setClientVisible: %s clientVisible=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
     "-2002500255": {
       "message": "Defer removing snapshot surface in %dms",
       "level": "VERBOSE",
@@ -511,6 +505,12 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-1556507536": {
+      "message": "Passing transform hint %d for window %s%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
     "-1554521902": {
       "message": "showInsets(ime) was requested by different window: %s ",
       "level": "WARN",
@@ -553,6 +553,12 @@
       "group": "WM_SHOW_TRANSACTIONS",
       "at": "com\/android\/server\/wm\/RootWindowContainer.java"
     },
+    "-1501564055": {
+      "message": "Organized TaskFragment is not ready= %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
     "-1499134947": {
       "message": "Removing starting %s from %s",
       "level": "VERBOSE",
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index 884d27f..9feb619 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -827,7 +827,7 @@
             case RAW_SENSOR:
                 return 16;
             case YCBCR_P010:
-                return 20;
+                return 24;
             case RAW_DEPTH10:
             case RAW10:
                 return 10;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java
deleted file mode 100644
index ce4e103..0000000
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions;
-
-import android.content.Context;
-
-import androidx.annotation.NonNull;
-import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
-import androidx.window.extensions.organizer.EmbeddingExtensionImpl;
-
-/**
- * Provider class that will instantiate the library implementation. It must be included in the
- * vendor library, and the vendor implementation must match the signature of this class.
- */
-public class ExtensionProvider {
-    /**
-     * Provides a simple implementation of {@link ExtensionInterface} that can be replaced by
-     * an OEM by overriding this method.
-     */
-    public static ExtensionInterface getExtensionImpl(Context context) {
-        return new SampleExtensionImpl(context);
-    }
-
-    /** Provides a reference implementation of {@link ActivityEmbeddingComponent}. */
-    public static ActivityEmbeddingComponent getActivityEmbeddingExtensionImpl(
-            @NonNull Context context) {
-        return new EmbeddingExtensionImpl();
-    }
-
-    /**
-     * The support library will use this method to check API version compatibility.
-     * @return API version string in MAJOR.MINOR.PATCH-description format.
-     */
-    public static String getApiVersion() {
-        return "1.0.0-settings_sample";
-    }
-}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/StubExtension.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/StubExtension.java
deleted file mode 100644
index 6a53efe..0000000
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/StubExtension.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions;
-
-import android.app.Activity;
-
-import androidx.annotation.NonNull;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Basic implementation of the {@link ExtensionInterface}. An OEM can choose to use it as the base
- * class for their implementation.
- */
-abstract class StubExtension implements ExtensionInterface {
-
-    private ExtensionCallback mExtensionCallback;
-    private final Set<Activity> mWindowLayoutChangeListenerActivities = new HashSet<>();
-
-    StubExtension() {
-    }
-
-    @Override
-    public void setExtensionCallback(@NonNull ExtensionCallback extensionCallback) {
-        this.mExtensionCallback = extensionCallback;
-    }
-
-    @Override
-    public void onWindowLayoutChangeListenerAdded(@NonNull Activity activity) {
-        this.mWindowLayoutChangeListenerActivities.add(activity);
-        this.onListenersChanged();
-    }
-
-    @Override
-    public void onWindowLayoutChangeListenerRemoved(@NonNull Activity activity) {
-        this.mWindowLayoutChangeListenerActivities.remove(activity);
-        this.onListenersChanged();
-    }
-
-    void updateWindowLayout(@NonNull Activity activity,
-            @NonNull ExtensionWindowLayoutInfo newLayout) {
-        if (this.mExtensionCallback != null) {
-            mExtensionCallback.onWindowLayoutChanged(activity, newLayout);
-        }
-    }
-
-    @NonNull
-    Set<Activity> getActivitiesListeningForLayoutChanges() {
-        return mWindowLayoutChangeListenerActivities;
-    }
-
-    protected boolean hasListeners() {
-        return !mWindowLayoutChangeListenerActivities.isEmpty();
-    }
-
-    protected abstract void onListenersChanged();
-}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
new file mode 100644
index 0000000..990d7b6
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
@@ -0,0 +1,91 @@
+/*
+ * 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 androidx.window.extensions;
+
+import android.app.ActivityThread;
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
+import androidx.window.extensions.embedding.SplitController;
+import androidx.window.extensions.layout.WindowLayoutComponent;
+import androidx.window.extensions.layout.WindowLayoutComponentImpl;
+
+/**
+ * The reference implementation of {@link WindowExtensions} that implements the initial API version.
+ */
+public class WindowExtensionsImpl implements WindowExtensions {
+
+    private final Object mLock = new Object();
+    private volatile WindowLayoutComponent mWindowLayoutComponent;
+    private volatile SplitController mSplitController;
+
+    @Override
+    public int getVendorApiLevel() {
+        return 1;
+    }
+
+    @Override
+    public boolean isWindowLayoutComponentAvailable() {
+        return true;
+    }
+
+    @Override
+    public WindowLayoutComponent getWindowLayoutComponent() {
+        if (mWindowLayoutComponent == null) {
+            synchronized (mLock) {
+                if (mWindowLayoutComponent == null) {
+                    Context context = ActivityThread.currentApplication();
+                    mWindowLayoutComponent = new WindowLayoutComponentImpl(context);
+                }
+            }
+        }
+        return mWindowLayoutComponent;
+    }
+
+    /**
+     * Returns {@code true} if {@link ActivityEmbeddingComponent} is present on the device,
+     * {@code false} otherwise. If the component is not available the developer will receive a
+     * single callback with empty data or default values where possible.
+     */
+    @Override
+    public boolean isEmbeddingComponentAvailable() {
+        return true;
+    }
+
+    /**
+     * Returns the OEM implementation of {@link ActivityEmbeddingComponent} if it is supported on
+     * the device. The implementation must match the API level reported in
+     * {@link androidx.window.extensions.WindowExtensions}. An
+     * {@link UnsupportedOperationException} will be thrown if the device does not support
+     * Activity Embedding. Use
+     * {@link WindowExtensions#isEmbeddingComponentAvailable()} to determine if
+     * {@link ActivityEmbeddingComponent} is present.
+     * @return the OEM implementation of {@link ActivityEmbeddingComponent}
+     */
+    @NonNull
+    public ActivityEmbeddingComponent getActivityEmbeddingComponent() {
+        if (mSplitController == null) {
+            synchronized (mLock) {
+                if (mSplitController == null) {
+                    mSplitController = new SplitController();
+                }
+            }
+        }
+        return mSplitController;
+    }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsProvider.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsProvider.java
new file mode 100644
index 0000000..f9e1f07
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsProvider.java
@@ -0,0 +1,38 @@
+/*
+ * 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 androidx.window.extensions;
+
+import android.annotation.NonNull;
+
+/**
+ * Provides the OEM implementation of {@link WindowExtensions}.
+ */
+public class WindowExtensionsProvider {
+
+    private static final WindowExtensions sWindowExtensions = new WindowExtensionsImpl();
+
+    /**
+     * Returns the OEM implementation of {@link WindowExtensions}. This method is implemented in
+     * the library provided on the device and overwrites one in the Jetpack library included in
+     * apps.
+     * @return the OEM implementation of {@link WindowExtensions}
+     */
+    @NonNull
+    public static WindowExtensions getWindowExtensions() {
+        return sWindowExtensions;
+    }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
similarity index 98%
rename from libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
rename to libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
index 46c8ffe..85ef270 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.window.extensions.organizer;
+package androidx.window.extensions.embedding;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -36,7 +36,6 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.window.extensions.embedding.SplitRule;
 
 import java.util.Map;
 import java.util.concurrent.Executor;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
similarity index 93%
rename from libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitContainer.java
rename to libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
index a41557d..06e7d14 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
@@ -14,15 +14,11 @@
  * limitations under the License.
  */
 
-package androidx.window.extensions.organizer;
+package androidx.window.extensions.embedding;
 
 import android.annotation.NonNull;
 import android.app.Activity;
 
-import androidx.window.extensions.embedding.SplitPairRule;
-import androidx.window.extensions.embedding.SplitPlaceholderRule;
-import androidx.window.extensions.embedding.SplitRule;
-
 /**
  * Client-side descriptor of a split that holds two containers.
  */
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
similarity index 88%
rename from libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
rename to libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index a783fcd..e1c8b11 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.window.extensions.organizer;
+package androidx.window.extensions.embedding;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -31,19 +31,10 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
-import android.util.Pair;
 import android.window.TaskFragmentAppearedInfo;
 import android.window.TaskFragmentInfo;
 import android.window.WindowContainerTransaction;
 
-import androidx.window.extensions.embedding.ActivityRule;
-import androidx.window.extensions.embedding.EmbeddingRule;
-import androidx.window.extensions.embedding.SplitInfo;
-import androidx.window.extensions.embedding.SplitPairRule;
-import androidx.window.extensions.embedding.SplitPlaceholderRule;
-import androidx.window.extensions.embedding.SplitRule;
-import androidx.window.extensions.embedding.TaskFragment;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -53,7 +44,8 @@
 /**
  * Main controller class that manages split states and presentation.
  */
-public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmentCallback {
+public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmentCallback,
+        ActivityEmbeddingComponent {
 
     private final SplitPresenter mPresenter;
 
@@ -64,6 +56,7 @@
 
     // Callback to Jetpack to notify about changes to split states.
     private @NonNull Consumer<List<SplitInfo>> mEmbeddingCallback;
+    private final List<SplitInfo> mLastReportedSplitStates = new ArrayList<>();
 
     public SplitController() {
         mPresenter = new SplitPresenter(new MainThreadExecutor(), this);
@@ -77,6 +70,7 @@
     }
 
     /** Updates the embedding rules applied to future activity launches. */
+    @Override
     public void setEmbeddingRules(@NonNull Set<EmbeddingRule> rules) {
         mSplitRules.clear();
         mSplitRules.addAll(rules);
@@ -103,7 +97,8 @@
     /**
      * Registers the split organizer callback to notify about changes to active splits.
      */
-    public void setEmbeddingCallback(@NonNull Consumer<List<SplitInfo>> callback) {
+    @Override
+    public void setSplitInfoCallback(@NonNull Consumer<List<SplitInfo>> callback) {
         mEmbeddingCallback = callback;
         updateCallbackIfNecessary();
     }
@@ -119,8 +114,8 @@
         container.setInfo(taskFragmentAppearedInfo.getTaskFragmentInfo());
         if (container.isFinished()) {
             mPresenter.cleanupContainer(container, false /* shouldFinishDependent */);
-            updateCallbackIfNecessary();
         }
+        updateCallbackIfNecessary();
     }
 
     @Override
@@ -139,8 +134,8 @@
             final boolean shouldFinishDependent =
                     !taskFragmentInfo.isTaskClearedForReuse();
             mPresenter.cleanupContainer(container, shouldFinishDependent);
-            updateCallbackIfNecessary();
         }
+        updateCallbackIfNecessary();
     }
 
     @Override
@@ -164,18 +159,23 @@
         }
     }
 
+    void onActivityCreated(@NonNull Activity launchedActivity) {
+        handleActivityCreated(launchedActivity);
+        updateCallbackIfNecessary();
+    }
+
     /**
      * Checks if the activity start should be routed to a particular container. It can create a new
      * container for the activity and a new split container if necessary.
      */
     // TODO(b/190433398): Break down into smaller functions.
-    void onActivityCreated(@NonNull Activity launchedActivity) {
+    void handleActivityCreated(@NonNull Activity launchedActivity) {
         final List<EmbeddingRule> splitRules = getSplitRules();
         final TaskFragmentContainer currentContainer = getContainerWithActivity(
                 launchedActivity.getActivityToken(), launchedActivity);
 
         // Check if the activity is configured to always be expanded.
-        if (shouldExpand(launchedActivity, splitRules)) {
+        if (shouldExpand(launchedActivity, null, splitRules)) {
             if (shouldContainerBeExpanded(currentContainer)) {
                 // Make sure that the existing container is expanded
                 mPresenter.expandTaskFragment(currentContainer.getTaskFragmentToken());
@@ -240,8 +240,6 @@
 
         mPresenter.createNewSplitContainer(activityBelow, launchedActivity,
                 splitPairRule);
-
-        updateCallbackIfNecessary();
     }
 
     private void onActivityConfigurationChanged(@NonNull Activity activity) {
@@ -501,7 +499,7 @@
                 continue;
             }
             SplitPlaceholderRule placeholderRule = (SplitPlaceholderRule) rule;
-            if (placeholderRule.getActivityPredicate().test(activity)) {
+            if (placeholderRule.matchesActivity(activity)) {
                 return placeholderRule;
             }
         }
@@ -515,8 +513,16 @@
         if (mEmbeddingCallback == null) {
             return;
         }
-        // TODO(b/190433398): Check if something actually changed
-        mEmbeddingCallback.accept(getActiveSplitStates());
+        if (!allActivitiesCreated()) {
+            return;
+        }
+        List<SplitInfo> currentSplitStates = getActiveSplitStates();
+        if (mLastReportedSplitStates.equals(currentSplitStates)) {
+            return;
+        }
+        mLastReportedSplitStates.clear();
+        mLastReportedSplitStates.addAll(currentSplitStates);
+        mEmbeddingCallback.accept(currentSplitStates);
     }
 
     /**
@@ -525,20 +531,46 @@
     private List<SplitInfo> getActiveSplitStates() {
         List<SplitInfo> splitStates = new ArrayList<>();
         for (SplitContainer container : mSplitContainers) {
-            TaskFragment primaryContainer =
-                    new TaskFragment(
+            if (container.getPrimaryContainer().isEmpty()
+                    || container.getSecondaryContainer().isEmpty()) {
+                // Skipping containers that do not have any activities to report.
+                continue;
+            }
+            ActivityStack primaryContainer =
+                    new ActivityStack(
                             container.getPrimaryContainer().collectActivities());
-            TaskFragment secondaryContainer =
-                    new TaskFragment(
+            ActivityStack secondaryContainer =
+                    new ActivityStack(
                             container.getSecondaryContainer().collectActivities());
             SplitInfo splitState = new SplitInfo(primaryContainer,
-                    secondaryContainer, container.getSplitRule().getSplitRatio());
+                    secondaryContainer,
+                    // Splits that are not showing side-by-side are reported as having 0 split
+                    // ratio, since by definition in the API the primary container occupies no
+                    // width of the split when covered by the secondary.
+                    mPresenter.shouldShowSideBySide(container)
+                            ? container.getSplitRule().getSplitRatio()
+                            : 0.0f);
             splitStates.add(splitState);
         }
         return splitStates;
     }
 
     /**
+     * Checks if all activities that are registered with the containers have already appeared in
+     * the client.
+     */
+    private boolean allActivitiesCreated() {
+        for (TaskFragmentContainer container : mContainers) {
+            if (container.getInfo() == null
+                    || container.getInfo().getActivities().size()
+                    != container.collectActivities().size()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
      * Returns {@code true} if the container is expanded to occupy full task size.
      * Returns {@code false} if the container is included in an active split.
      */
@@ -567,8 +599,7 @@
                 continue;
             }
             SplitPairRule pairRule = (SplitPairRule) rule;
-            if (pairRule.getActivityIntentPredicate().test(
-                    new Pair(primaryActivity, secondaryActivityIntent))) {
+            if (pairRule.matchesActivityIntentPair(primaryActivity, secondaryActivityIntent)) {
                 return pairRule;
             }
         }
@@ -587,10 +618,9 @@
             }
             SplitPairRule pairRule = (SplitPairRule) rule;
             final Intent intent = secondaryActivity.getIntent();
-            if (pairRule.getActivityPairPredicate().test(
-                    new Pair(primaryActivity, secondaryActivity))
-                    && (intent == null || pairRule.getActivityIntentPredicate().test(
-                            new Pair(primaryActivity, intent)))) {
+            if (pairRule.matchesActivityPair(primaryActivity, secondaryActivity)
+                    && (intent == null
+                    || pairRule.matchesActivityIntentPair(primaryActivity, intent))) {
                 return pairRule;
             }
         }
@@ -611,7 +641,7 @@
      * Returns {@code true} if an Activity with the provided component name should always be
      * expanded to occupy full task bounds. Such activity must not be put in a split.
      */
-    private static boolean shouldExpand(@NonNull Activity activity,
+    private static boolean shouldExpand(@Nullable Activity activity, @Nullable Intent intent,
             List<EmbeddingRule> splitRules) {
         if (splitRules == null) {
             return false;
@@ -624,7 +654,9 @@
             if (!activityRule.shouldAlwaysExpand()) {
                 continue;
             }
-            if (activityRule.getActivityPredicate().test(activity)) {
+            if (activity != null && activityRule.matchesActivity(activity)) {
+                return true;
+            } else if (intent != null && activityRule.matchesIntent(intent)) {
                 return true;
             }
         }
@@ -678,11 +710,11 @@
 
     /** Executor that posts on the main application thread. */
     private static class MainThreadExecutor implements Executor {
-        private final Handler handler = new Handler(Looper.getMainLooper());
+        private final Handler mHandler = new Handler(Looper.getMainLooper());
 
         @Override
         public void execute(Runnable r) {
-            handler.post(r);
+            mHandler.post(r);
         }
     }
 
@@ -703,13 +735,25 @@
             }
             final Activity launchingActivity = (Activity) who;
 
-            if (!setLaunchingToSideContainer(launchingActivity, intent, options)) {
+            if (shouldExpand(null, intent, getSplitRules())) {
+                setLaunchingInExpandedContainer(launchingActivity, options);
+            } else if (!setLaunchingToSideContainer(launchingActivity, intent, options)) {
                 setLaunchingInSameContainer(launchingActivity, intent, options);
             }
 
             return super.onStartActivity(who, intent, options);
         }
 
+        private void setLaunchingInExpandedContainer(Activity launchingActivity, Bundle options) {
+            TaskFragmentContainer newContainer = mPresenter.createNewExpandedContainer(
+                    launchingActivity);
+
+            // Amend the request to let the WM know that the activity should be placed in the
+            // dedicated container.
+            options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN,
+                    newContainer.getTaskFragmentToken());
+        }
+
         /**
          * Returns {@code true} if the activity that is going to be started via the
          * {@code intent} should be paired with the {@code launchingActivity} and is set to be
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
similarity index 80%
rename from libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
rename to libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index ac85ac8..25292b9 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -14,16 +14,19 @@
  * limitations under the License.
  */
 
-package androidx.window.extensions.organizer;
+package androidx.window.extensions.embedding;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 
 import android.app.Activity;
+import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.util.LayoutDirection;
+import android.view.View;
 import android.view.WindowInsets;
 import android.view.WindowMetrics;
 import android.window.TaskFragmentCreationParams;
@@ -32,8 +35,6 @@
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.window.extensions.embedding.SplitPairRule;
-import androidx.window.extensions.embedding.SplitRule;
 
 import java.util.concurrent.Executor;
 
@@ -42,13 +43,13 @@
  * {@link SplitController}.
  */
 class SplitPresenter extends JetpackTaskFragmentOrganizer {
-    private static final int POSITION_LEFT = 0;
-    private static final int POSITION_RIGHT = 1;
+    private static final int POSITION_START = 0;
+    private static final int POSITION_END = 1;
     private static final int POSITION_FILL = 2;
 
     @IntDef(value = {
-            POSITION_LEFT,
-            POSITION_RIGHT,
+            POSITION_START,
+            POSITION_END,
             POSITION_FILL,
     })
     private @interface Position {}
@@ -96,13 +97,15 @@
         final WindowContainerTransaction wct = new WindowContainerTransaction();
 
         final Rect parentBounds = getParentContainerBounds(primaryActivity);
-        final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
+        final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, parentBounds, rule,
+                isLtr(primaryActivity, rule));
         final TaskFragmentContainer primaryContainer = prepareContainerForActivity(wct,
                 primaryActivity, primaryRectBounds, null);
 
         // Create new empty task fragment
-        TaskFragmentContainer secondaryContainer = mController.newContainer(null);
-        final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
+        final TaskFragmentContainer secondaryContainer = mController.newContainer(null);
+        final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds,
+                rule, isLtr(primaryActivity, rule));
         createTaskFragment(wct, secondaryContainer.getTaskFragmentToken(),
                 primaryActivity.getActivityToken(), secondaryRectBounds,
                 WINDOWING_MODE_MULTI_WINDOW);
@@ -135,11 +138,13 @@
         final WindowContainerTransaction wct = new WindowContainerTransaction();
 
         final Rect parentBounds = getParentContainerBounds(primaryActivity);
-        final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
+        final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, parentBounds, rule,
+                isLtr(primaryActivity, rule));
         final TaskFragmentContainer primaryContainer = prepareContainerForActivity(wct,
                 primaryActivity, primaryRectBounds, null);
 
-        final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
+        final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds, rule,
+                isLtr(primaryActivity, rule));
         final TaskFragmentContainer secondaryContainer = prepareContainerForActivity(wct,
                 secondaryActivity, secondaryRectBounds, primaryContainer);
 
@@ -153,6 +158,20 @@
     }
 
     /**
+     * Creates a new expanded container.
+     */
+    TaskFragmentContainer createNewExpandedContainer(@NonNull Activity launchingActivity) {
+        final TaskFragmentContainer newContainer = mController.newContainer(null);
+
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
+        createTaskFragment(wct, newContainer.getTaskFragmentToken(),
+                launchingActivity.getActivityToken(), new Rect(), WINDOWING_MODE_MULTI_WINDOW);
+
+        applyTransaction(wct);
+        return newContainer;
+    }
+
+    /**
      * Creates a new container or resizes an existing container for activity to the provided bounds.
      * @param activity The activity to be re-parented to the container if necessary.
      * @param containerToAvoid Re-parent from this container if an activity is already in it.
@@ -197,8 +216,10 @@
     void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent activityIntent,
             @Nullable Bundle activityOptions, @NonNull SplitRule rule) {
         final Rect parentBounds = getParentContainerBounds(launchingActivity);
-        final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
-        final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
+        final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, parentBounds, rule,
+                isLtr(launchingActivity, rule));
+        final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds, rule,
+                isLtr(launchingActivity, rule));
 
         TaskFragmentContainer primaryContainer = mController.getContainerWithActivity(
                 launchingActivity.getActivityToken());
@@ -231,8 +252,15 @@
         // Getting the parent bounds using the updated container - it will have the recent value.
         final Rect parentBounds = getParentContainerBounds(updatedContainer);
         final SplitRule rule = splitContainer.getSplitRule();
-        final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
-        final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
+        final Activity activity = splitContainer.getPrimaryContainer().getTopNonFinishingActivity();
+        if (activity == null) {
+            return;
+        }
+        final boolean isLtr = isLtr(activity, rule);
+        final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, parentBounds, rule,
+                isLtr);
+        final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds, rule,
+                isLtr);
 
         // If the task fragments are not registered yet, the positions will be updated after they
         // are created again.
@@ -283,36 +311,64 @@
         // TODO(b/190433398): Supply correct insets.
         final WindowMetrics parentMetrics = new WindowMetrics(parentBounds,
                 new WindowInsets(new Rect()));
-        return rule.getParentWindowMetricsPredicate().test(parentMetrics);
+        return rule.checkParentMetrics(parentMetrics);
     }
 
     @NonNull
     private Rect getBoundsForPosition(@Position int position, @NonNull Rect parentBounds,
-            @NonNull SplitRule rule) {
+            @NonNull SplitRule rule, boolean isLtr) {
         if (!shouldShowSideBySide(parentBounds, rule)) {
             return new Rect();
         }
 
-        float splitRatio = rule.getSplitRatio();
+        final float splitRatio = rule.getSplitRatio();
+        final float rtlSplitRatio = 1 - splitRatio;
         switch (position) {
-            case POSITION_LEFT:
-                return new Rect(
-                        parentBounds.left,
-                        parentBounds.top,
-                        (int) (parentBounds.left + parentBounds.width() * splitRatio),
-                        parentBounds.bottom);
-            case POSITION_RIGHT:
-                return new Rect(
-                        (int) (parentBounds.left + parentBounds.width() * splitRatio),
-                        parentBounds.top,
-                        parentBounds.right,
-                        parentBounds.bottom);
+            case POSITION_START:
+                return isLtr ? getLeftContainerBounds(parentBounds, splitRatio)
+                        : getRightContainerBounds(parentBounds, rtlSplitRatio);
+            case POSITION_END:
+                return isLtr ? getRightContainerBounds(parentBounds, splitRatio)
+                        : getLeftContainerBounds(parentBounds, rtlSplitRatio);
             case POSITION_FILL:
                 return parentBounds;
         }
         return parentBounds;
     }
 
+    private Rect getLeftContainerBounds(@NonNull Rect parentBounds, float splitRatio) {
+        return new Rect(
+                parentBounds.left,
+                parentBounds.top,
+                (int) (parentBounds.left + parentBounds.width() * splitRatio),
+                parentBounds.bottom);
+    }
+
+    private Rect getRightContainerBounds(@NonNull Rect parentBounds, float splitRatio) {
+        return new Rect(
+                (int) (parentBounds.left + parentBounds.width() * splitRatio),
+                parentBounds.top,
+                parentBounds.right,
+                parentBounds.bottom);
+    }
+
+    /**
+     * Checks if a split with the provided rule should be displays in left-to-right layout
+     * direction, either always or with the current configuration.
+     */
+    private boolean isLtr(@NonNull Context context, @NonNull SplitRule rule) {
+        switch (rule.getLayoutDirection()) {
+            case LayoutDirection.LOCALE:
+                return context.getResources().getConfiguration().getLayoutDirection()
+                        == View.LAYOUT_DIRECTION_LTR;
+            case LayoutDirection.RTL:
+                return false;
+            case LayoutDirection.LTR:
+            default:
+                return true;
+        }
+    }
+
     @NonNull
     Rect getParentContainerBounds(@NonNull TaskFragmentContainer container) {
         final Configuration parentConfig = mFragmentParentConfigs.get(
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationAdapter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
similarity index 88%
rename from libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationAdapter.java
rename to libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
index 155c649..06f6228 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationAdapter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package androidx.window.extensions.organizer;
+package androidx.window.extensions.embedding;
 
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.view.Choreographer;
 import android.view.RemoteAnimationTarget;
@@ -24,6 +25,7 @@
 import android.view.animation.Transformation;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 /**
  * Wrapper to handle the TaskFragment animation update in one {@link SurfaceControl.Transaction}.
@@ -33,6 +35,7 @@
     private final RemoteAnimationTarget mTarget;
     private final SurfaceControl mLeash;
     private final boolean mSizeChanged;
+    private final Point mPosition;
     private final Transformation mTransformation = new Transformation();
     private final float[] mMatrix = new float[9];
     private final float[] mVecs = new float[4];
@@ -41,7 +44,7 @@
 
     TaskFragmentAnimationAdapter(@NonNull Animation animation,
             @NonNull RemoteAnimationTarget target) {
-        this(animation, target, target.leash, false /* sizeChanged */);
+        this(animation, target, target.leash, false /* sizeChanged */, null /* position */);
     }
 
     /**
@@ -49,11 +52,14 @@
      */
     TaskFragmentAnimationAdapter(@NonNull Animation animation,
             @NonNull RemoteAnimationTarget target, @NonNull SurfaceControl leash,
-            boolean sizeChanged) {
+            boolean sizeChanged, @Nullable Point position) {
         mAnimation = animation;
         mTarget = target;
         mLeash = leash;
         mSizeChanged = sizeChanged;
+        mPosition = position != null
+                ? position
+                : new Point(target.localBounds.left, target.localBounds.top);
     }
 
     /** Called on frame update. */
@@ -65,8 +71,7 @@
 
         currentPlayTime = Math.min(currentPlayTime, mAnimation.getDuration());
         mAnimation.getTransformation(currentPlayTime, mTransformation);
-        mTransformation.getMatrix().postTranslate(
-                mTarget.localBounds.left, mTarget.localBounds.top);
+        mTransformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
         t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
         t.setAlpha(mLeash, mTransformation.getAlpha());
         t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
similarity index 97%
rename from libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationController.java
rename to libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
index 6631243..6579766 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.window.extensions.organizer;
+package androidx.window.extensions.embedding;
 
 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
similarity index 96%
rename from libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationRunner.java
rename to libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
index da3d116..3980d07 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationRunner.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.window.extensions.organizer;
+package androidx.window.extensions.embedding;
 
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
@@ -23,6 +23,7 @@
 
 import android.animation.Animator;
 import android.animation.ValueAnimator;
+import android.graphics.Point;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
@@ -193,10 +194,12 @@
             if (target.startBounds != null) {
                 final Animation[] animations =
                         mAnimationSpec.createChangeBoundsChangeAnimations(target);
+                // The snapshot surface will always be at (0, 0) of its parent.
                 adapters.add(new TaskFragmentAnimationAdapter(animations[0], target,
-                        target.startLeash, false /* sizeChanged */));
+                        target.startLeash, false /* sizeChanged */, new Point(0, 0)));
+                // The end surface will have size change for scaling.
                 adapters.add(new TaskFragmentAnimationAdapter(animations[1], target,
-                        target.leash, true /* sizeChanged */));
+                        target.leash, true /* sizeChanged */, null /* position */));
                 continue;
             }
 
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationSpec.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
similarity index 92%
rename from libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationSpec.java
rename to libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
index ddcb27d..11a79b2 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationSpec.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.window.extensions.organizer;
+package androidx.window.extensions.embedding;
 
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 
@@ -32,6 +32,7 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.ClipRectAnimation;
 import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
 import android.view.animation.ScaleAnimation;
 import android.view.animation.TranslateAnimation;
 
@@ -46,12 +47,13 @@
 
     private static final String TAG = "TaskFragAnimationSpec";
     private static final int CHANGE_ANIMATION_DURATION = 517;
-    private static final int CHANGE_ANIMATION_FADE_DURATION = 82;
-    private static final int CHANGE_ANIMATION_FADE_OFFSET = 67;
+    private static final int CHANGE_ANIMATION_FADE_DURATION = 80;
+    private static final int CHANGE_ANIMATION_FADE_OFFSET = 30;
 
     private final Context mContext;
     private final TransitionAnimation mTransitionAnimation;
     private final Interpolator mFastOutExtraSlowInInterpolator;
+    private final LinearInterpolator mLinearInterpolator;
     private float mTransitionAnimationScaleSetting;
 
     TaskFragmentAnimationSpec(@NonNull Handler handler) {
@@ -61,6 +63,7 @@
         AttributeCache.init(mContext);
         mFastOutExtraSlowInInterpolator = AnimationUtils.loadInterpolator(
                 mContext, android.R.interpolator.fast_out_extra_slow_in);
+        mLinearInterpolator = new LinearInterpolator();
 
         // The transition animation should be adjusted based on the developer option.
         final ContentResolver resolver = mContext.getContentResolver();
@@ -118,9 +121,11 @@
      *         the second one is for the end leash.
      */
     Animation[] createChangeBoundsChangeAnimations(@NonNull RemoteAnimationTarget target) {
+        // Both start bounds and end bounds are in screen coordinates. We will post translate
+        // to the local coordinates in TaskFragmentAnimationAdapter#onAnimationUpdate
         final Rect startBounds = target.startBounds;
         final Rect parentBounds = target.taskInfo.configuration.windowConfiguration.getBounds();
-        final Rect endBounds = target.localBounds;
+        final Rect endBounds = target.screenSpaceBounds;
         float scaleX = ((float) startBounds.width()) / endBounds.width();
         float scaleY = ((float) startBounds.height()) / endBounds.height();
         // Start leash is a child of the end leash. Reverse the scale so that the start leash won't
@@ -129,14 +134,15 @@
         float startScaleY = 1.f / scaleY;
 
         // The start leash will be fade out.
-        final AnimationSet startSet = new AnimationSet(true /* shareInterpolator */);
-        startSet.setInterpolator(mFastOutExtraSlowInInterpolator);
+        final AnimationSet startSet = new AnimationSet(false /* shareInterpolator */);
         final Animation startAlpha = new AlphaAnimation(1f, 0f);
+        startAlpha.setInterpolator(mLinearInterpolator);
         startAlpha.setDuration(CHANGE_ANIMATION_FADE_DURATION);
         startAlpha.setStartOffset(CHANGE_ANIMATION_FADE_OFFSET);
         startSet.addAnimation(startAlpha);
         final Animation startScale = new ScaleAnimation(startScaleX, startScaleX, startScaleY,
                 startScaleY);
+        startScale.setInterpolator(mFastOutExtraSlowInInterpolator);
         startScale.setDuration(CHANGE_ANIMATION_DURATION);
         startSet.addAnimation(startScale);
         startSet.initialize(startBounds.width(), startBounds.height(), endBounds.width(),
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
similarity index 98%
rename from libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
rename to libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 8503b9f..54e44a7 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.window.extensions.organizer;
+package androidx.window.extensions.embedding;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -212,7 +212,9 @@
             @NonNull WindowContainerTransaction wct, @NonNull SplitController controller) {
         // Finish own activities
         for (Activity activity : collectActivities()) {
-            activity.finish();
+            if (!activity.isFinishing()) {
+                activity.finish();
+            }
         }
 
         if (!shouldFinishDependent) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
similarity index 63%
rename from libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java
rename to libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
index a0d5b00..383d91d 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.window.extensions;
+package androidx.window.extensions.layout;
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
@@ -36,19 +36,27 @@
 import androidx.window.util.PriorityDataProducer;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
+import java.util.function.Consumer;
 
 /**
- * Reference implementation of androidx.window.extensions OEM interface for use with
+ * Reference implementation of androidx.window.extensions.layout OEM interface for use with
  * WindowManager Jetpack.
  *
  * NOTE: This version is a work in progress and under active development. It MUST NOT be used in
  * production builds since the interface can still change before reaching stable version.
  * Please refer to {@link androidx.window.sidecar.SampleSidecarImpl} instead.
  */
-class SampleExtensionImpl extends StubExtension {
+public class WindowLayoutComponentImpl implements WindowLayoutComponent {
     private static final String TAG = "SampleExtension";
+    private static WindowLayoutComponent sInstance;
+
+    private final Map<Activity, Consumer<WindowLayoutInfo>> mWindowLayoutChangeListeners =
+            new HashMap<>();
 
     private final SettingsDevicePostureProducer mSettingsDevicePostureProducer;
     private final DataProducer<Integer> mDevicePostureProducer;
@@ -56,7 +64,7 @@
     private final SettingsDisplayFeatureProducer mSettingsDisplayFeatureProducer;
     private final DataProducer<List<DisplayFeature>> mDisplayFeatureProducer;
 
-    SampleExtensionImpl(Context context) {
+    public WindowLayoutComponentImpl(Context context) {
         mSettingsDevicePostureProducer = new SettingsDevicePostureProducer(context);
         mDevicePostureProducer = new PriorityDataProducer<>(List.of(
                 mSettingsDevicePostureProducer,
@@ -73,28 +81,68 @@
         mDisplayFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
     }
 
+    /**
+     * Adds a listener interested in receiving updates to {@link WindowLayoutInfo}
+     * @param activity hosting a {@link android.view.Window}
+     * @param consumer interested in receiving updates to {@link WindowLayoutInfo}
+     */
+    public void addWindowLayoutInfoListener(@NonNull Activity activity,
+            @NonNull Consumer<WindowLayoutInfo> consumer) {
+        mWindowLayoutChangeListeners.put(activity, consumer);
+        updateRegistrations();
+    }
+
+    /**
+     * Removes a listener no longer interested in receiving updates.
+     * @param consumer no longer interested in receiving updates to {@link WindowLayoutInfo}
+     */
+    public void removeWindowLayoutInfoListener(
+            @NonNull Consumer<WindowLayoutInfo> consumer) {
+        mWindowLayoutChangeListeners.values().remove(consumer);
+        updateRegistrations();
+    }
+
+    void updateWindowLayout(@NonNull Activity activity,
+            @NonNull WindowLayoutInfo newLayout) {
+        Consumer<WindowLayoutInfo> consumer = mWindowLayoutChangeListeners.get(activity);
+        if (consumer != null) {
+            consumer.accept(newLayout);
+        }
+    }
+
+    @NonNull
+    Set<Activity> getActivitiesListeningForLayoutChanges() {
+        return mWindowLayoutChangeListeners.keySet();
+    }
+
+    protected boolean hasListeners() {
+        return !mWindowLayoutChangeListeners.isEmpty();
+    }
+
     private int getFeatureState(DisplayFeature feature) {
         Integer featureState = feature.getState();
         Optional<Integer> posture = mDevicePostureProducer.getData();
-        int fallbackPosture = posture.orElse(ExtensionFoldingFeature.STATE_FLAT);
+        int fallbackPosture = posture.orElse(FoldingFeature.STATE_FLAT);
         return featureState == null ? fallbackPosture : featureState;
     }
 
     private void onDisplayFeaturesChanged() {
         for (Activity activity : getActivitiesListeningForLayoutChanges()) {
-            ExtensionWindowLayoutInfo newLayout = getWindowLayoutInfo(activity);
+            WindowLayoutInfo newLayout = getWindowLayoutInfo(activity);
             updateWindowLayout(activity, newLayout);
         }
     }
 
     @NonNull
-    private ExtensionWindowLayoutInfo getWindowLayoutInfo(@NonNull Activity activity) {
-        List<ExtensionDisplayFeature> displayFeatures = getDisplayFeatures(activity);
-        return new ExtensionWindowLayoutInfo(displayFeatures);
+    private WindowLayoutInfo getWindowLayoutInfo(@NonNull Activity activity) {
+        List<androidx.window.extensions.layout.DisplayFeature> displayFeatures =
+                getDisplayFeatures(activity);
+        return new WindowLayoutInfo(displayFeatures);
     }
 
-    private List<ExtensionDisplayFeature> getDisplayFeatures(@NonNull Activity activity) {
-        List<ExtensionDisplayFeature> features = new ArrayList<>();
+    private List<androidx.window.extensions.layout.DisplayFeature> getDisplayFeatures(
+            @NonNull Activity activity) {
+        List<androidx.window.extensions.layout.DisplayFeature> features = new ArrayList<>();
         int displayId = activity.getDisplay().getDisplayId();
         if (displayId != DEFAULT_DISPLAY) {
             Log.w(TAG, "This sample doesn't support display features on secondary displays");
@@ -115,15 +163,14 @@
                 rotateRectToDisplayRotation(displayId, featureRect);
                 transformToWindowSpaceRect(activity, featureRect);
 
-                features.add(new ExtensionFoldingFeature(featureRect, baseFeature.getType(),
+                features.add(new FoldingFeature(featureRect, baseFeature.getType(),
                         getFeatureState(baseFeature)));
             }
         }
         return features;
     }
 
-    @Override
-    protected void onListenersChanged() {
+    private void updateRegistrations() {
         if (hasListeners()) {
             mSettingsDevicePostureProducer.registerObserversIfNeeded();
             mSettingsDisplayFeatureProducer.registerObserversIfNeeded();
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/EmbeddingExtensionImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/EmbeddingExtensionImpl.java
deleted file mode 100644
index 9a8961f..0000000
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/EmbeddingExtensionImpl.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions.organizer;
-
-import androidx.annotation.NonNull;
-import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
-import androidx.window.extensions.embedding.EmbeddingRule;
-import androidx.window.extensions.embedding.SplitInfo;
-
-import java.util.List;
-import java.util.Set;
-import java.util.function.Consumer;
-
-/**
- * Reference implementation of the activity embedding interface defined in WM Jetpack.
- */
-public class EmbeddingExtensionImpl implements ActivityEmbeddingComponent {
-
-    private final SplitController mSplitController;
-
-    public EmbeddingExtensionImpl() {
-        mSplitController = new SplitController();
-    }
-
-    @Override
-    public void setEmbeddingRules(@NonNull Set<EmbeddingRule> rules) {
-        mSplitController.setEmbeddingRules(rules);
-    }
-
-    @Override
-    public void setEmbeddingCallback(@NonNull Consumer<List<SplitInfo>> consumer) {
-        mSplitController.setEmbeddingCallback(consumer);
-    }
-}
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
index 097febf..42e829e 100644
--- a/libs/WindowManager/Jetpack/window-extensions-release.aar
+++ b/libs/WindowManager/Jetpack/window-extensions-release.aar
Binary files differ
diff --git a/libs/WindowManager/Shell/res/color/split_divider_background.xml b/libs/WindowManager/Shell/res/color/split_divider_background.xml
index 84f4fdf..329e5b9 100644
--- a/libs/WindowManager/Shell/res/color/split_divider_background.xml
+++ b/libs/WindowManager/Shell/res/color/split_divider_background.xml
@@ -15,5 +15,5 @@
   ~ limitations under the License.
   -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@android:color/system_neutral2_500" android:lStar="35" />
+    <item android:color="@android:color/system_neutral1_500" android:lStar="35" />
 </selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index 1ace3cd..3258385 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -19,10 +19,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="pip_phone_close" msgid="5783752637260411309">"বন্ধ কৰক"</string>
     <string name="pip_phone_expand" msgid="2579292903468287504">"বিস্তাৰ কৰক"</string>
-    <string name="pip_phone_settings" msgid="5468987116750491918">"ছেটিংসমূহ"</string>
+    <string name="pip_phone_settings" msgid="5468987116750491918">"ছেটিং"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"মেনু"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> চিত্ৰৰ ভিতৰৰ চিত্ৰত আছে"</string>
-    <string name="pip_notification_message" msgid="8854051911700302620">"আপুনি যদি <xliff:g id="NAME">%s</xliff:g> সুবিধাটো ব্যৱহাৰ কৰিব নোখোজে, তেন্তে ছেটিংসমূহ খুলিবলৈ টিপক আৰু তালৈ গৈ ইয়াক অফ কৰক।"</string>
+    <string name="pip_notification_message" msgid="8854051911700302620">"আপুনি যদি <xliff:g id="NAME">%s</xliff:g> সুবিধাটো ব্যৱহাৰ কৰিব নোখোজে, তেন্তে ছেটিং খুলিবলৈ টিপক আৰু তালৈ গৈ ইয়াক অফ কৰক।"</string>
     <string name="pip_play" msgid="3496151081459417097">"প্লে কৰক"</string>
     <string name="pip_pause" msgid="690688849510295232">"পজ কৰক"</string>
     <string name="pip_skip_to_next" msgid="8403429188794867653">"পৰৱৰ্তী মিডিয়ালৈ যাওক"</string>
@@ -31,25 +31,25 @@
     <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"লুকুৱাওক"</string>
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"দেখুৱাওক"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"এপ্‌টোৱে বিভাজিত স্ক্ৰীনৰ সৈতে কাম নকৰিব পাৰে।"</string>
-    <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"এপটোৱে বিভাজিত স্ক্ৰীণ সমৰ্থন নকৰে।"</string>
+    <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"এপ্‌টোৱে বিভাজিত স্ক্ৰীন সমৰ্থন নকৰে।"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"গৌণ ডিছপ্লেত এপে সঠিকভাৱে কাম নকৰিব পাৰে।"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"গৌণ ডিছপ্লেত এপ্ লঞ্চ কৰিব নোৱাৰি।"</string>
-    <string name="accessibility_divider" msgid="703810061635792791">"স্প্লিট স্ক্ৰীণৰ বিভাজক"</string>
-    <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"বাওঁফালৰ স্ক্ৰীণখন সম্পূৰ্ণ স্ক্ৰীণ কৰক"</string>
+    <string name="accessibility_divider" msgid="703810061635792791">"স্প্লিট স্ক্ৰীনৰ বিভাজক"</string>
+    <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"বাওঁফালৰ স্ক্ৰীনখন সম্পূৰ্ণ স্ক্ৰীন কৰক"</string>
     <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"বাওঁফালৰ স্ক্ৰীণখন ৭০% কৰক"</string>
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"বাওঁফালৰ স্ক্ৰীণখন ৫০% কৰক"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"বাওঁফালৰ স্ক্ৰীণখন ৩০% কৰক"</string>
-    <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"সোঁফালৰ স্ক্ৰীণখন সম্পূৰ্ণ স্ক্ৰীণ কৰক"</string>
-    <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"শীৰ্ষ স্ক্ৰীণখন সম্পূৰ্ণ স্ক্ৰীণ কৰক"</string>
+    <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"সোঁফালৰ স্ক্ৰীনখন সম্পূৰ্ণ স্ক্ৰীন কৰক"</string>
+    <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"শীৰ্ষ স্ক্ৰীনখন সম্পূৰ্ণ স্ক্ৰীন কৰক"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"শীর্ষ স্ক্ৰীণখন ৭০% কৰক"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"শীর্ষ স্ক্ৰীণখন ৫০% কৰক"</string>
     <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"শীর্ষ স্ক্ৰীণখন ৩০% কৰক"</string>
-    <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"তলৰ স্ক্ৰীণখন সম্পূৰ্ণ স্ক্ৰীণ কৰক"</string>
+    <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"তলৰ স্ক্ৰীনখন সম্পূৰ্ণ স্ক্ৰীন কৰক"</string>
     <string name="one_handed_tutorial_title" msgid="4583241688067426350">"এখন হাতেৰে ব্যৱহাৰ কৰা ম’ড ব্যৱহাৰ কৰা"</string>
     <string name="one_handed_tutorial_description" msgid="3486582858591353067">"বাহিৰ হ’বলৈ স্ক্ৰীনখনৰ একেবাৰে তলৰ পৰা ওপৰলৈ ছোৱাইপ কৰক অথবা এপ্‌টোৰ ওপৰত যিকোনো ঠাইত টিপক"</string>
     <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"এখন হাতেৰে ব্যৱহাৰ কৰা ম\'ডটো আৰম্ভ কৰক"</string>
     <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"এখন হাতেৰে ব্যৱহাৰ কৰা ম\'ডটোৰ পৰা বাহিৰ হওক"</string>
-    <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ bubblesৰ ছেটিংসমূহ"</string>
+    <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ bubblesৰ ছেটিং"</string>
     <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"অভাৰফ্ল’"</string>
     <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"ষ্টেকত পুনৰ যোগ দিয়ক"</string>
     <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g>ৰ পৰা <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
@@ -58,7 +58,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"শীৰ্ষৰ সোঁফালে নিয়ক"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"বুটামটো বাওঁফালে নিয়ক"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"তলৰ সোঁফালে নিয়ক"</string>
-    <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ছেটিংসমূহ"</string>
+    <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ছেটিং"</string>
     <string name="bubble_dismiss_text" msgid="8816558050659478158">"বাবল অগ্ৰাহ্য কৰক"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"বাৰ্তালাপ বাবল নকৰিব"</string>
     <string name="bubbles_user_education_title" msgid="2112319053732691899">"Bubbles ব্যৱহাৰ কৰি চাট কৰক"</string>
diff --git a/libs/WindowManager/Shell/res/values-as/strings_tv.xml b/libs/WindowManager/Shell/res/values-as/strings_tv.xml
index 6c223f4..170b2db 100644
--- a/libs/WindowManager/Shell/res/values-as/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings_tv.xml
@@ -20,5 +20,5 @@
     <string name="notification_channel_tv_pip" msgid="2576686079160402435">"চিত্ৰৰ ভিতৰত চিত্ৰ"</string>
     <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(শিৰোনামবিহীন কাৰ্যক্ৰম)"</string>
     <string name="pip_close" msgid="9135220303720555525">"পিপ বন্ধ কৰক"</string>
-    <string name="pip_fullscreen" msgid="7278047353591302554">"সম্পূৰ্ণ স্ক্ৰীণ"</string>
+    <string name="pip_fullscreen" msgid="7278047353591302554">"সম্পূৰ্ণ স্ক্ৰীন"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 9d0dd3c..d590ab1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -968,7 +968,7 @@
             }
         });
         mExpandedViewAlphaAnimator.addUpdateListener(valueAnimator -> {
-            if (mExpandedBubble != null) {
+            if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
                 mExpandedBubble.getExpandedView().setTaskViewAlpha(
                         (float) valueAnimator.getAnimatedValue());
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
index 0a1cd22..74672a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
@@ -28,37 +28,40 @@
 import com.android.wm.shell.R
 import com.android.wm.shell.animation.PhysicsAnimator
 import com.android.wm.shell.common.DismissCircleView
+import android.view.WindowInsets
+import android.view.WindowManager
 
 /*
  * View that handles interactions between DismissCircleView and BubbleStackView.
  */
 class DismissView(context: Context) : FrameLayout(context) {
 
-    var circle = DismissCircleView(context).apply {
-        val targetSize: Int = context.resources.getDimensionPixelSize(R.dimen.dismiss_circle_size)
-        val newParams = LayoutParams(targetSize, targetSize)
-        newParams.gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
-        setLayoutParams(newParams)
-        setTranslationY(
-            resources.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height).toFloat())
-    }
-
+    var circle = DismissCircleView(context)
     var isShowing = false
+
     private val animator = PhysicsAnimator.getInstance(circle)
     private val spring = PhysicsAnimator.SpringConfig(STIFFNESS_LOW, DAMPING_RATIO_LOW_BOUNCY)
     private val DISMISS_SCRIM_FADE_MS = 200
+    private var wm: WindowManager =
+            context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
     init {
         setLayoutParams(LayoutParams(
             ViewGroup.LayoutParams.MATCH_PARENT,
             resources.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height),
             Gravity.BOTTOM))
-        setPadding(0, 0, 0, resources.getDimensionPixelSize(R.dimen.floating_dismiss_bottom_margin))
+        updatePadding()
         setClipToPadding(false)
         setClipChildren(false)
         setVisibility(View.INVISIBLE)
         setBackgroundResource(
             R.drawable.floating_dismiss_gradient_transition)
-        addView(circle)
+
+        val targetSize: Int = resources.getDimensionPixelSize(R.dimen.dismiss_circle_size)
+        addView(circle, LayoutParams(targetSize, targetSize,
+                Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL))
+        // start with circle offscreen so it's animated up
+        circle.setTranslationY(resources.getDimensionPixelSize(
+                R.dimen.floating_dismiss_gradient_height).toFloat())
     }
 
     /**
@@ -91,9 +94,21 @@
     }
 
     fun updateResources() {
-        val targetSize: Int = context.resources.getDimensionPixelSize(R.dimen.dismiss_circle_size)
+        updatePadding()
+        layoutParams.height = resources.getDimensionPixelSize(
+                R.dimen.floating_dismiss_gradient_height)
+
+        val targetSize: Int = resources.getDimensionPixelSize(R.dimen.dismiss_circle_size)
         circle.layoutParams.width = targetSize
         circle.layoutParams.height = targetSize
         circle.requestLayout()
     }
+
+    private fun updatePadding() {
+        val insets: WindowInsets = wm.getCurrentWindowMetrics().getWindowInsets()
+        val navInset = insets.getInsetsIgnoringVisibility(
+                WindowInsets.Type.navigationBars())
+        setPadding(0, 0, 0, navInset.bottom +
+                resources.getDimensionPixelSize(R.dimen.floating_dismiss_bottom_margin))
+    }
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index f9ba97f..6ea806b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -25,6 +25,7 @@
 import android.util.AttributeSet;
 import android.util.Property;
 import android.view.GestureDetector;
+import android.view.InsetsController;
 import android.view.InsetsSource;
 import android.view.InsetsState;
 import android.view.MotionEvent;
@@ -34,7 +35,6 @@
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.WindowManager;
-import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 
 import androidx.annotation.NonNull;
@@ -51,12 +51,6 @@
     public static final long TOUCH_ANIMATION_DURATION = 150;
     public static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
 
-    // TODO(b/191269755): use the value defined in InsetsController.
-    private static final Interpolator RESIZE_INTERPOLATOR = Interpolators.LINEAR;
-
-    // TODO(b/191269755): use the value defined in InsetsController.
-    private static final int ANIMATION_DURATION_RESIZE = 300;
-
     /** The task bar expanded height. Used to determine whether to insets divider bounds or not. */
     private float mExpandedTaskBarHeight;
 
@@ -142,8 +136,8 @@
             if (animate) {
                 ObjectAnimator animator = ObjectAnimator.ofInt(this,
                         DIVIDER_HEIGHT_PROPERTY, mDividerBounds.height(), mTempRect.height());
-                animator.setInterpolator(RESIZE_INTERPOLATOR);
-                animator.setDuration(ANIMATION_DURATION_RESIZE);
+                animator.setInterpolator(InsetsController.RESIZE_INTERPOLATOR);
+                animator.setDuration(InsetsController.ANIMATION_DURATION_RESIZE);
                 animator.start();
             } else {
                 DIVIDER_HEIGHT_PROPERTY.set(this, mTempRect.height());
@@ -226,16 +220,6 @@
     private void setTouching() {
         setSlippery(false);
         mHandle.setTouching(true, true);
-        if (isLandscape()) {
-            mBackground.animate().scaleX(1.4f);
-        } else {
-            mBackground.animate().scaleY(1.4f);
-        }
-        mBackground.animate()
-                .setInterpolator(Interpolators.TOUCH_RESPONSE)
-                .setDuration(TOUCH_ANIMATION_DURATION)
-                .translationZ(mTouchElevation)
-                .start();
         // Lift handle as well so it doesn't get behind the background, even though it doesn't
         // cast shadow.
         mHandle.animate()
@@ -248,13 +232,6 @@
     private void releaseTouching() {
         setSlippery(true);
         mHandle.setTouching(false, true);
-        mBackground.animate()
-                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
-                .translationZ(0)
-                .scaleX(1f)
-                .scaleY(1f)
-                .start();
         mHandle.animate()
                 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
                 .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 27c8d7a..1c308a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -776,26 +776,31 @@
         boolean adjustSurfaceLayoutForIme(SurfaceControl.Transaction t,
                 SurfaceControl dividerLeash, SurfaceControl leash1, SurfaceControl leash2,
                 SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
-            if (mYOffsetForIme == 0) return false;
+            final boolean showDim = mDimValue1 > 0.001f || mDimValue2 > 0.001f;
+            boolean adjusted = false;
+            if (mYOffsetForIme != 0) {
+                if (dividerLeash != null) {
+                    mTempRect.set(mDividerBounds);
+                    mTempRect.offset(0, mYOffsetForIme);
+                    t.setPosition(dividerLeash, mTempRect.left, mTempRect.top);
+                }
 
-            if (dividerLeash != null) {
-                mTempRect.set(mDividerBounds);
+                mTempRect.set(mBounds1);
                 mTempRect.offset(0, mYOffsetForIme);
-                t.setPosition(dividerLeash, mTempRect.left, mTempRect.top);
+                t.setPosition(leash1, mTempRect.left, mTempRect.top);
+
+                mTempRect.set(mBounds2);
+                mTempRect.offset(0, mYOffsetForIme);
+                t.setPosition(leash2, mTempRect.left, mTempRect.top);
+                adjusted = true;
             }
 
-            mTempRect.set(mBounds1);
-            mTempRect.offset(0, mYOffsetForIme);
-            t.setPosition(leash1, mTempRect.left, mTempRect.top);
-
-            mTempRect.set(mBounds2);
-            mTempRect.offset(0, mYOffsetForIme);
-            t.setPosition(leash2, mTempRect.left, mTempRect.top);
-
-            t.setAlpha(dimLayer1, mDimValue1).setVisibility(dimLayer1, mDimValue1 > 0.001f);
-            t.setAlpha(dimLayer2, mDimValue2).setVisibility(dimLayer2, mDimValue2 > 0.001f);
-
-            return true;
+            if (showDim) {
+                t.setAlpha(dimLayer1, mDimValue1).setVisibility(dimLayer1, mDimValue1 > 0.001f);
+                t.setAlpha(dimLayer2, mDimValue2).setVisibility(dimLayer2, mDimValue2 > 0.001f);
+                adjusted = true;
+            }
+            return adjusted;
         }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index e511bff..3ab0624 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -43,6 +43,7 @@
 import android.view.Surface;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
+import android.window.WindowContainerTransaction;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -64,7 +65,8 @@
 /**
  * Manages and manipulates the one handed states, transitions, and gesture for phones.
  */
-public class OneHandedController implements RemoteCallable<OneHandedController> {
+public class OneHandedController implements RemoteCallable<OneHandedController>,
+        DisplayChangeController.OnDisplayChangingListener {
     private static final String TAG = "OneHandedController";
 
     private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
@@ -106,19 +108,6 @@
     private OneHandedBackgroundPanelOrganizer mBackgroundPanelOrganizer;
     private OneHandedUiEventLogger mOneHandedUiEventLogger;
 
-    /**
-     * Handle rotation based on OnDisplayChangingListener callback
-     */
-    private final DisplayChangeController.OnDisplayChangingListener mRotationController =
-            (display, fromRotation, toRotation, wct) -> {
-                if (!isInitialized()) {
-                    return;
-                }
-                mDisplayAreaOrganizer.onRotateDisplay(mContext, toRotation, wct);
-                mOneHandedUiEventLogger.writeEvent(
-                        OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_ROTATION_OUT);
-            };
-
     private final DisplayController.OnDisplaysChangedListener mDisplaysChangedListener =
             new DisplayController.OnDisplaysChangedListener() {
                 @Override
@@ -296,7 +285,7 @@
                 getObserver(this::onSwipeToNotificationEnabledChanged);
         mShortcutEnabledObserver = getObserver(this::onShortcutEnabledChanged);
 
-        mDisplayController.addDisplayChangingController(mRotationController);
+        mDisplayController.addDisplayChangingController(this);
         setupCallback();
         registerSettingObservers(mUserId);
         setupTimeoutListener();
@@ -745,6 +734,27 @@
     }
 
     /**
+     * Handles rotation based on OnDisplayChangingListener callback
+     */
+    @Override
+    public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
+            WindowContainerTransaction wct) {
+        if (!isInitialized()) {
+            return;
+        }
+
+        if (!mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled(mContext.getContentResolver(),
+                mUserId) || mOneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
+                mContext.getContentResolver(), mUserId)) {
+            return;
+        }
+
+        mDisplayAreaOrganizer.onRotateDisplay(mContext, toRotation, wct);
+        mOneHandedUiEventLogger.writeEvent(
+                OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_ROTATION_OUT);
+    }
+
+    /**
      * The interface for calls from outside the Shell, within the host process.
      */
     @ExternalThread
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index c2bbd9e..1b2f476 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -16,8 +16,6 @@
 
 package com.android.wm.shell.onehanded;
 
-import static android.os.UserHandle.myUserId;
-
 import static com.android.wm.shell.onehanded.OneHandedAnimationController.TRANSITION_DIRECTION_EXIT;
 import static com.android.wm.shell.onehanded.OneHandedAnimationController.TRANSITION_DIRECTION_TRIGGER;
 
@@ -186,20 +184,8 @@
         if (mDisplayLayout.rotation() == toRotation) {
             return;
         }
-
-        if (!mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled(context.getContentResolver(),
-                myUserId())) {
-            return;
-        }
-
         mDisplayLayout.rotateTo(context.getResources(), toRotation);
         updateDisplayBounds();
-
-        if (mOneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
-                context.getContentResolver(), myUserId())) {
-            // If current settings is swipe notification, skip finishOffset.
-            return;
-        }
         finishOffset(0, TRANSITION_DIRECTION_EXIT);
     }
 
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 ac02075..8e5c5c5 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
@@ -315,13 +315,13 @@
         mOneHandedController = oneHandedController;
         mPipTransitionController = pipTransitionController;
         mTaskStackListener = taskStackListener;
-        mPipInputConsumer = new PipInputConsumer(WindowManagerGlobal.getWindowManagerService(),
-                INPUT_CONSUMER_PIP, mainExecutor);
         //TODO: move this to ShellInit when PipController can be injected
         mMainExecutor.execute(this::init);
     }
 
     public void init() {
+        mPipInputConsumer = new PipInputConsumer(WindowManagerGlobal.getWindowManagerService(),
+                INPUT_CONSUMER_PIP, mMainExecutor);
         mPipTransitionController.registerPipTransitionCallback(this);
         mPipTaskOrganizer.registerOnDisplayIdChangeCallback((int displayId) -> {
             mPipBoundsState.setDisplayId(displayId);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index 82092ac..0fbdf90 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -20,6 +20,7 @@
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Insets;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -30,6 +31,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.widget.FrameLayout;
 
@@ -93,6 +95,7 @@
     private int mTargetSize;
     private int mDismissAreaHeight;
     private float mMagneticFieldRadiusPercent = 1f;
+    private WindowInsets mWindowInsets;
 
     private SurfaceControl mTaskLeash;
     private boolean mHasDismissTargetSurface;
@@ -123,6 +126,13 @@
                 mContext.getDrawable(R.drawable.floating_dismiss_gradient_transition));
         mTargetViewContainer.setClipChildren(false);
         mTargetViewContainer.addView(mTargetView);
+        mTargetViewContainer.setOnApplyWindowInsetsListener((view, windowInsets) -> {
+            if (!windowInsets.equals(mWindowInsets)) {
+                mWindowInsets = windowInsets;
+                updateMagneticTargetSize();
+            }
+            return windowInsets;
+        });
 
         mMagnetizedPip = mMotionHelper.getMagnetizedPip();
         mMagneticTarget = mMagnetizedPip.addTarget(mTargetView, 0);
@@ -201,10 +211,13 @@
         final Resources res = mContext.getResources();
         mTargetSize = res.getDimensionPixelSize(R.dimen.dismiss_circle_size);
         mDismissAreaHeight = res.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height);
+        final WindowInsets insets = mWindowManager.getCurrentWindowMetrics().getWindowInsets();
+        final Insets navInset = insets.getInsetsIgnoringVisibility(
+                WindowInsets.Type.navigationBars());
         final FrameLayout.LayoutParams newParams =
                 new FrameLayout.LayoutParams(mTargetSize, mTargetSize);
         newParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
-        newParams.bottomMargin = mContext.getResources().getDimensionPixelSize(
+        newParams.bottomMargin = navInset.bottom + mContext.getResources().getDimensionPixelSize(
                 R.dimen.floating_dismiss_bottom_margin);
         mTargetView.setLayoutParams(newParams);
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 3538fd2..979aa1f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.startingsurface;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.graphics.Color.WHITE;
 import static android.graphics.Color.alpha;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
@@ -314,6 +315,12 @@
     }
 
     void scheduleRemove(Runnable onRemove) {
+        // Show the latest content as soon as possible for unlocking to home.
+        if (mActivityType == ACTIVITY_TYPE_HOME) {
+            removeImmediately();
+            onRemove.run();
+            return;
+        }
         if (mScheduledRunnable != null) {
             mSplashScreenExecutor.removeCallbacks(mScheduledRunnable);
             mScheduledRunnable = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
index e6d6028..bde2b5f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
@@ -71,23 +71,13 @@
                     + " topIsHome:" + topIsHome);
         }
 
-        final int visibleSplashScreenType = legacySplashScreen
-                ? STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN
-                : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
-
         if (!topIsHome) {
-            if (!processRunning) {
+            if (!processRunning || newTask || (taskSwitch && !activityCreated)) {
                 return useEmptySplashScreen
                         ? STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN
-                        : visibleSplashScreenType;
-            }
-            if (newTask) {
-                return useEmptySplashScreen
-                        ? STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN
-                        : visibleSplashScreenType;
-            }
-            if (taskSwitch && !activityCreated) {
-                return visibleSplashScreenType;
+                        : legacySplashScreen
+                                ? STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN
+                                : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
             }
         }
         if (taskSwitch && allowTaskSnapshot) {
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 4ba6aca..b673d48 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
@@ -141,8 +141,9 @@
     static boolean isRotationSeamless(@NonNull TransitionInfo info,
             DisplayController displayController) {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
-                "Display is rotating, check if it should be seamless.");
+                "Display is changing, check if it should be seamless.");
         boolean checkedDisplayLayout = false;
+        boolean hasTask = false;
         for (int i = info.getChanges().size() - 1; i >= 0; --i) {
             final TransitionInfo.Change change = info.getChanges().get(i);
 
@@ -166,6 +167,7 @@
                     return false;
                 }
             } else if (change.getTaskInfo() != null) {
+                hasTask = true;
                 // We only enable seamless rotation if all the visible task windows requested it.
                 if (change.getRotationAnimation() != ROTATION_ANIMATION_SEAMLESS) {
                     ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
@@ -209,8 +211,12 @@
             }
         }
 
-        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  Rotation IS seamless.");
-        return true;
+        // ROTATION_ANIMATION_SEAMLESS can only be requested by task.
+        if (hasTask) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  Rotation IS seamless.");
+            return true;
+        }
+        return false;
     }
 
     /**
@@ -280,7 +286,6 @@
             final TransitionInfo.Change change = info.getChanges().get(i);
 
             if (info.getType() == TRANSIT_CHANGE && change.getMode() == TRANSIT_CHANGE
-                    && (change.getEndRotation() != change.getStartRotation())
                     && (change.getFlags() & FLAG_IS_DISPLAY) != 0) {
                 boolean isSeamless = isRotationSeamless(info, mDisplayController);
                 final int anim = getRotationAnimation(info);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index ada2ed2..13c670a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -186,11 +186,11 @@
             t.setAlpha(mBackColorSurface, 1);
             t.show(mBackColorSurface);
 
+            t.setLayer(mAnimLeash, SCREEN_FREEZE_LAYER_BASE);
             t.setPosition(mAnimLeash, 0, 0);
             t.setAlpha(mAnimLeash, 1);
             t.show(mAnimLeash);
 
-            t.setLayer(mScreenshotLayer, SCREEN_FREEZE_LAYER_BASE);
             t.setBuffer(mScreenshotLayer, buffer);
             t.setColorSpace(mScreenshotLayer, screenshotBuffer.getColorSpace());
             t.show(mScreenshotLayer);
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
index d66a6e7..322d8b5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
@@ -31,6 +31,7 @@
 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.SYSTEMUI_PACKAGE
 import com.android.server.wm.flicker.repetitions
 import com.android.wm.shell.flicker.helpers.LaunchBubbleHelper
 import org.junit.Test
@@ -53,6 +54,7 @@
             testApp.component.packageName, 0).uid
 
     protected lateinit var addBubbleBtn: UiObject2
+    protected lateinit var cancelAllBtn: UiObject2
 
     protected abstract val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
 
@@ -69,6 +71,8 @@
                     testApp.launchViaIntent(wmHelper)
                     addBubbleBtn = device.wait(Until.findObject(
                             By.text("Add Bubble")), FIND_OBJECT_TIMEOUT)
+                    cancelAllBtn = device.wait(Until.findObject(
+                            By.text("Cancel All Bubble")), FIND_OBJECT_TIMEOUT)
                 }
             }
 
@@ -108,5 +112,7 @@
         }
 
         const val FIND_OBJECT_TIMEOUT = 2000L
+        const val SYSTEM_UI_PACKAGE = SYSTEMUI_PACKAGE
+        const val BUBBLE_RES_NAME = "bubble_view"
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
new file mode 100644
index 0000000..bfdcb36
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.bubble
+
+import android.content.Context
+import android.graphics.Point
+import android.util.DisplayMetrics
+import android.view.WindowManager
+import androidx.test.filters.RequiresDevice
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group4
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Test launching a new activity from bubble.
+ *
+ * To run this test: `atest WMShellFlickerTests:DismissBubbleScreen`
+ *
+ * Actions:
+ *     Dismiss a bubble notification
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@Group4
+class DismissBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+
+    val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
+    val displaySize = DisplayMetrics()
+
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = buildTransition() {
+            setup {
+                eachRun {
+                    addBubbleBtn?.run { addBubbleBtn.click() } ?: error("Add Bubble not found")
+                }
+            }
+            transitions {
+                wm?.run { wm.getDefaultDisplay().getMetrics(displaySize) } ?: error("WM not found")
+                val dist = Point((displaySize.widthPixels / 2), displaySize.heightPixels)
+                val showBubble = device.wait(Until.findObject(
+                        By.res(SYSTEM_UI_PACKAGE, BUBBLE_RES_NAME)), FIND_OBJECT_TIMEOUT)
+                showBubble?.run { drag(dist, 1000) } ?: error("Show bubble not found")
+            }
+        }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
new file mode 100644
index 0000000..194e28f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
@@ -0,0 +1,66 @@
+/*
+ * 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.bubble
+
+import android.os.SystemClock
+import androidx.test.filters.RequiresDevice
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group4
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Test launching a new activity from bubble.
+ *
+ * To run this test: `atest WMShellFlickerTests:MultiBubblesScreen`
+ *
+ * Actions:
+ *     Switch in different bubble notifications
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@Group4
+class MultiBubblesScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = buildTransition() {
+            setup {
+                test {
+                    for (i in 1..3) {
+                        addBubbleBtn?.run { addBubbleBtn.click() } ?: error("Add Bubble not found")
+                    }
+                    val showBubble = device.wait(Until.findObject(
+                            By.res(SYSTEM_UI_PACKAGE, BUBBLE_RES_NAME)), FIND_OBJECT_TIMEOUT)
+                    showBubble?.run { showBubble.click() } ?: error("Show bubble not found")
+                    SystemClock.sleep(1000)
+                }
+            }
+            transitions {
+                val bubbles = device.wait(Until.findObjects(
+                        By.res(SYSTEM_UI_PACKAGE, BUBBLE_RES_NAME)), FIND_OBJECT_TIMEOUT)
+                for (entry in bubbles) {
+                    entry?.run { entry.click() } ?: error("Bubble not found")
+                    SystemClock.sleep(1000)
+                }
+            }
+        }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
index 92867da..73626c2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
@@ -16,8 +16,6 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.platform.test.annotations.Postsubmit
-import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -26,7 +24,6 @@
 import com.android.server.wm.flicker.annotation.Group3
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import org.junit.FixMethodOrder
-import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
@@ -63,14 +60,6 @@
             }
         }
 
-    @Presubmit
-    @Test
-    override fun pipLayerBecomesInvisible() = super.pipLayerBecomesInvisible()
-
-    @Postsubmit
-    @Test
-    override fun pipWindowBecomesInvisible() = super.pipWindowBecomesInvisible()
-
     companion object {
         /**
          * Creates the test configurations.
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_main.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_main.xml
index 5c7b18e..f23c464 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_main.xml
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_main.xml
@@ -14,15 +14,35 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:orientation="vertical"
     android:background="@android:color/black">
 
         <Button
             android:id="@+id/button_create"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_gravity="center"
+            android:layout_centerHorizontal="true"
+            android:layout_centerVertical="true"
             android:text="Add Bubble" />
-</FrameLayout>
+
+        <Button
+            android:id="@+id/button_cancel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/button_create"
+            android:layout_centerHorizontal="true"
+            android:layout_marginTop="20dp"
+            android:text="Cancel Bubble" />
+
+        <Button
+            android:id="@+id/button_cancel_all"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/button_cancel"
+            android:layout_centerHorizontal="true"
+            android:layout_marginTop="20dp"
+            android:text="Cancel All Bubble" />
+</RelativeLayout>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleHelper.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleHelper.java
index d72c8d5..d743dff 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleHelper.java
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleHelper.java
@@ -28,6 +28,7 @@
 import android.graphics.Point;
 import android.graphics.drawable.Icon;
 import android.os.SystemClock;
+import android.service.notification.StatusBarNotification;
 import android.view.WindowManager;
 
 import java.util.HashMap;
@@ -151,4 +152,27 @@
                 .setIcon(info.icon)
                 .setDesiredHeight(info.height);
     }
-}
\ No newline at end of file
+
+    public void cancel(int id) {
+        mNotificationManager.cancel(id);
+    }
+
+    public void cancelAll() {
+        mNotificationManager.cancelAll();
+    }
+
+    public void cancelLast() {
+        StatusBarNotification[] activeNotifications = mNotificationManager.getActiveNotifications();
+        if (activeNotifications.length > 0) {
+            mNotificationManager.cancel(
+                    activeNotifications[activeNotifications.length - 1].getId());
+        }
+    }
+
+    public void cancelFirst() {
+        StatusBarNotification[] activeNotifications = mNotificationManager.getActiveNotifications();
+        if (activeNotifications.length > 0) {
+            mNotificationManager.cancel(activeNotifications[0].getId());
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/LaunchBubbleActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/LaunchBubbleActivity.java
index c55f9d7..71fa66d 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/LaunchBubbleActivity.java
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/LaunchBubbleActivity.java
@@ -25,7 +25,6 @@
 import android.content.pm.ShortcutManager;
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
-import android.os.Handler;
 import android.view.View;
 
 import java.util.Arrays;
@@ -41,12 +40,22 @@
         mBubbleHelper = BubbleHelper.getInstance(this);
         setContentView(R.layout.activity_main);
         findViewById(R.id.button_create).setOnClickListener(this::add);
+        findViewById(R.id.button_cancel).setOnClickListener(this::cancel);
+        findViewById(R.id.button_cancel_all).setOnClickListener(this::cancelAll);
     }
 
     private void add(View v) {
         mBubbleHelper.addNewBubble(false /* autoExpand */, false /* suppressNotif */);
     }
 
+    private void cancel(View v) {
+        mBubbleHelper.cancelLast();
+    }
+
+    private void cancelAll(View v) {
+        mBubbleHelper.cancelAll();
+    }
+
     private void addInboxShortcut(Context context) {
         Icon icon = Icon.createWithResource(this, R.drawable.bg);
         Person[] persons = new Person[4];
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index 911fe07..0a3a849 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -42,6 +42,7 @@
 import android.view.Display;
 import android.view.Surface;
 import android.view.SurfaceControl;
+import android.window.WindowContainerTransaction;
 
 import androidx.test.filters.SmallTest;
 
@@ -332,6 +333,58 @@
     }
 
     @Test
+    public void testOneHandedEnabledRotation90ShouldHandleRotate() {
+        when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn(true);
+        when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
+                false);
+        final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
+        mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
+                Surface.ROTATION_90, handlerWCT);
+
+        verify(mMockDisplayAreaOrganizer, atLeastOnce()).onRotateDisplay(eq(mContext),
+                eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
+    }
+
+    @Test
+    public void testOneHandedDisabledRotation90ShouldNotHandleRotate() {
+        when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn(false);
+        when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
+                false);
+        final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
+        mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
+                Surface.ROTATION_90, handlerWCT);
+
+        verify(mMockDisplayAreaOrganizer, never()).onRotateDisplay(eq(mContext),
+                eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
+    }
+
+    @Test
+    public void testSwipeToNotificationEnabledRotation90ShouldNotHandleRotate() {
+        when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn(true);
+        when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
+                true);
+        final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
+        mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
+                Surface.ROTATION_90, handlerWCT);
+
+        verify(mMockDisplayAreaOrganizer, never()).onRotateDisplay(eq(mContext),
+                eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
+    }
+
+    @Test
+    public void testSwipeToNotificationDisabledRotation90ShouldHandleRotate() {
+        when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn(true);
+        when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
+                false);
+        final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
+        mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
+                Surface.ROTATION_90, handlerWCT);
+
+        verify(mMockDisplayAreaOrganizer, atLeastOnce()).onRotateDisplay(eq(mContext),
+                eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
+    }
+
+    @Test
     public void testStateActive_shortcutRequestActivate_skipActions() {
         when(mSpiedTransitionState.getState()).thenReturn(STATE_ACTIVE);
         when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index b0f0d71..e391713 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -583,6 +583,13 @@
                         .setRotate(ROTATION_ANIMATION_SEAMLESS).build())
                 .build();
         assertFalse(DefaultTransitionHandler.isRotationSeamless(seamlessButAlert, displays));
+
+        // Not seamless if there is no changed task.
+        final TransitionInfo noTask = new TransitionInfoBuilder(TRANSIT_CHANGE)
+                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY)
+                        .setRotate().build())
+                .build();
+        assertFalse(DefaultTransitionHandler.isRotationSeamless(noTask, displays));
     }
 
     class TransitionInfoBuilder {
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 9cf300c..513ad9a 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -50,6 +50,7 @@
 bool Properties::skipEmptyFrames = true;
 bool Properties::useBufferAge = true;
 bool Properties::enablePartialUpdates = true;
+bool Properties::enableRenderEffectCache = false;
 
 DebugLevel Properties::debugLevel = kDebugDisabled;
 OverdrawColorSet Properties::overdrawColorSet = OverdrawColorSet::Default;
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 7f9782b..2f8c679 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -232,6 +232,7 @@
     static bool skipEmptyFrames;
     static bool useBufferAge;
     static bool enablePartialUpdates;
+    static bool enableRenderEffectCache;
 
     // TODO: Move somewhere else?
     static constexpr float textGamma = 1.45f;
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 7556af9..2c81c97 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -231,14 +231,34 @@
             SkASSERT(properties.effectiveLayerType() == LayerType::RenderLayer);
             SkPaint paint;
             layerNeedsPaint(layerProperties, alphaMultiplier, &paint);
-            const auto snapshotResult = renderNode->updateSnapshotIfRequired(
-                canvas->recordingContext(),
-                layerProperties.getImageFilter(),
-                clipBounds.roundOut()
-            );
-            sk_sp<SkImage> snapshotImage = snapshotResult->snapshot;
-            srcBounds = snapshotResult->outSubset;
-            offset = snapshotResult->outOffset;
+            sk_sp<SkImage> snapshotImage;
+            auto* imageFilter = layerProperties.getImageFilter();
+            auto recordingContext = canvas->recordingContext();
+            // On some GL vendor implementations, caching the result of
+            // getLayerSurface->makeImageSnapshot() causes a call to
+            // Fence::waitForever without a corresponding signal. This would
+            // lead to ANRs throughout the system.
+            // Instead only cache the SkImage created with the SkImageFilter
+            // for supported devices. Otherwise just create a new SkImage with
+            // the corresponding SkImageFilter each time.
+            // See b/193145089 and b/197263715
+            if (!Properties::enableRenderEffectCache) {
+                if (imageFilter) {
+                    auto subset = SkIRect::MakeWH(srcBounds.width(), srcBounds.height());
+                    snapshotImage = snapshotImage->makeWithFilter(recordingContext, imageFilter,
+                                                                  subset, clipBounds.roundOut(),
+                                                                  &srcBounds, &offset);
+                } else {
+                    snapshotImage = renderNode->getLayerSurface()->makeImageSnapshot();
+                }
+            } else {
+                const auto snapshotResult = renderNode->updateSnapshotIfRequired(
+                        recordingContext, layerProperties.getImageFilter(), clipBounds.roundOut());
+                snapshotImage = snapshotResult->snapshot;
+                srcBounds = snapshotResult->outSubset;
+                offset = snapshotResult->outOffset;
+            }
+
             const auto dstBounds = SkIRect::MakeXYWH(offset.x(),
                                                      offset.y(),
                                                      srcBounds.width(),
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index a116781..383c79b 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -146,6 +146,9 @@
         LOG_ALWAYS_FATAL("Unsupported wide color space.");
     }
     mHasWideColorGamutSupport = EglExtensions.glColorSpace && hasWideColorSpaceExtension;
+
+    auto* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
+    Properties::enableRenderEffectCache = (strcmp(vendor, "Qualcomm") != 0);
 }
 
 EGLConfig EglManager::load8BitsConfig(EGLDisplay display, EglManager::SwapBehavior swapBehavior) {
diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java
index 51586d7..e4a0d0c 100644
--- a/location/java/android/location/Geocoder.java
+++ b/location/java/android/location/Geocoder.java
@@ -16,8 +16,11 @@
 
 package android.location;
 
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
-import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 
@@ -27,24 +30,21 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 /**
- * A class for handling geocoding and reverse geocoding.  Geocoding is
- * the process of transforming a street address or other description
- * of a location into a (latitude, longitude) coordinate.  Reverse
- * geocoding is the process of transforming a (latitude, longitude)
- * coordinate into a (partial) address.  The amount of detail in a
- * reverse geocoded location description may vary, for example one
- * might contain the full street address of the closest building, while
- * another might contain only a city name and postal code.
+ * A class for handling geocoding and reverse geocoding. Geocoding is the process of transforming a
+ * street address or other description of a location into a (latitude, longitude) coordinate.
+ * Reverse geocoding is the process of transforming a (latitude, longitude) coordinate into a
+ * (partial) address. The amount of detail in a reverse geocoded location description may vary, for
+ * example one might contain the full street address of the closest building, while another might
+ * contain only a city name and postal code.
  *
- * The Geocoder class requires a backend service that is not included in
- * the core android framework.  The Geocoder query methods will return an
- * empty list if there no backend service in the platform.  Use the
- * isPresent() method to determine whether a Geocoder implementation
- * exists.
+ * The Geocoder class requires a backend service that is not included in the core android framework.
+ * The Geocoder query methods will return an empty list if there no backend service in the platform.
+ * Use the isPresent() method to determine whether a Geocoder implementation exists.
  *
  * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
  * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful or
@@ -52,20 +52,26 @@
  */
 public final class Geocoder {
 
+    /** A listener for asynchronous geocoding results. */
+    public interface GeocodeListener {
+        /** Invoked when geocoding completes successfully. May return an empty list. */
+        void onGeocode(@NonNull List<Address> addresses);
+        /** Invoked when geocoding fails, with a brief error message. */
+        default void onError(@Nullable String errorMessage) {}
+    }
+
     private static final long TIMEOUT_MS = 60000;
 
     private final GeocoderParams mParams;
     private final ILocationManager mService;
 
     /**
-     * Returns true if the Geocoder methods getFromLocation and
-     * getFromLocationName are implemented.  Lack of network
-     * connectivity may still cause these methods to return null or
-     * empty lists.
+     * Returns true if there is a geocoder implementation present that may return results. If true,
+     * there is still no guarantee that any individual geocoding attempt will succeed.
      */
     public static boolean isPresent() {
-        IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
-        ILocationManager lm = ILocationManager.Stub.asInterface(b);
+        ILocationManager lm = Objects.requireNonNull(ILocationManager.Stub.asInterface(
+                ServiceManager.getService(Context.LOCATION_SERVICE)));
         try {
             return lm.geocoderIsPresent();
         } catch (RemoteException e) {
@@ -74,40 +80,35 @@
     }
 
     /**
-     * Constructs a Geocoder whose responses will be localized for the
-     * given Locale.
-     *
-     * @param context the Context of the calling Activity
-     * @param locale the desired Locale for the query results
-     *
-     * @throws NullPointerException if Locale is null
+     * Constructs a Geocoder localized for the default locale.
      */
-    public Geocoder(Context context, Locale locale) {
+    public Geocoder(@NonNull Context context) {
+        this(context, Locale.getDefault());
+    }
+
+    /**
+     * Constructs a Geocoder localized for the given locale.
+     */
+    public Geocoder(@NonNull Context context, @NonNull Locale locale) {
         mParams = new GeocoderParams(context, locale);
         mService = ILocationManager.Stub.asInterface(
                 ServiceManager.getService(Context.LOCATION_SERVICE));
     }
 
     /**
-     * Constructs a Geocoder whose responses will be localized for the
-     * default system Locale.
-     *
-     * @param context the Context of the calling Activity
-     */
-    public Geocoder(Context context) {
-        this(context, Locale.getDefault());
-    }
-
-    /**
      * Returns an array of Addresses that attempt to describe the area immediately surrounding the
      * given latitude and longitude. The returned addresses should be localized for the locale
-     * provided to this class's constructor. Results may be obtained by means of a network lookup
-     * and this method may take some time to return, and so should not be called on the main thread.
+     * provided to this class's constructor.
      *
-     * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
+     * <p class="warning"><strong>Warning:</strong> Geocoding services may provide no guarantees on
      * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
      * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
-     * purposes.
+     * purposes.</p>
+     *
+     * <p class="warning"><strong>Warning:</strong> This API may hit the network, and may block for
+     * excessive amounts of time, up to 60 seconds or more. It's strongly encouraged to use the
+     * asynchronous version of this API. If that is not possible, this should be run on a background
+     * thread to avoid blocking other operations.</p>
      *
      * @param latitude the latitude a point for the search
      * @param longitude the longitude a point for the search
@@ -116,22 +117,51 @@
      * @return a list of Address objects. Returns null or empty list if no matches were
      * found or there is no backend service available.
      *
-     * @throws IllegalArgumentException if latitude is
-     * less than -90 or greater than 90
-     * @throws IllegalArgumentException if longitude is
-     * less than -180 or greater than 180
-     * @throws IOException if the network is unavailable or any other
-     * I/O problem occurs
+     * @throws IllegalArgumentException if latitude or longitude is invalid
+     * @throws IOException if there is a failure
+     *
+     * @deprecated Use {@link #getFromLocation(double, double, int, GeocodeListener)} instead to
+     * avoid blocking a thread waiting for results.
      */
-    public List<Address> getFromLocation(double latitude, double longitude, int maxResults)
+    @Deprecated
+    public @Nullable List<Address> getFromLocation(
+            @FloatRange(from = -90D, to = 90D) double latitude,
+            @FloatRange(from = -180D, to = 180D)double longitude,
+            @IntRange int maxResults)
             throws IOException {
+        SynchronousGeocoder listener = new SynchronousGeocoder();
+        getFromLocation(latitude, longitude, maxResults, listener);
+        return listener.getResults();
+    }
+
+    /**
+     * Provides an array of Addresses that attempt to describe the area immediately surrounding the
+     * given latitude and longitude. The returned addresses should be localized for the locale
+     * provided to this class's constructor.
+     *
+     * <p class="warning"><strong>Warning:</strong> Geocoding services may provide no guarantees on
+     * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
+     * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
+     * purposes.</p>
+     *
+     * @param latitude the latitude a point for the search
+     * @param longitude the longitude a point for the search
+     * @param maxResults max number of addresses to return. Smaller numbers (1 to 5) are recommended
+     * @param listener a listener for receiving results
+     *
+     * @throws IllegalArgumentException if latitude or longitude is invalid
+     */
+    public void getFromLocation(
+            @FloatRange(from = -90D, to = 90D) double latitude,
+            @FloatRange(from = -180D, to = 180D) double longitude,
+            @IntRange int maxResults,
+            @NonNull GeocodeListener listener) {
         Preconditions.checkArgumentInRange(latitude, -90.0, 90.0, "latitude");
         Preconditions.checkArgumentInRange(longitude, -180.0, 180.0, "longitude");
 
         try {
-            GeocodeListener listener = new GeocodeListener();
-            mService.getFromLocation(latitude, longitude, maxResults, mParams, listener);
-            return listener.getResults();
+            mService.getFromLocation(latitude, longitude, maxResults, mParams,
+                    new GeocoderImpl(listener));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -141,14 +171,17 @@
      * Returns an array of Addresses that attempt to describe the named location, which may be a
      * place name such as "Dalvik, Iceland", an address such as "1600 Amphitheatre Parkway, Mountain
      * View, CA", an airport code such as "SFO", and so forth. The returned addresses should be
-     * localized for the locale provided to this class's constructor. Results may be obtained by
-     * means of a network lookup and this method may take some time to return, and so should not be
-     * called on the main thread.
+     * localized for the locale provided to this class's constructor.
      *
      * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
      * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
      * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
-     * purposes.
+     * purposes.</p>
+     *
+     * <p class="warning"><strong>Warning:</strong> This API may hit the network, and may block for
+     * excessive amounts of time, up to 60 seconds or more. It's strongly encouraged to use the
+     * asynchronous version of this API. If that is not possible, this should be run on a background
+     * thread to avoid blocking other operations.</p>
      *
      * @param locationName a user-supplied description of a location
      * @param maxResults max number of results to return. Smaller numbers (1 to 5) are recommended
@@ -157,20 +190,47 @@
      * found or there is no backend service available.
      *
      * @throws IllegalArgumentException if locationName is null
-     * @throws IOException if the network is unavailable or any other
-     * I/O problem occurs
+     * @throws IOException if there is a failure
+     *
+     * @deprecated Use {@link #getFromLocationName(String, int, GeocodeListener)} instead to avoid
+     * blocking a thread waiting for results.
      */
-    public List<Address> getFromLocationName(String locationName, int maxResults) throws IOException {
+    @Deprecated
+    public @Nullable List<Address> getFromLocationName(
+            @NonNull String locationName,
+            @IntRange int maxResults) throws IOException {
         return getFromLocationName(locationName, maxResults, 0, 0, 0, 0);
     }
 
     /**
+     * Provides an array of Addresses that attempt to describe the named location, which may be a
+     * place name such as "Dalvik, Iceland", an address such as "1600 Amphitheatre Parkway, Mountain
+     * View, CA", an airport code such as "SFO", and so forth. The returned addresses should be
+     * localized for the locale provided to this class's constructor.
+     *
+     * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
+     * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
+     * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
+     * purposes.</p>
+     *
+     * @param locationName a user-supplied description of a location
+     * @param maxResults max number of results to return. Smaller numbers (1 to 5) are recommended
+     * @param listener a listener for receiving results
+     *
+     * @throws IllegalArgumentException if locationName is null
+     */
+    public void getFromLocationName(
+            @NonNull String locationName,
+            @IntRange int maxResults,
+            @NonNull GeocodeListener listener) {
+        getFromLocationName(locationName, maxResults, 0, 0, 0, 0, listener);
+    }
+
+    /**
      * Returns an array of Addresses that attempt to describe the named location, which may be a
      * place name such as "Dalvik, Iceland", an address such as "1600 Amphitheatre Parkway, Mountain
      * View, CA", an airport code such as "SFO", and so forth. The returned addresses should be
-     * localized for the locale provided to this class's constructor. Results may be obtained by
-     * means of a network lookup and this method may take some time to return, and so should not be
-     * called on the main thread.
+     * localized for the locale provided to this class's constructor.
      *
      * <p> You may specify a bounding box for the search results by including the latitude and
      * longitude of the lower left point and upper right point of the box.
@@ -178,29 +238,78 @@
      * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
      * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
      * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
-     * purposes.
+     * purposes.</p>
      *
-     * @param locationName a user-supplied description of a location
-     * @param maxResults max number of addresses to return. Smaller numbers (1 to 5) are recommended
-     * @param lowerLeftLatitude the latitude of the lower left corner of the bounding box
-     * @param lowerLeftLongitude the longitude of the lower left corner of the bounding box
-     * @param upperRightLatitude the latitude of the upper right corner of the bounding box
+     * <p class="warning"><strong>Warning:</strong> This API may hit the network, and may block for
+     * excessive amounts of time, up to 60 seconds or more. It's strongly encouraged to use the
+     * asynchronous version of this API. If that is not possible, this should be run on a background
+     * thread to avoid blocking other operations.</p>
+     *
+     * @param locationName        a user-supplied description of a location
+     * @param maxResults          max number of addresses to return. Smaller numbers (1 to 5) are
+     *                            recommended
+     * @param lowerLeftLatitude   the latitude of the lower left corner of the bounding box
+     * @param lowerLeftLongitude  the longitude of the lower left corner of the bounding box
+     * @param upperRightLatitude  the latitude of the upper right corner of the bounding box
      * @param upperRightLongitude the longitude of the upper right corner of the bounding box
      *
      * @return a list of Address objects. Returns null or empty list if no matches were
      * found or there is no backend service available.
      *
      * @throws IllegalArgumentException if locationName is null
-     * @throws IllegalArgumentException if any latitude is
-     * less than -90 or greater than 90
-     * @throws IllegalArgumentException if any longitude is
-     * less than -180 or greater than 180
-     * @throws IOException if the network is unavailable or any other
-     * I/O problem occurs
+     * @throws IllegalArgumentException if any latitude or longitude is invalid
+     * @throws IOException              if there is a failure
+     *
+     * @deprecated Use {@link #getFromLocationName(String, int, double, double, double, double,
+     * GeocodeListener)} instead to avoid blocking a thread waiting for results.
      */
-    public List<Address> getFromLocationName(String locationName, int maxResults,
-            double lowerLeftLatitude, double lowerLeftLongitude, double upperRightLatitude,
-            double upperRightLongitude) throws IOException {
+    @Deprecated
+    public @Nullable List<Address> getFromLocationName(
+            @NonNull String locationName,
+            @IntRange int maxResults,
+            @FloatRange(from = -90D, to = 90D) double lowerLeftLatitude,
+            @FloatRange(from = -180D, to = 180D) double lowerLeftLongitude,
+            @FloatRange(from = -90D, to = 90D) double upperRightLatitude,
+            @FloatRange(from = -180D, to = 180D) double upperRightLongitude) throws IOException {
+        SynchronousGeocoder listener = new SynchronousGeocoder();
+        getFromLocationName(locationName, maxResults, lowerLeftLatitude, lowerLeftLongitude,
+                upperRightLatitude, upperRightLongitude, listener);
+        return listener.getResults();
+    }
+
+    /**
+     * Returns an array of Addresses that attempt to describe the named location, which may be a
+     * place name such as "Dalvik, Iceland", an address such as "1600 Amphitheatre Parkway, Mountain
+     * View, CA", an airport code such as "SFO", and so forth. The returned addresses should be
+     * localized for the locale provided to this class's constructor.
+     *
+     * <p> You may specify a bounding box for the search results by including the latitude and
+     * longitude of the lower left point and upper right point of the box.
+     *
+     * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
+     * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
+     * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
+     * purposes.</p>
+     *
+     * @param locationName        a user-supplied description of a location
+     * @param maxResults          max number of addresses to return. Smaller numbers (1 to 5) are
+     *                            recommended
+     * @param lowerLeftLatitude   the latitude of the lower left corner of the bounding box
+     * @param lowerLeftLongitude  the longitude of the lower left corner of the bounding box
+     * @param upperRightLatitude  the latitude of the upper right corner of the bounding box
+     * @param upperRightLongitude the longitude of the upper right corner of the bounding box
+     *
+     * @throws IllegalArgumentException if locationName is null
+     * @throws IllegalArgumentException if any latitude or longitude is invalid
+     */
+    public void getFromLocationName(
+            @NonNull String locationName,
+            @IntRange int maxResults,
+            @FloatRange(from = -90D, to = 90D) double lowerLeftLatitude,
+            @FloatRange(from = -180D, to = 180D) double lowerLeftLongitude,
+            @FloatRange(from = -90D, to = 90D) double upperRightLatitude,
+            @FloatRange(from = -180D, to = 180D) double upperRightLongitude,
+            @NonNull GeocodeListener listener) {
         Preconditions.checkArgument(locationName != null);
         Preconditions.checkArgumentInRange(lowerLeftLatitude, -90.0, 90.0, "lowerLeftLatitude");
         Preconditions.checkArgumentInRange(lowerLeftLongitude, -180.0, 180.0, "lowerLeftLongitude");
@@ -209,27 +318,59 @@
                 "upperRightLongitude");
 
         try {
-            GeocodeListener listener = new GeocodeListener();
             mService.getFromLocationName(locationName, lowerLeftLatitude, lowerLeftLongitude,
-                    upperRightLatitude, upperRightLongitude, maxResults, mParams, listener);
-            return listener.getResults();
+                    upperRightLatitude, upperRightLongitude, maxResults, mParams,
+                    new GeocoderImpl(listener));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
-    private static class GeocodeListener extends IGeocodeListener.Stub {
+    private static class GeocoderImpl extends IGeocodeListener.Stub {
+
+        private GeocodeListener mListener;
+
+        GeocoderImpl(GeocodeListener listener) {
+            mListener = Objects.requireNonNull(listener);
+        }
+
+        @Override
+        public void onResults(String error, List<Address> addresses) throws RemoteException {
+            if (mListener == null) {
+                return;
+            }
+
+            GeocodeListener listener = mListener;
+            mListener = null;
+
+            if (error != null) {
+                listener.onError(error);
+            } else {
+                if (addresses == null) {
+                    addresses = Collections.emptyList();
+                }
+                listener.onGeocode(addresses);
+            }
+        }
+    }
+
+    private static class SynchronousGeocoder implements GeocodeListener {
         private final CountDownLatch mLatch = new CountDownLatch(1);
 
         private String mError = null;
         private List<Address> mResults = Collections.emptyList();
 
-        GeocodeListener() {}
+        SynchronousGeocoder() {}
 
         @Override
-        public void onResults(String error, List<Address> results) {
-            mError = error;
-            mResults = results;
+        public void onGeocode(List<Address> addresses) {
+            mResults = addresses;
+            mLatch.countDown();
+        }
+
+        @Override
+        public void onError(String errorMessage) {
+            mError = errorMessage;
             mLatch.countDown();
         }
 
diff --git a/location/java/android/location/GeocoderParams.java b/location/java/android/location/GeocoderParams.java
index b00a9a9..3ea6364 100644
--- a/location/java/android/location/GeocoderParams.java
+++ b/location/java/android/location/GeocoderParams.java
@@ -95,11 +95,11 @@
         new Parcelable.Creator<GeocoderParams>() {
             public GeocoderParams createFromParcel(Parcel in) {
                 int uid = in.readInt();
-                String packageName = in.readString();
-                String attributionTag = in.readString();
-                String language = in.readString();
-                String country = in.readString();
-                String variant = in.readString();
+                String packageName = in.readString8();
+                String attributionTag = in.readString8();
+                String language = in.readString8();
+                String country = in.readString8();
+                String variant = in.readString8();
 
                 return new GeocoderParams(uid, packageName, attributionTag,
                         new Locale(language, country, variant));
@@ -116,10 +116,10 @@
 
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeInt(mUid);
-        parcel.writeString(mPackageName);
-        parcel.writeString(mAttributionTag);
-        parcel.writeString(mLocale.getLanguage());
-        parcel.writeString(mLocale.getCountry());
-        parcel.writeString(mLocale.getVariant());
+        parcel.writeString8(mPackageName);
+        parcel.writeString8(mAttributionTag);
+        parcel.writeString8(mLocale.getLanguage());
+        parcel.writeString8(mLocale.getCountry());
+        parcel.writeString8(mLocale.getVariant());
     }
 }
diff --git a/media/aidl/android/media/audio/common/AudioDeviceDescription.aidl b/media/aidl/android/media/audio/common/AudioDeviceDescription.aidl
index 4e8a735..c21acca 100644
--- a/media/aidl/android/media/audio/common/AudioDeviceDescription.aidl
+++ b/media/aidl/android/media/audio/common/AudioDeviceDescription.aidl
@@ -39,7 +39,8 @@
      * Usually it's some kind of a communication protocol, e.g. Bluetooth SCO or
      * USB. There is a list of connection types recognized by the framework,
      * defined using 'CONNECTION_' constants. Vendors can add their own
-     * connection types with "vx.<vendor>." prefix.
+     * connection types with "VX_<vendor>_" prefix, where the "vendor" part
+     * must consist of at least 3 letters or numbers.
      *
      * When the 'connection' field is left empty and 'type != NONE | DEFAULT',
      * it is assumed that the device is permanently attached to the audio
@@ -50,14 +51,11 @@
      */
     @utf8InCpp String connection;
     /**
-     * Analog connection, for example, via 3.5 mm analog jack.
+     * Analog connection, for example, via 3.5 mm analog jack,
+     * or a low-end (analog) desk dock.
      */
     const @utf8InCpp String CONNECTION_ANALOG = "analog";
     /**
-     * Low-End (Analog) Desk Dock.
-     */
-    const @utf8InCpp String CONNECTION_ANALOG_DOCK = "analog-dock";
-    /**
      * Bluetooth A2DP connection.
      */
     const @utf8InCpp String CONNECTION_BT_A2DP = "bt-a2dp";
@@ -74,10 +72,6 @@
      */
     const @utf8InCpp String CONNECTION_BUS = "bus";
     /**
-     * High-End (Digital) Desk Dock.
-     */
-    const @utf8InCpp String CONNECTION_DIGITAL_DOCK = "digital-dock";
-    /**
      * HDMI connection.
      */
     const @utf8InCpp String CONNECTION_HDMI = "hdmi";
@@ -102,7 +96,7 @@
      */
     const @utf8InCpp String CONNECTION_WIRELESS = "wireless";
     /**
-     * USB connection.
+     * USB connection. The Android device is the USB Host.
      */
     const @utf8InCpp String CONNECTION_USB = "usb";
 }
diff --git a/media/aidl/android/media/audio/common/AudioDeviceType.aidl b/media/aidl/android/media/audio/common/AudioDeviceType.aidl
index 95dbe2a..afe6d10 100644
--- a/media/aidl/android/media/audio/common/AudioDeviceType.aidl
+++ b/media/aidl/android/media/audio/common/AudioDeviceType.aidl
@@ -47,6 +47,7 @@
     IN_DEFAULT = 1,
     /**
      * A device implementing Android Open Accessory protocol.
+     * Note: AOAv2 audio support has been deprecated in Android 8.0.
      */
     IN_ACCESSORY = 2,
     /**
@@ -94,12 +95,17 @@
      */
     IN_TV_TUNER = 13,
     /**
+     * Input from a phone / table dock.
+     */
+    IN_DOCK = 14,
+    /**
      * The "default" device is used when the client does not have any
      * preference for a particular device.
      */
     OUT_DEFAULT = 129,
     /**
      * A device implementing Android Open Accessory protocol.
+     * Note: AOAv2 audio support has been deprecated in Android 8.0.
      */
     OUT_ACCESSORY = 130,
     /**
@@ -158,4 +164,8 @@
      * Output into a telephone line.
      */
     OUT_TELEPHONY_TX = 144,
+    /**
+     * Output into a speaker of a phone / table dock.
+     */
+    OUT_DOCK = 145,
 }
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioDeviceDescription.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioDeviceDescription.aidl
index b4d71d7..1c66a8f 100644
--- a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioDeviceDescription.aidl
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioDeviceDescription.aidl
@@ -38,12 +38,10 @@
   android.media.audio.common.AudioDeviceType type = android.media.audio.common.AudioDeviceType.NONE;
   @utf8InCpp String connection;
   const @utf8InCpp String CONNECTION_ANALOG = "analog";
-  const @utf8InCpp String CONNECTION_ANALOG_DOCK = "analog-dock";
   const @utf8InCpp String CONNECTION_BT_A2DP = "bt-a2dp";
   const @utf8InCpp String CONNECTION_BT_LE = "bt-le";
   const @utf8InCpp String CONNECTION_BT_SCO = "bt-sco";
   const @utf8InCpp String CONNECTION_BUS = "bus";
-  const @utf8InCpp String CONNECTION_DIGITAL_DOCK = "digital-dock";
   const @utf8InCpp String CONNECTION_HDMI = "hdmi";
   const @utf8InCpp String CONNECTION_HDMI_ARC = "hdmi-arc";
   const @utf8InCpp String CONNECTION_HDMI_EARC = "hdmi-earc";
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioDeviceType.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioDeviceType.aidl
index ffdb778..0b7b77c 100644
--- a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioDeviceType.aidl
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioDeviceType.aidl
@@ -49,6 +49,7 @@
   IN_SUBMIX = 11,
   IN_TELEPHONY_RX = 12,
   IN_TV_TUNER = 13,
+  IN_DOCK = 14,
   OUT_DEFAULT = 129,
   OUT_ACCESSORY = 130,
   OUT_AFE_PROXY = 131,
@@ -65,4 +66,5 @@
   OUT_SPEAKER_SAFE = 142,
   OUT_SUBMIX = 143,
   OUT_TELEPHONY_TX = 144,
+  OUT_DOCK = 145,
 }
diff --git a/media/java/android/media/Spatializer.java b/media/java/android/media/Spatializer.java
index 3b835f7..8b1624b 100644
--- a/media/java/android/media/Spatializer.java
+++ b/media/java/android/media/Spatializer.java
@@ -129,6 +129,14 @@
      */
     public static final int SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL = 1;
 
+    /**
+     * @hide
+     * Constant indicating the {@code Spatializer} on this device supports the spatialization of
+     * multichannel bed plus objects.
+     * @see #getImmersiveAudioLevel()
+     */
+    public static final int SPATIALIZER_IMMERSIVE_LEVEL_MCHAN_BED_PLUS_OBJECTS = 2;
+
     /** @hide */
     @IntDef(flag = false, value = {
             HEAD_TRACKING_MODE_UNSUPPORTED,
diff --git a/media/jni/soundpool/Sound.cpp b/media/jni/soundpool/Sound.cpp
index 6ef0740..ac5f35f 100644
--- a/media/jni/soundpool/Sound.cpp
+++ b/media/jni/soundpool/Sound.cpp
@@ -140,7 +140,7 @@
                                 __func__);
                         break;
                     }
-                    const size_t dataSize = std::min((size_t)info.size, available);
+                    const size_t dataSize = std::min(available, (size_t)std::max(info.size, 0));
                     memcpy(writePos, buf + info.offset, dataSize);
                     writePos += dataSize;
                     written += dataSize;
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
index ece700d..d82b00d 100644
--- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
@@ -39,7 +39,6 @@
 import libcore.io.IoUtils;
 
 import java.io.IOException;
-import java.util.List;
 import java.util.UUID;
 
 /**
@@ -50,7 +49,8 @@
     private static final String TAG = "BluetoothMidiDevice";
     private static final boolean DEBUG = false;
 
-    private static final int MAX_PACKET_SIZE = 20;
+    private static final int DEFAULT_PACKET_SIZE = 20;
+    private static final int MAX_PACKET_SIZE = 512;
 
     //  Bluetooth MIDI Gatt service UUID
     private static final UUID MIDI_SERVICE = UUID.fromString(
@@ -103,6 +103,11 @@
                 Log.d(TAG, "Connected to GATT server.");
                 Log.d(TAG, "Attempting to start service discovery:" +
                         mBluetoothGatt.discoverServices());
+                if (!mBluetoothGatt.requestMtu(MAX_PACKET_SIZE)) {
+                    Log.e(TAG, "request mtu failed");
+                    mPacketEncoder.setMaxPacketSize(DEFAULT_PACKET_SIZE);
+                    mPacketDecoder.setMaxPacketSize(DEFAULT_PACKET_SIZE);
+                }
             } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                 Log.i(TAG, "Disconnected from GATT server.");
                 close();
@@ -182,21 +187,27 @@
             }
             mPacketDecoder.decodePacket(characteristic.getValue(), mOutputReceiver);
         }
+
+        @Override
+        public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
+            Log.d(TAG, "onMtuChanged callback received. mtu: " + mtu + ", status: " + status);
+            if (status == BluetoothGatt.GATT_SUCCESS) {
+                mPacketEncoder.setMaxPacketSize(Math.min(mtu, MAX_PACKET_SIZE));
+                mPacketDecoder.setMaxPacketSize(Math.min(mtu, MAX_PACKET_SIZE));
+            } else {
+                mPacketEncoder.setMaxPacketSize(DEFAULT_PACKET_SIZE);
+                mPacketDecoder.setMaxPacketSize(DEFAULT_PACKET_SIZE);
+            }
+        }
     };
 
     // This receives MIDI data that has already been passed through our MidiEventScheduler
     // and has been normalized by our MidiFramer.
 
     private class PacketReceiver implements PacketEncoder.PacketReceiver {
-        // buffers of every possible packet size
-        private final byte[][] mWriteBuffers;
+        private byte[] mCachedBuffer;
 
         public PacketReceiver() {
-            // Create buffers of every possible packet size
-            mWriteBuffers = new byte[MAX_PACKET_SIZE + 1][];
-            for (int i = 0; i <= MAX_PACKET_SIZE; i++) {
-                mWriteBuffers[i] = new byte[i];
-            }
         }
 
         @Override
@@ -205,9 +216,14 @@
                 Log.w(TAG, "not ready to send packet yet");
                 return;
             }
-            byte[] writeBuffer = mWriteBuffers[count];
-            System.arraycopy(buffer, 0, writeBuffer, 0, count);
-            mCharacteristic.setValue(writeBuffer);
+
+            // Cache the previous buffer for writePacket so buffers aren't
+            // consistently created if the buffer sizes are consistent.
+            if ((mCachedBuffer == null) || (mCachedBuffer.length != count)) {
+                mCachedBuffer = new byte[count];
+            }
+            System.arraycopy(buffer, 0, mCachedBuffer, 0, count);
+            mCharacteristic.setValue(mCachedBuffer);
             if (DEBUG) {
                 logByteArray("Sent ", mCharacteristic.getValue(), 0,
                        mCharacteristic.getValue().length);
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketDecoder.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketDecoder.java
index 8d18b77..71d542e 100644
--- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketDecoder.java
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketDecoder.java
@@ -30,6 +30,7 @@
     private static final String TAG = "BluetoothPacketDecoder";
 
     private final byte[] mBuffer;
+    private int mMaxPacketSize;
     private int mBytesInBuffer;
     private MidiBtleTimeTracker mTimeTracker;
 
@@ -42,6 +43,14 @@
 
     public BluetoothPacketDecoder(int maxPacketSize) {
         mBuffer = new byte[maxPacketSize];
+        setMaxPacketSize(maxPacketSize);
+    }
+
+    /**
+     * Dynamically sets the maximum packet size
+     */
+    public void setMaxPacketSize(int maxPacketSize) {
+        mMaxPacketSize = Math.min(maxPacketSize, mBuffer.length);
     }
 
     private void flushOutput(MidiReceiver receiver) {
@@ -83,6 +92,7 @@
         int previousLowTimestamp = 0;
         int currentTimestamp = highTimestamp | mLowTimestamp;
 
+        int curMaxPacketSize = mMaxPacketSize;
         // Iterate through the rest of the packet, separating MIDI data from timestamps.
         for (int i = 1; i < buffer.length; i++) {
             byte b = buffer[i];
@@ -113,7 +123,7 @@
             } else {
                 lastWasTimestamp = false;
                 // Flush if full before adding more data.
-                if (mBytesInBuffer == mBuffer.length) {
+                if (mBytesInBuffer >= curMaxPacketSize) {
                     flushOutput(receiver);
                 }
                 mBuffer[mBytesInBuffer++] = b;
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketEncoder.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketEncoder.java
index 8ac6b56..92585ea 100644
--- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketEncoder.java
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketEncoder.java
@@ -45,6 +45,8 @@
     private int mPacketTimestamp;
     // current running status, or zero if none
     private byte mRunningStatus;
+    // max size of a packet
+    private int mMaxPacketSize;
 
     private boolean mWritePending;
 
@@ -86,7 +88,7 @@
                 if (needsTimestamp) bytesNeeded++;  // add one for timestamp byte
                 if (status == mRunningStatus) bytesNeeded--;    // subtract one for status byte
 
-                if (mAccumulatedBytes + bytesNeeded > mAccumulationBuffer.length) {
+                if (mAccumulatedBytes + bytesNeeded > mMaxPacketSize) {
                     // write out our data if there is no more room
                     // if necessary, block until previous packet is sent
                     flushLocked(true);
@@ -112,14 +114,14 @@
                     int remaining = (hasSysExEnd ? count - 1 : count);
 
                     while (remaining > 0) {
-                        if (mAccumulatedBytes == mAccumulationBuffer.length) {
+                        if (mAccumulatedBytes == mMaxPacketSize) {
                             // write out our data if there is no more room
                             // if necessary, block until previous packet is sent
                             flushLocked(true);
                             appendHeader(milliTimestamp);
                         }
 
-                        int copy = mAccumulationBuffer.length - mAccumulatedBytes;
+                        int copy = mMaxPacketSize - mAccumulatedBytes;
                         if (copy > remaining) copy = remaining;
                         System.arraycopy(msg, offset, mAccumulationBuffer, mAccumulatedBytes, copy);
                         mAccumulatedBytes += copy;
@@ -129,7 +131,7 @@
 
                     if (hasSysExEnd) {
                         // SysEx End command must be preceeded by a timestamp byte
-                        if (mAccumulatedBytes + 2 > mAccumulationBuffer.length) {
+                        if (mAccumulatedBytes + 2 > mMaxPacketSize) {
                             // write out our data if there is no more room
                             // if necessary, block until previous packet is sent
                             flushLocked(true);
@@ -182,6 +184,16 @@
     public BluetoothPacketEncoder(PacketReceiver packetReceiver, int maxPacketSize) {
         mPacketReceiver = packetReceiver;
         mAccumulationBuffer = new byte[maxPacketSize];
+        setMaxPacketSize(maxPacketSize);
+    }
+
+    /**
+     * Dynamically sets the maximum packet size
+     */
+    public void setMaxPacketSize(int maxPacketSize) {
+        synchronized (mLock) {
+            mMaxPacketSize = Math.min(maxPacketSize, mAccumulationBuffer.length);
+        }
     }
 
     @Override
diff --git a/packages/PrintSpooler/res/values-ru/strings.xml b/packages/PrintSpooler/res/values-ru/strings.xml
index 9e2f479..c471ab1 100644
--- a/packages/PrintSpooler/res/values-ru/strings.xml
+++ b/packages/PrintSpooler/res/values-ru/strings.xml
@@ -24,7 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Размер бумаги"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Размер бумаги:"</string>
     <string name="label_color" msgid="1108690305218188969">"Печать"</string>
-    <string name="label_duplex" msgid="5370037254347072243">"Двусторонний"</string>
+    <string name="label_duplex" msgid="5370037254347072243">"С двух сторон"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Ориентация"</string>
     <string name="label_pages" msgid="7768589729282182230">"Страницы"</string>
     <string name="destination_default_text" msgid="5422708056807065710">"Выберите принтер"</string>
diff --git a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
index 8216edf..fe7988f 100644
--- a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
@@ -43,6 +43,7 @@
     View.OnClickListener mLearnMoreListener;
     private CharSequence mContentDescription;
     private CharSequence mLearnMoreContentDescription;
+    private FooterLearnMoreSpan mLearnMoreSpan;
 
     public FooterPreference(Context context, AttributeSet attrs) {
         super(context, attrs, R.attr.footerPreferenceStyle);
@@ -68,7 +69,11 @@
         if (learnMore != null && mLearnMoreListener != null) {
             learnMore.setVisibility(View.VISIBLE);
             SpannableString learnMoreText = new SpannableString(learnMore.getText());
-            learnMoreText.setSpan(new FooterLearnMoreSpan(mLearnMoreListener), 0,
+            if (mLearnMoreSpan != null) {
+                learnMoreText.removeSpan(mLearnMoreSpan);
+            }
+            mLearnMoreSpan = new FooterLearnMoreSpan(mLearnMoreListener);
+            learnMoreText.setSpan(mLearnMoreSpan, 0,
                     learnMoreText.length(), 0);
             learnMore.setText(learnMoreText);
             if (!TextUtils.isEmpty(mLearnMoreContentDescription)) {
diff --git a/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml b/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
index 54145d6..eecb4bf 100644
--- a/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
+++ b/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
@@ -34,17 +34,21 @@
         android:orientation="vertical">
 
         <ImageView
+            android:id="@+id/background_view"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:scaleType="centerInside"
+            android:layout_gravity="center"
+            android:adjustViewBounds="true"
             android:src="@drawable/protection_background"/>
 
         <com.airbnb.lottie.LottieAnimationView
             android:id="@+id/lottie_view"
-            android:adjustViewBounds="true"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_gravity="center" />
+            android:layout_gravity="center"
+            android:maxWidth="@dimen/settingslib_illustration_width"
+            android:maxHeight="@dimen/settingslib_illustration_height"
+            android:adjustViewBounds="true"/>
 
         <FrameLayout
             android:id="@+id/middleground_layout"
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
index 1f80a3e..468a976 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
@@ -17,6 +17,7 @@
 package com.android.settingslib.widget;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Animatable2;
@@ -50,7 +51,9 @@
     private static final String TAG = "IllustrationPreference";
 
     private static final boolean IS_ENABLED_LOTTIE_ADAPTIVE_COLOR = false;
+    private static final int SIZE_UNSPECIFIED = -1;
 
+    private int mMaxHeight = SIZE_UNSPECIFIED;
     private int mImageResId;
     private boolean mIsAutoScale;
     private Uri mImageUri;
@@ -98,6 +101,8 @@
     public void onBindViewHolder(PreferenceViewHolder holder) {
         super.onBindViewHolder(holder);
 
+        final ImageView backgroundView =
+                (ImageView) holder.findViewById(R.id.background_view);
         final FrameLayout middleGroundLayout =
                 (FrameLayout) holder.findViewById(R.id.middleground_layout);
         final LottieAnimationView illustrationView =
@@ -115,6 +120,7 @@
         illustrationFrame.setLayoutParams(lp);
 
         handleImageWithAnimation(illustrationView);
+        handleImageFrameMaxHeight(backgroundView, illustrationView);
 
         if (mIsAutoScale) {
             illustrationView.setScaleType(mIsAutoScale
@@ -220,6 +226,19 @@
         return mImageUri;
     }
 
+    /**
+     * Sets the maximum height of the views, still use the specific one if the maximum height was
+     * larger than the specific height from XML.
+     *
+     * @param maxHeight the maximum height of the frame views in terms of pixels.
+     */
+    public void setMaxHeight(int maxHeight) {
+        if (maxHeight != mMaxHeight) {
+            mMaxHeight = maxHeight;
+            notifyChanged();
+        }
+    }
+
     private void resetImageResourceCache() {
         mImageDrawable = null;
         mImageUri = null;
@@ -274,6 +293,23 @@
         }
     }
 
+    private void handleImageFrameMaxHeight(ImageView backgroundView, ImageView illustrationView) {
+        if (mMaxHeight == SIZE_UNSPECIFIED) {
+            return;
+        }
+
+        final Resources res = backgroundView.getResources();
+        final int frameWidth = res.getDimensionPixelSize(R.dimen.settingslib_illustration_width);
+        final int frameHeight = res.getDimensionPixelSize(R.dimen.settingslib_illustration_height);
+        final int restrictedMaxHeight = Math.min(mMaxHeight, frameHeight);
+        backgroundView.setMaxHeight(restrictedMaxHeight);
+        illustrationView.setMaxHeight(restrictedMaxHeight);
+
+        // Ensures the illustration view size is smaller than or equal to the background view size.
+        final float aspectRatio = (float) frameWidth / frameHeight;
+        illustrationView.setMaxWidth((int) (restrictedMaxHeight * aspectRatio));
+    }
+
     private void startAnimation(Drawable drawable) {
         if (!(drawable instanceof Animatable)) {
             return;
diff --git a/packages/SettingsLib/SearchWidget/res/values-as/strings.xml b/packages/SettingsLib/SearchWidget/res/values-as/strings.xml
index d3f922a..8d95131 100644
--- a/packages/SettingsLib/SearchWidget/res/values-as/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-as/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="search_menu" msgid="1914043873178389845">"সন্ধান সম্পৰ্কীয় ছেটিংসমূহ"</string>
+    <string name="search_menu" msgid="1914043873178389845">"সন্ধান সম্পৰ্কীয় ছেটিং"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 5347e82..bbd89fe 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -182,7 +182,7 @@
     <string name="running_process_item_user_label" msgid="3988506293099805796">"ব্যৱহাৰকাৰী: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="launch_defaults_some" msgid="3631650616557252926">"কিছুমান ডিফ\'ল্ট ছেট কৰা হৈছে"</string>
     <string name="launch_defaults_none" msgid="8049374306261262709">"কোনো ডিফ\'ল্ট ছেট কৰা হোৱা নাই"</string>
-    <string name="tts_settings" msgid="8130616705989351312">"পাঠৰ পৰা কথনৰ ছেটিংসমূহ"</string>
+    <string name="tts_settings" msgid="8130616705989351312">"পাঠৰ পৰা কথনৰ ছেটিং"</string>
     <string name="tts_settings_title" msgid="7602210956640483039">"পাঠৰ পৰা কথনৰ আউটপুট"</string>
     <string name="tts_default_rate_title" msgid="3964187817364304022">"কথা কোৱাৰ হাৰ"</string>
     <string name="tts_default_rate_summary" msgid="3781937042151716987">"পাঠ কথনৰ বেগ"</string>
@@ -204,8 +204,8 @@
     <string name="tts_status_requires_network" msgid="8327617638884678896">"<xliff:g id="LOCALE">%1$s</xliff:g>ক নেটৱৰ্ক সংযোগৰ দৰকাৰ"</string>
     <string name="tts_status_not_supported" msgid="2702997696245523743">"<xliff:g id="LOCALE">%1$s</xliff:g> সমৰ্থিত নহয়"</string>
     <string name="tts_status_checking" msgid="8026559918948285013">"পৰীক্ষা কৰি থকা হৈছে…"</string>
-    <string name="tts_engine_settings_title" msgid="7849477533103566291">"<xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>ৰ বাবে ছেটিংসমূহ"</string>
-    <string name="tts_engine_settings_button" msgid="477155276199968948">"ইঞ্জিনৰ ছেটিংসমূহ লঞ্চ কৰক"</string>
+    <string name="tts_engine_settings_title" msgid="7849477533103566291">"<xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>ৰ ছেটিং"</string>
+    <string name="tts_engine_settings_button" msgid="477155276199968948">"ইঞ্জিনৰ ছেটিং লঞ্চ কৰক"</string>
     <string name="tts_engine_preference_section_title" msgid="3861562305498624904">"অগ্ৰাধিকাৰপ্ৰাপ্ত ইঞ্জিন"</string>
     <string name="tts_general_section_title" msgid="8919671529502364567">"সাধাৰণ"</string>
     <string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"কথনভংগী তীব্ৰতা ৰিছেট কৰক"</string>
@@ -228,9 +228,9 @@
     <string name="development_settings_enable" msgid="4285094651288242183">"বিকাশকৰ্তা বিষয়ক বিকল্পসমূহ সক্ষম কৰক"</string>
     <string name="development_settings_summary" msgid="8718917813868735095">"এপৰ বিকাশৰ বাবে বিকল্পসমূহ ছেট কৰক"</string>
     <string name="development_settings_not_available" msgid="355070198089140951">"এইজন ব্যৱহাৰকাৰীৰ বাবে বিকাশকৰ্তাৰ বিকল্পসমূহ উপলব্ধ নহয়"</string>
-    <string name="vpn_settings_not_available" msgid="2894137119965668920">"ভিপিএন ছেটিংসমূহ এই ব্যৱহাৰকাৰীজনৰ বাবে উপলব্ধ নহয়"</string>
-    <string name="tethering_settings_not_available" msgid="266821736434699780">"এই ব্যৱহাৰকাৰীৰ বাবে টেডাৰিং ছেটিংসমূহ উপলব্ধ নহয়"</string>
-    <string name="apn_settings_not_available" msgid="1147111671403342300">"এই ব্যৱহাৰকাৰীৰ বাবে একচেছ পইণ্টৰ নাম ছেটিংসমূহ উপলব্ধ নহয়"</string>
+    <string name="vpn_settings_not_available" msgid="2894137119965668920">"ভিপিএন ছেটিং এই ব্যৱহাৰকাৰীজনৰ বাবে উপলব্ধ নহয়"</string>
+    <string name="tethering_settings_not_available" msgid="266821736434699780">"এই ব্যৱহাৰকাৰীৰ বাবে টেডাৰিং ছেটিং উপলব্ধ নহয়"</string>
+    <string name="apn_settings_not_available" msgid="1147111671403342300">"এই ব্যৱহাৰকাৰীৰ বাবে এক্সেছ পইণ্টৰ নামৰ ছেটিং উপলব্ধ নহয়"</string>
     <string name="enable_adb" msgid="8072776357237289039">"ইউএছবি ডিবাগিং"</string>
     <string name="enable_adb_summary" msgid="3711526030096574316">"ইউএছবি সংযোগ হৈ থকাৰ অৱস্থাত ডিবাগ ম\'ড"</string>
     <string name="clear_adb_keys" msgid="3010148733140369917">"ইউএছবি ডিবাগিং অনুমতিসমূহ প্ৰত্যাহাৰ কৰক"</string>
@@ -332,7 +332,7 @@
     <string name="adbwifi_warning_title" msgid="727104571653031865">"ৱায়াৰলেচ ডি\'বাগিংৰ অনুমতি দিবনে?"</string>
     <string name="adbwifi_warning_message" msgid="8005936574322702388">"ৱায়াৰলেচ ডি\'বাগিং কেৱল বিকাশৰ উদ্দেশ্যেৰে কৰা হয়। আপোনাৰ কম্পিউটাৰ আৰু আপোনাৰ ডিভাইচৰ মাজত ডেটা প্ৰতিলিপি কৰিবলৈ, কোনো জাননী নিদিয়াকৈয়ে আপোনাৰ ডিভাইচত এপ্‌সমূহ ইনষ্টল কৰিবলৈ আৰু লগ ডেটা পঢ়িবলৈ এইটো ব্যৱহাৰ কৰক।"</string>
     <string name="adb_keys_warning_message" msgid="2968555274488101220">"আপুনি আগতে ইউএছবি ডিবাগিঙৰ বাবে প্ৰৱেশৰ অনুমতি দিয়া সকলো কম্পিউটাৰৰ পৰা সেই অনুমতি প্ৰত্যাহাৰ কৰেনে?"</string>
-    <string name="dev_settings_warning_title" msgid="8251234890169074553">"বিকাশৰ কামৰ বাবে থকা ছেটিংবিলাকক অনুমতি দিবনে?"</string>
+    <string name="dev_settings_warning_title" msgid="8251234890169074553">"বিকাশৰ কামৰ বাবে থকা ছেটিঙৰ অনুমতি দিবনে?"</string>
     <string name="dev_settings_warning_message" msgid="37741686486073668">"এই ছেটিংসমূহ বিকাশৰ কামত ব্যৱহাৰ কৰিবলৈ তৈয়াৰ কৰা হৈছে। সেইবিলাকে আপোনাৰ ডিভাইচ আৰু তাত থকা এপ্লিকেশ্বনসমূহক অকামিলা কৰি পেলাব পাৰে আৰু সেইবিলাকৰ কাৰণে এপ্লিকেশ্বনসমূহে অদ্ভুত আচৰণ কৰিব পাৰে।"</string>
     <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"ইউএছবিৰ যোগেৰে এপৰ সত্যাপন কৰক"</string>
     <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"ADB/ADTৰ যোগেৰে ইনষ্টল কৰা এপসমূহে কিবা ক্ষতিকাৰক আচৰণ কৰিছে নেকি পৰীক্ষা কৰক।"</string>
@@ -495,7 +495,7 @@
     <string name="external_source_trusted" msgid="1146522036773132905">"অনুমতি দিয়া হৈছে"</string>
     <string name="external_source_untrusted" msgid="5037891688911672227">"অনুমতি দিয়া হোৱা নাই"</string>
     <string name="install_other_apps" msgid="3232595082023199454">"অজ্ঞাত এপ্ ইনষ্টল কৰক"</string>
-    <string name="home" msgid="973834627243661438">"ছেটিংসমূহৰ গৃহপৃষ্ঠা"</string>
+    <string name="home" msgid="973834627243661438">"Settingsৰ গৃহপৃষ্ঠা"</string>
   <string-array name="battery_labels">
     <item msgid="7878690469765357158">"০%"</item>
     <item msgid="8894873528875953317">"৫০%"</item>
@@ -515,7 +515,7 @@
     <string name="retail_demo_reset_title" msgid="1866911701095959800">"পাছৱৰ্ড দৰকাৰী"</string>
     <string name="active_input_method_subtypes" msgid="4232680535471633046">"সক্ৰিয়হৈ থকা ইনপুট পদ্ধতিসমূহ"</string>
     <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"ছিষ্টেমৰ ভাষা ব্যৱহাৰ কৰক"</string>
-    <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g>ৰ ছেটিংবিলাক খুলিব পৰা নগ\'ল"</string>
+    <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g>ৰ ছেটিং খুলিব পৰা নগ\'ল"</string>
     <string name="ime_security_warning" msgid="6547562217880551450">"এই ইনপুট পদ্ধতিটোৱে আপুনি টাইপ কৰা আপোনাৰ ব্যক্তিগত ডেটা যেনে পাছৱৰ্ডসমূহ আৰু ক্ৰেডিট কাৰ্ডৰ নম্বৰসমূহকে ধৰি সকলো পাঠ সংগ্ৰহ কৰিবলৈ সক্ষম হ\'ব পাৰে। <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> এপটোৰ লগত ই সংলগ্ন। এই ইনপুট পদ্ধতিটো ব্যৱহাৰ কৰেনে?"</string>
     <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"টোকা: ৰিবুট কৰাৰ পিছত আপুনি ফ\'নটো আনলক নকৰালৈকে এই এপটো ষ্টাৰ্ট নহ’ব"</string>
     <string name="ims_reg_title" msgid="8197592958123671062">"আইএমএছ পঞ্জীয়ন স্থিতি"</string>
@@ -573,7 +573,7 @@
     <string name="user_add_user_item_title" msgid="2394272381086965029">"ব্যৱহাৰকাৰী"</string>
     <string name="user_add_profile_item_title" msgid="3111051717414643029">"সীমিত প্ৰ\'ফাইল"</string>
     <string name="user_add_user_title" msgid="5457079143694924885">"নতুন ব্যৱহাৰকাৰী যোগ কৰিবনে?"</string>
-    <string name="user_add_user_message_long" msgid="1527434966294733380">"আপুনি অতিৰিক্ত ব্য়ৱহাৰকাৰীক যোগ কৰি এই ডিভাইচটো অন্য় ব্য়ক্তিৰ সৈতে শ্বেয়াৰ কৰিব পাৰে। প্ৰতিজন ব্য়ৱহাৰকাৰীৰ বাবে নিজাকৈ ঠাই আছে যাক তেওঁলোকে এপ্, ৱালপেপাৰ আৰু অন্য়ান্য় বস্তুৰ বাবে নিজৰ উপযোগিতা অনুযায়ী ব্য়ৱহাৰ কৰিব পাৰে। ব্য়ৱহাৰকাৰীসকলে সকলোকে প্ৰভাৱান্বিত কৰা ৱাই-ফাইৰ নিচিনা ডিভাইচৰ ছেটিংসমূহ সাল-সলনি কৰিবও পাৰে।\n\nআপুনি যেতিয়া কোনো নতুন ব্য়ৱহাৰকাৰীক যোগ কৰে সেই ব্য়ক্তিজনে নিজেই নিজৰ বাবে ঠাই ছেট আপ কৰিব লাগিব।\n\nসকলো ব্য়ৱহাৰকাৰীএ অন্য় ব্য়ৱহাৰকাৰীৰ বাবে এপসমূহ আপডে’ট কৰিব পাৰে। সাধ্য় সুবিধাসমূহৰ ছেটিং আৰু সেৱাসমূহ নতুন ব্য়ৱহাৰকাৰীলৈ স্থানান্তৰ নহ\'বও পাৰে।"</string>
+    <string name="user_add_user_message_long" msgid="1527434966294733380">"আপুনি অতিৰিক্ত ব্য়ৱহাৰকাৰীক যোগ কৰি এই ডিভাইচটো অন্য় ব্য়ক্তিৰ সৈতে শ্বেয়াৰ কৰিব পাৰে। প্ৰতিজন ব্য়ৱহাৰকাৰীৰ বাবে নিজাকৈ ঠাই আছে যাক তেওঁলোকে এপ্, ৱালপেপাৰ আৰু অন্য়ান্য় বস্তুৰ বাবে নিজৰ উপযোগিতা অনুযায়ী ব্য়ৱহাৰ কৰিব পাৰে। ব্য়ৱহাৰকাৰীসকলে সকলোকে প্ৰভাৱান্বিত কৰা ৱাই-ফাইৰ নিচিনা ডিভাইচৰ ছেটিং সাল-সলনি কৰিবও পাৰে।\n\nআপুনি যেতিয়া কোনো নতুন ব্য়ৱহাৰকাৰীক যোগ কৰে সেই ব্য়ক্তিজনে নিজেই নিজৰ বাবে ঠাই ছেট আপ কৰিব লাগিব।\n\nসকলো ব্য়ৱহাৰকাৰীয়ে অন্য় ব্য়ৱহাৰকাৰীৰ বাবে এপ্‌সমূহ আপডে’ট কৰিব পাৰে। সাধ্য় সুবিধাসমূহৰ ছেটিং আৰু সেৱাসমূহ নতুন ব্য়ৱহাৰকাৰীলৈ স্থানান্তৰ নহ\'বও পাৰে।"</string>
     <string name="user_add_user_message_short" msgid="3295959985795716166">"আপুনি যেতিয়া এজন নতুন ব্যৱহাৰকাৰী যোগ কৰে, তেওঁ নিজৰ ঠাই ছেট আপ কৰা প্ৰয়োজন।\n\nযিকোনো ব্যৱহাৰকাৰীয়ে সকলো ব্যৱহাৰকাৰীৰ বাবে এপ্ আপডেইট কৰিব পাৰে।"</string>
     <string name="user_setup_dialog_title" msgid="8037342066381939995">"ব্যৱহাৰকাৰী এতিয়া ছেট আপ কৰিবনে?"</string>
     <string name="user_setup_dialog_message" msgid="269931619868102841">"ডিভাইচটো লৈ নিজৰ ঠাই ছেটআপ কৰিবলৈ নতুন ব্যৱহাৰকাৰী উপলব্ধ থকাটো নিশ্চিত কৰক"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index b189595..fd39167 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -194,8 +194,8 @@
     <string name="tts_default_lang_summary" msgid="9042620014800063470">"టెక్స్ట్‌ను చదివి వినిపించేటప్పుడు, ఒక్కో భాషకు వాడాల్సిన నిర్దిష్ట వాయిస్‌ను సెట్ చేస్తుంది"</string>
     <string name="tts_play_example_title" msgid="1599468547216481684">"ఒక ఉదాహరణ వినండి"</string>
     <string name="tts_play_example_summary" msgid="634044730710636383">"ప్రసంగ సమన్వయం గురించి సంక్షిప్త ప్రదర్శనను ప్లే చేయి"</string>
-    <string name="tts_install_data_title" msgid="1829942496472751703">"వాయిస్ డేటాను ఇన్‌స్టాల్ చేయి"</string>
-    <string name="tts_install_data_summary" msgid="3608874324992243851">"ప్రసంగ సమన్వయం కోసం అవసరమైన వాయిస్ డేటాను ఇన్‌స్టాల్ చేయండి"</string>
+    <string name="tts_install_data_title" msgid="1829942496472751703">"వాయిస్ డేటాను ఇన్‌స్టాల్ చేయండి"</string>
+    <string name="tts_install_data_summary" msgid="3608874324992243851">"స్పీచ్ సమన్వయం కోసం అవసరమైన వాయిస్ డేటాను ఇన్‌స్టాల్ చేయండి"</string>
     <string name="tts_engine_security_warning" msgid="3372432853837988146">"ఈ ప్రసంగ సమన్వయ ఇంజిన్ చదివి వినిపించబడే మొత్తం వచనాన్ని అలాగే పాస్‌వర్డ‌లు మరియు క్రెడిట్ కార్డు నంబర్‌ల వంటి వ్యక్తిగత డేటాను సేకరించగలదు. ఇది <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> ఇంజిన్‌లో అందించబడుతుంది. ఈ ప్రసంగ సమన్వయ ఇంజిన్ యొక్క వినియోగాన్ని ప్రారంభించాలా?"</string>
     <string name="tts_engine_network_required" msgid="8722087649733906851">"వచనం నుండి ప్రసంగం అవుట్‌పుట్ కోసం ఈ భాషకు పని చేస్తున్న నెట్‌వర్క్ కనెక్షన్ కావాలి."</string>
     <string name="tts_default_sample_string" msgid="6388016028292967973">"ఇది ప్రసంగ సమన్వయానికి ఉదాహరణ"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 51008bd..8750309 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -18,6 +18,7 @@
 
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothCsipSetCoordinator;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothHearingAid;
@@ -126,6 +127,9 @@
         addHandler(BluetoothDevice.ACTION_ACL_CONNECTED, new AclStateChangedHandler());
         addHandler(BluetoothDevice.ACTION_ACL_DISCONNECTED, new AclStateChangedHandler());
 
+        addHandler(BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE,
+                new SetMemberAvailableHandler());
+
         registerAdapterIntentReceiver();
     }
 
@@ -339,6 +343,12 @@
             }
             int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
                     BluetoothDevice.ERROR);
+
+            if (mDeviceManager.onBondStateChangedIfProcess(device, bondState)) {
+                Log.d(TAG, "Should not update UI for the set member");
+                return;
+            }
+
             CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
             if (cachedDevice == null) {
                 Log.w(TAG, "Got bonding state changed for " + device +
@@ -352,8 +362,10 @@
             cachedDevice.onBondingStateChanged(bondState);
 
             if (bondState == BluetoothDevice.BOND_NONE) {
-                /* Check if we need to remove other Hearing Aid devices */
-                if (cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
+                // Check if we need to remove other Coordinated set member devices / Hearing Aid
+                // devices
+                if (cachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID
+                        || cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
                     mDeviceManager.onDeviceUnpaired(cachedDevice);
                 }
                 int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
@@ -503,4 +515,29 @@
             dispatchAudioModeChanged();
         }
     }
+
+    private class SetMemberAvailableHandler implements Handler {
+        @Override
+        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+            final String action = intent.getAction();
+            if (device == null) {
+                Log.e(TAG, "SetMemberAvailableHandler: device is null");
+                return;
+            }
+
+            if (action == null) {
+                Log.e(TAG, "SetMemberAvailableHandler: action is null");
+                return;
+            }
+
+            final int groupId = intent.getIntExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID,
+                    BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+            if (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+                Log.e(TAG, "SetMemberAvailableHandler: Invalid group id");
+                return;
+            }
+
+            mDeviceManager.onSetMemberAppear(device, groupId);
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 485b313..00a7b6c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -18,6 +18,7 @@
 
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothCsipSetCoordinator;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHearingAid;
 import android.bluetooth.BluetoothProfile;
@@ -49,7 +50,9 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
@@ -74,6 +77,7 @@
     private final Object mProfileLock = new Object();
     BluetoothDevice mDevice;
     private long mHiSyncId;
+    private int mGroupId;
     // Need this since there is no method for getting RSSI
     short mRssi;
     // mProfiles and mRemovedProfiles does not do swap() between main and sub device. It is
@@ -111,6 +115,8 @@
     private boolean mUnpairing;
     // Group second device for Hearing Aid
     private CachedBluetoothDevice mSubDevice;
+    // Group member devices for the coordinated set
+    private Set<CachedBluetoothDevice> mMemberDevices = new HashSet<CachedBluetoothDevice>();
     @VisibleForTesting
     LruCache<String, BitmapDrawable> mDrawableCache;
 
@@ -144,6 +150,7 @@
         mDevice = device;
         fillData();
         mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
+        mGroupId = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
         initDrawableCache();
         mUnpairing = false;
     }
@@ -342,6 +349,24 @@
         return mIsCoordinatedSetMember;
     }
 
+    /**
+    * Get the coordinated set group id.
+    *
+    * @return the group id.
+    */
+    public int getGroupId() {
+        return mGroupId;
+    }
+
+    /**
+    * Set the coordinated set group id.
+    *
+    * @param id the group id from the CSIP.
+    */
+    public void setGroupId(int id) {
+        mGroupId = id;
+    }
+
     void onBondingDockConnect() {
         // Attempt to connect if UUIDs are available. Otherwise,
         // we will connect when the ACTION_UUID intent arrives.
@@ -1241,6 +1266,54 @@
     }
 
     /**
+     * @return a set of member devices that are in the same coordinated set with this device.
+     */
+    public Set<CachedBluetoothDevice> getMemberDevice() {
+        return mMemberDevices;
+    }
+
+    /**
+     * Store the member devices that are in the same coordinated set.
+     */
+    public void setMemberDevice(CachedBluetoothDevice memberDevice) {
+        mMemberDevices.add(memberDevice);
+    }
+
+    /**
+     * Remove a device from the member device sets.
+     */
+    public void removeMemberDevice(CachedBluetoothDevice memberDevice) {
+        mMemberDevices.remove(memberDevice);
+    }
+
+    /**
+     * In order to show the preference for the whole group, we always set the main device as the
+     * first connected device in the coordinated set, and then switch the content of the main
+     * device and member devices.
+     *
+     * @param prevMainDevice the previous Main device, it will be added into the member device set.
+     * @param newMainDevie the new Main device, it will be removed from the member device set.
+     */
+    public void switchMemberDeviceContent(CachedBluetoothDevice prevMainDevice,
+            CachedBluetoothDevice newMainDevie) {
+        // Backup from main device
+        final BluetoothDevice tmpDevice = mDevice;
+        final short tmpRssi = mRssi;
+        final boolean tmpJustDiscovered = mJustDiscovered;
+        // Set main device from sub device
+        mDevice = newMainDevie.mDevice;
+        mRssi = newMainDevie.mRssi;
+        mJustDiscovered = newMainDevie.mJustDiscovered;
+        setMemberDevice(prevMainDevice);
+        mMemberDevices.remove(newMainDevie);
+        // Set sub device from backup
+        newMainDevie.mDevice = tmpDevice;
+        newMainDevie.mRssi = tmpRssi;
+        newMainDevie.mJustDiscovered = tmpJustDiscovered;
+        fetchActiveDevices();
+    }
+
+    /**
      * Get cached bluetooth icon with description
      */
     public Pair<Drawable, String> getDrawableWithDescription() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index cca9cfa..0256615 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -18,6 +18,7 @@
 
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.util.Log;
 
@@ -26,6 +27,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Set;
 
 /**
  * CachedBluetoothDeviceManager manages the set of remote Bluetooth devices.
@@ -41,11 +43,15 @@
     final List<CachedBluetoothDevice> mCachedDevices = new ArrayList<CachedBluetoothDevice>();
     @VisibleForTesting
     HearingAidDeviceManager mHearingAidDeviceManager;
+    @VisibleForTesting
+    CsipDeviceManager mCsipDeviceManager;
+    BluetoothDevice mOngoingSetMemberPair;
 
     CachedBluetoothDeviceManager(Context context, LocalBluetoothManager localBtManager) {
         mContext = context;
         mBtManager = localBtManager;
         mHearingAidDeviceManager = new HearingAidDeviceManager(localBtManager, mCachedDevices);
+        mCsipDeviceManager = new CsipDeviceManager(localBtManager, mCachedDevices);
     }
 
     public synchronized Collection<CachedBluetoothDevice> getCachedDevicesCopy() {
@@ -79,7 +85,16 @@
             if (cachedDevice.getDevice().equals(device)) {
                 return cachedDevice;
             }
-            // Check sub devices if it exists
+            // Check the member devices for the coordinated set if it exists
+            final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
+            if (memberDevices != null) {
+                for (CachedBluetoothDevice memberDevice : memberDevices) {
+                    if (memberDevice.getDevice().equals(device)) {
+                        return memberDevice;
+                    }
+                }
+            }
+            // Check sub devices for hearing aid if it exists
             CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
             if (subDevice != null && subDevice.getDevice().equals(device)) {
                 return subDevice;
@@ -102,8 +117,10 @@
             newDevice = findDevice(device);
             if (newDevice == null) {
                 newDevice = new CachedBluetoothDevice(mContext, profileManager, device);
+                mCsipDeviceManager.initCsipDeviceIfNeeded(newDevice);
                 mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(newDevice);
-                if (!mHearingAidDeviceManager.setSubDeviceIfNeeded(newDevice)) {
+                if (!mCsipDeviceManager.setMemberDeviceIfNeeded(newDevice)
+                        && !mHearingAidDeviceManager.setSubDeviceIfNeeded(newDevice)) {
                     mCachedDevices.add(newDevice);
                     mBtManager.getEventManager().dispatchDeviceAdded(newDevice);
                 }
@@ -114,13 +131,23 @@
     }
 
     /**
-     * Returns device summary of the pair of the hearing aid passed as the parameter.
+     * Returns device summary of the pair of the hearing aid / CSIP passed as the parameter.
      *
      * @param CachedBluetoothDevice device
-     * @return Device summary, or if the pair does not exist or if it is not a hearing aid,
-     * then {@code null}.
+     * @return Device summary, or if the pair does not exist or if it is not a hearing aid or
+     * a CSIP set member, then {@code null}.
      */
     public synchronized String getSubDeviceSummary(CachedBluetoothDevice device) {
+        final Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
+        if (memberDevices != null) {
+            for (CachedBluetoothDevice memberDevice : memberDevices) {
+                if (!memberDevice.isConnected()) {
+                    return null;
+                }
+            }
+
+            return device.getConnectionSummary();
+        }
         CachedBluetoothDevice subDevice = device.getSubDevice();
         if (subDevice != null && subDevice.isConnected()) {
             return subDevice.getConnectionSummary();
@@ -132,12 +159,22 @@
      * Search for existing sub device {@link CachedBluetoothDevice}.
      *
      * @param device the address of the Bluetooth device
-     * @return true for found sub device or false.
+     * @return true for found sub / member device or false.
      */
     public synchronized boolean isSubDevice(BluetoothDevice device) {
         for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
             if (!cachedDevice.getDevice().equals(device)) {
-                // Check sub devices if it exists
+                // Check the member devices of the coordinated set if it exists
+                Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
+                if (memberDevices != null) {
+                    for (CachedBluetoothDevice memberDevice : memberDevices) {
+                        if (memberDevice.getDevice().equals(device)) {
+                            return true;
+                        }
+                    }
+                    continue;
+                }
+                // Check sub devices of hearing aid if it exists
                 CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
                 if (subDevice != null && subDevice.getDevice().equals(device)) {
                     return true;
@@ -157,6 +194,14 @@
     }
 
     /**
+     * Updates the Csip devices; specifically the GroupId's. This routine is called when the
+     * CSIS is connected and the GroupId's are now available.
+     */
+    public synchronized void updateCsipDevices() {
+        mCsipDeviceManager.updateCsipDevices();
+    }
+
+    /**
      * Attempts to get the name of a remote device, otherwise returns the address.
      *
      * @param device The remote device.
@@ -185,6 +230,16 @@
     private void clearNonBondedSubDevices() {
         for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
             CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
+            final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
+            if (memberDevices != null) {
+                for (CachedBluetoothDevice memberDevice : memberDevices) {
+                    // Member device exists and it is not bonded
+                    if (memberDevice.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
+                        cachedDevice.removeMemberDevice(memberDevice);
+                    }
+                }
+                return;
+            }
             CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
             if (subDevice != null
                     && subDevice.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
@@ -201,6 +256,13 @@
         for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
             CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
             cachedDevice.setJustDiscovered(false);
+            final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
+            if (memberDevices != null) {
+                for (CachedBluetoothDevice memberDevice : memberDevices) {
+                    memberDevice.setJustDiscovered(false);
+                }
+                return;
+            }
             final CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
             if (subDevice != null) {
                 subDevice.setJustDiscovered(false);
@@ -214,10 +276,19 @@
         if (bluetoothState == BluetoothAdapter.STATE_TURNING_OFF) {
             for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
                 CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
-                CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
-                if (subDevice != null) {
-                    if (subDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
-                        cachedDevice.setSubDevice(null);
+                final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
+                if (memberDevices != null) {
+                    for (CachedBluetoothDevice memberDevice : memberDevices) {
+                        if (memberDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
+                            cachedDevice.removeMemberDevice(memberDevice);
+                        }
+                    }
+                } else {
+                    CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
+                    if (subDevice != null) {
+                        if (subDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
+                            cachedDevice.setSubDevice(null);
+                        }
                     }
                 }
                 if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
@@ -229,13 +300,32 @@
     }
 
     public synchronized boolean onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice
-            cachedDevice, int state) {
-        return mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
+            cachedDevice, int state, int profileId) {
+        if (profileId == BluetoothProfile.HEARING_AID) {
+            return mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
                 state);
+        }
+        if (profileId == BluetoothProfile.CSIP_SET_COORDINATOR) {
+            return mCsipDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
+                state);
+        }
+        return false;
     }
 
     public synchronized void onDeviceUnpaired(CachedBluetoothDevice device) {
-        CachedBluetoothDevice mainDevice = mHearingAidDeviceManager.findMainDevice(device);
+        CachedBluetoothDevice mainDevice = mCsipDeviceManager.findMainDevice(device);
+        final Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
+        if (memberDevices != null) {
+            // Main device is unpaired, to unpair the member device
+            for (CachedBluetoothDevice memberDevice : memberDevices) {
+                memberDevice.unpair();
+                device.removeMemberDevice(memberDevice);
+            }
+        } else if (mainDevice != null) {
+            // the member device unpaired, to unpair main device
+            mainDevice.unpair();
+        }
+        mainDevice = mHearingAidDeviceManager.findMainDevice(device);
         CachedBluetoothDevice subDevice = device.getSubDevice();
         if (subDevice != null) {
             // Main device is unpaired, to unpair sub device
@@ -248,6 +338,74 @@
         }
     }
 
+    /**
+     * Called when we found a set member of a group. The function will check the {@code groupId} if
+     * it exists and if there is a ongoing pair, the device would be ignored.
+     *
+     * @param device The found device
+     * @param groupId The group id of the found device
+     */
+    public synchronized void onSetMemberAppear(BluetoothDevice device, int groupId) {
+        Log.d(TAG, "onSetMemberAppear, groupId: " + groupId + " device: " + device.toString());
+
+        if (mOngoingSetMemberPair != null) {
+            Log.d(TAG, "Ongoing set memberPairing in process, drop it!");
+            return;
+        }
+
+        if (mCsipDeviceManager.onSetMemberAppear(device, groupId)) {
+            mOngoingSetMemberPair = device;
+        }
+    }
+
+    /**
+     * Called when the bond state change. If the bond state change is related with the
+     * ongoing set member pair, the cachedBluetoothDevice will be created but the UI
+     * would not be updated. For the other case, return {@code false} to go through the normal
+     * flow.
+     *
+     * @param device The device
+     * @param bondState The new bond state
+     *
+     * @return {@code true}, if the bond state change for the device is handled inside this
+     * function, and would not like to update the UI. If not, return {@code false}.
+     */
+    public synchronized boolean onBondStateChangedIfProcess(BluetoothDevice device, int bondState) {
+        if (mOngoingSetMemberPair == null || !mOngoingSetMemberPair.equals(device)) {
+            return false;
+        }
+
+        if (bondState == BluetoothDevice.BOND_BONDING) {
+            return true;
+        }
+
+        mOngoingSetMemberPair = null;
+        if (bondState != BluetoothDevice.BOND_NONE) {
+            if (findDevice(device) == null) {
+                final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
+                CachedBluetoothDevice newDevice =
+                        new CachedBluetoothDevice(mContext, profileManager, device);
+                mCachedDevices.add(newDevice);
+                findDevice(device).connect();
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Check if the device is the one which is initial paired locally by CSIP. The setting
+     * would depned on it to accept the pairing request automatically
+     *
+     * @param device The device
+     *
+     * @return {@code true}, if the device is ongoing pair by CSIP. Otherwise, return
+     * {@code false}.
+     */
+    public boolean isOngoingPairByCsip(BluetoothDevice device) {
+        return !(mOngoingSetMemberPair == null) && mOngoingSetMemberPair.equals(device);
+    }
+
     private void log(String msg) {
         if (DEBUG) {
             Log.d(TAG, msg);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
new file mode 100644
index 0000000..347e14b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -0,0 +1,270 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothCsipSetCoordinator;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * CsipDeviceManager manages the set of remote CSIP Bluetooth devices.
+ */
+public class CsipDeviceManager {
+    private static final String TAG = "CsipDeviceManager";
+    private static final boolean DEBUG = BluetoothUtils.D;
+
+    private final LocalBluetoothManager mBtManager;
+    private final List<CachedBluetoothDevice> mCachedDevices;
+
+    CsipDeviceManager(LocalBluetoothManager localBtManager,
+            List<CachedBluetoothDevice> cachedDevices) {
+        mBtManager = localBtManager;
+        mCachedDevices = cachedDevices;
+    };
+
+    void initCsipDeviceIfNeeded(CachedBluetoothDevice newDevice) {
+        // Current it only supports the base uuid for CSIP and group this set in UI.
+        final int groupId = getBaseGroupId(newDevice.getDevice());
+        if (isValidGroupId(groupId)) {
+            log("initCsipDeviceIfNeeded: " + newDevice + " (group: " + groupId + ")");
+            // Once groupId is valid, assign groupId
+            newDevice.setGroupId(groupId);
+        }
+    }
+
+    private int getBaseGroupId(BluetoothDevice device) {
+        final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
+        final CsipSetCoordinatorProfile profileProxy = profileManager
+                .getCsipSetCoordinatorProfile();
+        if (profileProxy != null) {
+            final Map<Integer, ParcelUuid> groupIdMap = profileProxy
+                    .getGroupUuidMapByDevice(device);
+            if (groupIdMap == null) {
+                return BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
+            }
+
+            for (Map.Entry<Integer, ParcelUuid> entry: groupIdMap.entrySet()) {
+                if (entry.getValue().equals(BluetoothUuid.BASE_UUID)) {
+                    return entry.getKey();
+                }
+            }
+        }
+        return BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
+    }
+
+    boolean setMemberDeviceIfNeeded(CachedBluetoothDevice newDevice) {
+        final int groupId = newDevice.getGroupId();
+        if (isValidGroupId(groupId)) {
+            final CachedBluetoothDevice CsipDevice = getCachedDevice(groupId);
+            log("setMemberDeviceIfNeeded, main: " + CsipDevice + ", member: " + newDevice);
+            // Just add one of the coordinated set from a pair in the list that is shown in the UI.
+            // Once there is other devices with the same groupId, to add new device as member
+            // devices.
+            if (CsipDevice != null) {
+                CsipDevice.setMemberDevice(newDevice);
+                newDevice.setName(CsipDevice.getName());
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isValidGroupId(int groupId) {
+        return groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
+    }
+
+    private CachedBluetoothDevice getCachedDevice(int groupId) {
+        for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
+            CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
+            if (cachedDevice.getGroupId() == groupId) {
+                return cachedDevice;
+            }
+        }
+        return null;
+    }
+
+    // To collect all set member devices and call #onGroupIdChanged to group device by GroupId
+    void updateCsipDevices() {
+        final Set<Integer> newGroupIdSet = new HashSet<Integer>();
+        for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
+            // Do nothing if GroupId has been assigned
+            if (!isValidGroupId(cachedDevice.getGroupId())) {
+                final int newGroupId = getBaseGroupId(cachedDevice.getDevice());
+                // Do nothing if there is no GroupId on Bluetooth device
+                if (isValidGroupId(newGroupId)) {
+                    cachedDevice.setGroupId(newGroupId);
+                    newGroupIdSet.add(newGroupId);
+                }
+            }
+        }
+        for (int groupId : newGroupIdSet) {
+            onGroupIdChanged(groupId);
+        }
+    }
+
+    // Group devices by groupId
+    @VisibleForTesting
+    void onGroupIdChanged(int groupId) {
+        int firstMatchedIndex = -1;
+        CachedBluetoothDevice mainDevice = null;
+
+        for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
+            final CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
+            if (cachedDevice.getGroupId() != groupId) {
+                continue;
+            }
+
+            if (firstMatchedIndex == -1) {
+                // Found the first one
+                firstMatchedIndex = i;
+                mainDevice = cachedDevice;
+                continue;
+            }
+
+            log("onGroupIdChanged: removed from UI device =" + cachedDevice
+                    + ", with groupId=" + groupId + " firstMatchedIndex=" + firstMatchedIndex);
+
+            mainDevice.setMemberDevice(cachedDevice);
+            mCachedDevices.remove(i);
+            mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
+            break;
+        }
+    }
+
+    // @return {@code true}, the event is processed inside the method. It is for updating
+    // le audio device on group relationship when receiving connected or disconnected.
+    // @return {@code false}, it is not le audio device or to process it same as other profiles
+    boolean onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice cachedDevice,
+            int state) {
+        log("onProfileConnectionStateChangedIfProcessed: " + cachedDevice + ", state: " + state);
+        switch (state) {
+            case BluetoothProfile.STATE_CONNECTED:
+                onGroupIdChanged(cachedDevice.getGroupId());
+                CachedBluetoothDevice mainDevice = findMainDevice(cachedDevice);
+                if (mainDevice != null) {
+                    if (mainDevice.isConnected()) {
+                        // When main device exists and in connected state, receiving member device
+                        // connection. To refresh main device UI
+                        mainDevice.refresh();
+                        return true;
+                    } else {
+                        // When both LE Audio devices are disconnected, receiving member device
+                        // connection. To switch content and dispatch to notify UI change
+                        mBtManager.getEventManager().dispatchDeviceRemoved(mainDevice);
+                        mainDevice.switchMemberDeviceContent(mainDevice, cachedDevice);
+                        mainDevice.refresh();
+                        // It is necessary to do remove and add for updating the mapping on
+                        // preference and device
+                        mBtManager.getEventManager().dispatchDeviceAdded(mainDevice);
+                        return true;
+                    }
+                }
+                break;
+            case BluetoothProfile.STATE_DISCONNECTED:
+                mainDevice = findMainDevice(cachedDevice);
+                if (mainDevice != null) {
+                    // When main device exists, receiving sub device disconnection
+                    // To update main device UI
+                    mainDevice.refresh();
+                    return true;
+                }
+                final Set<CachedBluetoothDevice> memberSet = cachedDevice.getMemberDevice();
+                if (memberSet == null) {
+                    break;
+                }
+
+                for (CachedBluetoothDevice device: memberSet) {
+                    if (device.isConnected()) {
+                        // Main device is disconnected and sub device is connected
+                        // To copy data from sub device to main device
+                        mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
+                        cachedDevice.switchMemberDeviceContent(device, cachedDevice);
+                        cachedDevice.refresh();
+                        // It is necessary to do remove and add for updating the mapping on
+                        // preference and device
+                        mBtManager.getEventManager().dispatchDeviceAdded(cachedDevice);
+                        return true;
+                    }
+                }
+                break;
+            default:
+                // Do not handle this state.
+        }
+        return false;
+    }
+
+    CachedBluetoothDevice findMainDevice(CachedBluetoothDevice device) {
+        if (device == null || mCachedDevices == null) {
+            return null;
+        }
+
+        for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
+            if (isValidGroupId(cachedDevice.getGroupId())) {
+                Set<CachedBluetoothDevice> memberSet = cachedDevice.getMemberDevice();
+                if (memberSet == null) {
+                    continue;
+                }
+
+                for (CachedBluetoothDevice memberDevice: memberSet) {
+                    if (memberDevice != null && memberDevice.equals(device)) {
+                        return cachedDevice;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Called when we found a set member of a group. The function will check bond state, and
+     * the {@code groupId} if it exists, and then create the bond.
+     *
+     * @param device The found device
+     * @param groupId The group id of the found device
+     *
+     * @return {@code true}, if the we create bond with the device. Otherwise, return
+     * {@code false}.
+     */
+    public boolean onSetMemberAppear(BluetoothDevice device, int groupId) {
+        if (device.getBondState() != BluetoothDevice.BOND_NONE) {
+            return false;
+        }
+
+        if (getCachedDevice(groupId) != null) {
+            device.createBond(BluetoothDevice.TRANSPORT_LE);
+            return true;
+        }
+
+        return false;
+    }
+
+    private void log(String msg) {
+        if (DEBUG) {
+            Log.d(TAG, msg);
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipSetCoordinatorProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipSetCoordinatorProfile.java
index 754914f..6da249c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipSetCoordinatorProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipSetCoordinatorProfile.java
@@ -26,6 +26,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
+import android.os.ParcelUuid;
 import android.util.Log;
 
 import androidx.annotation.RequiresApi;
@@ -34,6 +35,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 /**
  * CSIP Set Coordinator handles Bluetooth CSIP Set Coordinator role profile.
@@ -80,6 +82,7 @@
                 device.refresh();
             }
 
+            mDeviceManager.updateCsipDevices();
             mProfileManager.callServiceConnectedListeners();
             mIsProfileReady = true;
         }
@@ -212,6 +215,18 @@
     }
 
     /**
+     * Get the device's groups and correspondsing uuids map.
+     * @param device the bluetooth device
+     * @return Map of groups ids and related UUIDs
+     */
+    public Map<Integer, ParcelUuid> getGroupUuidMapByDevice(BluetoothDevice device) {
+        if (mService == null || device == null) {
+            return null;
+        }
+        return mService.getGroupUuidMapByDevice(device);
+    }
+
+    /**
      * Return the profile name as a string.
      */
     public String toString() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 201825f..bcb3455 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -318,11 +318,35 @@
                     }
                 }
             }
+
+            if (getCsipSetCoordinatorProfile() != null
+                    && mProfile instanceof CsipSetCoordinatorProfile
+                    && newState == BluetoothProfile.STATE_CONNECTED) {
+                // Check if the GroupID has being initialized
+                if (cachedDevice.getGroupId() == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+                    final Map<Integer, ParcelUuid> groupIdMap = getCsipSetCoordinatorProfile()
+                            .getGroupUuidMapByDevice(cachedDevice.getDevice());
+                    if (groupIdMap != null) {
+                        for (Map.Entry<Integer, ParcelUuid> entry: groupIdMap.entrySet()) {
+                            if (entry.getValue().equals(BluetoothUuid.BASE_UUID)) {
+                                cachedDevice.setGroupId(entry.getKey());
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+
             cachedDevice.onProfileStateChanged(mProfile, newState);
             // Dispatch profile changed after device update
-            if (!(cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID
-                    && mDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
-                    newState))) {
+            boolean needDispatchProfileConnectionState = true;
+            if (cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID
+                    || cachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+                needDispatchProfileConnectionState = !mDeviceManager
+                        .onProfileConnectionStateChangedIfProcessed(cachedDevice, newState,
+                        mProfile.getProfileId());
+            }
+            if (needDispatchProfileConnectionState) {
                 cachedDevice.refresh();
                 mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState,
                         mProfile.getProfileId());
diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompat.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompat.java
index 692dfbf..1d8f71e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompat.java
+++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompat.java
@@ -36,6 +36,7 @@
 import androidx.preference.TwoStatePreference;
 
 import com.android.internal.app.LocaleHelper;
+import com.android.settingslib.PrimarySwitchPreference;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -173,9 +174,14 @@
             }
             // In the choose input method screen or in the subtype enabler screen,
             // <code>pref</code> is an instance of TwoStatePreference.
-            final boolean isImeChecked = (pref instanceof TwoStatePreference) ?
-                    ((TwoStatePreference) pref).isChecked()
-                    : enabledIMEsAndSubtypesMap.containsKey(imiId);
+            final boolean isImeChecked;
+            if (pref instanceof TwoStatePreference) {
+                isImeChecked = ((TwoStatePreference) pref).isChecked();
+            } else if (pref instanceof PrimarySwitchPreference) {
+                isImeChecked = ((PrimarySwitchPreference) pref).isChecked();
+            } else {
+                isImeChecked = enabledIMEsAndSubtypesMap.containsKey(imiId);
+            }
             final boolean isCurrentInputMethod = imiId.equals(currentInputMethodId);
             final boolean systemIme = imi.isSystem();
             if ((!hasHardKeyboard && InputMethodSettingValuesWrapper.getInstance(
diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java
index 546095e..94a0c00 100644
--- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java
@@ -29,16 +29,20 @@
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodSubtype;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.Switch;
 import android.widget.Toast;
 
 import androidx.preference.Preference;
 import androidx.preference.Preference.OnPreferenceChangeListener;
 import androidx.preference.Preference.OnPreferenceClickListener;
+import androidx.preference.PreferenceViewHolder;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.PrimarySwitchPreference;
 import com.android.settingslib.R;
 import com.android.settingslib.RestrictedLockUtilsInternal;
-import com.android.settingslib.RestrictedSwitchPreference;
 
 import java.text.Collator;
 import java.util.List;
@@ -46,15 +50,12 @@
 /**
  * Input method preference.
  *
- * This preference represents an IME. It is used for two purposes. 1) An instance with a switch
- * is used to enable or disable the IME. 2) An instance without a switch is used to invoke the
- * setting activity of the IME.
+ * This preference represents an IME. It is used for two purposes. 1) Using a switch to enable or
+ * disable the IME 2) Invoking the setting activity of the IME.
  */
-public class InputMethodPreference extends RestrictedSwitchPreference implements OnPreferenceClickListener,
-        OnPreferenceChangeListener {
+public class InputMethodPreference extends PrimarySwitchPreference
+        implements OnPreferenceClickListener, OnPreferenceChangeListener {
     private static final String TAG = InputMethodPreference.class.getSimpleName();
-    private static final String EMPTY_TEXT = "";
-    private static final int NO_WIDGET = 0;
 
     public interface OnSavePreferenceListener {
         /**
@@ -82,23 +83,15 @@
      *
      * @param context The Context this is associated with.
      * @param imi The {@link InputMethodInfo} of this preference.
-     * @param isImeEnabler true if this preference is the IME enabler that has enable/disable
-     *     switches for all available IMEs, not the list of enabled IMEs.
      * @param isAllowedByOrganization false if the IME has been disabled by a device or profile
      *     owner.
      * @param onSaveListener The listener called when this preference has been changed and needs
      *     to save the state to shared preference.
      */
     public InputMethodPreference(final Context context, final InputMethodInfo imi,
-            final boolean isImeEnabler, final boolean isAllowedByOrganization,
-            final OnSavePreferenceListener onSaveListener) {
+            final boolean isAllowedByOrganization, final OnSavePreferenceListener onSaveListener) {
         this(context, imi, imi.loadLabel(context.getPackageManager()), isAllowedByOrganization,
                 onSaveListener);
-        if (!isImeEnabler) {
-            // Remove switch widget.
-            setWidgetLayoutResource(NO_WIDGET);
-        }
-        setIconSize(context.getResources().getDimensionPixelSize(R.dimen.secondary_app_icon_size));
     }
 
     @VisibleForTesting
@@ -110,9 +103,6 @@
         mImi = imi;
         mIsAllowedByOrganization = isAllowedByOrganization;
         mOnSaveListener = onSaveListener;
-        // Disable on/off switch texts.
-        setSwitchTextOn(EMPTY_TEXT);
-        setSwitchTextOff(EMPTY_TEXT);
         setKey(imi.getId());
         setTitle(title);
         final String settingsActivity = imi.getSettingsActivity();
@@ -135,20 +125,36 @@
         return mImi;
     }
 
-    private boolean isImeEnabler() {
-        // If this {@link SwitchPreference} doesn't have a widget layout, we explicitly hide the
-        // switch widget at constructor.
-        return getWidgetLayoutResource() != NO_WIDGET;
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+        final Switch switchWidget = getSwitch();
+        if (switchWidget != null) {
+            switchWidget.setOnClickListener(v -> {
+                // no-op, avoid default behavior in {@link PrimarySwitchPreference#onBindViewHolder}
+            });
+            switchWidget.setOnCheckedChangeListener((buttonView, isChecked) -> {
+                // Avoid the invocation after we call {@link PrimarySwitchPreference#setChecked()}
+                // in {@link setCheckedInternal}
+                if (isChecked != isChecked()) {
+                    // Keep switch to previous state because we have to show the dialog first
+                    buttonView.setChecked(!isChecked);
+                    callChangeListener(isChecked());
+                }
+            });
+        }
+        final ImageView icon = holder.itemView.findViewById(android.R.id.icon);
+        final int iconSize = getContext().getResources().getDimensionPixelSize(
+                R.dimen.secondary_app_icon_size);
+        if (icon != null && iconSize > 0) {
+            icon.setLayoutParams(new LinearLayout.LayoutParams(iconSize, iconSize));
+        }
     }
 
     @Override
     public boolean onPreferenceChange(final Preference preference, final Object newValue) {
         // Always returns false to prevent default behavior.
         // See {@link TwoStatePreference#onClick()}.
-        if (!isImeEnabler()) {
-            // Prevent disabling an IME because this preference is for invoking a settings activity.
-            return false;
-        }
         if (isChecked()) {
             // Disable this IME.
             setCheckedInternal(false);
@@ -176,11 +182,6 @@
     public boolean onPreferenceClick(final Preference preference) {
         // Always returns true to prevent invoking an intent without catching exceptions.
         // See {@link Preference#performClick(PreferenceScreen)}/
-        if (isImeEnabler()) {
-            // Prevent invoking a settings activity because this preference is for enabling and
-            // disabling an input method.
-            return true;
-        }
         final Context context = getContext();
         try {
             final Intent intent = getIntent();
@@ -204,9 +205,9 @@
         // this preference should be disabled to prevent accidentally disabling an input method.
         // This preference should also be disabled in case the admin does not allow this input
         // method.
-        if (isAlwaysChecked && isImeEnabler()) {
+        if (isAlwaysChecked) {
             setDisabledByAdmin(null);
-            setEnabled(false);
+            setSwitchEnabled(false);
         } else if (!mIsAllowedByOrganization) {
             EnforcedAdmin admin =
                     RestrictedLockUtilsInternal.checkIfInputMethodDisallowed(getContext(),
@@ -214,6 +215,7 @@
             setDisabledByAdmin(admin);
         } else {
             setEnabled(true);
+            setSwitchEnabled(true);
         }
         setChecked(mInputMethodSettingValues.isEnabledImi(mImi));
         if (!isDisabledByAdmin()) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java b/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java
index a0c8663..ea5105b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java
+++ b/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java
@@ -319,23 +319,11 @@
 
         @Override
         public boolean onPreferenceClick(Preference preference) {
-            // Activity to start if they click on the preference. Must start in new task to ensure
-            // that "android.settings.LOCATION_SOURCE_SETTINGS" brings user back to
-            // Settings > Location.
+            // Activity to start if they click on the preference.
             Intent settingIntent = new Intent();
             settingIntent.setClassName(mInfo.packageName, mInfo.settingsActivity);
+            // No flags set to ensure the activity is launched within the same settings task.
             logPreferenceClick(settingIntent);
-            // Sometimes the user may navigate back to "Settings" and launch another different
-            // injected setting after one injected setting has been launched.
-            //
-            // FLAG_ACTIVITY_CLEAR_TOP allows multiple Activities to stack on each other. When
-            // "back" button is clicked, the user will navigate through all the injected settings
-            // launched before. Such behavior could be quite confusing sometimes.
-            //
-            // In order to avoid such confusion, we use FLAG_ACTIVITY_CLEAR_TASK, which always clear
-            // up all existing injected settings and make sure that "back" button always brings the
-            // user back to "Settings" directly.
-            settingIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
             mContext.startActivityAsUser(settingIntent, mInfo.mUserHandle);
             return true;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
index b65637f..5ee919b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.icu.text.MeasureFormat;
 import android.icu.text.MeasureFormat.FormatWidth;
+import android.icu.text.MessageFormat;
 import android.icu.text.RelativeDateTimeFormatter;
 import android.icu.text.RelativeDateTimeFormatter.RelativeUnit;
 import android.icu.util.Measure;
@@ -31,7 +32,9 @@
 import com.android.settingslib.R;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Locale;
+import java.util.Map;
 
 /** Utility class for generally useful string methods **/
 public class StringUtil {
@@ -183,4 +186,37 @@
         return formatRelativeTime(context, millis, withSeconds,
                 RelativeDateTimeFormatter.Style.LONG);
     }
+
+    /**
+     * Get ICU plural string without additional arguments
+     *
+     * @param context Context used to get the string
+     * @param count The number used to get the correct string for the current language's plural
+     *              rules.
+     * @param resId Resource id of the string
+     *
+     * @return Formatted plural string
+     */
+    public static String getIcuPluralsString(Context context, int count, int resId) {
+        MessageFormat msgFormat = new MessageFormat(context.getResources().getString(resId),
+                Locale.getDefault());
+        Map<String, Object> arguments = new HashMap<>();
+        arguments.put("count", count);
+        return msgFormat.format(arguments);
+    }
+
+    /**
+     * Get ICU plural string with additional arguments
+     *
+     * @param context Context used to get the string
+     * @param args String arguments
+     * @param resId Resource id of the string
+     *
+     * @return Formatted plural string
+     */
+    public static String getIcuPluralsString(Context context, Map<String, Object> args, int resId) {
+        MessageFormat msgFormat = new MessageFormat(context.getResources().getString(resId),
+                Locale.getDefault());
+        return msgFormat.format(args);
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
index fd5b053..4f8fa2f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
@@ -206,7 +206,7 @@
         mContext.sendBroadcast(mIntent);
 
         verify(mDeviceManager).onProfileConnectionStateChangedIfProcessed(mCachedBluetoothDevice,
-                BluetoothProfile.STATE_CONNECTED);
+                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
     }
 
     /**
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
index 9e3312a..29549d9 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
@@ -55,6 +55,7 @@
     @Mock
     private ViewGroup mRootView;
     private Uri mImageUri;
+    private ImageView mBackgroundView;
     private LottieAnimationView mAnimationView;
     private IllustrationPreference mPreference;
     private PreferenceViewHolder mViewHolder;
@@ -66,6 +67,7 @@
         MockitoAnnotations.initMocks(this);
 
         mImageUri = new Uri.Builder().build();
+        mBackgroundView = new ImageView(mContext);
         mAnimationView = spy(new LottieAnimationView(mContext));
         mMiddleGroundLayout = new FrameLayout(mContext);
         final FrameLayout illustrationFrame = new FrameLayout(mContext);
@@ -73,6 +75,7 @@
                 new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                         ViewGroup.LayoutParams.WRAP_CONTENT));
         doReturn(mMiddleGroundLayout).when(mRootView).findViewById(R.id.middleground_layout);
+        doReturn(mBackgroundView).when(mRootView).findViewById(R.id.background_view);
         doReturn(mAnimationView).when(mRootView).findViewById(R.id.lottie_view);
         doReturn(illustrationFrame).when(mRootView).findViewById(R.id.illustration_frame);
         mViewHolder = spy(PreferenceViewHolder.createInstanceForTests(mRootView));
@@ -155,4 +158,32 @@
 
         verify(mAnimationView).setFailureListener(any());
     }
+
+    @Test
+    public void setMaxHeight_smallerThanRestrictedHeight_matchResult() {
+        final int restrictedHeight =
+                mContext.getResources().getDimensionPixelSize(
+                        R.dimen.settingslib_illustration_height);
+        final int maxHeight = restrictedHeight - 200;
+
+        mPreference.setMaxHeight(maxHeight);
+        mPreference.onBindViewHolder(mViewHolder);
+
+        assertThat(mBackgroundView.getMaxHeight()).isEqualTo(maxHeight);
+        assertThat(mAnimationView.getMaxHeight()).isEqualTo(maxHeight);
+    }
+
+    @Test
+    public void setMaxHeight_largerThanRestrictedHeight_specificHeight() {
+        final int restrictedHeight =
+                mContext.getResources().getDimensionPixelSize(
+                        R.dimen.settingslib_illustration_height);
+        final int maxHeight = restrictedHeight + 200;
+
+        mPreference.setMaxHeight(maxHeight);
+        mPreference.onBindViewHolder(mViewHolder);
+
+        assertThat(mBackgroundView.getMaxHeight()).isEqualTo(restrictedHeight);
+        assertThat(mAnimationView.getMaxHeight()).isEqualTo(restrictedHeight);
+    }
 }
diff --git a/packages/SettingsProvider/res/values-as/strings.xml b/packages/SettingsProvider/res/values-as/strings.xml
index 89b7c1e..ead9f4d 100644
--- a/packages/SettingsProvider/res/values-as/strings.xml
+++ b/packages/SettingsProvider/res/values-as/strings.xml
@@ -19,7 +19,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="4567566098528588863">"ছেটিংছসমূহৰ সঞ্চয়াগাৰ"</string>
-    <string name="wifi_softap_config_change" msgid="5688373762357941645">"হটস্পটৰ ছেটিংসমূহ সলনি হৈছে"</string>
+    <string name="app_label" msgid="4567566098528588863">"ছেটিঙৰ ষ্ট\'ৰেজ"</string>
+    <string name="wifi_softap_config_change" msgid="5688373762357941645">"হটস্পটৰ ছেটিং সলনি হৈছে"</string>
     <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"সবিশেষ চাবলৈ টিপক"</string>
 </resources>
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 4ebfbd2..df7bf20 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -272,6 +272,7 @@
                     Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
                     Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
                     Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS,
+                    Settings.Global.ENABLE_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT,
                     Settings.Global.ENABLE_ADB_INCREMENTAL_INSTALL_DEFAULT,
                     Settings.Global.ENABLE_MULTI_SLOT_TIMEOUT_MILLIS,
                     Settings.Global.ENHANCED_4G_MODE_ENABLED,
@@ -721,7 +722,6 @@
                  Settings.Secure.DOCKED_CLOCK_FACE,
                  Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
                  Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION,
-                 Settings.Secure.ENABLE_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT,
                  Settings.Secure.ENABLED_INPUT_METHODS,  // Intentionally removed in P
                  Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT,
                  Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
index b8039e1..e026012 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
@@ -37,8 +37,7 @@
 
 const val GOOGLE_BLUE = 0xFF1b6ef3.toInt()
 
-const val MIN_CHROMA = 15
-const val MIN_LSTAR = 10
+const val MIN_CHROMA = 5
 
 public class ColorScheme(@ColorInt seed: Int, val darkTheme: Boolean) {
 
@@ -75,7 +74,14 @@
         get() = ColorUtils.setAlphaComponent(if (darkTheme) accent1[2] else accent1[6], 0xFF)
 
     init {
-        val seedArgb = if (seed == Color.TRANSPARENT) GOOGLE_BLUE else seed
+        val proposedSeedCam = Cam.fromInt(seed)
+        val seedArgb = if (seed == Color.TRANSPARENT) {
+            GOOGLE_BLUE
+        } else if (proposedSeedCam.chroma < 5) {
+            GOOGLE_BLUE
+        } else {
+            seed
+        }
         val camSeed = Cam.fromInt(seedArgb)
         val hue = camSeed.hue
         val chroma = camSeed.chroma.coerceAtLeast(ACCENT1_CHROMA)
@@ -129,9 +135,7 @@
                 val distinctColors = wallpaperColors.mainColors.map {
                     it.toArgb()
                 }.distinct().filter {
-                    val cam = Cam.fromInt(it)
-                    val lstar = lstarFromInt(it)
-                    cam.chroma >= MIN_CHROMA && lstar >= MIN_LSTAR
+                    Cam.fromInt(it).chroma >= MIN_CHROMA
                 }.toList()
 
                 if (distinctColors.isEmpty()) {
@@ -164,30 +168,38 @@
                 val cam = it.value
                 val lstar = lstarFromInt(it.key)
                 val proportion = intToHueProportion[it.key]!!
-                cam.chroma >= MIN_CHROMA && lstar >= MIN_LSTAR &&
+                cam.chroma >= MIN_CHROMA &&
                         (totalPopulationMeaningless || proportion > 0.01)
             }
             // Sort the colors by score, from high to low.
-            val seeds = mutableListOf<Int>()
             val intToScoreIntermediate = filteredIntToCam.mapValues {
                 score(it.value, intToHueProportion[it.key]!!)
             }
             val intToScore = intToScoreIntermediate.entries.toMutableList()
             intToScore.sortByDescending { it.value }
 
-            // Go through the colors, from high score to low score. If there isn't already a seed
-            // color with a hue close to color being examined, add the color being examined to the
-            // seed colors.
-            for (entry in intToScore) {
-                val int = entry.key
-                val existingSeedNearby = seeds.find {
-                    val hueA = intToCam[int]!!.hue
-                    val hueB = intToCam[it]!!.hue
-                    hueDiff(hueA, hueB) < 15 } != null
-                if (existingSeedNearby) {
-                    continue
+            // Go through the colors, from high score to low score.
+            // If the color is distinct in hue from colors picked so far, pick the color.
+            // Iteratively decrease the amount of hue distinctness required, thus ensuring we
+            // maximize difference between colors.
+            val minimumHueDistance = 15
+            val seeds = mutableListOf<Int>()
+            maximizeHueDistance@ for (i in 90 downTo minimumHueDistance step 1) {
+                seeds.clear()
+                for (entry in intToScore) {
+                    val int = entry.key
+                    val existingSeedNearby = seeds.find {
+                        val hueA = intToCam[int]!!.hue
+                        val hueB = intToCam[it]!!.hue
+                        hueDiff(hueA, hueB) < i } != null
+                    if (existingSeedNearby) {
+                        continue
+                    }
+                    seeds.add(int)
+                    if (seeds.size >= 4) {
+                        break@maximizeHueDistance
+                    }
                 }
-                seeds.add(int)
             }
 
             if (seeds.isEmpty()) {
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java b/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java
index 498b7dd..aab3538 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java
@@ -53,10 +53,15 @@
      */
     public static @ColorInt int[] of(float hue, float chroma) {
         int[] shades = new int[12];
-        shades[0] = ColorUtils.CAMToColor(hue, chroma, 99);
-        shades[1] = ColorUtils.CAMToColor(hue, chroma, 95);
+        // At tone 90 and above, blue and yellow hues can reach a much higher chroma.
+        // To preserve a consistent appearance across all hues, use a maximum chroma of 40.
+        shades[0] = ColorUtils.CAMToColor(hue, Math.min(40f, chroma), 99);
+        shades[1] = ColorUtils.CAMToColor(hue, Math.min(40f, chroma), 95);
         for (int i = 2; i < 12; i++) {
             float lStar = (i == 6) ? MIDDLE_LSTAR : 100 - 10 * (i - 1);
+            if (lStar >= 90) {
+                chroma = Math.min(40f, chroma);
+            }
             shades[i] = ColorUtils.CAMToColor(hue, chroma, lStar);
         }
         return shades;
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_media_recommendation_bg_gradient.xml b/packages/SystemUI/res-keyguard/drawable/qs_media_recommendation_bg_gradient.xml
new file mode 100644
index 0000000..495fbb8
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_media_recommendation_bg_gradient.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <corners android:radius="24dp"/>
+    <gradient
+        android:angle="0"
+        android:startColor="#00000000"
+        android:endColor="#ff000000"
+        android:type="linear" />
+</shape>
diff --git a/packages/SystemUI/res/color/docked_divider_background.xml b/packages/SystemUI/res/color/docked_divider_background.xml
index 85ede9a..2ab8ecd 100644
--- a/packages/SystemUI/res/color/docked_divider_background.xml
+++ b/packages/SystemUI/res/color/docked_divider_background.xml
@@ -14,5 +14,5 @@
      limitations under the License.
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-  <item android:color="@android:color/system_neutral2_500" android:lStar="35" />
+  <item android:color="@android:color/system_neutral1_500" android:lStar="35" />
 </selector>
diff --git a/packages/SystemUI/res/color/segmented_button_text_selector.xml b/packages/SystemUI/res/color/segmented_button_text_selector.xml
index d4f0181..8f07419 100644
--- a/packages/SystemUI/res/color/segmented_button_text_selector.xml
+++ b/packages/SystemUI/res/color/segmented_button_text_selector.xml
@@ -12,7 +12,7 @@
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      See the License for the specific language governing permissions and
-     limitations under the License. ?android:attr/colorControlHighlight"
+     limitations under the License.
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
diff --git a/packages/SystemUI/res/drawable/action_chip_background.xml b/packages/SystemUI/res/drawable/action_chip_background.xml
index 0e1453c..eeff39b 100644
--- a/packages/SystemUI/res/drawable/action_chip_background.xml
+++ b/packages/SystemUI/res/drawable/action_chip_background.xml
@@ -17,7 +17,7 @@
 <ripple
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-    android:color="@color/global_screenshot_button_ripple">
+    android:color="@color/screenshot_button_ripple">
     <item android:id="@android:id/background">
         <shape android:shape="rectangle">
             <solid android:color="?androidprv:attr/colorAccentSecondary"/>
diff --git a/packages/SystemUI/res/drawable/screenshot_actions_background_protection.xml b/packages/SystemUI/res/drawable/screenshot_actions_background_protection.xml
index 21013c6..dd818a0 100644
--- a/packages/SystemUI/res/drawable/screenshot_actions_background_protection.xml
+++ b/packages/SystemUI/res/drawable/screenshot_actions_background_protection.xml
@@ -17,6 +17,6 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
     <gradient
         android:angle="90"
-        android:startColor="@color/global_screenshot_background_protection_start"
+        android:startColor="@color/screenshot_background_protection_start"
         android:endColor="#00000000"/>
 </shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_screenshot_legacy.xml b/packages/SystemUI/res/layout/global_screenshot_legacy.xml
deleted file mode 100644
index 791c7ea..0000000
--- a/packages/SystemUI/res/layout/global_screenshot_legacy.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 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.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <ImageView android:id="@+id/global_screenshot_legacy_background"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:src="@android:color/black"
-        android:visibility="gone" />
-    <ImageView android:id="@+id/global_screenshot_legacy"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:background="@drawable/screenshot_panel"
-        android:visibility="gone"
-        android:adjustViewBounds="true" />
-    <ImageView android:id="@+id/global_screenshot_legacy_flash"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:src="@android:color/white"
-        android:visibility="gone" />
-    <com.android.systemui.screenshot.ScreenshotSelectorView
-        android:id="@+id/global_screenshot_legacy_selector"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:visibility="gone"
-        android:pointerIcon="crosshair"/>
-</FrameLayout>
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index d286832..918635d 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -38,8 +38,7 @@
             android:gravity="center_vertical|center_horizontal"
             android:layout_width="wrap_content"
             android:layout_height="32dp"
-            android:textColor="?android:attr/textColorPrimary"
-            android:fontFamily="@*android:string/config_headlineFontFamily"
+            android:textAppearance="@style/TextAppearance.InternetDialog"
             android:textSize="24sp"/>
 
         <TextView
@@ -50,8 +49,7 @@
             android:layout_marginTop="4dp"
             android:ellipsize="end"
             android:maxLines="1"
-            android:fontFamily="@*android:string/config_headlineFontFamily"
-            android:textSize="14sp"/>
+            android:textAppearance="@style/TextAppearance.InternetDialog.Secondary"/>
     </LinearLayout>
 
     <LinearLayout
@@ -165,10 +163,11 @@
                         android:layout_gravity="end|center_vertical">
                         <Switch
                             android:id="@+id/mobile_toggle"
+                            android:contentDescription="@string/mobile_data_settings_title"
                             android:switchMinWidth="@dimen/settingslib_switch_track_width"
                             android:layout_gravity="center"
                             android:layout_width="@dimen/settingslib_switch_track_width"
-                            android:layout_height="@dimen/settingslib_switch_track_height"
+                            android:layout_height="match_parent"
                             android:track="@drawable/settingslib_track_selector"
                             android:thumb="@drawable/settingslib_thumb_selector"
                             android:theme="@style/MainSwitch.Settingslib"/>
@@ -180,7 +179,9 @@
                     android:id="@+id/turn_on_wifi_layout"
                     style="@style/InternetDialog.Network"
                     android:layout_height="72dp"
-                    android:gravity="center">
+                    android:gravity="center"
+                    android:clickable="false"
+                    android:focusable="false">
 
                     <FrameLayout
                         android:layout_weight="1"
@@ -204,10 +205,11 @@
                         android:layout_marginBottom="10dp">
                         <Switch
                             android:id="@+id/wifi_toggle"
+                            android:contentDescription="@string/turn_on_wifi"
                             android:switchMinWidth="@dimen/settingslib_switch_track_width"
                             android:layout_gravity="center"
                             android:layout_width="@dimen/settingslib_switch_track_width"
-                            android:layout_height="@dimen/settingslib_switch_track_height"
+                            android:layout_height="match_parent"
                             android:track="@drawable/settingslib_track_selector"
                             android:thumb="@drawable/settingslib_thumb_selector"
                             android:theme="@style/MainSwitch.Settingslib"/>
@@ -319,25 +321,27 @@
                         android:textAppearance="@style/TextAppearance.InternetDialog"
                         android:textSize="14sp"/>
                 </FrameLayout>
-
             </LinearLayout>
 
             <FrameLayout
-                android:layout_width="match_parent"
+                android:id="@+id/done_layout"
+                android:layout_width="67dp"
                 android:layout_height="48dp"
-                android:layout_marginBottom="40dp">
+                android:layout_marginEnd="24dp"
+                android:layout_marginBottom="40dp"
+                android:layout_gravity="end|center_vertical"
+                android:clickable="true"
+                android:focusable="true">
                 <Button
-                    style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
-                    android:id="@+id/done"
-                    android:layout_width="67dp"
-                    android:layout_height="36dp"
-                    android:layout_marginEnd="24dp"
-                    android:layout_gravity="end|center_vertical"
-                    android:background="@drawable/internet_dialog_footer_background"
-                    android:textColor="?android:attr/textColorPrimary"
                     android:text="@string/inline_done_button"
+                    style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+                    android:layout_width="match_parent"
+                    android:layout_height="36dp"
+                    android:layout_gravity="center"
+                    android:textAppearance="@style/TextAppearance.InternetDialog"
                     android:textSize="14sp"
-                    android:fontFamily="@*android:string/config_headlineFontFamily"/>
+                    android:background="@drawable/internet_dialog_footer_background"
+                    android:clickable="false"/>
             </FrameLayout>
         </LinearLayout>
     </androidx.core.widget.NestedScrollView>
diff --git a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
index c7e54d4..c3fc669 100644
--- a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
+++ b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
@@ -48,20 +48,41 @@
         android:id="@+id/recommendation_card_icon"
         android:layout_width="@dimen/qs_media_icon_size"
         android:layout_height="@dimen/qs_media_icon_size"
+        android:layout_marginTop="@dimen/qs_media_padding"
         android:src="@drawable/ic_headset"
-        style="@style/MediaPlayer.AppIcon"/>
+        style="@style/MediaPlayer.AppIcon"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/media_vertical_start_guideline"
+        app:layout_constraintHorizontal_bias="0"/>
 
     <TextView
         android:id="@+id/recommendation_card_text"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:maxLines="2"
+        android:maxLines="1"
         android:text="@string/controls_media_smartspace_rec_title"
         android:fontFamily="google-sans-medium"
         android:textDirection="locale"
         android:textSize="@dimen/qq_aa_media_rec_header_text_size"
-        android:breakStrategy="balanced"
-        android:hyphenationFrequency="none"/>
+        android:hyphenationFrequency="none"
+        app:layout_constraintTop_toBottomOf="@id/recommendation_card_icon"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/media_vertical_start_guideline"
+        app:layout_constraintHorizontal_bias="0"/>
+
+    <View
+        android:id="@+id/recommendation_gradient_view"
+        android:layout_width="@dimen/qs_aa_media_gradient_bg_width"
+        android:layout_height="0dp"
+        android:clipToPadding="false"
+        android:clipChildren="false"
+        android:background="@drawable/qs_media_recommendation_bg_gradient"
+        app:layout_constraintTop_toTopOf="@id/recommendation_card_text"
+        app:layout_constraintBottom_toBottomOf="@id/recommendation_card_text"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/media_vertical_start_guideline"
+        app:layout_constraintHorizontal_bias="1"/>
 
     <FrameLayout
         android:id="@+id/media_cover1_container"
diff --git a/packages/SystemUI/res/layout/privacy_dialog.xml b/packages/SystemUI/res/layout/privacy_dialog.xml
index 459fb66..ee4530c 100644
--- a/packages/SystemUI/res/layout/privacy_dialog.xml
+++ b/packages/SystemUI/res/layout/privacy_dialog.xml
@@ -24,9 +24,9 @@
     android:layout_marginEnd="@dimen/ongoing_appops_dialog_side_margins"
     android:layout_marginTop="8dp"
     android:orientation="vertical"
-    android:paddingBottom="12dp"
-    android:paddingTop="8dp"
+    android:paddingBottom="8dp"
+    android:paddingTop="12dp"
+    android:paddingHorizontal="@dimen/ongoing_appops_dialog_side_padding"
     android:background="@drawable/qs_dialog_bg"
 />
-<!-- 12dp padding bottom so there's 20dp total under the icon -->
-<!-- 8dp padding top, as there's 4dp margin in each row -->
\ No newline at end of file
+<!-- 8dp padding bottom so there's 16dp total under the icon -->
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/privacy_dialog_item.xml b/packages/SystemUI/res/layout/privacy_dialog_item.xml
index 7c8945e..e1f0793 100644
--- a/packages/SystemUI/res/layout/privacy_dialog_item.xml
+++ b/packages/SystemUI/res/layout/privacy_dialog_item.xml
@@ -24,8 +24,6 @@
     android:layout_marginTop="4dp"
     android:importantForAccessibility="yes"
     android:background="?android:attr/selectableItemBackground"
-    android:paddingLeft="@dimen/ongoing_appops_dialog_side_padding"
-    android:paddingRight="@dimen/ongoing_appops_dialog_side_padding"
     android:focusable="true"
     >
     <!-- 4dp marginTop makes 20dp minimum between icons -->
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/screenshot.xml
similarity index 86%
rename from packages/SystemUI/res/layout/global_screenshot.xml
rename to packages/SystemUI/res/layout/screenshot.xml
index c92b10c..7c0ee665 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/screenshot.xml
@@ -16,7 +16,7 @@
   -->
 <com.android.systemui.screenshot.ScreenshotView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/global_screenshot_frame"
+    android:id="@+id/screenshot_frame"
     android:theme="@style/Screenshot"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
@@ -29,25 +29,25 @@
         android:clickable="true"
         android:importantForAccessibility="no"/>
     <ImageView
-        android:id="@+id/global_screenshot_actions_background"
+        android:id="@+id/screenshot_actions_background"
         android:layout_height="@dimen/screenshot_bg_protection_height"
         android:layout_width="match_parent"
         android:layout_gravity="bottom"
         android:alpha="0.0"
         android:src="@drawable/screenshot_actions_background_protection"/>
     <ImageView
-        android:id="@+id/global_screenshot_flash"
+        android:id="@+id/screenshot_flash"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:visibility="gone"
         android:elevation="@dimen/screenshot_preview_elevation"
         android:src="@android:color/white"/>
     <com.android.systemui.screenshot.ScreenshotSelectorView
-        android:id="@+id/global_screenshot_selector"
+        android:id="@+id/screenshot_selector"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:visibility="gone"
         android:pointerIcon="crosshair"/>
-    <include layout="@layout/global_screenshot_static"
-             android:id="@+id/global_screenshot_static"/>
+    <include layout="@layout/screenshot_static"
+             android:id="@+id/screenshot_static"/>
 </com.android.systemui.screenshot.ScreenshotView>
diff --git a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml b/packages/SystemUI/res/layout/screenshot_action_chip.xml
similarity index 97%
rename from packages/SystemUI/res/layout/global_screenshot_action_chip.xml
rename to packages/SystemUI/res/layout/screenshot_action_chip.xml
index aeae722..b80469f 100644
--- a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
+++ b/packages/SystemUI/res/layout/screenshot_action_chip.xml
@@ -16,7 +16,7 @@
   -->
 <com.android.systemui.screenshot.ScreenshotActionChip
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/global_screenshot_action_chip"
+    android:id="@+id/screenshot_action_chip"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_marginStart="@dimen/screenshot_action_chip_margin_start"
diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/screenshot_static.xml
similarity index 69%
rename from packages/SystemUI/res/layout/global_screenshot_static.xml
rename to packages/SystemUI/res/layout/screenshot_static.xml
index 6a9254c..f571fa6 100644
--- a/packages/SystemUI/res/layout/global_screenshot_static.xml
+++ b/packages/SystemUI/res/layout/screenshot_static.xml
@@ -20,19 +20,19 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <ImageView
-        android:id="@+id/global_screenshot_actions_container_background"
+        android:id="@+id/screenshot_actions_container_background"
         android:visibility="gone"
         android:layout_height="0dp"
         android:layout_width="0dp"
         android:elevation="1dp"
         android:background="@drawable/action_chip_container_background"
         android:layout_marginStart="@dimen/screenshot_action_container_margin_horizontal"
-        app:layout_constraintBottom_toBottomOf="@+id/global_screenshot_actions_container"
+        app:layout_constraintBottom_toBottomOf="@+id/screenshot_actions_container"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="@+id/global_screenshot_actions_container"
-        app:layout_constraintEnd_toEndOf="@+id/global_screenshot_actions_container"/>
+        app:layout_constraintTop_toTopOf="@+id/screenshot_actions_container"
+        app:layout_constraintEnd_toEndOf="@+id/screenshot_actions_container"/>
     <HorizontalScrollView
-        android:id="@+id/global_screenshot_actions_container"
+        android:id="@+id/screenshot_actions_container"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_marginEnd="@dimen/screenshot_action_container_margin_horizontal"
@@ -44,23 +44,23 @@
         app:layout_constraintWidth_percent="1.0"
         app:layout_constraintWidth_max="wrap"
         app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toEndOf="@+id/global_screenshot_preview_border"
+        app:layout_constraintStart_toEndOf="@+id/screenshot_preview_border"
         app:layout_constraintEnd_toEndOf="parent">
         <LinearLayout
-            android:id="@+id/global_screenshot_actions"
+            android:id="@+id/screenshot_actions"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content">
-            <include layout="@layout/global_screenshot_action_chip"
+            <include layout="@layout/screenshot_action_chip"
                      android:id="@+id/screenshot_share_chip"/>
-            <include layout="@layout/global_screenshot_action_chip"
+            <include layout="@layout/screenshot_action_chip"
                      android:id="@+id/screenshot_edit_chip"/>
-            <include layout="@layout/global_screenshot_action_chip"
+            <include layout="@layout/screenshot_action_chip"
                      android:id="@+id/screenshot_scroll_chip"
                      android:visibility="gone" />
         </LinearLayout>
     </HorizontalScrollView>
     <View
-        android:id="@+id/global_screenshot_preview_border"
+        android:id="@+id/screenshot_preview_border"
         android:layout_width="0dp"
         android:layout_height="0dp"
         android:layout_marginStart="@dimen/screenshot_offset_x"
@@ -78,18 +78,18 @@
         android:layout_height="wrap_content"
         app:barrierMargin="4dp"
         app:barrierDirection="end"
-        app:constraint_referenced_ids="global_screenshot_preview"/>
+        app:constraint_referenced_ids="screenshot_preview"/>
     <androidx.constraintlayout.widget.Barrier
         android:id="@+id/screenshot_preview_top"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         app:barrierDirection="top"
         app:barrierMargin="-4dp"
-        app:constraint_referenced_ids="global_screenshot_preview"/>
+        app:constraint_referenced_ids="screenshot_preview"/>
     <ImageView
-        android:id="@+id/global_screenshot_preview"
+        android:id="@+id/screenshot_preview"
         android:visibility="invisible"
-        android:layout_width="@dimen/global_screenshot_x_scale"
+        android:layout_width="@dimen/screenshot_x_scale"
         android:layout_margin="4dp"
         android:layout_height="wrap_content"
         android:layout_gravity="center"
@@ -98,24 +98,24 @@
         android:scaleType="fitEnd"
         android:background="@drawable/screenshot_preview_background"
         android:adjustViewBounds="true"
-        app:layout_constraintBottom_toBottomOf="@+id/global_screenshot_preview_border"
-        app:layout_constraintStart_toStartOf="@+id/global_screenshot_preview_border"
-        app:layout_constraintEnd_toEndOf="@+id/global_screenshot_preview_border"
-        app:layout_constraintTop_toTopOf="@+id/global_screenshot_preview_border">
+        app:layout_constraintBottom_toBottomOf="@+id/screenshot_preview_border"
+        app:layout_constraintStart_toStartOf="@+id/screenshot_preview_border"
+        app:layout_constraintEnd_toEndOf="@+id/screenshot_preview_border"
+        app:layout_constraintTop_toTopOf="@+id/screenshot_preview_border">
     </ImageView>
     <FrameLayout
-        android:id="@+id/global_screenshot_dismiss_button"
+        android:id="@+id/screenshot_dismiss_button"
         android:layout_width="@dimen/screenshot_dismiss_button_tappable_size"
         android:layout_height="@dimen/screenshot_dismiss_button_tappable_size"
         android:elevation="7dp"
         android:visibility="gone"
-        app:layout_constraintStart_toEndOf="@id/global_screenshot_preview"
-        app:layout_constraintEnd_toEndOf="@id/global_screenshot_preview"
-        app:layout_constraintTop_toTopOf="@id/global_screenshot_preview"
-        app:layout_constraintBottom_toTopOf="@id/global_screenshot_preview"
+        app:layout_constraintStart_toEndOf="@id/screenshot_preview"
+        app:layout_constraintEnd_toEndOf="@id/screenshot_preview"
+        app:layout_constraintTop_toTopOf="@id/screenshot_preview"
+        app:layout_constraintBottom_toTopOf="@id/screenshot_preview"
         android:contentDescription="@string/screenshot_dismiss_description">
         <ImageView
-            android:id="@+id/global_screenshot_dismiss_image"
+            android:id="@+id/screenshot_dismiss_image"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_margin="@dimen/screenshot_dismiss_button_margin"
@@ -127,16 +127,16 @@
         android:layout_height="wrap_content"
         android:scaleType="matrix"
         android:visibility="gone"
-        app:layout_constraintStart_toStartOf="@id/global_screenshot_preview"
-        app:layout_constraintTop_toTopOf="@id/global_screenshot_preview"
+        app:layout_constraintStart_toStartOf="@id/screenshot_preview"
+        app:layout_constraintTop_toTopOf="@id/screenshot_preview"
         android:elevation="@dimen/screenshot_preview_elevation"/>
     <View
         android:id="@+id/screenshot_transition_view"
         android:layout_width="0dp"
         android:layout_height="0dp"
         android:visibility="invisible"
-        app:layout_constraintStart_toStartOf="@id/global_screenshot_preview"
-        app:layout_constraintTop_toTopOf="@id/global_screenshot_preview"
-        app:layout_constraintEnd_toEndOf="@id/global_screenshot_preview"
-        app:layout_constraintBottom_toBottomOf="@id/global_screenshot_preview"/>
+        app:layout_constraintStart_toStartOf="@id/screenshot_preview"
+        app:layout_constraintTop_toTopOf="@id/screenshot_preview"
+        app:layout_constraintEnd_toEndOf="@id/screenshot_preview"
+        app:layout_constraintBottom_toBottomOf="@id/screenshot_preview"/>
 </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 85e2ee7..db63e73 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -1175,7 +1175,9 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ontsluit om netwerke te bekyk"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Soek tans na netwerke …"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kon nie aan netwerk koppel nie"</string>
+    <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-fi sal vir nou nie outomaties koppel nie"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Sien alles"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ontkoppel Ethernet om netwerke te wissel"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wil die volgende teël by Kitsinstellings voeg"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Voeg teël by"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Moenie teël byvoeg nie"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 4a6110b..68cd774 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"አውታረ መረቦችን ለመመልከት ይክፈቱ"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"አውታረ መረቦችን በመፈለግ ላይ…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ከአውታረ መረቡ ጋር መገናኘት አልተሳካም"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"ሁሉንም ይመልከቱ"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"አውታረ መረቦችን ለመቀየር፣ የኢተርኔት ግንኙነት ያቋርጡ"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> የሚከተለውን ሰቅ ወደ ፈጣን ቅንብሮች ማከል ይፈልጋል"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ሰቅ አክል"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ሰቅ አታክል"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 98ffae5..13ebcef 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -1199,7 +1199,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"فتح القفل لعرض الشبكات"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"جارٍ البحث عن شبكات…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"تعذّر الاتصال بالشبكة."</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"عرض الكل"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"للتبديل بين الشبكات، يجب فصل إيثرنت."</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"يريد تطبيق <xliff:g id="APPNAME">%1$s</xliff:g> إضافة المربّع التالي إلى \"الإعدادات السريعة\""</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"إضافة مربّع"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"عدم إضافة مربّع"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index fbf1fb4..492198d 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -37,7 +37,7 @@
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"বেটাৰী সঞ্চয়কাৰীৰ বিষয়ে"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"অন কৰক"</string>
     <string name="battery_saver_start_action" msgid="4553256017945469937">"বেটাৰি সঞ্চয়কাৰী অন কৰক"</string>
-    <string name="status_bar_settings_settings_button" msgid="534331565185171556">"ছেটিংসমূহ"</string>
+    <string name="status_bar_settings_settings_button" msgid="534331565185171556">"ছেটিং"</string>
     <string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"ৱাই-ফাই"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"স্বয়ং-ঘূৰ্ণন স্ক্ৰীন"</string>
     <string name="status_bar_settings_mute_label" msgid="914392730086057522">"মিউট"</string>
@@ -233,7 +233,7 @@
     <string name="accessibility_battery_level" msgid="5143715405241138822">"<xliff:g id="NUMBER">%d</xliff:g> শতাংশ বেটাৰি।"</string>
     <string name="accessibility_battery_level_with_estimate" msgid="4843119982547599452">"আপোনাৰ ব্যৱহাৰৰ ওপৰত ভিত্তি কৰি বেটাৰী <xliff:g id="PERCENTAGE">%1$s</xliff:g> শতাংশ, প্ৰায় <xliff:g id="TIME">%2$s</xliff:g> বাকী আছে"</string>
     <string name="accessibility_battery_level_charging" msgid="8892191177774027364">"বেটাৰি চাৰ্জ হৈ আছে, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> শতাংশ।"</string>
-    <string name="accessibility_settings_button" msgid="2197034218538913880">"ছিষ্টেমৰ ছেটিংসমূহ৷"</string>
+    <string name="accessibility_settings_button" msgid="2197034218538913880">"ছিষ্টেমৰ ছেটিং৷"</string>
     <string name="accessibility_notifications_button" msgid="3960913924189228831">"জাননীসমূহ।"</string>
     <string name="accessibility_overflow_action" msgid="8555835828182509104">"সকলো জাননীবোৰ চাওক"</string>
     <string name="accessibility_remove_notification" msgid="1641455251495815527">"জাননী মচক৷"</string>
@@ -248,9 +248,9 @@
     <skip />
     <string name="accessibility_notification_dismissed" msgid="4411652015138892952">"জাননী অগ্ৰাহ্য কৰা হৈছে।"</string>
     <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"জাননী পেনেল।"</string>
-    <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ক্ষিপ্ৰ ছেটিংসমূহ।"</string>
+    <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ক্ষিপ্ৰ ছেটিং।"</string>
     <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"বন্ধ স্ক্ৰীন।"</string>
-    <string name="accessibility_desc_settings" msgid="6728577365389151969">"ছেটিংসমূহ"</string>
+    <string name="accessibility_desc_settings" msgid="6728577365389151969">"ছেটিং"</string>
     <string name="accessibility_desc_recent_apps" msgid="1748675199348914194">"অৱলোকন।"</string>
     <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"কৰ্মস্থানৰ প্ৰ\'ফাইলৰ লক স্ক্ৰীন"</string>
     <string name="accessibility_desc_close" msgid="8293708213442107755">"বন্ধ কৰক"</string>
@@ -318,8 +318,8 @@
       <item quantity="other"> ভিতৰত আৰু <xliff:g id="NUMBER_1">%s</xliff:g>টা জাননী আছে।</item>
     </plurals>
     <string name="notification_summary_message_format" msgid="5158219088501909966">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
-    <string name="status_bar_notification_inspect_item_title" msgid="6818779631806163080">"জাননীৰ ছেটিংসমূহ"</string>
-    <string name="status_bar_notification_app_settings_title" msgid="5050006438806013903">"<xliff:g id="APP_NAME">%s</xliff:g> ছেটিংসমূহ"</string>
+    <string name="status_bar_notification_inspect_item_title" msgid="6818779631806163080">"জাননীৰ ছেটিং"</string>
+    <string name="status_bar_notification_app_settings_title" msgid="5050006438806013903">"<xliff:g id="APP_NAME">%s</xliff:g> ছেটিং"</string>
     <string name="accessibility_rotation_lock_off" msgid="3880436123632448930">"আপোনাৰ ফ\'নৰ স্ক্ৰীন স্বয়ংক্ৰিয়ভাৱে ঘূৰিব।"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"স্ক্ৰীন লেণ্ডস্কে\'প দিশত লক কৰা হ’ল।"</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"স্ক্ৰীন প\'ৰ্ট্ৰেইট দিশত লক কৰা হ’ল।"</string>
@@ -361,7 +361,7 @@
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"মিডিয়া ডিভাইচ"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"জৰুৰীকালীন কল মাত্ৰ"</string>
-    <string name="quick_settings_settings_label" msgid="2214639529565474534">"ছেটিংসমূহ"</string>
+    <string name="quick_settings_settings_label" msgid="2214639529565474534">"ছেটিং"</string>
     <string name="quick_settings_time_label" msgid="3352680970557509303">"সময়"</string>
     <string name="quick_settings_user_label" msgid="1253515509432672496">"মোক"</string>
     <string name="quick_settings_user_title" msgid="8673045967216204537">"ব্যৱহাৰকাৰী"</string>
@@ -555,9 +555,9 @@
     <string name="disconnect_vpn" msgid="26286850045344557">"ভিপিএন সংযোগ বিচ্ছিন্ন কৰক"</string>
     <string name="monitoring_button_view_policies" msgid="3869724835853502410">"নীতিসমূহ চাওক"</string>
     <string name="monitoring_button_view_controls" msgid="8316440345340701117">"নিয়ন্ত্ৰণসমূহ চাওক"</string>
-    <string name="monitoring_description_named_management" msgid="505833016545056036">"এই ডিভাইচটো <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>ৰ।\n\nআপোনাৰ আইটি প্ৰশাসকে আপোনাৰ ডিভাইচটোৰ লগত জড়িত ছেটিংসমূহ, কৰ্পৰে’টৰ এক্সেছ, এপ্‌সমূহ, ডেটা আৰু আপোনাৰ ডিভাইচটোৰ অৱস্থান সম্পৰ্কীয় তথ্য নিৰীক্ষণ কৰাৰ লগতে সেয়া পৰিচালনা কৰিব পাৰে।\n\nঅধিক তথ্যৰ বাবে আপোনাৰ আইটি প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।"</string>
+    <string name="monitoring_description_named_management" msgid="505833016545056036">"এই ডিভাইচটো <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>ৰ।\n\nআপোনাৰ আইটি প্ৰশাসকে আপোনাৰ ডিভাইচটোৰ লগত জড়িত ছেটিং, কৰ্পৰে’টৰ এক্সেছ, এপ্‌, ডেটা আৰু আপোনাৰ ডিভাইচটোৰ অৱস্থান সম্পৰ্কীয় তথ্য নিৰীক্ষণ কৰাৰ লগতে সেয়া পৰিচালনা কৰিব পাৰে।\n\nঅধিক তথ্যৰ বাবে আপোনাৰ আইটি প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।"</string>
     <string name="monitoring_financed_description_named_management" msgid="6108439201399938668">"<xliff:g id="ORGANIZATION_NAME_0">%1$s</xliff:g>এ হয়তো এই ডিভাইচটোৰ সৈতে জড়িত হৈ থকা ডেটা এক্সেছ কৰিব, এপ্‌ পৰিচালনা কৰিব আৰু এই ডিভাইচটোৰ ছেটিং সলনি কৰিব পাৰিব।\n\nআপোনাৰ যদি কিবা প্ৰশ্ন আছে, তেন্তে <xliff:g id="ORGANIZATION_NAME_1">%2$s</xliff:g>ৰ সৈতে যোগাযোগ কৰক।"</string>
-    <string name="monitoring_description_management" msgid="4308879039175729014">"এই ডিভাইচটো আপোনাৰ প্ৰতিষ্ঠানৰ।\n\nআপোনাৰ আইটি প্ৰশাসকে আপোনাৰ ডিভাইচটোৰ লগত জড়িত ছেটিংসমূহ, কৰ্পৰে’টৰ এক্সেছ, এপ্‌সমূহ, ডেটা আৰু আপোনাৰ ডিভাইচটোৰ অৱস্থান সম্পৰ্কীয় তথ্য নিৰীক্ষণ কৰাৰ লগতে সেয়া পৰিচালনা কৰিব পাৰে।\n\nঅধিক তথ্যৰ বাবে আপোনাৰ আইটি প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।"</string>
+    <string name="monitoring_description_management" msgid="4308879039175729014">"এই ডিভাইচটো আপোনাৰ প্ৰতিষ্ঠানৰ।\n\nআপোনাৰ আইটি প্ৰশাসকে আপোনাৰ ডিভাইচটোৰ লগত জড়িত ছেটিং, কৰ্পৰে’টৰ এক্সেছ, এপ্‌, ডেটা আৰু আপোনাৰ ডিভাইচটোৰ অৱস্থান সম্পৰ্কীয় তথ্য নিৰীক্ষণ কৰাৰ লগতে সেয়া পৰিচালনা কৰিব পাৰে।\n\nঅধিক তথ্যৰ বাবে আপোনাৰ আইটি প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।"</string>
     <string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"আপোনাৰ প্ৰতিষ্ঠানে এই ডিভাইচটোত এটা প্ৰমাণপত্ৰ সম্পৰ্কীয় কৰ্তৃপক্ষ ইনষ্টল কৰিছে। আপোনাৰ সুৰক্ষিত নেটৱৰ্ক ট্ৰেফিক পৰ্যবেক্ষণ বা সংশোধন কৰা হ\'ব পাৰে।"</string>
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"আপোনাৰ প্ৰতিষ্ঠানে আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলটোত এটা প্ৰমাণপত্ৰ সম্পৰ্কীয় কৰ্তৃপক্ষ ইনষ্টল কৰিছে। আপোনাৰ সুৰক্ষিত নেটৱৰ্কৰ ট্ৰেফিক পৰ্যবেক্ষণ বা সংশোধন কৰা হ\'ব পাৰে।"</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"এই ডিভাইচটোত এটা প্ৰমাণপত্ৰ সম্পৰ্কীয় কৰ্তৃপক্ষ ইনষ্টল কৰা হৈছে। আপোনাৰ সুৰক্ষিত নেটৱৰ্কৰ ট্ৰেফিক পৰ্যবেক্ষণ বা সংশোধন কৰা হ\'ব পাৰে।"</string>
@@ -569,12 +569,12 @@
     <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"আপোনাৰ ব্যক্তিগত প্ৰ\'ফাইলটো <xliff:g id="VPN_APP">%1$s</xliff:g>ৰে সংযুক্ত হৈ আছে, যিয়ে আপোনাৰ ইমেইল, এপ্ আৰু ৱেবছাইটকে ধৰি নেটৱর্কৰ কাৰ্যকলাপ পৰ্যবেক্ষণ কৰিব পাৰে।"</string>
     <string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"আপোনাৰ ডিভাইচটো <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>ৰ দ্বাৰা পৰিচালিত।"</string>
     <string name="monitoring_description_do_header_with_name" msgid="2696255132542779511">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>এ আপোনাৰ ডিভাইচটো পৰিচালনা কৰিবলৈ <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ব্যৱহাৰ কৰে।"</string>
-    <string name="monitoring_description_do_body" msgid="7700878065625769970">"আপোনাৰ প্ৰশাসকে আপোনাৰ ডিভাইচৰ লগত জড়িত ছেটিংসমূহ, কৰ্প\'ৰেইট অনুমতি, এপসমূহ, ডেটা আৰু ডিভাইচৰ অৱস্থান সম্পৰ্কীয় তথ্য পৰ্যবেক্ষণ কৰাৰ লগতে পৰিচালনা কৰিব পাৰিব।"</string>
+    <string name="monitoring_description_do_body" msgid="7700878065625769970">"আপোনাৰ প্ৰশাসকে আপোনাৰ ডিভাইচৰ লগত জড়িত ছেটিং, কৰ্প\'ৰেইট এক্সেছ, এপ্‌, ডেটা আৰু ডিভাইচৰ অৱস্থান সম্পৰ্কীয় তথ্য পৰ্যবেক্ষণ তথা পৰিচালনা কৰিব পাৰে।"</string>
     <string name="monitoring_description_do_learn_more_separator" msgid="1467280496376492558">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="645149183455573790">"অধিক জানক"</string>
     <string name="monitoring_description_do_body_vpn" msgid="7699280130070502303">"আপুনি <xliff:g id="VPN_APP">%1$s</xliff:g> ৰে সংযুক্ত হৈ আছে, ই ইমেইল, এপ্ আৰু ৱেবছাইটকে ধৰি আপোনাৰ নেটৱর্কৰ কাৰ্যকলাপ পৰ্যবেক্ষণ কৰিব পাৰে।"</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="8292589617720435430">" "</string>
-    <string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"ভিপিএন ছেটিংসমূহ খোলক"</string>
+    <string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"VPN ছেটিং খোলক"</string>
     <string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string>
     <string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"বিশ্বাসী পৰিচয়-পত্ৰসমূহ খোলক"</string>
     <string name="monitoring_description_network_logging" msgid="577305979174002252">"আপোনাৰ প্ৰশাসকে নেটৱৰ্ক লগিং অন কৰিছে, যিয়ে আপোনাৰ ডিভাইচটোত নেটৱৰ্ক ট্ৰেফিক পৰ্যবেক্ষণ কৰে।\n\nএই সম্পৰ্কে অধিক জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।"</string>
@@ -596,7 +596,7 @@
     <string name="hidden_notifications_setup" msgid="2064795578526982467">"ছেট আপ কৰক"</string>
     <string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
     <string name="volume_zen_end_now" msgid="5901885672973736563">"এতিয়া অফ কৰক"</string>
-    <string name="accessibility_volume_settings" msgid="1458961116951564784">"ধ্বনিৰ ছেটিংসমূহ"</string>
+    <string name="accessibility_volume_settings" msgid="1458961116951564784">"ধ্বনিৰ ছেটিং"</string>
     <string name="accessibility_volume_expand" msgid="7653070939304433603">"সম্প্ৰসাৰণ কৰক"</string>
     <string name="accessibility_volume_collapse" msgid="2746845391013829996">"সংকুচিত কৰক"</string>
     <string name="volume_odi_captions_tip" msgid="8825655463280990941">"স্বয়ংক্ৰিয় কেপশ্বন মিডিয়া"</string>
@@ -621,7 +621,7 @@
     <string name="screen_pinning_start" msgid="7483998671383371313">"এপ্‌টো পিন কৰা হ’ল"</string>
     <string name="screen_pinning_exit" msgid="4553787518387346893">"এপ্‌টো আনপিন কৰা হ’ল"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> লুকুৱাবনে?"</string>
-    <string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"আপুনি ইয়াক পৰৱৰ্তী সময়ত ছেটিংসমূহত অন কৰিলে ই পুনৰ প্ৰকট হ\'ব।"</string>
+    <string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"আপুনি পৰৱৰ্তী সময়ত ছেটিঙত ইয়াক অন কৰিলে ই পুনৰ প্ৰকট হ\'ব।"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"লুকুৱাওক"</string>
     <string name="stream_voice_call" msgid="7468348170702375660">"কল"</string>
     <string name="stream_system" msgid="7663148785370565134">"ছিষ্টেম"</string>
@@ -659,7 +659,7 @@
     <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="6235377891802910455">"সংযুক্ত বেটাৰিৰ কিমান শতাংশ বাকী আছে দেখুওৱাক"</string>
     <string name="show_battery_percentage_summary" msgid="9053024758304102915">"চাৰ্জ হৈ নথকা অৱস্থাত বেটাৰি কিমান শতাংশ বাকী স্থিতি দণ্ডৰ ভিতৰত দেখুৱাওক"</string>
-    <string name="quick_settings" msgid="6211774484997470203">"ক্ষিপ্ৰ ছেটিংসমূহ"</string>
+    <string name="quick_settings" msgid="6211774484997470203">"ক্ষিপ্ৰ ছেটিং"</string>
     <string name="status_bar" msgid="4357390266055077437">"স্থিতি দণ্ড"</string>
     <string name="overview" msgid="3522318590458536816">"অৱলোকন"</string>
     <string name="demo_mode" msgid="263484519766901593">"ছিষ্টেমৰ UI প্ৰদৰ্শন ম\'ড"</string>
@@ -684,21 +684,21 @@
     <string name="zen_alarm_warning" msgid="7844303238486849503">"আপুনি আপোনাৰ পিছৰটো এলাৰ্ম <xliff:g id="WHEN">%1$s</xliff:g> বজাত শুনা নাপাব"</string>
     <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> বজাত"</string>
     <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> বজাত"</string>
-    <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ক্ষিপ্ৰ ছেটিংসমূহ, <xliff:g id="TITLE">%s</xliff:g>।"</string>
+    <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ক্ষিপ্ৰ ছেটিং, <xliff:g id="TITLE">%s</xliff:g>।"</string>
     <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"হটস্পট"</string>
     <string name="accessibility_managed_profile" msgid="4703836746209377356">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string>
     <string name="tuner_warning_title" msgid="7721976098452135267">"কিছুমানৰ বাবে আমোদজনক হয় কিন্তু সকলোৰে বাবে নহয়"</string>
     <string name="tuner_warning" msgid="1861736288458481650">"System UI Tunerএ আপোনাক Android ব্যৱহাৰকাৰী ইণ্টাৰফেইচ সলনি কৰিবলৈ আৰু নিজৰ উপযোগিতা অনুসৰি ব্যৱহাৰ কৰিবলৈ অতিৰিক্ত সুবিধা প্ৰদান কৰে। এই পৰীক্ষামূলক সুবিধাসমূহ সলনি হ\'ব পাৰে, সেইবোৰে কাম নকৰিব পাৰে বা আগন্তুক সংস্কৰণসমূহত সেইবোৰ অন্তৰ্ভুক্ত কৰা নহ’ব পাৰে। সাৱধানেৰে আগবাঢ়ক।"</string>
     <string name="tuner_persistent_warning" msgid="230466285569307806">"এই পৰীক্ষামূলক সুবিধাসমূহ সলনি হ\'ব পাৰে, সেইবোৰে কাম নকৰিব পাৰে বা আগন্তুক সংস্কৰণসমূহত সেইবোৰ অন্তৰ্ভুক্ত কৰা নহ’ব পাৰে। সাৱধানেৰে আগবাঢ়ক।"</string>
     <string name="got_it" msgid="477119182261892069">"বুজি পালোঁ"</string>
-    <string name="tuner_toast" msgid="3812684836514766951">"অভিনন্দন! ছেটিংসমূহত System UI Tuner যোগ কৰা হৈছে"</string>
-    <string name="remove_from_settings" msgid="633775561782209994">"ছেটিংসমূহৰ পৰা আঁতৰাওক"</string>
-    <string name="remove_from_settings_prompt" msgid="551565437265615426">"ছেটিংসমূহৰ পৰা System UI Tuner আঁতৰাই ইয়াৰ সুবিধাসমূহ ব্যৱহাৰ কৰাটো বন্ধ কৰিবনে?"</string>
+    <string name="tuner_toast" msgid="3812684836514766951">"অভিনন্দন! ছেটিঙত System UI Tuner যোগ কৰা হৈছে"</string>
+    <string name="remove_from_settings" msgid="633775561782209994">"ছেটিঙৰ পৰা আঁতৰাওক"</string>
+    <string name="remove_from_settings_prompt" msgid="551565437265615426">"ছেটিঙৰ পৰা System UI Tuner আঁতৰাই ইয়াৰ সুবিধাসমূহ ব্যৱহাৰ কৰাটো বন্ধ কৰিবনে?"</string>
     <string name="activity_not_found" msgid="8711661533828200293">"আপোনাৰ ডিভাইচত এপ্লিকেশ্বনটো ইনষ্টল কৰা হোৱা নাই"</string>
     <string name="clock_seconds" msgid="8709189470828542071">"ঘড়ীৰ ছেকেণ্ড দেখুৱাওক"</string>
     <string name="clock_seconds_desc" msgid="2415312788902144817">"স্থিতি দণ্ডত ঘড়ীৰ ছেকেণ্ড দেখুৱাওক। এই কার্যই বেটাৰিৰ অৱস্থাত প্ৰভাৱ পেলাব পাৰে।"</string>
-    <string name="qs_rearrange" msgid="484816665478662911">"ক্ষিপ্ৰ ছেটিংসমূহ পুনৰ সজাওক"</string>
-    <string name="show_brightness" msgid="6700267491672470007">"দ্ৰুত ছেটিংসমূহত উজ্জ্বলতা দেখুৱাওক"</string>
+    <string name="qs_rearrange" msgid="484816665478662911">"ক্ষিপ্ৰ ছেটিং পুনৰ সজাওক"</string>
+    <string name="show_brightness" msgid="6700267491672470007">"দ্ৰুত ছেটিঙত উজ্জ্বলতা দেখুৱাওক"</string>
     <string name="experimental" msgid="3549865454812314826">"পৰীক্ষামূলক"</string>
     <string name="enable_bluetooth_title" msgid="866883307336662596">"ব্লুটুথ অন কৰিবনে?"</string>
     <string name="enable_bluetooth_message" msgid="6740938333772779717">"আপোনাৰ টেবলেটত আপোনাৰ কীব\'ৰ্ড সংযোগ কৰিবলৈ আপুনি প্ৰথমে ব্লুটুথ অন কৰিব লাগিব।"</string>
@@ -748,7 +748,7 @@
     <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"বাৰ্তালাপৰ জাননীৰ শীৰ্ষত আৰু প্ৰ’ফাইল চিত্ৰ হিচাপে লক স্ক্ৰীনত দেখুৱায়, এটা বাবল হিচাপে দেখা পোৱা যায়"</string>
     <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"বাৰ্তালাপৰ জাননীৰ শীৰ্ষত আৰু প্ৰ’ফাইল চিত্ৰ হিচাপে লক স্ক্ৰীনত দেখুৱায়, অসুবিধা নিদিব ম’ডত ব্যাঘাত জন্মায়"</string>
     <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"বাৰ্তালাপৰ জাননীৰ শীৰ্ষত আৰু প্ৰ’ফাইল চিত্ৰ হিচাপে লক স্ক্ৰীনত দেখুৱায়, এটা বাবল হিচাপে দেখা পোৱা যায়, অসুবিধা নিদিব ম’ডত ব্যাঘাত জন্মায়"</string>
-    <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ছেটিংসমূহ"</string>
+    <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ছেটিং"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"অগ্ৰাধিকাৰ"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বাৰ্তালাপৰ সুবিধাসমূহ সমৰ্থন নকৰে"</string>
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"এই জাননীসমূহ সংশোধন কৰিব নোৱাৰি।"</string>
@@ -763,7 +763,7 @@
     <string name="appops_camera_overlay" msgid="6466845606058816484">"এই এপে আপোনাৰ স্ক্ৰীনত থকা অন্য় এপৰ ওপৰত প্ৰদৰ্শিত হৈ কেমেৰা ব্য়ৱহাৰ কৰি আছে।"</string>
     <string name="appops_mic_overlay" msgid="4609326508944233061">"এই এপে আপোনাৰ স্ক্ৰীনত থকা অন্য় এপৰ ওপৰত প্ৰদৰ্শিত হৈ মাইক্ৰ\'ফ\'ন ব্য়ৱহাৰ কৰি আছে।"</string>
     <string name="appops_camera_mic_overlay" msgid="5584311236445644095">"এই এপে আপোনাৰ স্ক্ৰীনত থকা অন্য় এপৰ ওপৰত প্ৰদৰ্শিত হৈ মাইক্ৰ\'ফ\'ন আৰু কেমেৰা ব্য়ৱহাৰ কৰি আছে।"</string>
-    <string name="notification_appops_settings" msgid="5208974858340445174">"ছেটিংসমূহ"</string>
+    <string name="notification_appops_settings" msgid="5208974858340445174">"ছেটিং"</string>
     <string name="notification_appops_ok" msgid="2177609375872784124">"ঠিক আছে"</string>
     <string name="feedback_alerted" msgid="5192459808484271208">"ছিষ্টেমটোৱে স্বয়ংক্ৰিয়ভাৱে এই জাননীটোৰ ক্ষেত্ৰত দিয়া &lt;b&gt;গুৰুত্ব ডিফ’ল্ট&lt;/b&gt;লৈ বৃদ্ধি কৰিছে।"</string>
     <string name="feedback_silenced" msgid="9116540317466126457">"ছিষ্টেমটোৱে স্বয়ংক্ৰিয়ভাৱে এই জাননীটোৰ ক্ষেত্ৰত দিয়া &lt;b&gt;গুৰুত্ব নীৰৱ&lt;/b&gt;লৈ হ্ৰাস কৰিছে।"</string>
@@ -791,7 +791,7 @@
     <string name="notification_menu_gear_description" msgid="6429668976593634862">"জাননীৰ নিয়ন্ত্ৰণসমূহ"</string>
     <string name="notification_menu_snooze_description" msgid="4740133348901973244">"জাননীক স্নুজ কৰাৰ বিকল্পসমূহ"</string>
     <string name="notification_menu_snooze_action" msgid="5415729610393475019">"মোক মনত পেলাই দিব"</string>
-    <string name="notification_menu_settings_action" msgid="7085494017202764285">"ছেটিংসমূহ"</string>
+    <string name="notification_menu_settings_action" msgid="7085494017202764285">"ছেটিং"</string>
     <string name="snooze_undo" msgid="2738844148845992103">"আনডু কৰক"</string>
     <string name="snoozed_for_time" msgid="7586689374860469469">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g>ৰ বাবে স্নুজ কৰক"</string>
     <plurals name="snoozeHourOptions" formatted="false" msgid="2066838694120718170">
@@ -856,7 +856,7 @@
     <string name="battery" msgid="769686279459897127">"বেটাৰি"</string>
     <string name="clock" msgid="8978017607326790204">"ঘড়ী"</string>
     <string name="headset" msgid="4485892374984466437">"হেডছেট"</string>
-    <string name="accessibility_long_click_tile" msgid="210472753156768705">"ছেটিংসমূহ খোলক"</string>
+    <string name="accessibility_long_click_tile" msgid="210472753156768705">"ছেটিং খোলক"</string>
     <string name="accessibility_status_bar_headphones" msgid="1304082414912647414">"হেডফ\'ন সংযোগ হৈ আছে"</string>
     <string name="accessibility_status_bar_headset" msgid="2699275863720926104">"হেডছেট সংযোগ হৈ আছে"</string>
     <string name="data_saver" msgid="3484013368530820763">"ডেটা সঞ্চয়কাৰী"</string>
@@ -920,19 +920,19 @@
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> নম্বৰ স্থান"</string>
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"টাইল যোগ দিয়া হৈছে"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"টাইল আঁতৰোৱা হৈছে"</string>
-    <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ক্ষিপ্ৰ ছেটিংসমূহৰ সম্পাদক।"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ক্ষিপ্ৰ ছেটিঙৰ সম্পাদক।"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> জাননী: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
-    <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ছেটিংসমূহ খোলক।"</string>
-    <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"ক্ষিপ্ৰ ছেটিংসমূহ খোলক।"</string>
-    <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"ক্ষিপ্ৰ ছেটিংসমূহ বন্ধ কৰক।"</string>
+    <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ছেটিং খোলক।"</string>
+    <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"ক্ষিপ্ৰ ছেটিং খোলক।"</string>
+    <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"ক্ষিপ্ৰ ছেটিং বন্ধ কৰক।"</string>
     <string name="accessibility_quick_settings_alarm_set" msgid="7237918261045099853">"এলার্ম ছেট কৰা হ’ল।"</string>
     <string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> হিচাপে ছাইন ইন হ’ল"</string>
     <string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"ব্যৱহাৰকাৰী বাছনি কৰক"</string>
     <string name="data_connection_no_internet" msgid="691058178914184544">"ইণ্টাৰনেট সংযোগ নাই"</string>
     <string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"বিৱৰণসমূহ খোলক।"</string>
     <string name="accessibility_quick_settings_not_available" msgid="6860875849497473854">"<xliff:g id="REASON">%s</xliff:g>ৰ বাবে উপলব্ধ নহয়"</string>
-    <string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g>ৰ ছেটিংসমূহ খোলক।"</string>
-    <string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ছেটিংসমূহৰ ক্ৰম সম্পাদনা কৰক।"</string>
+    <string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g>ৰ ছেটিং খোলক।"</string>
+    <string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ছেটিঙৰ ক্ৰম সম্পাদনা কৰক।"</string>
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"পাৱাৰ মেনু"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>ৰ পৃষ্ঠা <xliff:g id="ID_1">%1$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"লক স্ক্ৰীন"</string>
@@ -990,7 +990,7 @@
     <string name="mobile_data_disable_title" msgid="5366476131671617790">"ম’বাইল ডেটা অফ কৰিবনে?"</string>
     <string name="mobile_data_disable_message" msgid="8604966027899770415">"আপুনি <xliff:g id="CARRIER">%s</xliff:g>ৰ জৰিয়তে ডেটা সংযোগ বা ইণ্টাৰনেট সংযোগ নাপাব। কেৱল ৱাই-ফাইৰ যোগেৰে ইণ্টাৰনেট উপলব্ধ হ\'ব।"</string>
     <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"আপোনাৰ বাহক"</string>
-    <string name="touch_filtered_warning" msgid="8119511393338714836">"এটা এপে অনুমতি বিচাৰি কৰা অনুৰোধ এটা ঢাকি ধৰা বাবে ছেটিংসমূহে আপোনাৰ উত্তৰ সত্যাপন কৰিব পৰা নাই।"</string>
+    <string name="touch_filtered_warning" msgid="8119511393338714836">"এটা এপে অনুমতি বিচাৰি কৰা অনুৰোধ এটা ঢাকি ধৰা বাবে ছেটিঙৰ পৰা আপোনাৰ উত্তৰ সত্যাপন কৰিব পৰা নাই।"</string>
     <string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g>ক <xliff:g id="APP_2">%2$s</xliff:g>ৰ অংশ দেখুওৱাবলৈ অনুমতি দিবনে?"</string>
     <string name="slice_permission_text_1" msgid="6675965177075443714">"- ই <xliff:g id="APP">%1$s</xliff:g>ৰ তথ্য পঢ়িব পাৰে"</string>
     <string name="slice_permission_text_2" msgid="6758906940360746983">"- ই <xliff:g id="APP">%1$s</xliff:g>ৰ ভিতৰত কাৰ্য কৰিব পাৰে"</string>
@@ -1002,7 +1002,7 @@
     <string name="no_auto_saver_action" msgid="7467924389609773835">"নালাগে, ধন্যবাদ"</string>
     <string name="auto_saver_enabled_title" msgid="4294726198280286333">"বেটাৰি সঞ্চয়কাৰীৰ সময়সূচী অন কৰা অৱস্থাত আছে"</string>
     <string name="auto_saver_enabled_text" msgid="7889491183116752719">"বেটাৰি চ্চাৰ্জৰ স্তৰ <xliff:g id="PERCENTAGE">%d</xliff:g>%%তকৈ কম হোৱাৰ লগে লগে বেটাৰি সঞ্চয়কাৰী স্বয়ংক্ৰিয়ভাৱে অন হ’ব।"</string>
-    <string name="open_saver_setting_action" msgid="2111461909782935190">"ছেটিংবোৰ"</string>
+    <string name="open_saver_setting_action" msgid="2111461909782935190">"ছেটিং"</string>
     <string name="auto_saver_okay_action" msgid="7815925750741935386">"বুজি পালোঁ"</string>
     <string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI হীপ ডাম্প কৰক"</string>
     <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="TYPES_LIST">%2$s</xliff:g> ব্যৱহাৰ কৰি আছে।"</string>
@@ -1021,8 +1021,8 @@
     <string name="device_services" msgid="1549944177856658705">"ডিভাইচ সেৱা"</string>
     <string name="music_controls_no_title" msgid="4166497066552290938">"কোনো শিৰোনাম নাই"</string>
     <string name="bubble_accessibility_action_move" msgid="3185080443743819178">"আঁতৰাওক"</string>
-    <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ছিষ্টেম নেভিগেশ্বন আপডে’ট কৰা হ’ল। সলনি কৰিবলৈ ছেটিংসমূহ-লৈ যাওক।"</string>
-    <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ছিষ্টেম নেভিগেশ্বন আপডে’ট কৰিবলৈ ছেটিংসমূহ-লৈ যাওক"</string>
+    <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ছিষ্টেম নেভিগেশ্বন আপডে’ট কৰা হ’ল। সলনি কৰিবলৈ ছেটিঙলৈ যাওক।"</string>
+    <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ছিষ্টেম নেভিগেশ্বন আপডে’ট কৰিবলৈ ছেটিঙলৈ যাওক"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ষ্টেণ্ডবাই"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"বিবৰ্ধন ৱিণ্ড’"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"বিবৰ্ধন ৱিণ্ড’ৰ নিয়ন্ত্ৰণসমূহ"</string>
@@ -1065,7 +1065,7 @@
     <string name="controls_favorite_removed" msgid="5276978408529217272">"সকলো নিয়ন্ত্ৰণ আঁতৰোৱা হৈছে"</string>
     <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"সালসলনিসমূহ ছেভ নহ’ল"</string>
     <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"অন্য এপ্‌সমূহ চাওক"</string>
-    <string name="controls_favorite_load_error" msgid="5126216176144877419">"নিয়ন্ত্ৰণসমূহ ল’ড কৰিবপৰা নগ’ল। এপ্‌টোৰ ছেটিংসমূহ সলনি কৰা হোৱা নাই বুলি নিশ্চিত কৰিবলৈ <xliff:g id="APP">%s</xliff:g> এপ্‌টো পৰীক্ষা কৰক।"</string>
+    <string name="controls_favorite_load_error" msgid="5126216176144877419">"নিয়ন্ত্ৰণসমূহ ল’ড কৰিবপৰা নগ’ল। এপ্‌টোৰ ছেটিং সলনি কৰা হোৱা নাই বুলি নিশ্চিত কৰিবলৈ <xliff:g id="APP">%s</xliff:g> এপ্‌টো পৰীক্ষা কৰক।"</string>
     <string name="controls_favorite_load_none" msgid="7687593026725357775">"সমিল নিয়ন্ত্ৰণসমূহ উপলব্ধ নহয়"</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"অন্য"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহত যোগ দিয়ক"</string>
@@ -1088,7 +1088,7 @@
     <string name="controls_media_active_session" msgid="3146882316024153337">"বৰ্তমানৰ মিডিয়াৰ ছেশ্বনটো লুকুৱাব নোৱাৰি।"</string>
     <string name="controls_media_dismiss_button" msgid="9081375542265132213">"অগ্ৰাহ্য কৰক"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"পুনৰ আৰম্ভ কৰক"</string>
-    <string name="controls_media_settings_button" msgid="5815790345117172504">"ছেটিংসমূহ"</string>
+    <string name="controls_media_settings_button" msgid="5815790345117172504">"ছেটিং"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ত <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ৰ <xliff:g id="SONG_NAME">%1$s</xliff:g> গীতটো প্লে’ হৈ আছে"</string>
     <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"প্লে’ কৰক"</string>
     <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> খোলক"</string>
@@ -1098,7 +1098,7 @@
     <string name="controls_error_retryable" msgid="864025882878378470">"আসোঁৱাহ, পুনৰ চেষ্টা কৰি আছে…"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"বিচাৰি পোৱা নগ’ল"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"নিয়ন্ত্ৰণটো উপলব্ধ নহয়"</string>
-    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> এক্সেছ কৰিব পৰা নগ’ল। নিয়ন্ত্ৰণটো এতিয়াও উপলব্ধ আৰু এপ্‌টোৰ ছেটিংসমূহ সলনি কৰা হোৱা নাই বুলি নিশ্চিত কৰিবলৈ <xliff:g id="APPLICATION">%2$s</xliff:g> এপ্‌টো পৰীক্ষা কৰক।"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> এক্সেছ কৰিব পৰা নগ’ল। নিয়ন্ত্ৰণটো এতিয়াও উপলব্ধ আৰু এপ্‌টোৰ ছেটিং সলনি কৰা হোৱা নাই বুলি নিশ্চিত কৰিবলৈ <xliff:g id="APPLICATION">%2$s</xliff:g> এপ্‌টো পৰীক্ষা কৰক।"</string>
     <string name="controls_open_app" msgid="483650971094300141">"এপ্‌টো খোলক"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"স্থিতি ল’ড কৰিব নোৱাৰি"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"আসোঁৱাহ হৈছে, আকৌ চেষ্টা কৰক"</string>
@@ -1175,10 +1175,12 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"নেটৱর্ক চাবলৈ আনলক কৰক"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"নেটৱৰ্ক সন্ধান কৰি থকা হৈছে…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"নেটৱৰ্কৰ সৈতে সংযোগ কৰিব পৰা নগ\'ল"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"আটাইবোৰ চাওক"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"নেটৱৰ্ক সলনি কৰিবলৈ ইথাৰনেটৰ পৰা সংযোগ বিচ্ছিন্ন কৰক"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g>এ ক্ষিপ্ৰ ছেটিঙত এই টাইলটো যোগ দিব বিচাৰিছে"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"টাইল যোগ দিয়ক"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"টাইল যোগ নিদিব"</string>
-    <!-- no translation found for qs_user_switch_dialog_title (3045189293587781366) -->
-    <skip />
+    <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ব্যৱহাৰকাৰী বাছনি কৰক"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 44e6474..7b107e0 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Şəbəkələrə baxmaq üçün kilidi açın"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Şəbəkə axtarılır…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Şəbəkəyə qoşulmaq alınmadı"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Hamısına baxın"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Şəbəkəni dəyişmək üçün etherneti ayırın"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> aşağıdakı mozaiki Sürətli Ayarlara əlavə etmək istəyir"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Mozaik əlavə edin"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Mozaik əlavə etməyin"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index b40f48d..435c890 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -1181,7 +1181,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte da biste videli mreže"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traže se mreže…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje sa mrežom nije uspelo"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Pogledajte sve"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da biste promenili mrežu, prekinite eternet vezu"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> želi da doda sledeću pločicu u Brza podešavanja"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Dodaj pločicu"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne dodaj pločicu"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 29f46ba..6a36507 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -703,8 +703,8 @@
     <string name="activity_not_found" msgid="8711661533828200293">"Праграма не ўсталявана на вашым тэлефоне"</string>
     <string name="clock_seconds" msgid="8709189470828542071">"Паказваць секунды гадзінніка"</string>
     <string name="clock_seconds_desc" msgid="2415312788902144817">"Паказваць секунды гадзінніка на панэлі стану. Можа паўплываць на рэсурс акумулятара."</string>
-    <string name="qs_rearrange" msgid="484816665478662911">"Змяніць парадак Хуткіх налад"</string>
-    <string name="show_brightness" msgid="6700267491672470007">"Паказваць яркасць у Хуткіх наладах"</string>
+    <string name="qs_rearrange" msgid="484816665478662911">"Змяніць парадак хуткіх налад"</string>
+    <string name="show_brightness" msgid="6700267491672470007">"Паказваць яркасць у хуткіх наладах"</string>
     <string name="experimental" msgid="3549865454812314826">"Эксперыментальныя"</string>
     <string name="enable_bluetooth_title" msgid="866883307336662596">"Уключыць Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="6740938333772779717">"Для падлучэння клавіятуры да планшэта трэба спачатку ўключыць Bluetooth."</string>
@@ -1072,7 +1072,7 @@
     <string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"выдаліць з абранага"</string>
     <string name="accessibility_control_move" msgid="8980344493796647792">"Перамясціць у пазіцыю <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="controls_favorite_default_title" msgid="967742178688938137">"Сродкі кіравання"</string>
-    <string name="controls_favorite_subtitle" msgid="6481675111056961083">"Выберыце элементы кіравання, да якіх вы хочаце мець доступ з Хуткіх налад"</string>
+    <string name="controls_favorite_subtitle" msgid="6481675111056961083">"Выберыце элементы кіравання, да якіх вы хочаце мець доступ з хуткіх налад"</string>
     <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Каб змяніць парадак элементаў кіравання, утрымлівайце і перацягвайце іх"</string>
     <string name="controls_favorite_removed" msgid="5276978408529217272">"Усе элементы кіравання выдалены"</string>
     <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Змяненні не захаваны"</string>
@@ -1187,8 +1187,11 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Разблакіраваць для прагляду сетак"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Выконваецца пошук сетак…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не ўдалося падключыцца да сеткі"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Паказаць усе"</string>
-    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> запытвае дазвол на дадаванне ў Хуткія налады наступнай пліткі"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Каб падключыцца да сетак, выключыце Ethernet"</string>
+    <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> запытвае дазвол на дадаванне ў хуткія налады наступнай пліткі"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Дадаць плітку"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Не дадаваць плітку"</string>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Выбар карыстальніка"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 43f4bd7..07b231a 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Отключване с цел преглед на мрежите"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Търсят се мрежи…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Свързването с мрежата не бе успешно"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Вижте всички"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"За да превключите мрежите, прекъснете връзката с Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> иска да добави следния панел към бързите настройки"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Добавяне на панел"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Отмяна на добавянето"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 05cbfc0..78b04c1 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"নেটওয়ার্ক দেখার জন্য আনলক করুন"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"নেটওয়ার্ক সার্চ করা হচ্ছে…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"নেটওয়ার্কে কানেক্ট করা যায়নি"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"সবকটি দেখুন"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"নেটওয়ার্ক বদলাতে ইথারনেট ডিসকানেক্ট করুন"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> নিম্নলিখিত টাইল দ্রুত সেটিংস মেনুতে যোগ করতে চায়"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"টাইল যোগ করুন"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"টাইল যোগ করবেন না"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 81b0274..1e05870 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -1181,7 +1181,9 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte da vidite mreže"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traženje mreža…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje s mrežom nije uspjelo"</string>
+    <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi se trenutno ne može automatski povezati"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da promijenite mrežu, isključite ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> želi dodati sljedeću karticu u Brze postavke"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Dodaj karticu"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nemoj dodati karticu"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 59fef13..c03f8a9 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueja per veure xarxes"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"S\'estan cercant xarxes…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"No s\'ha pogut connectar a la xarxa"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Mostra-ho tot"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Per canviar de xarxa, desconnecta la connexió Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vol afegir la icona següent a la configuració ràpida"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Afegeix la icona"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"No afegeixis la icona"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index b04559a..a3284b7 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -1187,7 +1187,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Sítě uvidíte po odemknutí"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Vyhledávání sítí…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Připojení k síti se nezdařilo"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Zobrazit vše"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pokud chcete přepnout sítě, odpojte ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Aplikace <xliff:g id="APPNAME">%1$s</xliff:g> chce do Rychlého nastavení přidat následující dlaždici"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Přidat dlaždici"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nepřidávat dlaždici"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index afe693a..499b2b8 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås op for at se netværk"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Søger efter netværk…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Der kunne ikke oprettes forbindelse til netværket"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Afbryd ethernetforbindelsen for at skifte netværk"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vil gerne føje dette handlingsfelt til Kvikmenu"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Tilføj handlingsfelt"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Tilføj ikke felt"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 20e967d..72ed84e 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Entsperren, um Netzwerke anzuzeigen"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Netzwerke werden gesucht…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Netzwerkverbindung konnte nicht hergestellt werden"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Alle ansehen"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Trenne das Ethernetkabel, um das Netzwerk zu wechseln"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> möchte die folgende Kachel den Schnelleinstellungen hinzufügen"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Kachel hinzufügen"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Kachel nicht hinzu"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 5a11e3d..1eb7da7 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ξεκλειδώστε για προβολή δικτύων"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Αναζήτηση δικτύων…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Αποτυχία σύνδεσης στο δίκτυο"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Εμφάνιση όλων"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Για εναλλαγή δικτύων, αποσυνδέστε το ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Η εφαρμογή <xliff:g id="APPNAME">%1$s</xliff:g> θέλει να προσθέσει το παρακάτω πλακίδιο στις Γρήγορες ρυθμίσεις"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Προσθήκη πλακιδίου"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Χωρίς προσθ. πλακιδ."</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 8e9c550..0e1e49a 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wants to add the following tile to Quick Settings"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Add tile"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Do not add tile"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 9d8008b..bcfc47a 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wants to add the following tile to Quick Settings"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Add tile"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Do not add tile"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 8e9c550..0e1e49a 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wants to add the following tile to Quick Settings"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Add tile"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Do not add tile"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 8e9c550..0e1e49a 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wants to add the following tile to Quick Settings"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Add tile"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Do not add tile"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index fd5faaf..a667418 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -1175,7 +1175,9 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‎‏‏‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‎‎‎Unlock to view networks‎‏‎‎‏‎"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‎‎‎‎‏‎‎‎‎‎‏‏‎‎‎‎‏‎‎‏‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‎Searching for networks…‎‏‎‎‏‎"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‎‎‏‏‎‎‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‏‏‏‎Failed to connect to network‎‏‎‎‏‎"</string>
+    <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‎Wi‑Fi won’t auto-connect for now‎‏‎‎‏‎"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‎‎‎‎‏‏‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎‎See all‎‏‎‎‏‎"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‎‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‎‏‏‎To switch networks, disconnect ethernet‎‏‎‎‏‎"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‎‎‏‎‏‏‏‎‏‎‏‎‎‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‎‏‏‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="APPNAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ wants to add the following tile to Quick Settings‎‏‎‎‏‎"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‎‏‎‎‏‎‎‎‎‎‎‎Add tile‎‏‎‎‏‎"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‏‏‎‏‎‎‎‏‎‏‏‏‎‏‏‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‏‎‎‎‎‎‎Do not add tile‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 335a66b..b07038c 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -1175,7 +1175,9 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea para ver las redes"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Se produjo un error al establecer conexión con la red"</string>
+    <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Por ahora, el Wi-Fi no se conectará automáticamente"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de red, desconéctate de Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> quiere agregar el siguiente azulejo a la Configuración rápida"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Agregar azulejo"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"No agregar azulejo"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index b5cb7c4..23f275a 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -683,7 +683,7 @@
     <string name="zen_alarm_warning_indef" msgid="5252866591716504287">"No oirás la próxima alarma (<xliff:g id="WHEN">%1$s</xliff:g>) a menos que desactives esta opción antes"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"No oirás la próxima alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string>
     <string name="alarm_template" msgid="2234991538018805736">"a las <xliff:g id="WHEN">%1$s</xliff:g>"</string>
-    <string name="alarm_template_far" msgid="3561752195856839456">"el <xliff:g id="WHEN">%1$s</xliff:g>"</string>
+    <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Ajustes rápidos, <xliff:g id="TITLE">%s</xliff:g>."</string>
     <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Compartir Internet"</string>
     <string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de trabajo"</string>
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea para ver redes"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"No se ha podido conectar a la red"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de red, desconecta el cable Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> quiere añadir el siguiente recuadro a ajustes rápidos"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Añadir recuadro"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"No añadir recuadro"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 3bcf351..9595838 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Võrkude vaatamiseks avage"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Võrkude otsimine …"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Võrguühenduse loomine ebaõnnestus"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Kuva kõik"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Võrkude vahetamiseks katkestage Etherneti-ühendus"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> soovib kiirseadetesse lisada järgmise paani"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Lisa paan"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ära lisa paani"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 5003b4e..a33e4e8 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -1175,7 +1175,9 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Sareak ikusteko, desblokeatu pantaila"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Sareak bilatzen…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ezin izan da konektatu sarera"</string>
+    <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Oraingoz ez da automatikoki konektatuko wifira"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Ikusi guztiak"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Sarea aldatzeko, deskonektatu Ethernet-a"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> aplikazioak lauza hau gehitu nahi du Ezarpen bizkorrak menuan:"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Gehitu lauza"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ez gehitu lauza"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index abe01d5..69d542a 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"برای مشاهده شبکه‌ها، قفل صفحه را باز کنید"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"درحال جستجوی شبکه…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"اتصال به شبکه برقرار نشد"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"مشاهده همه"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"برای تغییر شبکه، اترنت را قطع کنید"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> می‌خواهد کاشی زیر را به «تنظیمات فوری» اضافه کند"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"افزودن کاشی"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"کاشی اضافه نشود"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index db11c26..121c955 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Avaa lukitus nähdäksesi verkot"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Etsitään verkkoja…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Yhteyden muodostaminen verkkoon epäonnistui"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Näytä kaikki"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Irrota Ethernet-johto, jos haluat vaihtaa verkkoa"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> haluaa lisätä seuraavan laatan pika-asetuksiin"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Lisää laatta"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Älä lisää laattaa"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 35ca25a..2d43614 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -1175,10 +1175,12 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Déverrouillez l\'écran pour afficher les réseaux Wi-Fi"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Recherche de réseaux en cours…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Échec de la connexion au réseau"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pour changer de réseau, débranchez le câble Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"L\'application <xliff:g id="APPNAME">%1$s</xliff:g> veut ajouter la tuile suivante au menu Paramètres rapides"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ajouter la tuile"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne pas ajouter tuile"</string>
-    <!-- no translation found for qs_user_switch_dialog_title (3045189293587781366) -->
-    <skip />
+    <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Sélect. utilisateur"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 47b1b45..c10ae39 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -1175,10 +1175,12 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Déverrouiller pour afficher les réseaux"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Recherche de réseaux…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Échec de la connexion au réseau"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pour changer de réseau, déconnectez l\'Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> veut ajouter le bloc suivant aux Réglages rapides"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ajouter un bloc"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne pas ajouter bloc"</string>
-    <!-- no translation found for qs_user_switch_dialog_title (3045189293587781366) -->
-    <skip />
+    <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Choisir utilisateur"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index b36173d..4c7f71c 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -1175,10 +1175,12 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea a pantalla para ver as redes"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Produciuse un erro ao conectarse á rede"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de rede, desconecta a Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> solicita a túa aprobación para engadir o seguinte atallo a Configuración rápida"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Engadir atallo"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Non engadir atallo"</string>
-    <!-- no translation found for qs_user_switch_dialog_title (3045189293587781366) -->
-    <skip />
+    <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleccionar usuario"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index d51cce9..a0b3fc7 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -1175,10 +1175,12 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"વાઇ-ફાઇ નેટવર્ક જોવા માટે અનલૉક કરો"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"નેટવર્ક શોધી રહ્યાં છીએ…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"નેટવર્ક સાથે કનેક્ટ કરવામાં નિષ્ફળ થયાં"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"બધા જુઓ"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"બીજા નેટવર્ક પર જવા માટે, ઇથરનેટ ડિસ્કનેક્ટ કરો"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"ઝડપી સેટિંગમાં <xliff:g id="APPNAME">%1$s</xliff:g> નીચે જણાવેલા ટાઇલ ઉમેરવા માગે છે"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ટાઇલ ઉમેરો"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ટાઇલ ઉમેરશો નહીં"</string>
-    <!-- no translation found for qs_user_switch_dialog_title (3045189293587781366) -->
-    <skip />
+    <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"વપરાશકર્તા પસંદ કરો"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 1726b81..1fc0246 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -1175,7 +1175,9 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"वाई-फ़ाई नेटवर्क देखने के लिए, स्क्रीन को अनलॉक करें"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"नेटवर्क खोजे जा रहे हैं…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"नेटवर्क से कनेक्ट नहीं किया जा सका"</string>
+    <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"फ़िलहाल, वाई-फ़ाई अपने-आप कनेक्ट नहीं होगा"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"सभी देखें"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क बदलने के लिए, पहले ईथरनेट को डिसकनेक्ट करें"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> इस टाइल को \'फटाफट सेटिंग\' में जोड़ने के लिए अनुमति चाहता है"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"टाइल जोड़ें"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"टाइल न जोड़ें"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 2a69589..df68e07 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -1181,7 +1181,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte za prikaz mreža"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traženje mreža…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje s mrežom nije uspjelo"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da biste se prebacili na drugu mrežu, odspojite Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> želi dodati sljedeću pločicu u Brze postavke"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Dodaj pločicu"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nemoj dodati pločicu"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index d964611..a2d7be1 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Zárolás feloldása a hálózatok megtekintéséhez"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Hálózatok keresése…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nem sikerült hálózathoz csatlakozni."</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Megtekintés"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Hálózatváltáshoz válassza le az ethernetet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"A(z) <xliff:g id="APPNAME">%1$s</xliff:g> a következő mozaikot szeretné hozzáadni a Gyorsbeállításokhoz"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Mozaik hozzáadása"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne legyen hozzáadva"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 2372265..c4e61af 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ապակողպեք՝ ցանցերը դիտելու համար"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ցանցերի որոնում…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Չհաջողվեց միանալ ցանցին"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Տեսնել բոլորը"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Մի ցանցից մյուսին անցնելու համար անջատեք Ethernet-ը"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> հավելվածն ուզում է ավելացնել հետևյալ սալիկը Արագ կարգավորումներում"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ավելացնել սալիկ"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Չավելացնել սալիկ"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 7de4c70..b3da8f6 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Buka kunci untuk melihat jaringan"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Mencari jaringan …"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Gagal menghubungkan ke jaringan"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Untuk beralih jaringan, lepaskan kabel ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ingin menambahkan kartu berikut ke Setelan Cepat"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Tambahkan kartu"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Jangan tambah kartu"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 9805fe9..22a43c7 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Taktu úr lás til að skoða netkerfi"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Leitar að netum…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ekki tókst að tengjast neti"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Sjá allt"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Aftengdu ethernet til að skipta um net"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vill bæta eftirfarandi reit við flýtistillingar"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Bæta reit við"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ekki bæta reit við"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index e97a9a5..0fc23f7 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Sblocca per visualizzare le reti"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ricerca di reti in corso…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Connessione alla rete non riuscita"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Mostra tutte"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Per cambiare rete, scollega il cavo Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vuole aggiungere il seguente riquadro alle Impostazioni rapide"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Aggiungi riquadro"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Non aggiungerlo"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index ae5dc08..35236cd 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -1187,10 +1187,12 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"צריך לבטל את הנעילה כדי להציג את הרשתות"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"בתהליך חיפוש רשתות…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"נכשל הניסיון להתחבר לרשת"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"הצגת הכול"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"כדי לעבור בין רשתות, צריך לנתק את האתרנט"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"האפליקציה <xliff:g id="APPNAME">%1$s</xliff:g> מבקשת להוסיף להגדרות המהירות את האריח הבא"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"הוספת אריח"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"אין להוסיף אריח"</string>
-    <!-- no translation found for qs_user_switch_dialog_title (3045189293587781366) -->
-    <skip />
+    <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"בחירת משתמש"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 8f07a2c..2d871ba 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"ネットワークを表示するにはロック解除してください"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ネットワークを検索しています…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ネットワークに接続できませんでした"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"すべて表示"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ネットワークを変更するにはイーサネット接続を解除してください"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> が以下のタイルをクイック設定に追加しようとしています"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"タイルを追加"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"タイルを追加しない"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index c6e2bec..3df7a69d 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"განბლოკვა ქსელების სანახავად"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"მიმდინარეობს ქსელების ძიება…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ქსელთან დაკავშირება ვერ ხერხდება"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"ყველას ნახვა"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ქსელების გადასართავად, გაწყვიტეთ Ethernet-თან კავშირი"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g>-ს სურს, დაამატოს შემდეგი მოზაიკა სწრაფ პარამეტრებში"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"მოზაიკის დამატება"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"არ დაემატოს მოზაიკა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 4fb68e9..824ec86 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Желілерді көру үшін құлыпты ашыңыз."</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Маңайдағы желілер ізделуде…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Желіге қосылмады."</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Барлығын көру"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Желілерді ауыстыру үшін ethernet кабелін ажыратыңыз."</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> Жылдам параметрлерге келесі бөлшекті қосқысы келеді."</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Бөлшек қосу"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Бөлшек қоспау"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 5e734f6..9b69265 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"ដោះសោ​ដើម្បីមើល​បណ្ដាញ"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"កំពុងស្វែងរកបណ្ដាញ…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"មិន​អាច​ភ្ជាប់​បណ្ដាញ​បានទេ"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"មើលទាំងអស់"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ដើម្បី​ប្ដូរ​បណ្ដាញ សូមផ្ដាច់​អ៊ីសឺរណិត"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ចង់បញ្ចូល​ប្រអប់​ខាងក្រោម​ទៅក្នុង​ការកំណត់រហ័ស"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"បញ្ចូល​ប្រអប់"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"កុំ​បញ្ចូល​ប្រអប់"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 798ea99..2b07d2b 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -1175,10 +1175,12 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"ನೆಟ್‌ವರ್ಕ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ನೆಟ್‌ವರ್ಕ್‌ಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"ಎಲ್ಲವನ್ನೂ ನೋಡಿ"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ನೆಟ್‌ವರ್ಕ್‌ಗಳನ್ನು ಬದಲಿಸಲು, ಇಥರ್ನೆಟ್ ಅನ್ನು ಡಿಸ್‌ಕನೆಕ್ಟ್ ಮಾಡಿ"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ಈ ಕೆಳಗಿನ ಟೈಲ್ ಅನ್ನು ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳಿಗೆ ಸೇರಿಸಲು ಬಯಸುತ್ತದೆ"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ಟೈಲ್ ಅನ್ನು ಸೇರಿಸಿ"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ಟೈಲ್ ಅನ್ನು ಸೇರಿಸಬೇಡಿ"</string>
-    <!-- no translation found for qs_user_switch_dialog_title (3045189293587781366) -->
-    <skip />
+    <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ಬಳಕೆದಾರ ಆಯ್ಕೆಮಾಡಿ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index de38570..1e1509c 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"네트워크를 보려면 잠금 해제하세요"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"네트워크 검색 중…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"네트워크에 연결하지 못했습니다."</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"모두 보기"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"네트워크를 전환하려면 이더넷을 연결 해제하세요."</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g>에서 빠른 설정에 다음 타일을 추가하려고 합니다."</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"타일 추가"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"타일 추가 안함"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 90f4689..cdfb768 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Тармактарды көрүү үчүн кулпусун ачыңыз"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Тармактар изделүүдө…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Тармакка туташпай калды"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Баарын көрүү"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Башка тармактарга которулуу үчүн Ethernet кабелин ажыратыңыз"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> төмөнкү ыкчам баскычты Ыкчам жөндөөлөргө кошкону жатат"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ыкчам баскыч кошуу"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ыкчам баскыч кошулбасын"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 7f20d1f..a021bfb 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"ປົດລັອກເພື່ອເບິ່ງເຄືອຂ່າຍ"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ກຳລັງຊອກຫາເຄືອຂ່າຍ…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ເຊື່ອມຕໍ່ເຄືອຂ່າຍບໍ່ສຳເລັດ"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"ເບິ່ງທັງໝົດ"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ເພື່ອສະຫຼັບເຄືອຂ່າຍ, ໃຫ້ຕັດການເຊື່ອມຕໍ່ອີເທີເນັດກ່ອນ"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ຕ້ອງການເພີ່ມແຜ່ນຕໍ່ໄປນີ້ໃສ່ການຕັ້ງຄ່າດ່ວນ"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ເພີ່ມແຜ່ນ"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ຢ່າເພີ່ມແຜ່ນ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 03858d5..6d57dafe 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -1187,7 +1187,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Atrakinkite, kad peržiūrėtumėte visus tinklus"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ieškoma tinklų…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Jungiantis prie tinklo įvyko klaida"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Žiūrėti viską"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Norėdami perjungti tinklus, atjunkite eternetą"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"„<xliff:g id="APPNAME">%1$s</xliff:g>“ nori prie sparčiųjų nustatymų pridėti toliau pateiktą išklotinės elementą"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Pridėti išklotinės elementą"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nepridėti išklotinės elemento"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 2db4fd4..0d2c375 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -1181,7 +1181,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lai skatītu tīklus, atbloķējiet"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Notiek tīklu meklēšana…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Neizdevās izveidot savienojumu ar tīklu"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Visu tīklu skatīšana"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Lai pārslēgtu tīklus, atvienojiet tīkla Ethernet vadu."</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> pieprasa atļauju pievienot tālāk norādīto elementu ātrajiem iestatījumiem"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Pievienot elementu"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nepievienot elementu"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index b1a5a5e..d63a2e6 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Отклучете за да се прикажат мрежите"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Се пребаруваат мрежи…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не успеа да се поврзе на мрежата"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Прикажи ги сите"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"За промена на мрежата, прекинете ја врската со етернетот"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> сака да ја додаде следнава плочка на „Брзите поставки“"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Додајте плочка"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Не додавајте плочка"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index dd937a8..93af5c3 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"നെറ്റ്‌വർക്കുകൾ കാണാൻ അൺ‌ലോക്ക് ചെയ്യുക"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"നെറ്റ്‌വർക്കുകൾ തിരയുന്നു…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"നെറ്റ്‌വർക്കിൽ കണക്റ്റ് ചെയ്യാനായില്ല"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"എല്ലാം കാണുക"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"മറ്റ് നെറ്റ്‌വർക്കുകളിലേക്ക് മാറാൻ, ഇതർനെറ്റ് വിച്ഛേദിക്കുക"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"ദ്രുത ക്രമീകരണത്തിലേക്ക് ഇനിപ്പറയുന്ന ടൈൽ ചേർക്കാൻ <xliff:g id="APPNAME">%1$s</xliff:g> ആവശ്യപ്പെടുന്നു"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ടൈൽ ചേർക്കുക"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ടൈൽ ചേർക്കരുത്"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 341b22d..0cae107 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Сүлжээг харахын тулд түгжээг тайлах"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Сүлжээ хайж байна…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Сүлжээнд холбогдож чадсангүй"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Бүгдийг харах"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Сүлжээг сэлгэхийн тулд этернэтийг салгана уу"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> нь дараах хавтанг Шуурхай тохиргоонд нэмэх хүсэлтэй байна"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Хавтан нэмэх"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Хавтанг бүү нэм"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index c071582..9450815 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -688,7 +688,7 @@
     <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"हॉटस्पॉट"</string>
     <string name="accessibility_managed_profile" msgid="4703836746209377356">"कार्य प्रोफाईल"</string>
     <string name="tuner_warning_title" msgid="7721976098452135267">"सर्वांसाठी नाही तर काहींसाठी मजेदार असू शकते"</string>
-    <string name="tuner_warning" msgid="1861736288458481650">"सिस्टम UI ट्युनर आपल्‍याला Android वापरकर्ता इंटरफेस ट्विक आणि कस्टमाइझ करण्‍याचे अनेक प्रकार देते. ही प्रयोगात्मक वैशिष्‍ट्ये बदलू शकतात, खंडित होऊ शकतात किंवा भविष्‍यातील रिलीज मध्‍ये कदाचित दिसणार नाहीत. सावधगिरी बाळगून पुढे सुरू ठेवा."</string>
+    <string name="tuner_warning" msgid="1861736288458481650">"सिस्टम UI ट्युनर आपल्‍याला Android यूझर इंटरफेस ट्विक आणि कस्टमाइझ करण्‍याचे अनेक प्रकार देते. ही प्रयोगात्मक वैशिष्‍ट्ये बदलू शकतात, खंडित होऊ शकतात किंवा भविष्‍यातील रिलीज मध्‍ये कदाचित दिसणार नाहीत. सावधगिरी बाळगून पुढे सुरू ठेवा."</string>
     <string name="tuner_persistent_warning" msgid="230466285569307806">"ही प्रयोगात्मक वैशिष्‍ट्ये बदलू शकतात, खंडित होऊ शकतात किंवा भविष्‍यातील रिलीज मध्‍ये कदाचित दिसणार नाहीत."</string>
     <string name="got_it" msgid="477119182261892069">"समजले"</string>
     <string name="tuner_toast" msgid="3812684836514766951">"अभिनंदन! सिस्टम UI ट्युनर सेटिंग्जमध्‍ये जोडले गेले आहे"</string>
@@ -1175,10 +1175,12 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"नेटवर्क पाहण्यासाठी स्क्रीन अनलॉक करा"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"नेटवर्क शोधत आहे…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"नेटवर्कशी कनेक्‍ट करता आले नाही"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"सर्व पहा"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क स्विच करण्यासाठी, इथरनेट केबल डिस्कनेक्ट करा"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ला क्विक सेटिंग्जमध्ये पुढील टाइल जोडायची आहे"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"टाइल जोडा"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"टाइल जोडू नका"</string>
-    <!-- no translation found for qs_user_switch_dialog_title (3045189293587781366) -->
-    <skip />
+    <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"वापरकर्ता निवडा"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 8388cdd..0c45ea7 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Buka kunci untuk melihat rangkaian"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Mencari rangkaian…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Gagal menyambung kepada rangkaian"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Untuk menukar rangkaian, putuskan sambungan ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> mahu menambah jubin yang berikut kepada Tetapan Pantas"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Tambahkan jubin"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Jangan tambah jubin"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index a40f944..5d129c9e4 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"ကွန်ရက်များကြည့်ရန် ဖွင့်ပါ"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ကွန်ရက်များကို ရှာဖွေနေသည်…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ကွန်ရက်သို့ ချိတ်ဆက်၍မရပါ"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"အားလုံးကြည့်ရန်"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ကွန်ရက်ပြောင်းရန် အီသာနက်ကို ချိတ်ဆက်မှုဖြုတ်ပါ"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> က ‘အမြန် ဆက်တင်များ’ တွင် အောက်ပါအကွက်ငယ်ကို ထည့်လိုသည်"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"အကွက်ငယ် ထည့်ရန်"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"အကွက်ငယ် မထည့်ပါ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 5542ad3..5f4e7ca5 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås opp for å se nettverk"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Søker etter nettverk …"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kunne ikke koble til nettverket"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"For å bytte nettverk, koble fra Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vil legge til denne brikken i Hurtiginnstillinger"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Legg til brikke"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ikke legg til brikke"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 9a2e9a1..b7ea6ac 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -1175,10 +1175,12 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"नेटवर्कहरू हेर्न आफ्नो स्क्रिन अनलक गर्नुहोस्"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"नेटवर्कहरू खोजिँदै छन्…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"नेटवर्कमा कनेक्ट गर्न सकिएन"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"सबै नेटवर्क हेर्नुहोस्"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क बदल्न इथरनेट डिस्कनेक्ट गर्नुहोस्"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> द्रुत सेटिङमा निम्न टाइल हाल्न चाहन्छ"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"टाइल हाल्नुहोस्"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"टाइल नहाल्नुहोस्"</string>
-    <!-- no translation found for qs_user_switch_dialog_title (3045189293587781366) -->
-    <skip />
+    <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"प्रयोगकर्ता चयन गर्नु…"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index b98694e..e7a158e 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -59,14 +59,8 @@
     <color name="global_actions_alert_text">@color/GM2_red_300</color>
 
     <!-- Global screenshot actions -->
-    <color name="global_screenshot_button_background">@color/GM2_grey_800</color>
-    <color name="global_screenshot_button_ripple">#42FFFFFF</color>
-    <color name="global_screenshot_button_text">#FFFFFF</color>
-    <color name="global_screenshot_button_border">@color/GM2_grey_600</color>
-    <color name="global_screenshot_button_icon">@color/GM2_blue_300</color>
-    <color name="global_screenshot_dismiss_background">@color/GM2_grey_800</color>
-    <color name="global_screenshot_dismiss_foreground">#FFFFFF</color>
-    <color name="global_screenshot_background_protection_start">#80000000</color> <!-- 50% black -->
+    <color name="screenshot_button_ripple">#42FFFFFF</color>
+    <color name="screenshot_background_protection_start">#80000000</color> <!-- 50% black -->
 
     <!-- Media -->
     <color name="media_divider">#85ffffff</color>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 8851c70e..0fd9227 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ontgrendel het scherm om netwerken te bekijken"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Netwerken zoeken…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kan geen verbinding maken met het netwerk"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Alles tonen"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Verbreek de ethernetverbinding om van netwerk te wisselen"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wil de volgende tegel toevoegen aan Snelle instellingen"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Tegel toevoegen"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Tegel niet toevoegen"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 3b2f79d..3379405 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -1175,10 +1175,12 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"ନେଟୱାର୍କଗୁଡ଼ିକୁ ଦେଖିବା ପାଇଁ ଅନଲକ୍ କରନ୍ତୁ"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ନେଟୱାର୍କଗୁଡ଼ିକ ସନ୍ଧାନ କରାଯାଉଛି…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ନେଟୱାର୍କକୁ ସଂଯୋଗ କରିବାରେ ବିଫଳ ହୋଇଛି"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"ସବୁ ଦେଖନ୍ତୁ"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ନେଟୱାର୍କ ସ୍ୱିଚ୍ କରିବାକୁ, ଇଥରନେଟ୍ ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> କ୍ୱିକ୍ ସେଟିଂସରେ ନିମ୍ନୋକ୍ତ ଟାଇଲ୍ ଯୋଗ କରିବାକୁ ଚାହେଁ"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ଟାଇଲ୍ ଯୋଗ କରନ୍ତୁ"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ଟାଇଲ୍ ଯୋଗ କର ନାହିଁ"</string>
-    <!-- no translation found for qs_user_switch_dialog_title (3045189293587781366) -->
-    <skip />
+    <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ଉପଯୋଗକର୍ତ୍ତା ଚୟନ କର"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 88d158d..2bfcc9e 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -1175,10 +1175,12 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"ਨੈੱਟਵਰਕਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ਨੈੱਟਵਰਕ ਖੋਜੇ ਜਾ ਰਹੇ ਹਨ…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"ਸਭ ਦੇਖੋ"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ਨੈੱਟਵਰਕਾਂ ਨੂੰ ਬਦਲਣ ਲਈ, ਈਥਰਨੈੱਟ ਨੂੰ ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ਅੱਗੇ ਦਿੱਤੀ ਟਾਇਲ ਨੂੰ ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰਨਾ ਚਾਹੁੰਦੀ ਹੈ"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ਟਾਇਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ਟਾਇਲ ਸ਼ਾਮਲ ਨਾ ਕਰੋ"</string>
-    <!-- no translation found for qs_user_switch_dialog_title (3045189293587781366) -->
-    <skip />
+    <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ਵਰਤੋਂਕਾਰ ਚੁਣੋ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 969b38b..2dc8e6a 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -1187,7 +1187,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Odblokuj, by wyświetlić sieci"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Szukam sieci…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nie udało się połączyć z siecią"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Pokaż wszystko"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Aby przełączać sieci, odłącz Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Aplikacja <xliff:g id="APPNAME">%1$s</xliff:g> chce dodać do Szybkich ustawień ten kafelek"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Dodaj kafelek"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nie dodawaj kafelka"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 9546571..199dbcc 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -592,7 +592,7 @@
     <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Receba notificações mais rápido"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Veja-as antes de desbloquear"</string>
-    <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Não, obrigado"</string>
+    <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Agora não"</string>
     <string name="hidden_notifications_setup" msgid="2064795578526982467">"Configurar"</string>
     <string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
     <string name="volume_zen_end_now" msgid="5901885672973736563">"Desativar agora"</string>
@@ -617,7 +617,7 @@
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Para liberar o app, toque nos botões \"Voltar\" e home e os mantenha pressionados"</string>
     <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Para liberar o app, deslize para cima e mantenha a tela pressionada"</string>
     <string name="screen_pinning_positive" msgid="3285785989665266984">"Entendi"</string>
-    <string name="screen_pinning_negative" msgid="6882816864569211666">"Não, obrigado"</string>
+    <string name="screen_pinning_negative" msgid="6882816864569211666">"Agora não"</string>
     <string name="screen_pinning_start" msgid="7483998671383371313">"App fixado"</string>
     <string name="screen_pinning_exit" msgid="4553787518387346893">"App liberado"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Esconder <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -1175,7 +1175,9 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Procurando redes…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Falha ao conectar à rede"</string>
+    <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"A conexão automática ao Wi-Fi ficará indisponível"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desconecte o cabo Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"O app <xliff:g id="APPNAME">%1$s</xliff:g> quer adicionar o bloco a seguir às Configurações rápidas"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adicionar bloco"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Não adicionar bloco"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 173eaa5..845de5f 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -1175,7 +1175,9 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"A procurar redes…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Não foi possível estabelecer ligação à rede"</string>
+    <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Por agora, o Wi-Fi não irá estabelecer lig. automaticamente"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Veja tudo"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desligue a Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"A app <xliff:g id="APPNAME">%1$s</xliff:g> pretende adicionar o seguinte mosaico às Definições rápidas"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adicionar mosaico"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Não adicion. mosaico"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 9546571..199dbcc 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -592,7 +592,7 @@
     <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Receba notificações mais rápido"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Veja-as antes de desbloquear"</string>
-    <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Não, obrigado"</string>
+    <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Agora não"</string>
     <string name="hidden_notifications_setup" msgid="2064795578526982467">"Configurar"</string>
     <string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
     <string name="volume_zen_end_now" msgid="5901885672973736563">"Desativar agora"</string>
@@ -617,7 +617,7 @@
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Para liberar o app, toque nos botões \"Voltar\" e home e os mantenha pressionados"</string>
     <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Para liberar o app, deslize para cima e mantenha a tela pressionada"</string>
     <string name="screen_pinning_positive" msgid="3285785989665266984">"Entendi"</string>
-    <string name="screen_pinning_negative" msgid="6882816864569211666">"Não, obrigado"</string>
+    <string name="screen_pinning_negative" msgid="6882816864569211666">"Agora não"</string>
     <string name="screen_pinning_start" msgid="7483998671383371313">"App fixado"</string>
     <string name="screen_pinning_exit" msgid="4553787518387346893">"App liberado"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Esconder <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -1175,7 +1175,9 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Procurando redes…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Falha ao conectar à rede"</string>
+    <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"A conexão automática ao Wi-Fi ficará indisponível"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desconecte o cabo Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"O app <xliff:g id="APPNAME">%1$s</xliff:g> quer adicionar o bloco a seguir às Configurações rápidas"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adicionar bloco"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Não adicionar bloco"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 3bca61f..59138ea 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -1181,7 +1181,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Deblocați pentru a vedea rețelele"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Se caută rețele…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nu s-a realizat conexiunea la rețea"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Afișează-le pe toate"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pentru a schimba rețeaua, deconectați ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vrea să adauge următorul card la Setări rapide"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adăugați un card"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nu adăugați un card"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 84d4210..19f779c 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -1187,7 +1187,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Разблокируйте, чтобы посмотреть сети Wi-Fi."</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Поиск сетей…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не удалось подключиться к сети"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Показать все"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Чтобы переключиться между сетями, отключите кабель Ethernet."</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Приложение \"<xliff:g id="APPNAME">%1$s</xliff:g>\" хочет добавить в меню \"Быстрые настройки\" указанный параметр."</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Добавить параметр"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Не добавлять"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 65855f4..540ff08 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"ජාල බැලීමට අගුලු හරින්න"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ජාල සඳහා සොයමින්…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ජාලය වෙත සම්බන්ධ වීම අසාර්ථක විය"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"සියල්ල බලන්න"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ජාල මාරු කිරීමට, ඊතර්නෙට් විසන්ධි කරන්න"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> හට ක්ෂණික සැකසීම් වෙත පහත ටයිල් එක් කිරීමට අවශ්‍යයි"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ටයිල් එක් කරන්න"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ටයිල් එක් නොකරන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 1202041..8a6afdd 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -1187,7 +1187,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Odomknutím si zobrazte siete"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Vyhľadávajú sa siete…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nepodarilo sa pripojiť k sieti"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Zobraziť všetko"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ak chcete prepnúť siete, odpojte ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Aplikácia <xliff:g id="APPNAME">%1$s</xliff:g> chce pridať do rýchlych nastavení túto kartu"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Pridať kartu"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nepridať kartu"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 94437330..fc2fe7c 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -1187,7 +1187,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Odklenite za ogled omrežij"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Iskanje omrežij …"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Vzpostavljanje povezave z omrežjem ni uspelo."</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Prikaz vseh omrežij"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Če želite preklopiti omrežje, prekinite ethernetno povezavo."</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Aplikacija <xliff:g id="APPNAME">%1$s</xliff:g> želi dodati to ploščico v hitre nastavitve."</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Dodaj ploščico"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne dodaj ploščice"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index b6789a8..0495d35 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -1175,10 +1175,12 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Shkyçe për të parë rrjetet"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Po kërkon për rrjete…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Lidhja me rrjetin dështoi"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Shiko të gjitha"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Për të ndërruar rrjetet, shkëput Ethernet-in"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> dëshiron të shtojë pllakëzën e mëposhtme te \"Cilësimet e shpejta\""</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Shto një pllakëz"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Mos e shto pllakëzën"</string>
-    <!-- no translation found for qs_user_switch_dialog_title (3045189293587781366) -->
-    <skip />
+    <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Zgjidh përdoruesin"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index e4e324b..70567e1 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -1181,7 +1181,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Откључајте да бисте видели мреже"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Траже се мреже…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Повезивање са мрежом није успело"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Погледајте све"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Да бисте променили мрежу, прекините етернет везу"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> жели да дода следећу плочицу у Брза подешавања"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Додај плочицу"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Не додај плочицу"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index b3dc3fc..672e778 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås upp för att visa nätverk"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Söker efter nätverk …"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Det gick inte att ansluta till nätverket"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Visa alla"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Koppla bort Ethernet för att växla nätverk"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vill lägga till följande ruta i snabbinställningarna"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Lägg till ruta"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Lägg inte till ruta"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index fbf3094..97abfca 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Fungua ili uangalie mitandao"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Inatafuta mitandao…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Imeshindwa kuunganisha kwenye mtandao"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Angalia yote"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ili kubadili mitandao, tenganisha ethaneti"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ingependa kuongeza kigae kifuatacho kwenye Mipangilio ya Haraka"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ongeza kigae"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Usiongeze kigae"</string>
diff --git a/packages/SystemUI/res/values-sw600dp-port/config.xml b/packages/SystemUI/res/values-sw600dp-port/config.xml
new file mode 100644
index 0000000..02fd25b
--- /dev/null
+++ b/packages/SystemUI/res/values-sw600dp-port/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+
+    <!-- The maximum number of tiles in the QuickQSPanel -->
+    <integer name="quick_qs_panel_max_tiles">6</integer>
+
+    <!-- The maximum number of rows in the QuickSettings -->
+    <integer name="quick_settings_max_rows">3</integer>
+
+    <!-- The number of columns in the QuickSettings -->
+    <integer name="quick_settings_num_columns">3</integer>
+</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
index 40838f3..da2403a 100644
--- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
@@ -16,6 +16,6 @@
   -->
 <resources>
     <!-- Size of the panel of large phones on portrait. This shouldn't fill, but have some padding on the side -->
-    <dimen name="notification_panel_width">416dp</dimen>
+    <dimen name="notification_panel_width">504dp</dimen>
 
 </resources>
diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml
index 436f8d0..ac44251 100644
--- a/packages/SystemUI/res/values-sw720dp/config.xml
+++ b/packages/SystemUI/res/values-sw720dp/config.xml
@@ -22,5 +22,14 @@
 <resources>
     <integer name="status_bar_config_maxNotificationIcons">5</integer>
 
+    <!-- The maximum number of tiles in the QuickQSPanel -->
+    <integer name="quick_qs_panel_max_tiles">6</integer>
+
+    <!-- The number of columns in the QuickSettings -->
+    <integer name="quick_settings_num_columns">3</integer>
+
+    <!-- The maximum number of rows in the QuickSettings -->
+    <integer name="quick_settings_max_rows">3</integer>
+
 </resources>
 
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 18f94ac..43000fd 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -513,7 +513,7 @@
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> மூலம் ரெக்கார்டிங் செய்யவோ அனுப்புவதற்கோ தொடங்கிவீட்டீர்களா?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"மீண்டும் காட்டாதே"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"எல்லாவற்றையும் அழி"</string>
-    <string name="manage_notifications_text" msgid="6885645344647733116">"அறிவிப்புகளை நிர்வகி"</string>
+    <string name="manage_notifications_text" msgid="6885645344647733116">"நிர்வகி"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"இதுவரை வந்த அறிவிப்புகள்"</string>
     <string name="notification_section_header_incoming" msgid="850925217908095197">"புதிது"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"சைலன்ட்"</string>
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"நெட்வொர்க்குகளைப் பார்க்க அன்லாக் செய்யுங்கள்"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"நெட்வொர்க்குகளைத் தேடுகிறது…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"நெட்வொர்க்குடன் இணைக்க முடியவில்லை"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"அனைத்தையும் காட்டு"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"நெட்வொர்க்குகளை மாற்ற ஈதர்நெட் இணைப்பைத் துண்டிக்கவும்"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"விரைவு அமைப்புகளில் பின்வரும் கட்டத்தைச் சேர்க்க <xliff:g id="APPNAME">%1$s</xliff:g> ஆப்ஸ் விரும்புகிறது"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"கட்டத்தைச் சேர்"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"கட்டத்தை சேர்க்காதே"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index ec279d0..b63a3e8 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -125,7 +125,7 @@
     <string name="screenrecord_start_error" msgid="2200660692479682368">"స్క్రీన్ రికార్డింగ్ ప్రారంభించడంలో ఎర్రర్ ఏర్పడింది"</string>
     <string name="usb_preference_title" msgid="1439924437558480718">"USB ఫైల్ బదిలీ ఎంపికలు"</string>
     <string name="use_mtp_button_title" msgid="5036082897886518086">"మీడియా ప్లేయర్‌గా (MTP) మౌంట్ చేయి"</string>
-    <string name="use_ptp_button_title" msgid="7676427598943446826">"కెమెరాగా (PTP) మౌంట్ చేయి"</string>
+    <string name="use_ptp_button_title" msgid="7676427598943446826">"ఒక కెమెరాగా (PTP) మౌంట్ చేయండి"</string>
     <string name="installer_cd_button_title" msgid="5499998592841984743">"Macకు Android ఫైల్ బదిలీ యాప్ ఇన్‌స్టాల్ చేయండి"</string>
     <string name="accessibility_back" msgid="6530104400086152611">"వెనుకకు"</string>
     <string name="accessibility_home" msgid="5430449841237966217">"హోమ్"</string>
@@ -147,7 +147,7 @@
     <string name="accessibility_manage_notification" msgid="582215815790143983">"నోటిఫికేషన్‌లను నిర్వహించండి"</string>
     <string name="phone_label" msgid="5715229948920451352">"ఫోన్‌ను తెరువు"</string>
     <string name="voice_assist_label" msgid="3725967093735929020">"వాయిస్ అసిస్టెంట్‌ను తెరువు"</string>
-    <string name="camera_label" msgid="8253821920931143699">"కెమెరాను తెరువు"</string>
+    <string name="camera_label" msgid="8253821920931143699">"కెమెరాను తెరవండి"</string>
     <string name="cancel" msgid="1089011503403416730">"రద్దు చేయి"</string>
     <string name="biometric_dialog_confirm" msgid="2005978443007344895">"నిర్ధారించు"</string>
     <string name="biometric_dialog_try_again" msgid="8575345628117768844">"మళ్లీ ప్రయత్నించు"</string>
@@ -430,11 +430,11 @@
     <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ప్రారంభించు"</string>
     <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ఆపు"</string>
     <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"పరికరం మైక్రోఫోన్‌ను అన్‌బ్లాక్ చేయమంటారా?"</string>
-    <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"పరికరం కెమెరాను అన్‌బ్లాక్ చేయమంటారా?"</string>
-    <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"పరికరం కెమెరా, మైక్రోఫోన్‌ను అన్‌బ్లాక్ చేయమంటారా?"</string>
+    <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"పరికరంలోని కెమెరాను అన్‌బ్లాక్ చేయమంటారా?"</string>
+    <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"పరికరంలోని కెమెరా, మైక్రోఫోన్‌లను అన్‌బ్లాక్ చేయమంటారా?"</string>
     <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"మీ మైక్రోఫోన్‌ను ఉపయోగించడానికి అనుమతి పొందిన అన్ని యాప్‌లు, సర్వీస్‌లకు యాక్సెస్‌ను ఇది అన్‌బ్లాక్ చేస్తుంది."</string>
-    <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"మీ కెమెరాను ఉపయోగించడానికి అనుమతి పొందిన అన్ని యాప్‌లు, సర్వీస్‌లకు యాక్సెస్‌ను ఇది అన్‌బ్లాక్ చేస్తుంది."</string>
-    <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"మీ కెమెరాను లేదా మైక్రోఫోన్‌ను ఉపయోగించడానికి అనుమతి పొందిన అన్ని యాప్‌లు, సర్వీస్‌లకు యాక్సెస్‌ను ఇది అన్‌బ్లాక్ చేస్తుంది."</string>
+    <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ఇది, మీ కెమెరాను ఉపయోగించడానికి అనుమతి పొందిన అన్ని యాప్‌లకు, సర్వీస్‌లకు యాక్సెస్‌ను అన్‌బ్లాక్ చేస్తుంది."</string>
+    <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ఇది, మీ కెమెరాను లేదా మైక్రోఫోన్‌ను ఉపయోగించడానికి అనుమతి పొందిన అన్ని యాప్‌లకు, సర్వీస్‌లకు యాక్సెస్‌ను అన్‌బ్లాక్ చేస్తుంది."</string>
     <string name="media_seamless_other_device" msgid="4654849800789196737">"ఇతర పరికరం"</string>
     <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"స్థూలదృష్టిని టోగుల్ చేయి"</string>
     <string name="expanded_header_battery_charged" msgid="5307907517976548448">"ఛార్జ్ చేయబడింది"</string>
@@ -462,7 +462,7 @@
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ఈ పరికరం <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>కు చెందినది"</string>
     <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"ఈ పరికరం <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ద్వారా అందించబడింది"</string>
     <string name="phone_hint" msgid="6682125338461375925">"ఫోన్ కోసం చిహ్నాన్ని స్వైప్ చేయండి"</string>
-    <string name="voice_hint" msgid="7476017460191291417">"వాయిస్ అసిస్టెంట్ చిహ్నం నుండి స్వైప్"</string>
+    <string name="voice_hint" msgid="7476017460191291417">"వాయిస్ అసిస్టెంట్ కోసం చిహ్నం నుండి స్వైప్ చేయండి"</string>
     <string name="camera_hint" msgid="4519495795000658637">"కెమెరా కోసం చిహ్నాన్ని స్వైప్ చేయండి"</string>
     <string name="interruption_level_none_with_warning" msgid="8394434073508145437">"మొత్తం నిశ్శబ్దం. దీని వలన స్క్రీన్ రీడర్‌లు కూడా నిశ్శబ్దమవుతాయి."</string>
     <string name="interruption_level_none" msgid="219484038314193379">"మొత్తం నిశ్శబ్దం"</string>
@@ -756,13 +756,13 @@
     <string name="notification_delegate_header" msgid="1264510071031479920">"ప్రాక్సీ చేయబడిన నోటిఫికేషన్"</string>
     <string name="notification_channel_dialog_title" msgid="6856514143093200019">"అన్ని <xliff:g id="APP_NAME">%1$s</xliff:g> నోటిఫికేషన్‌లు"</string>
     <string name="see_more_title" msgid="7409317011708185729">"మరిన్ని చూడండి"</string>
-    <string name="appops_camera" msgid="5215967620896725715">"ఈ యాప్ ఈ కెమెరాను ఉపయోగిస్తోంది."</string>
+    <string name="appops_camera" msgid="5215967620896725715">"ఈ యాప్, కెమెరాను ఉపయోగిస్తోంది."</string>
     <string name="appops_microphone" msgid="8805468338613070149">"ఈ యాప్ మైక్రోఫోన్‌ను ఉపయోగిస్తుంది."</string>
     <string name="appops_overlay" msgid="4822261562576558490">"ఈ యాప్ మీ స్క్రీన్‌లోని ఇతర యాప్‌లపై ప్రదర్శించబడుతోంది."</string>
-    <string name="appops_camera_mic" msgid="7032239823944420431">"ఈ యాప్ మైక్రోఫోన్ మరియు కెమెరాను ఉపయోగిస్తుంది."</string>
-    <string name="appops_camera_overlay" msgid="6466845606058816484">"ఈ యాప్ మీ స్క్రీన్‌లోని ఇతర యాప్‌లపై ప్రదర్శించబడుతోంది మరియు కెమెరాను ఉపయోగిస్తుంది."</string>
+    <string name="appops_camera_mic" msgid="7032239823944420431">"ఈ యాప్ మైక్రోఫోన్‌ను, కెమెరాను ఉపయోగిస్తోంది."</string>
+    <string name="appops_camera_overlay" msgid="6466845606058816484">"ఈ యాప్ మీ స్క్రీన్‌లోని ఇతర యాప్‌లపై ప్రదర్శించబడుతోంది, కెమెరాను ఉపయోగిస్తోంది."</string>
     <string name="appops_mic_overlay" msgid="4609326508944233061">"ఈ యాప్ మీ స్క్రీన్‌లోని ఇతర యాప్‌లపై ప్రదర్శించబడుతోంది మరియు మైక్రోఫోన్‌ను ఉపయోగిస్తుంది."</string>
-    <string name="appops_camera_mic_overlay" msgid="5584311236445644095">"ఈ యాప్ మీ స్క్రీన్‌లోని ఇతర యాప్‌లపై ప్రదర్శించబడుతోంది మరియు మైక్రోఫోన్, కెమెరాను ఉపయోగిస్తుంది."</string>
+    <string name="appops_camera_mic_overlay" msgid="5584311236445644095">"ఈ యాప్ మీ స్క్రీన్‌లోని ఇతర యాప్‌లపై ప్రదర్శించబడుతోంది, మైక్రోఫోన్, కెమెరాను ఉపయోగిస్తోంది."</string>
     <string name="notification_appops_settings" msgid="5208974858340445174">"సెట్టింగ్‌లు"</string>
     <string name="notification_appops_ok" msgid="2177609375872784124">"సరే"</string>
     <string name="feedback_alerted" msgid="5192459808484271208">"ఈ నోటిఫికేషన్, సిస్టమ్ ద్వారా దానంతట అదే &lt;b&gt;ఆటోమేటిక్‌గా ప్రమోట్ చేయబడింది&lt;/b&gt;."</string>
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"నెట్‌వర్క్‌లను చూడటానికి అన్‌లాక్ చేయండి"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"నెట్‌వర్క్‌ల కోసం సెర్చ్ చేస్తోంది…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"నెట్‌వర్క్‌కు కనెక్ట్ చేయడం విఫలమైంది"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"అన్నీ చూడండి"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"నెట్‌వర్క్‌లను మార్చడానికి, ఈథర్‌నెట్‌ను డిస్‌కనెక్ట్ చేయండి"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"కింది టైల్‌ను క్విక్ సెట్టింగ్‌లకు జోడించడానికి <xliff:g id="APPNAME">%1$s</xliff:g> అనుమతి కోరుతోంది"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"టైల్‌ను జోడించండి"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"టైల్‌ను జోడించవద్దు"</string>
diff --git a/packages/SystemUI/res/values-te/strings_tv.xml b/packages/SystemUI/res/values-te/strings_tv.xml
index 7eded1e..592f8ce 100644
--- a/packages/SystemUI/res/values-te/strings_tv.xml
+++ b/packages/SystemUI/res/values-te/strings_tv.xml
@@ -28,8 +28,8 @@
     <string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"నోటిఫికేషన్‌లు లేవు"</string>
     <string name="mic_recording_announcement" msgid="7587123608060316575">"మైక్రోఫోన్ రికార్డింగ్ చేస్తోంది"</string>
     <string name="camera_recording_announcement" msgid="7240177719403759112">"కెమెరా రికార్డింగ్ చేస్తోంది"</string>
-    <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"కెమెరా, మైక్రోఫోన్ రికార్డింగ్ చేస్తున్నాయి"</string>
+    <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"కెమెరా, మైక్రోఫోన్‌లు రికార్డింగ్ చేస్తున్నాయి"</string>
     <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"మైక్రోఫోన్ రికార్డింగ్ చేయడం ఆపివేసింది"</string>
-    <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"కెమెరా రికార్డింగ్ చేయడం ఆపివేసింది"</string>
-    <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"కెమెరా, మైక్రోఫోన్ రికార్డింగ్ చేయడం ఆపివేశాయి"</string>
+    <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"రికార్డింగ్ చేయడాన్ని కెమెరా ఆపివేసింది"</string>
+    <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"కెమెరా, మైక్రోఫోన్‌లు రికార్డింగ్ చేయడం ఆపివేశాయి"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 639432d..d49fe51 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"ปลดล็อกเพื่อดูเครือข่าย"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"กำลังค้นหาเครือข่าย…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"เชื่อมต่อเครือข่ายไม่สำเร็จ"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"ดูทั้งหมด"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ตัดการเชื่อมต่ออีเทอร์เน็ตเพื่อสลับเครือข่าย"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ต้องการเพิ่มชิ้นส่วนต่อไปนี้ในการตั้งค่าด่วน"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"เพิ่มชิ้นส่วน"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ไม่ต้องเพิ่มชิ้นส่วน"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 4da06b8..5f0a8f1 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"I-unlock para tingnan ang mga network"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Naghahanap ng mga network…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Hind nakakonekta sa network"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Tingnan lahat"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para lumipat ng network, idiskonekta ang ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Gustong idagdag ng <xliff:g id="APPNAME">%1$s</xliff:g> ang sumusunod na tile sa Mga Mabilisang Setting"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Idagdag ang tile"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Huwag idagdag"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 88665e0..9200a8e 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ağları görmek için kilidi açın"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ağlar aranıyor…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ağa bağlanılamadı"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Tümünü göster"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ağ değiştirmek için ethernet bağlantısını kesin"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> aşağıdaki kartı Hızlı Ayarlar\'a eklemek istiyor"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Kart ekle"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Kart ekleme"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 267fe09..bd2fc40 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -1187,7 +1187,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Розблокувати, щоб переглянути мережі"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Пошук мереж…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не вдалося підключитися до мережі"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Показати все"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Щоб вибрати іншу мережу, від’єднайте кабель Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Додаток <xliff:g id="APPNAME">%1$s</xliff:g> хоче додати такий параметр у меню швидких налаштувань:"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Додати параметр"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Не додавати параметр"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index f8e5ca1..f8e0785 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -1175,10 +1175,12 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"نیٹ ورکس کو دیکھنے کے لیے غیر مقفل کریں"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"نیٹ ورکس تلاش کیے جا رہے ہیں…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"نیٹ ورک سے منسلک ہونے میں ناکام ہو گیا"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"سبھی دیکھیں"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"نیٹ ورکس پر سوئچ کرنے کیلئے، ایتھرنیٹ غیر منسلک کریں"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> درج ذیل ٹائل کو فوری ترتیبات میں شامل کرنا چاہتی ہے"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ٹائل شامل کریں"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ٹائل شامل نہ کریں"</string>
-    <!-- no translation found for qs_user_switch_dialog_title (3045189293587781366) -->
-    <skip />
+    <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"صارف منتخب کریں"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index b3a605c..b5e9b4f 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -1175,7 +1175,9 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Tarmoqlarni koʻrish uchun qulfdan chiqaring"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Tarmoqlar qidirilmoqda…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Tarmoqqa ulanmadi"</string>
+    <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi hozir avtomatik ulanmaydi"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Hammasi"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Boshqa tarmoqqa almashish uchun Ethernet tarmogʻini uzing"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ilovasi Tezkor sozlamalarga quyidagi tugmani kiritmoqchi"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Tugma kiritish"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Tugma kiritilmasin"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index e952e83..18e7824 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Mở khóa để xem mạng"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Đang tìm mạng…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Không kết nối được với mạng"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Xem tất cả"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Để chuyển mạng, hãy rút cáp Ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> muốn thêm ô bên dưới vào trình đơn Cài đặt nhanh"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Thêm ô"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Không thêm ô"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index eab642c..a297e24 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -1175,10 +1175,12 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"解锁即可查看网络"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"正在搜索网络…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"未能连接到网络"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切换网络,请断开以太网连接"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"“<xliff:g id="APPNAME">%1$s</xliff:g>”希望将以下图块添加到“快捷设置”"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"添加图块"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"不添加图块"</string>
-    <!-- no translation found for qs_user_switch_dialog_title (3045189293587781366) -->
-    <skip />
+    <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"选择用户"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index b25851b..f53acd2 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"解鎖即可查看網絡"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"正在搜尋網絡…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"無法連接網絡"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"顯示全部"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切換網絡,請中斷以太網連線"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"「<xliff:g id="APPNAME">%1$s</xliff:g>」想在「快速設定」選單新增以下圖塊"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"新增圖塊"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"不要新增圖塊"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 4ef03a6..2ba3a68 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"解鎖螢幕即可查看網路"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"正在搜尋網路…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"無法連上網路"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切換網路,請中斷乙太網路連線"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"「<xliff:g id="APPNAME">%1$s</xliff:g>」想在快速設定選單新增以下設定方塊"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"新增設定方塊"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"不要新增設定方塊"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 30f0f4e..8c5d6de 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -1175,7 +1175,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Vula ukuze ubuke amanethiwekhi"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Iseshela amanethiwekhi…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Yehlulekile ukuxhuma kunethiwekhi"</string>
+    <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+    <skip />
     <string name="see_all_networks" msgid="3773666844913168122">"Bona konke"</string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ukuze ushintshe amanethiwekhi, nqamula i-ethernet"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"I-<xliff:g id="APPNAME">%1$s</xliff:g> ifuna ukwengeza ithayela elilandelayo Kumasethingi Asheshayo"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Engeza ithayela"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ungafaki ithayela"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 08778bf..4b606bc 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -196,8 +196,8 @@
     <color name="default_invocation_lights_color">#ffffffff</color>         <!-- white -->
 
     <!-- Global screenshot actions -->
-    <color name="global_screenshot_button_ripple">#1f000000</color>
-    <color name="global_screenshot_background_protection_start">#40000000</color> <!-- 25% black -->
+    <color name="screenshot_button_ripple">#1f000000</color>
+    <color name="screenshot_background_protection_start">#40000000</color> <!-- 25% black -->
 
     <!-- GM2 colors -->
     <color name="GM2_grey_50">#F8F9FA</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 182c9b7..2c439f5 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -322,10 +322,7 @@
     <!-- Dimensions related to screenshots -->
 
     <!-- The padding on the global screenshot background image -->
-    <dimen name="global_screenshot_legacy_bg_padding">20dp</dimen>
-    <dimen name="global_screenshot_bg_padding">20dp</dimen>
-    <dimen name="global_screenshot_bg_protection_height">400dp</dimen>
-    <dimen name="global_screenshot_x_scale">80dp</dimen>
+    <dimen name="screenshot_x_scale">80dp</dimen>
     <dimen name="screenshot_bg_protection_height">242dp</dimen>
     <dimen name="screenshot_preview_elevation">4dp</dimen>
     <dimen name="screenshot_offset_y">8dp</dimen>
@@ -1279,7 +1276,7 @@
 
     <dimen name="ongoing_appops_dialog_circle_size">32dp</dimen>
 
-    <dimen name="ongoing_appops_dialog_icon_size">20dp</dimen>
+    <dimen name="ongoing_appops_dialog_icon_size">16dp</dimen>
 
     <dimen name="ongoing_appops_dialog_side_padding">16dp</dimen>
 
@@ -1310,6 +1307,7 @@
     <!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
     <dimen name="qs_aa_media_rec_album_size_collapsed">72dp</dimen>
     <dimen name="qs_aa_media_rec_album_size_expanded">76dp</dimen>
+    <dimen name="qs_aa_media_gradient_bg_width">32dp</dimen>
     <dimen name="qs_aa_media_rec_album_margin">8dp</dimen>
     <dimen name="qs_aa_media_rec_album_margin_vert">4dp</dimen>
     <dimen name="qq_aa_media_rec_header_text_size">16sp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 49bbf7d..b3bdffd 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3020,6 +3020,8 @@
     <string name="wifi_empty_list_wifi_on">Searching for networks\u2026</string>
     <!-- Provider Model: Failure notification for connect -->
     <string name="wifi_failed_connect_message">Failed to connect to network</string>
+    <!-- Provider Model: Toast message for when the user selects cellular as the internet provider and Wi-Fi auto-connect is temporarily disabled [CHAR LIMIT=60]-->
+    <string name="wifi_wont_autoconnect_for_now">Wi\u2011Fi won\u2019t auto-connect for now</string>
     <!-- Provider Model: Title to see all the networks [CHAR LIMIT=50] -->
     <string name="see_all_networks">See all</string>
     <!-- Summary for warning to disconnect ethernet first then switch to other networks. [CHAR LIMIT=60] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 33edca1..5aba333 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -416,7 +416,9 @@
     </style>
 
     <!-- Overridden by values-television/styles.xml with tv-specific settings -->
-    <style name="volume_dialog_theme" parent="Theme.SystemUI"/>
+    <style name="volume_dialog_theme" parent="Theme.SystemUI">
+        <item name="android:windowIsFloating">true</item>
+    </style>
 
     <style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog" />
 
@@ -1043,7 +1045,7 @@
 
     <style name="TextAppearance.InternetDialog.Secondary">
         <item name="android:textSize">14sp</item>
-        <item name="android:textColor">?android:attr/textColorTertiary</item>
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
     </style>
 
     <style name="TextAppearance.InternetDialog.Active"/>
diff --git a/packages/SystemUI/res/xml/media_recommendation_collapsed.xml b/packages/SystemUI/res/xml/media_recommendation_collapsed.xml
index 5c41ad8..b6258d1 100644
--- a/packages/SystemUI/res/xml/media_recommendation_collapsed.xml
+++ b/packages/SystemUI/res/xml/media_recommendation_collapsed.xml
@@ -19,25 +19,6 @@
     xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <Constraint
-        android:id="@+id/recommendation_card_icon"
-        android:layout_width="@dimen/qs_media_icon_size"
-        android:layout_height="@dimen/qs_media_icon_size"
-        android:layout_marginTop="@dimen/qs_media_padding"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toStartOf="@id/media_vertical_start_guideline"
-        app:layout_constraintHorizontal_bias="0" />
-
-    <Constraint
-        android:id="@+id/recommendation_card_text"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        app:layout_constraintTop_toBottomOf="@id/recommendation_card_icon"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toStartOf="@id/media_vertical_start_guideline"
-        app:layout_constraintHorizontal_bias="0" />
-
-    <Constraint
         android:id="@+id/media_cover1_container"
         android:layout_width="0dp"
         android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
diff --git a/packages/SystemUI/res/xml/media_recommendation_expanded.xml b/packages/SystemUI/res/xml/media_recommendation_expanded.xml
index 8a3d5ca..2fb3341 100644
--- a/packages/SystemUI/res/xml/media_recommendation_expanded.xml
+++ b/packages/SystemUI/res/xml/media_recommendation_expanded.xml
@@ -19,25 +19,6 @@
     xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <Constraint
-        android:id="@+id/recommendation_card_icon"
-        android:layout_width="@dimen/qs_media_icon_size"
-        android:layout_height="@dimen/qs_media_icon_size"
-        android:layout_marginTop="@dimen/qs_media_padding"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toStartOf="@id/media_vertical_start_guideline"
-        app:layout_constraintHorizontal_bias="0" />
-
-    <Constraint
-        android:id="@+id/recommendation_card_text"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        app:layout_constraintTop_toBottomOf="@id/recommendation_card_icon"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toStartOf="@id/media_vertical_start_guideline"
-        app:layout_constraintHorizontal_bias="0" />
-
-    <Constraint
         android:id="@+id/media_cover1_container"
         android:layout_width="0dp"
         android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
index e33985d..6154d84 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
@@ -18,16 +18,19 @@
 
 import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
 import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
+import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
 
+import android.annotation.TargetApi;
 import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.graphics.Color;
+import android.graphics.Rect;
 import android.inputmethodservice.InputMethodService;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
 import android.util.DisplayMetrics;
 import android.view.Surface;
+import android.view.WindowManager;
 
 /* Common code */
 public class Utilities {
@@ -117,21 +120,20 @@
         return hints;
     }
 
-    /** See {@link #isTablet(Configuration, Context)} */
+    /** @return whether or not {@param context} represents that of a large screen device or not */
+    @TargetApi(Build.VERSION_CODES.R)
     public static boolean isTablet(Context context) {
-        Configuration newConfig = context.getResources().getConfiguration();
-        return isTablet(newConfig, context);
+        final WindowManager windowManager = context.getSystemService(WindowManager.class);
+        final Rect bounds = windowManager.getCurrentWindowMetrics().getBounds();
+
+        float originalSmallestWidth = dpiFromPx(Math.min(bounds.width(), bounds.height()),
+                context.getResources().getConfiguration().densityDpi);
+        return dpiFromPx(Math.min(bounds.width(), bounds.height()), DENSITY_DEVICE_STABLE)
+                >= TABLET_MIN_DPS && originalSmallestWidth >= TABLET_MIN_DPS;
     }
 
-    /**
-     * @return whether or not {@param newConfig} represents that of a large screen device or not
-     */
-    public static boolean isTablet(Configuration newConfig, Context context) {
-        float density = Resources.getSystem().getDisplayMetrics().density;
-        int size = Math.min((int) (density * newConfig.screenWidthDp),
-                (int) (density* newConfig.screenHeightDp));
-        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
-        float densityRatio = (float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT;
-        return (size / densityRatio) >= TABLET_MIN_DPS;
+    public static float dpiFromPx(float size, int densityDpi) {
+        float densityRatio = (float) densityDpi / DisplayMetrics.DENSITY_DEFAULT;
+        return (size / densityRatio);
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
index 92f8454..0529cdbc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
@@ -208,8 +208,7 @@
         mView.post(() -> {
             if (mView.isShown()) {
                 mPasswordEntry.requestFocus();
-                mInputMethodManager.showSoftInput(
-                        mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
+                mPasswordEntry.getWindowInsetsController().show(WindowInsets.Type.ime());
             }
         });
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 13cb036..a5b18ca 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -56,7 +56,6 @@
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.shared.system.SysUiStatsLog;
-import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
index 371564a..ef4353b 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
@@ -48,6 +48,7 @@
     private ImageView mBgView;
 
     private int mLockIconColor;
+    private boolean mUseBackground = false;
 
     public LockIconView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -61,8 +62,8 @@
         mBgView = findViewById(R.id.lock_icon_bg);
     }
 
-    void updateColorAndBackgroundVisibility(boolean useBackground) {
-        if (useBackground && mLockIcon.getDrawable() != null) {
+    void updateColorAndBackgroundVisibility() {
+        if (mUseBackground && mLockIcon.getDrawable() != null) {
             mLockIconColor = Utils.getColorAttrDefaultColor(getContext(),
                     android.R.attr.textColorPrimary);
             mBgView.setBackground(getContext().getDrawable(R.drawable.fingerprint_bg));
@@ -78,6 +79,9 @@
 
     void setImageDrawable(Drawable drawable) {
         mLockIcon.setImageDrawable(drawable);
+
+        if (!mUseBackground) return;
+
         if (drawable == null) {
             mBgView.setVisibility(View.INVISIBLE);
         } else {
@@ -86,6 +90,14 @@
     }
 
     /**
+     * Whether or not to render the lock icon background. Mainly used for UDPFS.
+     */
+    public void setUseBackground(boolean useBackground) {
+        mUseBackground = useBackground;
+        updateColorAndBackgroundVisibility();
+    }
+
+    /**
      * Set the location of the lock icon.
      */
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 28e19ac..8cfd225 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -346,7 +346,7 @@
     }
 
     private void updateColors() {
-        mView.updateColorAndBackgroundVisibility(mUdfpsSupported);
+        mView.updateColorAndBackgroundVisibility();
     }
 
     private void updateConfiguration() {
@@ -427,6 +427,8 @@
         boolean wasUdfpsEnrolled = mUdfpsEnrolled;
 
         mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null;
+        mView.setUseBackground(mUdfpsSupported);
+
         mUdfpsEnrolled = mKeyguardUpdateMonitor.isUdfpsEnrolled();
         if (wasUdfpsSupported != mUdfpsSupported || wasUdfpsEnrolled != mUdfpsEnrolled) {
             updateVisibility();
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
index 05256e6..f182e77 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
@@ -41,6 +41,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Prefs;
+import com.android.systemui.shared.system.SysUiStatsLog;
 
 /**
  * Contains logic for an accessibility floating menu view.
@@ -177,6 +178,9 @@
     }
 
     private void onDragEnd(Position position) {
+        SysUiStatsLog.write(SysUiStatsLog.ACCESSIBILITY_FLOATING_MENU_UI_CHANGED,
+                position.getPercentageX(), position.getPercentageY(),
+                mContext.getResources().getConfiguration().orientation);
         savePosition(mContext, position);
         showDockTooltipIfNecessary(mContext);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt
index 41c7ebe..b7398d8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt
@@ -17,6 +17,8 @@
 
 import android.content.Context
 import android.graphics.PixelFormat
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffColorFilter
 import android.graphics.Rect
 import android.hardware.biometrics.BiometricOverlayConstants
 import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
@@ -34,6 +36,8 @@
 import android.view.WindowManager
 import androidx.annotation.RawRes
 import com.airbnb.lottie.LottieAnimationView
+import com.airbnb.lottie.LottieProperty
+import com.airbnb.lottie.model.KeyPath
 import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.R
 import com.android.systemui.dagger.SysUISingleton
@@ -140,6 +144,7 @@
                 windowManager.updateViewLayout(overlayView, overlayViewParams)
             }
         }
+        lottie.addOverlayDynamicColor(context)
 
         return view
     }
@@ -194,3 +199,21 @@
 
 private fun Display.isPortrait(): Boolean =
     rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180
+
+private fun LottieAnimationView.addOverlayDynamicColor(context: Context) {
+    fun update() {
+        val c = context.getColor(R.color.biometric_dialog_accent)
+        for (key in listOf(".blue600", ".blue400")) {
+            addValueCallback(
+                KeyPath(key, "**"),
+                LottieProperty.COLOR_FILTER
+            ) { PorterDuffColorFilter(c, PorterDuff.Mode.SRC_ATOP) }
+        }
+    }
+
+    if (composition != null) {
+        update()
+    } else {
+        addLottieOnCompositionLoadedListener { update() }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 4d1608f..b210a19 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -367,6 +367,12 @@
 
     @Provides
     @Singleton
+    static Optional<TelecomManager> provideOptionalTelecomManager(Context context) {
+        return Optional.ofNullable(context.getSystemService(TelecomManager.class));
+    }
+
+    @Provides
+    @Singleton
     static TelephonyManager provideTelephonyManager(Context context) {
         return context.getSystemService(TelephonyManager.class);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java
index d4d01c8..3b1cc19 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java
@@ -21,16 +21,23 @@
 import android.util.SparseArray;
 
 import androidx.annotation.BoolRes;
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dump.DumpManager;
 import com.android.systemui.plugins.FlagReaderPlugin;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.util.wrapper.BuildInfo;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
 import javax.inject.Inject;
 /**
  * Reads and caches feature flags for quick access
@@ -55,7 +62,7 @@
  * Calls to this class should probably be wrapped by a method in {@link FeatureFlags}.
  */
 @SysUISingleton
-public class FeatureFlagReader {
+public class FeatureFlagReader implements Dumpable {
     private final Resources mResources;
     private final boolean mAreFlagsOverrideable;
     private final PluginManager mPluginManager;
@@ -68,6 +75,7 @@
     public FeatureFlagReader(
             @Main Resources resources,
             BuildInfo build,
+            DumpManager dumpManager,
             PluginManager pluginManager,
             SystemPropertiesHelper systemPropertiesHelper) {
         mResources = resources;
@@ -76,6 +84,7 @@
         mAreFlagsOverrideable =
                 build.isDebuggable() && mResources.getBoolean(R.bool.are_flags_overrideable);
 
+        dumpManager.registerDumpable("FeatureFlags", this);
         mPluginManager.addPluginListener(mPluginListener, FlagReaderPlugin.class);
     }
 
@@ -172,6 +181,23 @@
         }
     }
 
+    @Override
+    public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+        ArrayList<String> flagStrings = new ArrayList<>(mCachedFlags.size());
+        for (int i = 0; i < mCachedFlags.size(); i++) {
+            int key = mCachedFlags.keyAt(i);
+            // get the object by the key.
+            CachedFlag flag = mCachedFlags.get(key);
+            flagStrings.add("  " + RESNAME_PREFIX + flag.name + ": " + flag.value + "\n");
+        }
+        flagStrings.sort(String.CASE_INSENSITIVE_ORDER);
+        pw.println("AreFlagsOverrideable: " + mAreFlagsOverrideable);
+        pw.println("Cached FeatureFlags:");
+        for (String flagString : flagStrings) {
+            pw.print(flagString);
+        }
+    }
+
     private static class CachedFlag {
         public final String name;
         public final boolean value;
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index db5dbb0..c743fe1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -772,7 +772,8 @@
                     31, // MEDIA_RESUME
                 uid,
                 interactedSubcardRank,
-                interactedSubcardCardinality
+                interactedSubcardCardinality,
+                0 // received_latency_millis
         )
         /* ktlint-disable max-line-length */
     }
@@ -857,7 +858,8 @@
     ) {
         shouldPrioritizeSs = shouldPrioritize
         removeMediaPlayer(key)
-        val sortKey = MediaSortKey(isSsMediaRec = true, EMPTY, clock.currentTimeMillis())
+        val sortKey = MediaSortKey(/* isSsMediaRec= */ true,
+            EMPTY.copy(isPlaying = false), clock.currentTimeMillis())
         mediaData.put(key, sortKey)
         mediaPlayers.put(sortKey, player)
         smartspaceMediaData = data
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index b998fb5..e7445f9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -254,7 +254,8 @@
                 openGuts();
                 return true;
             } else {
-                return false;
+                closeGuts();
+                return true;
             }
         });
         mRecommendationViewHolder.getCancel().setOnClickListener(v -> {
@@ -587,6 +588,14 @@
             ViewGroup mediaCoverContainer = mediaCoverContainers.get(uiComponentIndex);
             setSmartspaceRecItemOnClickListener(mediaCoverContainer, recommendation,
                     uiComponentIndex);
+            // Bubble up the long-click event to the card.
+            mediaCoverContainer.setOnLongClickListener(v -> {
+                View parent = (View) v.getParent();
+                if (parent != null) {
+                    parent.performLongClick();
+                }
+                return true;
+            });
 
             // Set up the accessibility label for the media item.
             String artistName = recommendation.getExtras()
diff --git a/packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaDataProvider.kt b/packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaDataProvider.kt
index b6c2ef1..140a1fe 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaDataProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaDataProvider.kt
@@ -1,10 +1,13 @@
 package com.android.systemui.media
 
 import android.app.smartspace.SmartspaceTarget
+import android.util.Log
 import com.android.systemui.plugins.BcSmartspaceDataPlugin
 import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
 import javax.inject.Inject
 
+private const val TAG = "SsMediaDataProvider"
+
 /** Provides SmartspaceTargets of media types for SystemUI media control. */
 class SmartspaceMediaDataProvider @Inject constructor() : BcSmartspaceDataPlugin {
 
@@ -31,6 +34,10 @@
             }
         }
 
+        if (!mediaTargets.isEmpty()) {
+            Log.d(TAG, "Forwarding Smartspace media updates $mediaTargets")
+        }
+
         smartspaceMediaTargets = mediaTargets
         smartspaceMediaTargetListeners.forEach {
             it.onSmartspaceTargetsUpdated(smartspaceMediaTargets)
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 43315f6..d3a664b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -93,7 +93,6 @@
 import android.view.Display;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
-import android.view.IWindowManager;
 import android.view.InsetsState.InternalInsetsType;
 import android.view.InsetsVisibilities;
 import android.view.KeyEvent;
@@ -118,20 +117,17 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.LatencyTracker;
 import com.android.internal.view.AppearanceRegion;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
 import com.android.systemui.accessibility.SystemActions;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dump.DumpManager;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
 import com.android.systemui.navigationbar.buttons.KeyButtonView;
 import com.android.systemui.navigationbar.buttons.RotationContextButton;
 import com.android.systemui.navigationbar.gestural.QuickswitchOrientedNavHandle;
-import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
@@ -151,8 +147,6 @@
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
-import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.pip.Pip;
@@ -162,6 +156,8 @@
 import java.util.Optional;
 import java.util.function.Consumer;
 
+import javax.inject.Inject;
+
 import dagger.Lazy;
 
 /**
@@ -243,7 +239,13 @@
     private boolean mTransientShown;
     private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
     private LightBarController mLightBarController;
+    private final LightBarController mMainLightBarController;
+    private final LightBarController.Factory mLightBarControllerFactory;
     private AutoHideController mAutoHideController;
+    private final AutoHideController mMainAutoHideController;
+    private final AutoHideController.Factory mAutoHideControllerFactory;
+    private final Optional<TelecomManager> mTelecomManagerOptional;
+    private final InputMethodManager mInputMethodManager;
 
     @VisibleForTesting
     public int mDisplayId;
@@ -267,6 +269,7 @@
     private ViewTreeObserver.OnGlobalLayoutListener mOrientationHandleGlobalLayoutListener;
     private boolean mShowOrientedHandleForImmersiveMode;
 
+
     @com.android.internal.annotations.VisibleForTesting
     public enum NavBarActionEvent implements UiEventLogger.UiEventEnum {
 
@@ -478,11 +481,10 @@
                 }
             };
 
-    public NavigationBar(Context context,
+    private NavigationBar(Context context,
             WindowManager windowManager,
             Lazy<AssistManager> assistManagerLazy,
             AccessibilityManager accessibilityManager,
-            AccessibilityManagerWrapper accessibilityManagerWrapper,
             DeviceProvisionedController deviceProvisionedController,
             MetricsLogger metricsLogger,
             OverviewProxyService overviewProxyService,
@@ -504,7 +506,13 @@
             NavigationBarOverlayController navbarOverlayController,
             UiEventLogger uiEventLogger,
             NavigationBarA11yHelper navigationBarA11yHelper,
-            UserTracker userTracker) {
+            UserTracker userTracker,
+            LightBarController mainLightBarController,
+            LightBarController.Factory lightBarControllerFactory,
+            AutoHideController mainAutoHideController,
+            AutoHideController.Factory autoHideControllerFactory,
+            Optional<TelecomManager> telecomManagerOptional,
+            InputMethodManager inputMethodManager) {
         mContext = context;
         mWindowManager = windowManager;
         mAccessibilityManager = accessibilityManager;
@@ -531,6 +539,12 @@
         mNavigationBarA11yHelper = navigationBarA11yHelper;
         mUserTracker = userTracker;
         mNotificationShadeDepthController = notificationShadeDepthController;
+        mMainLightBarController = mainLightBarController;
+        mLightBarControllerFactory = lightBarControllerFactory;
+        mMainAutoHideController = mainAutoHideController;
+        mAutoHideControllerFactory = autoHideControllerFactory;
+        mTelecomManagerOptional = telecomManagerOptional;
+        mInputMethodManager = inputMethodManager;
 
         mNavBarMode = mNavigationModeController.addListener(this);
     }
@@ -548,7 +562,7 @@
         mNavigationBarView = barView.findViewById(R.id.navigation_bar_view);
 
         if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + barView);
-        mContext.getSystemService(WindowManager.class).addView(mFrame,
+        mWindowManager.addView(mFrame,
                 getBarLayoutParams(mContext.getResources().getConfiguration().windowConfiguration
                         .getRotation()));
         mDisplayId = mContext.getDisplayId();
@@ -606,8 +620,7 @@
     public void destroyView() {
         setAutoHideController(/* autoHideController */ null);
         mCommandQueue.removeCallback(this);
-        mContext.getSystemService(WindowManager.class).removeViewImmediate(
-                mNavigationBarView.getRootView());
+        mWindowManager.removeViewImmediate(mNavigationBarView.getRootView());
         mNavigationModeController.removeListener(this);
 
         mNavigationBarA11yHelper.removeA11yEventListener(mAccessibilityListener);
@@ -673,22 +686,16 @@
         // before notifications creation. We cannot directly use getLightBarController()
         // from NavigationBarFragment directly.
         LightBarController lightBarController = mIsOnDefaultDisplay
-                ? Dependency.get(LightBarController.class)
-                : new LightBarController(mContext,
-                        Dependency.get(DarkIconDispatcher.class),
-                        Dependency.get(BatteryController.class),
-                        Dependency.get(NavigationModeController.class),
-                        Dependency.get(DumpManager.class));
+                ? mMainLightBarController : mLightBarControllerFactory.create(mContext);
         setLightBarController(lightBarController);
 
         // TODO(b/118592525): to support multi-display, we start to add something which is
         //                    per-display, while others may be global. I think it's time to
         //                    add a new class maybe named DisplayDependency to solve
         //                    per-display Dependency problem.
+        // Alternative: this is a good case for a Dagger subcomponent. Same with LightBarController.
         AutoHideController autoHideController = mIsOnDefaultDisplay
-                ? Dependency.get(AutoHideController.class)
-                : new AutoHideController(mContext, mHandler,
-                        Dependency.get(IWindowManager.class));
+                ? mMainAutoHideController : mAutoHideControllerFactory.create(mContext);
         setAutoHideController(autoHideController);
         restoreAppearanceAndTransientState();
     }
@@ -712,6 +719,7 @@
         mHandler.removeCallbacks(mAutoDim);
         mHandler.removeCallbacks(mOnVariableDurationHomeLongClick);
         mHandler.removeCallbacks(mEnableLayoutTransitions);
+        mNavigationBarA11yHelper.removeA11yEventListener(mAccessibilityListener);
         mFrame = null;
         mNavigationBarView = null;
         mOrientationHandle = null;
@@ -1182,9 +1190,8 @@
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 mHomeBlockedThisTouch = false;
-                TelecomManager telecomManager =
-                        mContext.getSystemService(TelecomManager.class);
-                if (telecomManager != null && telecomManager.isRinging()) {
+                if (mTelecomManagerOptional.isPresent()
+                        && mTelecomManagerOptional.get().isRinging()) {
                     if (statusBarOptional.map(StatusBar::isKeyguardShowing).orElse(false)) {
                         Log.i(TAG, "Ignoring HOME; there's a ringing incoming call. " +
                                 "No heads up");
@@ -1266,7 +1273,7 @@
     }
 
     private void onImeSwitcherClick(View v) {
-        mContext.getSystemService(InputMethodManager.class).showInputMethodPickerFromSystem(
+        mInputMethodManager.showInputMethodPickerFromSystem(
                 true /* showAuxiliarySubtypes */, mDisplayId);
     };
 
@@ -1391,10 +1398,11 @@
     void updateAccessibilityServicesState() {
         int a11yFlags = mNavigationBarA11yHelper.getA11yButtonState();
 
-        boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
-        boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
-        mNavigationBarView.setAccessibilityButtonState(clickable, longClickable);
-
+        if (mNavigationBarView != null) {
+            boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
+            boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
+            mNavigationBarView.setAccessibilityButtonState(clickable, longClickable);
+        }
         updateSystemUiStateFlags(a11yFlags);
     }
 
@@ -1700,4 +1708,123 @@
     int getNavigationIconHints() {
         return mNavigationIconHints;
     }
-}
+
+    /**
+     * Injectable factory for construction a {@link NavigationBar}.
+     */
+    public static class Factory {
+        private final WindowManager mWindowManager;
+        private final Lazy<AssistManager> mAssistManagerLazy;
+        private final AccessibilityManager mAccessibilityManager;
+        private final DeviceProvisionedController mDeviceProvisionedController;
+        private final MetricsLogger mMetricsLogger;
+        private final OverviewProxyService mOverviewProxyService;
+        private final NavigationModeController mNavigationModeController;
+        private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
+        private final StatusBarStateController mStatusBarStateController;
+        private final SysUiState mSysUiFlagsContainer;
+        private final BroadcastDispatcher mBroadcastDispatcher;
+        private final CommandQueue mCommandQueue;
+        private final Optional<Pip> mPipOptional;
+        private final Optional<LegacySplitScreen> mSplitScreenOptional;
+        private final Optional<Recents> mRecentsOptional;
+        private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy;
+        private final ShadeController mShadeController;
+        private final NotificationRemoteInputManager mNotificationRemoteInputManager;
+        private final NotificationShadeDepthController mNotificationShadeDepthController;
+        private final SystemActions mSystemActions;
+        private final Handler mMainHandler;
+        private final NavigationBarOverlayController mNavbarOverlayController;
+        private final UiEventLogger mUiEventLogger;
+        private final NavigationBarA11yHelper mNavigationBarA11yHelper;
+        private final UserTracker mUserTracker;
+        private final LightBarController mMainLightBarController;
+        private final LightBarController.Factory mLightBarControllerFactory;
+        private final AutoHideController mMainAutoHideController;
+        private final AutoHideController.Factory mAutoHideControllerFactory;
+        private final Optional<TelecomManager> mTelecomManagerOptional;
+        private final InputMethodManager mInputMethodManager;
+
+        @Inject
+        public Factory(
+                WindowManager windowManager,
+                Lazy<AssistManager> assistManagerLazy,
+                AccessibilityManager accessibilityManager,
+                DeviceProvisionedController deviceProvisionedController,
+                MetricsLogger metricsLogger,
+                OverviewProxyService overviewProxyService,
+                NavigationModeController navigationModeController,
+                AccessibilityButtonModeObserver accessibilityButtonModeObserver,
+                StatusBarStateController statusBarStateController,
+                SysUiState sysUiFlagsContainer,
+                BroadcastDispatcher broadcastDispatcher,
+                CommandQueue commandQueue,
+                Optional<Pip> pipOptional,
+                Optional<LegacySplitScreen> splitScreenOptional,
+                Optional<Recents> recentsOptional,
+                Lazy<Optional<StatusBar>> statusBarOptionalLazy,
+                ShadeController shadeController,
+                NotificationRemoteInputManager notificationRemoteInputManager,
+                NotificationShadeDepthController notificationShadeDepthController,
+                SystemActions systemActions,
+                @Main Handler mainHandler,
+                NavigationBarOverlayController navbarOverlayController,
+                UiEventLogger uiEventLogger,
+                NavigationBarA11yHelper navigationBarA11yHelper,
+                UserTracker userTracker,
+                LightBarController mainLightBarController,
+                LightBarController.Factory lightBarControllerFactory,
+                AutoHideController mainAutoHideController,
+                AutoHideController.Factory autoHideControllerFactory,
+                Optional<TelecomManager> telecomManagerOptional,
+                InputMethodManager inputMethodManager) {
+            mWindowManager = windowManager;
+            mAssistManagerLazy = assistManagerLazy;
+            mAccessibilityManager = accessibilityManager;
+            mDeviceProvisionedController = deviceProvisionedController;
+            mMetricsLogger = metricsLogger;
+            mOverviewProxyService = overviewProxyService;
+            mNavigationModeController = navigationModeController;
+            mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
+            mStatusBarStateController = statusBarStateController;
+            mSysUiFlagsContainer = sysUiFlagsContainer;
+            mBroadcastDispatcher = broadcastDispatcher;
+            mCommandQueue = commandQueue;
+            mPipOptional = pipOptional;
+            mSplitScreenOptional = splitScreenOptional;
+            mRecentsOptional = recentsOptional;
+            mStatusBarOptionalLazy = statusBarOptionalLazy;
+            mShadeController = shadeController;
+            mNotificationRemoteInputManager = notificationRemoteInputManager;
+            mNotificationShadeDepthController = notificationShadeDepthController;
+            mSystemActions = systemActions;
+            mMainHandler = mainHandler;
+            mNavbarOverlayController = navbarOverlayController;
+            mUiEventLogger = uiEventLogger;
+            mNavigationBarA11yHelper = navigationBarA11yHelper;
+            mUserTracker = userTracker;
+            mMainLightBarController = mainLightBarController;
+            mLightBarControllerFactory = lightBarControllerFactory;
+            mMainAutoHideController = mainAutoHideController;
+            mAutoHideControllerFactory = autoHideControllerFactory;
+            mTelecomManagerOptional = telecomManagerOptional;
+            mInputMethodManager = inputMethodManager;
+        }
+
+        /** Construct a {@link NavigationBar} */
+        public NavigationBar create(Context context) {
+            return new NavigationBar(context, mWindowManager, mAssistManagerLazy,
+                    mAccessibilityManager, mDeviceProvisionedController, mMetricsLogger,
+                    mOverviewProxyService, mNavigationModeController,
+                    mAccessibilityButtonModeObserver, mStatusBarStateController,
+                    mSysUiFlagsContainer, mBroadcastDispatcher, mCommandQueue, mPipOptional,
+                    mSplitScreenOptional, mRecentsOptional, mStatusBarOptionalLazy,
+                    mShadeController, mNotificationRemoteInputManager,
+                    mNotificationShadeDepthController, mSystemActions, mMainHandler,
+                    mNavbarOverlayController, mUiEventLogger, mNavigationBarA11yHelper,
+                    mUserTracker, mMainLightBarController, mLightBarControllerFactory,
+                    mMainAutoHideController, mAutoHideControllerFactory, mTelecomManagerOptional,
+                    mInputMethodManager);
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index b8df49e..8dc6b99 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -32,52 +32,30 @@
 import android.view.Display;
 import android.view.IWindowManager;
 import android.view.View;
-import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
-import android.view.accessibility.AccessibilityManager;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
 import com.android.internal.statusbar.RegisterStatusBarResult;
 import com.android.settingslib.applications.InterestingConfigChanges;
 import com.android.systemui.Dumpable;
-import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
-import com.android.systemui.accessibility.SystemActions;
-import com.android.systemui.assist.AssistManager;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.model.SysUiState;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.recents.OverviewProxyService;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
-import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
-import com.android.wm.shell.pip.Pip;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.Optional;
 
 import javax.inject.Inject;
 
-import dagger.Lazy;
-
 
 /** A controller to handle navigation bars. */
 @SysUISingleton
@@ -90,36 +68,12 @@
     private static final String TAG = NavigationBarController.class.getSimpleName();
 
     private final Context mContext;
-    private final WindowManager mWindowManager;
-    private final Lazy<AssistManager> mAssistManagerLazy;
-    private final AccessibilityManager mAccessibilityManager;
-    private final AccessibilityManagerWrapper mAccessibilityManagerWrapper;
-    private final DeviceProvisionedController mDeviceProvisionedController;
-    private final MetricsLogger mMetricsLogger;
-    private final OverviewProxyService mOverviewProxyService;
-    private final NavigationModeController mNavigationModeController;
-    private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
-    private final StatusBarStateController mStatusBarStateController;
-    private final SysUiState mSysUiFlagsContainer;
-    private final BroadcastDispatcher mBroadcastDispatcher;
-    private final CommandQueue mCommandQueue;
-    private final Optional<Pip> mPipOptional;
-    private final Optional<LegacySplitScreen> mSplitScreenOptional;
-    private final Optional<Recents> mRecentsOptional;
-    private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy;
-    private final ShadeController mShadeController;
-    private final NotificationRemoteInputManager mNotificationRemoteInputManager;
-    private final SystemActions mSystemActions;
-    private final UiEventLogger mUiEventLogger;
     private final Handler mHandler;
-    private final NavigationBarA11yHelper mNavigationBarA11yHelper;
+    private final NavigationBar.Factory mNavigationBarFactory;
     private final DisplayManager mDisplayManager;
-    private final NavigationBarOverlayController mNavBarOverlayController;
     private final TaskbarDelegate mTaskbarDelegate;
-    private final NotificationShadeDepthController mNotificationShadeDepthController;
     private int mNavMode;
     @VisibleForTesting boolean mIsTablet;
-    private final UserTracker mUserTracker;
 
     /** A displayId - nav bar maps. */
     @VisibleForTesting
@@ -132,72 +86,28 @@
 
     @Inject
     public NavigationBarController(Context context,
-            WindowManager windowManager,
-            Lazy<AssistManager> assistManagerLazy,
-            AccessibilityManager accessibilityManager,
-            AccessibilityManagerWrapper accessibilityManagerWrapper,
-            DeviceProvisionedController deviceProvisionedController,
-            MetricsLogger metricsLogger,
             OverviewProxyService overviewProxyService,
             NavigationModeController navigationModeController,
-            AccessibilityButtonModeObserver accessibilityButtonModeObserver,
-            StatusBarStateController statusBarStateController,
             SysUiState sysUiFlagsContainer,
-            BroadcastDispatcher broadcastDispatcher,
             CommandQueue commandQueue,
-            Optional<Pip> pipOptional,
-            Optional<LegacySplitScreen> splitScreenOptional,
-            Optional<Recents> recentsOptional,
-            Lazy<Optional<StatusBar>> statusBarOptionalLazy,
-            ShadeController shadeController,
-            NotificationRemoteInputManager notificationRemoteInputManager,
-            NotificationShadeDepthController notificationShadeDepthController,
-            SystemActions systemActions,
             @Main Handler mainHandler,
-            UiEventLogger uiEventLogger,
-            NavigationBarOverlayController navBarOverlayController,
             ConfigurationController configurationController,
             NavigationBarA11yHelper navigationBarA11yHelper,
             TaskbarDelegate taskbarDelegate,
-            UserTracker userTracker,
+            NavigationBar.Factory navigationBarFactory,
             DumpManager dumpManager) {
         mContext = context;
-        mWindowManager = windowManager;
-        mAssistManagerLazy = assistManagerLazy;
-        mAccessibilityManager = accessibilityManager;
-        mAccessibilityManagerWrapper = accessibilityManagerWrapper;
-        mDeviceProvisionedController = deviceProvisionedController;
-        mMetricsLogger = metricsLogger;
-        mOverviewProxyService = overviewProxyService;
-        mNavigationModeController = navigationModeController;
-        mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
-        mStatusBarStateController = statusBarStateController;
-        mSysUiFlagsContainer = sysUiFlagsContainer;
-        mBroadcastDispatcher = broadcastDispatcher;
-        mCommandQueue = commandQueue;
-        mPipOptional = pipOptional;
-        mSplitScreenOptional = splitScreenOptional;
-        mRecentsOptional = recentsOptional;
-        mStatusBarOptionalLazy = statusBarOptionalLazy;
-        mShadeController = shadeController;
-        mNotificationRemoteInputManager = notificationRemoteInputManager;
-        mNotificationShadeDepthController = notificationShadeDepthController;
-        mSystemActions = systemActions;
-        mUiEventLogger = uiEventLogger;
         mHandler = mainHandler;
-        mNavigationBarA11yHelper = navigationBarA11yHelper;
+        mNavigationBarFactory = navigationBarFactory;
         mDisplayManager = mContext.getSystemService(DisplayManager.class);
         commandQueue.addCallback(this);
         configurationController.addCallback(this);
         mConfigChanges.applyNewConfig(mContext.getResources());
-        mNavBarOverlayController = navBarOverlayController;
-        mNavMode = mNavigationModeController.addListener(this);
-        mNavigationModeController.addListener(this);
+        mNavMode = navigationModeController.addListener(this);
         mTaskbarDelegate = taskbarDelegate;
         mTaskbarDelegate.setOverviewProxyService(commandQueue, overviewProxyService,
                 navigationBarA11yHelper, navigationModeController, sysUiFlagsContainer);
         mIsTablet = isTablet(mContext);
-        mUserTracker = userTracker;
 
         dumpManager.registerDumpable(this);
     }
@@ -205,7 +115,7 @@
     @Override
     public void onConfigChanged(Configuration newConfig) {
         boolean isOldConfigTablet = mIsTablet;
-        mIsTablet = isTablet(newConfig, mContext);
+        mIsTablet = isTablet(mContext);
         boolean largeScreenChanged = mIsTablet != isOldConfigTablet;
         // If we folded/unfolded while in 3 button, show navbar in folded state, hide in unfolded
         if (largeScreenChanged && updateNavbarForTaskbar()) {
@@ -354,33 +264,8 @@
         final Context context = isOnDefaultDisplay
                 ? mContext
                 : mContext.createDisplayContext(display);
-        NavigationBar navBar = new NavigationBar(context,
-                mWindowManager,
-                mAssistManagerLazy,
-                mAccessibilityManager,
-                mAccessibilityManagerWrapper,
-                mDeviceProvisionedController,
-                mMetricsLogger,
-                mOverviewProxyService,
-                mNavigationModeController,
-                mAccessibilityButtonModeObserver,
-                mStatusBarStateController,
-                mSysUiFlagsContainer,
-                mBroadcastDispatcher,
-                mCommandQueue,
-                mPipOptional,
-                mSplitScreenOptional,
-                mRecentsOptional,
-                mStatusBarOptionalLazy,
-                mShadeController,
-                mNotificationRemoteInputManager,
-                mNotificationShadeDepthController,
-                mSystemActions,
-                mHandler,
-                mNavBarOverlayController,
-                mUiEventLogger,
-                mNavigationBarA11yHelper,
-                mUserTracker);
+        NavigationBar navBar = mNavigationBarFactory.create(context);
+
         mNavigationBars.put(displayId, navBar);
 
         View navigationBarView = navBar.createView(savedState);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index 0e32e9d..71d2a73 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -71,7 +71,6 @@
     private int mDisabledFlags;
     private @WindowVisibleState int mTaskBarWindowState = WINDOW_STATE_SHOWING;
     private @Behavior int mBehavior;
-    private boolean mTaskbarVisible = false;
 
     @Inject
     public TaskbarDelegate(Context context) {
@@ -98,7 +97,6 @@
         mNavigationModeController.removeListener(this);
         mNavigationBarA11yHelper.removeA11yEventListener(mNavA11yEventListener);
         mEdgeBackGestureHandler.onNavBarDetached();
-        mTaskbarVisible = false;
     }
 
     public void init(int displayId) {
@@ -109,7 +107,6 @@
                 mNavigationModeController.addListener(this));
         mNavigationBarA11yHelper.registerA11yEventListener(mNavA11yEventListener);
         mEdgeBackGestureHandler.onNavBarAttached();
-        mTaskbarVisible = true;
         // Set initial state for any listeners
         updateSysuiFlags();
     }
@@ -185,19 +182,6 @@
     }
 
     @Override
-    public void onTaskbarStatusUpdated(boolean visible, boolean stashed) {
-        if (mTaskbarVisible == visible) {
-            return;
-        }
-        mTaskbarVisible = visible;
-        if (visible) {
-            mEdgeBackGestureHandler.onNavBarAttached();
-        } else {
-            mEdgeBackGestureHandler.onNavBarDetached();
-        }
-    }
-
-    @Override
     public void onNavigationModeChanged(int mode) {
         mEdgeBackGestureHandler.onNavigationModeChanged(mode);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 1bd3664..1a7a306 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -114,6 +114,7 @@
         super.onConfigurationChanged(newConfig);
         if (mLayoutOrientation != newConfig.orientation) {
             mLayoutOrientation = newConfig.orientation;
+            mDistributeTiles = true;
             setCurrentItem(0, false);
             mPageToRestore = 0;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 97568f9..f7d1b1e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -26,6 +26,7 @@
 import android.metrics.LogMaker;
 import android.view.View;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.Dumpable;
@@ -79,7 +80,8 @@
 
     private final QSHost.Callback mQSHostCallback = this::setTiles;
 
-    private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
+    @VisibleForTesting
+    protected final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
             new QSPanel.OnConfigurationChangedListener() {
                 @Override
                 public void onConfigurationChange(Configuration newConfig) {
@@ -156,6 +158,7 @@
         mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener);
         mHost.addCallback(mQSHostCallback);
         setTiles();
+        mLastOrientation = getResources().getConfiguration().orientation;
         switchTileLayout(true);
 
         mDumpManager.registerDumpable(mView.getDumpableTag(), this);
@@ -356,8 +359,7 @@
             return false;
         }
         return mUsingMediaPlayer && mMediaHost.getVisible()
-                    && getResources().getConfiguration().orientation
-                    == Configuration.ORIENTATION_LANDSCAPE;
+                && mLastOrientation == Configuration.ORIENTATION_LANDSCAPE;
     }
 
     private void logTiles() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING b/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING
index 55da203..2d45c5b2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING
+++ b/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING
@@ -1,15 +1,9 @@
 {
   "presubmit": [
     {
-      "name": "CtsAppTestCases",
+      "name": "CtsTileServiceTestCases",
       "options": [
         {
-          "include-filter": "android.app.cts.TileServiceTest"
-        },
-        {
-          "include-filter": "android.app.cts.BooleanTileServiceTest"
-        },
-        {
           "exclude-annotation": "org.junit.Ignore"
         },
         {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
index 73d1370..14e0f70 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
@@ -54,7 +54,7 @@
     private var lastAlarmInfo: AlarmManager.AlarmClockInfo? = null
     private val icon = ResourceIcon.get(R.drawable.ic_alarm)
     @VisibleForTesting
-    internal val defaultIntent = Intent(AlarmClock.ACTION_SET_ALARM)
+    internal val defaultIntent = Intent(AlarmClock.ACTION_SHOW_ALARMS)
     private val callback = NextAlarmController.NextAlarmChangeCallback { nextAlarm ->
         lastAlarmInfo = nextAlarm
         refreshState()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index 16b41a7..dc54e1b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -45,7 +45,7 @@
 import android.view.Window;
 import android.view.WindowInsets;
 import android.view.WindowManager;
-import android.widget.Button;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ProgressBar;
@@ -121,7 +121,7 @@
     private TextView mMobileSummaryText;
     private Switch mMobileDataToggle;
     private Switch mWiFiToggle;
-    private Button mDoneButton;
+    private FrameLayout mDoneLayout;
     private Drawable mBackgroundOn;
     private int mListMaxHeight;
     private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -227,7 +227,7 @@
         mWifiSettingsIcon = mDialogView.requireViewById(R.id.wifi_settings_icon);
         mWifiRecyclerView = mDialogView.requireViewById(R.id.wifi_list_layout);
         mSeeAllLayout = mDialogView.requireViewById(R.id.see_all_layout);
-        mDoneButton = mDialogView.requireViewById(R.id.done);
+        mDoneLayout = mDialogView.requireViewById(R.id.done_layout);
         mSignalIcon = mDialogView.requireViewById(R.id.signal_icon);
         mMobileTitleText = mDialogView.requireViewById(R.id.mobile_title);
         mMobileSummaryText = mDialogView.requireViewById(R.id.mobile_summary);
@@ -279,7 +279,7 @@
         mConnectedWifListLayout.setOnClickListener(null);
         mSeeAllLayout.setOnClickListener(null);
         mWiFiToggle.setOnCheckedChangeListener(null);
-        mDoneButton.setOnClickListener(null);
+        mDoneLayout.setOnClickListener(null);
         mInternetDialogController.onStop();
         mInternetDialogFactory.destroyDialog();
     }
@@ -347,7 +347,7 @@
                     buttonView.setChecked(isChecked);
                     mWifiManager.setWifiEnabled(isChecked);
                 });
-        mDoneButton.setOnClickListener(v -> dismiss());
+        mDoneLayout.setOnClickListener(v -> dismiss());
     }
 
     @MainThread
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index 66d9c55..aaba5ef 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -19,11 +19,15 @@
 import static com.android.settingslib.mobile.MobileMappings.getIconKey;
 import static com.android.settingslib.mobile.MobileMappings.mapIconSets;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Resources;
 import android.graphics.Color;
+import android.graphics.PixelFormat;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
@@ -32,6 +36,7 @@
 import android.net.NetworkCapabilities;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.NetworkRegistrationInfo;
@@ -45,7 +50,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.Gravity;
-import android.widget.Toast;
+import android.view.View;
+import android.view.WindowManager;
 
 import androidx.annotation.MainThread;
 import androidx.annotation.NonNull;
@@ -66,11 +72,15 @@
 import com.android.settingslib.wifi.WifiUtils;
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
+import com.android.systemui.toast.SystemUIToast;
+import com.android.systemui.toast.ToastFactory;
+import com.android.systemui.util.CarrierConfigTracker;
 import com.android.systemui.util.settings.GlobalSettings;
 import com.android.wifitrackerlib.MergedCarrierEntry;
 import com.android.wifitrackerlib.WifiEntry;
@@ -116,10 +126,12 @@
     private SubscriptionManager mSubscriptionManager;
     private TelephonyManager mTelephonyManager;
     private ConnectivityManager mConnectivityManager;
+    private CarrierConfigTracker mCarrierConfigTracker;
     private TelephonyDisplayInfo mTelephonyDisplayInfo =
             new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_UNKNOWN,
                     TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE);
     private Handler mHandler;
+    private Handler mWorkerHandler;
     private MobileMappings.Config mConfig = null;
     private Executor mExecutor;
     private AccessPointController mAccessPointController;
@@ -133,8 +145,16 @@
     private GlobalSettings mGlobalSettings;
     private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
     private ConnectivityManager.NetworkCallback mConnectivityManagerNetworkCallback;
+    private WindowManager mWindowManager;
+    private ToastFactory mToastFactory;
 
     @VisibleForTesting
+    static final float TOAST_PARAMS_HORIZONTAL_WEIGHT = 1.0f;
+    @VisibleForTesting
+    static final float TOAST_PARAMS_VERTICAL_WEIGHT = 1.0f;
+    @VisibleForTesting
+    static final long SHORT_DURATION_TIMEOUT = 4000;
+    @VisibleForTesting
     protected ActivityStarter mActivityStarter;
     @VisibleForTesting
     protected SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangedListener;
@@ -173,11 +193,15 @@
             @Nullable WifiManager wifiManager, ConnectivityManager connectivityManager,
             @Main Handler handler, @Main Executor mainExecutor,
             BroadcastDispatcher broadcastDispatcher, KeyguardUpdateMonitor keyguardUpdateMonitor,
-            GlobalSettings globalSettings, KeyguardStateController keyguardStateController) {
+            GlobalSettings globalSettings, KeyguardStateController keyguardStateController,
+            WindowManager windowManager, ToastFactory toastFactory,
+            @Background Handler workerHandler,
+            CarrierConfigTracker carrierConfigTracker) {
         if (DEBUG) {
             Log.d(TAG, "Init InternetDialogController");
         }
         mHandler = handler;
+        mWorkerHandler = workerHandler;
         mExecutor = mainExecutor;
         mContext = context;
         mGlobalSettings = globalSettings;
@@ -185,17 +209,20 @@
         mTelephonyManager = telephonyManager;
         mConnectivityManager = connectivityManager;
         mSubscriptionManager = subscriptionManager;
+        mCarrierConfigTracker = carrierConfigTracker;
         mBroadcastDispatcher = broadcastDispatcher;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mKeyguardStateController = keyguardStateController;
         mConnectionStateFilter = new IntentFilter();
         mConnectionStateFilter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
+        mConnectionStateFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
         mUiEventLogger = uiEventLogger;
         mActivityStarter = starter;
         mAccessPointController = accessPointController;
-        mConfig = MobileMappings.Config.readConfig(mContext);
         mWifiIconInjector = new WifiUtils.InternetIconInjector(mContext);
         mConnectivityManagerNetworkCallback = new DataConnectivityListener();
+        mWindowManager = windowManager;
+        mToastFactory = toastFactory;
     }
 
     void onStart(@NonNull InternetDialogCallback callback, boolean canConfigWifi) {
@@ -215,6 +242,7 @@
         if (DEBUG) {
             Log.d(TAG, "Init, SubId: " + mDefaultDataSubId);
         }
+        mConfig = MobileMappings.Config.readConfig(mContext);
         mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId);
         mInternetTelephonyCallback = new InternetTelephonyCallback();
         mTelephonyManager.registerTelephonyCallback(mExecutor, mInternetTelephonyCallback);
@@ -518,7 +546,7 @@
     String getMobileNetworkSummary() {
         String description = getNetworkTypeDescription(mContext, mConfig,
                 mTelephonyDisplayInfo, mDefaultDataSubId);
-        return getMobileSummary(mContext, mTelephonyManager, description);
+        return getMobileSummary(mContext, description);
     }
 
     /**
@@ -546,8 +574,7 @@
                 ? SubscriptionManager.getResourcesForSubId(context, subId).getString(resId) : "";
     }
 
-    private String getMobileSummary(Context context, TelephonyManager telephonyManager,
-            String networkTypeDescription) {
+    private String getMobileSummary(Context context, String networkTypeDescription) {
         if (!isMobileDataEnabled()) {
             return context.getString(R.string.mobile_data_off_summary);
         }
@@ -580,7 +607,8 @@
         final MergedCarrierEntry mergedCarrierEntry =
                 mAccessPointController.getMergedCarrierEntry();
         if (mergedCarrierEntry != null && mergedCarrierEntry.canConnect()) {
-            mergedCarrierEntry.connect(null /* ConnectCallback */);
+            mergedCarrierEntry.connect(null /* ConnectCallback */, false);
+            makeOverlayToast(R.string.wifi_wont_autoconnect_for_now);
         }
     }
 
@@ -590,6 +618,24 @@
         return mergedCarrierEntry != null && mergedCarrierEntry.isDefaultNetwork();
     }
 
+    @WorkerThread
+    void setMergedCarrierWifiEnabledIfNeed(int subId, boolean enabled) {
+        // If the Carrier Provisions Wi-Fi Merged Networks enabled, do not set the merged carrier
+        // Wi-Fi state together.
+        if (mCarrierConfigTracker.getCarrierProvisionsWifiMergedNetworksBool(subId)) {
+            return;
+        }
+
+        final MergedCarrierEntry entry = mAccessPointController.getMergedCarrierEntry();
+        if (entry == null) {
+            if (DEBUG) {
+                Log.d(TAG, "MergedCarrierEntry is null, can not set the status.");
+            }
+            return;
+        }
+        entry.setEnabled(enabled);
+    }
+
     WifiManager getWifiManager() {
         return mWifiManager;
     }
@@ -664,6 +710,7 @@
                 }
             }
         }
+        mWorkerHandler.post(() -> setMergedCarrierWifiEnabledIfNeed(subId, enabled));
     }
 
     boolean isDataStateInService() {
@@ -729,20 +776,20 @@
                 Log.d(TAG, "connect to unsaved network " + ap.getTitle());
             }
         }
-        ap.connect(new WifiEntryConnectCallback(mActivityStarter, mContext, ap));
+        ap.connect(new WifiEntryConnectCallback(mActivityStarter, ap, this));
         return false;
     }
 
     static class WifiEntryConnectCallback implements WifiEntry.ConnectCallback {
         final ActivityStarter mActivityStarter;
-        final Context mContext;
         final WifiEntry mWifiEntry;
+        final InternetDialogController mInternetDialogController;
 
-        WifiEntryConnectCallback(ActivityStarter activityStarter, Context context,
-                WifiEntry connectWifiEntry) {
+        WifiEntryConnectCallback(ActivityStarter activityStarter, WifiEntry connectWifiEntry,
+                InternetDialogController internetDialogController) {
             mActivityStarter = activityStarter;
-            mContext = context;
             mWifiEntry = connectWifiEntry;
+            mInternetDialogController = internetDialogController;
         }
 
         @Override
@@ -757,8 +804,7 @@
                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 mActivityStarter.startActivity(intent, false /* dismissShade */);
             } else if (status == CONNECT_STATUS_FAILURE_UNKNOWN) {
-                Toast.makeText(mContext, R.string.wifi_failed_connect_message,
-                        Toast.LENGTH_SHORT).show();
+                mInternetDialogController.makeOverlayToast(R.string.wifi_failed_connect_message);
             } else {
                 if (DEBUG) {
                     Log.d(TAG, "connect failure reason=" + status);
@@ -907,10 +953,13 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
-            if (action.equals(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
+            if (TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED.equals(action)) {
                 if (DEBUG) {
                     Log.d(TAG, "ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED");
                 }
+                mConfig = MobileMappings.Config.readConfig(context);
+                updateListener();
+            } else if (WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION.equals(action)) {
                 updateListener();
             }
         }
@@ -967,4 +1016,57 @@
         void onAccessPointsChanged(@Nullable List<WifiEntry> wifiEntries,
                 @Nullable WifiEntry connectedEntry);
     }
+
+    void makeOverlayToast(int stringId) {
+        final Resources res = mContext.getResources();
+
+        final SystemUIToast systemUIToast = mToastFactory.createToast(mContext,
+                res.getString(stringId), mContext.getPackageName(), UserHandle.myUserId(),
+                res.getConfiguration().orientation);
+        if (systemUIToast == null) {
+            return;
+        }
+
+        View toastView = systemUIToast.getView();
+
+        final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
+        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
+        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
+        params.format = PixelFormat.TRANSLUCENT;
+        params.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
+        params.y = systemUIToast.getYOffset();
+
+        int absGravity = Gravity.getAbsoluteGravity(systemUIToast.getGravity(),
+                res.getConfiguration().getLayoutDirection());
+        params.gravity = absGravity;
+        if ((absGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
+            params.horizontalWeight = TOAST_PARAMS_HORIZONTAL_WEIGHT;
+        }
+        if ((absGravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
+            params.verticalWeight = TOAST_PARAMS_VERTICAL_WEIGHT;
+        }
+
+        mWindowManager.addView(toastView, params);
+
+        Animator inAnimator = systemUIToast.getInAnimation();
+        if (inAnimator != null) {
+            inAnimator.start();
+        }
+
+        mHandler.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                Animator outAnimator = systemUIToast.getOutAnimation();
+                if (outAnimator != null) {
+                    outAnimator.start();
+                    outAnimator.addListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationEnd(Animator animator) {
+                            mWindowManager.removeViewImmediate(toastView);
+                        }
+                    });
+                }
+            }
+        }, SHORT_DURATION_TIMEOUT);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
index 26781f4..2133cf6 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
@@ -29,8 +29,8 @@
 import android.graphics.Bitmap;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.VirtualDisplay;
+import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
-import android.media.MediaCodecList;
 import android.media.MediaFormat;
 import android.media.MediaMuxer;
 import android.media.MediaRecorder;
@@ -187,77 +187,63 @@
      * @param refreshRate Desired refresh rate
      * @return array with supported width, height, and refresh rate
      */
-    private int[] getSupportedSize(final int screenWidth, final int screenHeight, int refreshRate) {
-        double maxScale = 0;
+    private int[] getSupportedSize(final int screenWidth, final int screenHeight, int refreshRate)
+            throws IOException {
+        String videoType = MediaFormat.MIMETYPE_VIDEO_AVC;
 
-        MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
-        MediaCodecInfo.VideoCapabilities maxInfo = null;
-        for (MediaCodecInfo codec : codecList.getCodecInfos()) {
-            String videoType = MediaFormat.MIMETYPE_VIDEO_AVC;
-            String[] types = codec.getSupportedTypes();
-            for (String t : types) {
-                if (!t.equalsIgnoreCase(videoType)) {
-                    continue;
-                }
-                MediaCodecInfo.CodecCapabilities capabilities =
-                        codec.getCapabilitiesForType(videoType);
-                if (capabilities != null && capabilities.getVideoCapabilities() != null) {
-                    MediaCodecInfo.VideoCapabilities vc = capabilities.getVideoCapabilities();
+        // Get max size from the decoder, to ensure recordings will be playable on device
+        MediaCodec decoder = MediaCodec.createDecoderByType(videoType);
+        MediaCodecInfo.VideoCapabilities vc = decoder.getCodecInfo()
+                .getCapabilitiesForType(videoType).getVideoCapabilities();
+        decoder.release();
 
-                    int width = vc.getSupportedWidths().getUpper();
-                    int height = vc.getSupportedHeights().getUpper();
+        // Check if we can support screen size as-is
+        int width = vc.getSupportedWidths().getUpper();
+        int height = vc.getSupportedHeights().getUpper();
 
-                    int screenWidthAligned = screenWidth;
-                    if (screenWidthAligned % vc.getWidthAlignment() != 0) {
-                        screenWidthAligned -= (screenWidthAligned % vc.getWidthAlignment());
-                    }
-                    int screenHeightAligned = screenHeight;
-                    if (screenHeightAligned % vc.getHeightAlignment() != 0) {
-                        screenHeightAligned -= (screenHeightAligned % vc.getHeightAlignment());
-                    }
+        int screenWidthAligned = screenWidth;
+        if (screenWidthAligned % vc.getWidthAlignment() != 0) {
+            screenWidthAligned -= (screenWidthAligned % vc.getWidthAlignment());
+        }
+        int screenHeightAligned = screenHeight;
+        if (screenHeightAligned % vc.getHeightAlignment() != 0) {
+            screenHeightAligned -= (screenHeightAligned % vc.getHeightAlignment());
+        }
 
-                    if (width >= screenWidthAligned && height >= screenHeightAligned
-                            && vc.isSizeSupported(screenWidthAligned, screenHeightAligned)) {
-                        // Desired size is supported, now get the rate
-                        int maxRate = vc.getSupportedFrameRatesFor(screenWidthAligned,
-                                screenHeightAligned).getUpper().intValue();
+        if (width >= screenWidthAligned && height >= screenHeightAligned
+                && vc.isSizeSupported(screenWidthAligned, screenHeightAligned)) {
+            // Desired size is supported, now get the rate
+            int maxRate = vc.getSupportedFrameRatesFor(screenWidthAligned,
+                    screenHeightAligned).getUpper().intValue();
 
-                        if (maxRate < refreshRate) {
-                            refreshRate = maxRate;
-                        }
-                        Log.d(TAG, "Screen size supported at rate " + refreshRate);
-                        return new int[]{screenWidthAligned, screenHeightAligned, refreshRate};
-                    }
-
-                    // Otherwise, continue searching
-                    double scale = Math.min(((double) width / screenWidth),
-                            ((double) height / screenHeight));
-                    if (scale > maxScale) {
-                        maxScale = Math.min(1, scale);
-                        maxInfo = vc;
-                    }
-                }
+            if (maxRate < refreshRate) {
+                refreshRate = maxRate;
             }
+            Log.d(TAG, "Screen size supported at rate " + refreshRate);
+            return new int[]{screenWidthAligned, screenHeightAligned, refreshRate};
         }
 
-        // Resize for max supported size
-        int scaledWidth = (int) (screenWidth * maxScale);
-        int scaledHeight = (int) (screenHeight * maxScale);
-        if (scaledWidth % maxInfo.getWidthAlignment() != 0) {
-            scaledWidth -= (scaledWidth % maxInfo.getWidthAlignment());
+        // Otherwise, resize for max supported size
+        double scale = Math.min(((double) width / screenWidth),
+                ((double) height / screenHeight));
+
+        int scaledWidth = (int) (screenWidth * scale);
+        int scaledHeight = (int) (screenHeight * scale);
+        if (scaledWidth % vc.getWidthAlignment() != 0) {
+            scaledWidth -= (scaledWidth % vc.getWidthAlignment());
         }
-        if (scaledHeight % maxInfo.getHeightAlignment() != 0) {
-            scaledHeight -= (scaledHeight % maxInfo.getHeightAlignment());
+        if (scaledHeight % vc.getHeightAlignment() != 0) {
+            scaledHeight -= (scaledHeight % vc.getHeightAlignment());
         }
 
         // Find max supported rate for size
-        int maxRate = maxInfo.getSupportedFrameRatesFor(scaledWidth, scaledHeight)
+        int maxRate = vc.getSupportedFrameRatesFor(scaledWidth, scaledHeight)
                 .getUpper().intValue();
         if (maxRate < refreshRate) {
             refreshRate = maxRate;
         }
 
-        Log.d(TAG, "Resized by " + maxScale + ": " + scaledWidth + ", " + scaledHeight
+        Log.d(TAG, "Resized by " + scale + ": " + scaledWidth + ", " + scaledHeight
                 + ", " + refreshRate);
         return new int[]{scaledWidth, scaledHeight, refreshRate};
     }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index e9dea65..04f33c1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -378,8 +378,7 @@
             List<Notification.Action> actions, Context context) {
         List<Notification.Action> broadcastActions = new ArrayList<>();
         for (Notification.Action action : actions) {
-            // Proxy smart actions through {@link GlobalScreenshot.SmartActionsReceiver}
-            // for logging smart actions.
+            // Proxy smart actions through {@link SmartActionsReceiver} for logging smart actions.
             Bundle extras = action.getExtras();
             String actionType = extras.getString(
                     ScreenshotNotificationSmartActionsProvider.ACTION_TYPE,
@@ -433,8 +432,7 @@
                 context, 0, sharingIntent,
                 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
 
-        // Proxy smart actions through {@link GlobalScreenshot.SmartActionsReceiver}
-        // for logging smart actions.
+        // Proxy smart actions through {@link SmartActionsReceiver} for logging smart actions.
         Bundle extras = action.getExtras();
         String actionType = extras.getString(
                 ScreenshotNotificationSmartActionsProvider.ACTION_TYPE,
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 8def475..c8a97e9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -452,7 +452,7 @@
 
         // Inflate the screenshot layout
         mScreenshotView = (ScreenshotView)
-                LayoutInflater.from(mContext).inflate(R.layout.global_screenshot, null);
+                LayoutInflater.from(mContext).inflate(R.layout.screenshot, null);
         mScreenshotView.init(mUiEventLogger, new ScreenshotView.ScreenshotViewCallback() {
             @Override
             public void onUserInteraction() {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index dfb39e3..01dc0ca 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -193,7 +193,7 @@
         super(context, attrs, defStyleAttr, defStyleRes);
         mResources = mContext.getResources();
 
-        mCornerSizeX = mResources.getDimensionPixelSize(R.dimen.global_screenshot_x_scale);
+        mCornerSizeX = mResources.getDimensionPixelSize(R.dimen.screenshot_x_scale);
         mDismissDeltaY = mResources.getDimensionPixelSize(
                 R.dimen.screenshot_dismissal_height_delta);
 
@@ -339,23 +339,23 @@
     @Override // View
     protected void onFinishInflate() {
         mScrollingScrim = requireNonNull(findViewById(R.id.screenshot_scrolling_scrim));
-        mScreenshotStatic = requireNonNull(findViewById(R.id.global_screenshot_static));
-        mScreenshotPreview = requireNonNull(findViewById(R.id.global_screenshot_preview));
+        mScreenshotStatic = requireNonNull(findViewById(R.id.screenshot_static));
+        mScreenshotPreview = requireNonNull(findViewById(R.id.screenshot_preview));
         mTransitionView = requireNonNull(findViewById(R.id.screenshot_transition_view));
         mScreenshotPreviewBorder = requireNonNull(
-                findViewById(R.id.global_screenshot_preview_border));
+                findViewById(R.id.screenshot_preview_border));
         mScreenshotPreview.setClipToOutline(true);
 
         mActionsContainerBackground = requireNonNull(findViewById(
-                R.id.global_screenshot_actions_container_background));
-        mActionsContainer = requireNonNull(findViewById(R.id.global_screenshot_actions_container));
-        mActionsView = requireNonNull(findViewById(R.id.global_screenshot_actions));
+                R.id.screenshot_actions_container_background));
+        mActionsContainer = requireNonNull(findViewById(R.id.screenshot_actions_container));
+        mActionsView = requireNonNull(findViewById(R.id.screenshot_actions));
         mBackgroundProtection = requireNonNull(
-                findViewById(R.id.global_screenshot_actions_background));
-        mDismissButton = requireNonNull(findViewById(R.id.global_screenshot_dismiss_button));
+                findViewById(R.id.screenshot_actions_background));
+        mDismissButton = requireNonNull(findViewById(R.id.screenshot_dismiss_button));
         mScrollablePreview = requireNonNull(findViewById(R.id.screenshot_scrollable_preview));
-        mScreenshotFlash = requireNonNull(findViewById(R.id.global_screenshot_flash));
-        mScreenshotSelectorView = requireNonNull(findViewById(R.id.global_screenshot_selector));
+        mScreenshotFlash = requireNonNull(findViewById(R.id.screenshot_flash));
+        mScreenshotSelectorView = requireNonNull(findViewById(R.id.screenshot_selector));
         mShareChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_share_chip));
         mEditChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_edit_chip));
         mScrollChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_scroll_chip));
@@ -452,7 +452,7 @@
         mOrientationPortrait = (orientation == ORIENTATION_PORTRAIT);
         updateInsets(insets);
         int screenshotFixedSize =
-                mContext.getResources().getDimensionPixelSize(R.dimen.global_screenshot_x_scale);
+                mContext.getResources().getDimensionPixelSize(R.dimen.screenshot_x_scale);
         ViewGroup.LayoutParams params = mScreenshotPreview.getLayoutParams();
         if (mOrientationPortrait) {
             params.width = screenshotFixedSize;
@@ -748,7 +748,7 @@
 
             for (Notification.Action smartAction : imageData.smartActions) {
                 ScreenshotActionChip actionChip = (ScreenshotActionChip) inflater.inflate(
-                        R.layout.global_screenshot_action_chip, mActionsView, false);
+                        R.layout.screenshot_action_chip, mActionsView, false);
                 actionChip.setText(smartAction.title);
                 actionChip.setIcon(smartAction.getIcon(), false);
                 actionChip.setPendingIntent(smartAction.actionIntent,
@@ -767,7 +767,7 @@
         if (mPendingInteraction == null) {
             LayoutInflater inflater = LayoutInflater.from(mContext);
             mQuickShareChip = (ScreenshotActionChip) inflater.inflate(
-                    R.layout.global_screenshot_action_chip, mActionsView, false);
+                    R.layout.screenshot_action_chip, mActionsView, false);
             mQuickShareChip.setText(quickShareAction.title);
             mQuickShareChip.setIcon(quickShareAction.getIcon(), false);
             mQuickShareChip.setOnClickListener(v -> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 17bcfe7..8a39719 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -335,7 +335,7 @@
                 info = mLockPatternUtils.getOwnerInfo(KeyguardUpdateMonitor.getCurrentUser());
             }
         }
-        if (info != null) {
+        if (!TextUtils.isEmpty(info)) {
             mRotateTextViewController.updateIndication(
                     INDICATION_TYPE_OWNER_INFO,
                     new KeyguardIndication.Builder()
@@ -433,7 +433,7 @@
     }
 
     private void updateResting() {
-        if (mRestingIndication != null
+        if (!TextUtils.isEmpty(mRestingIndication)
                 && !mRotateTextViewController.hasIndications()) {
             mRotateTextViewController.updateIndication(
                     INDICATION_TYPE_RESTING,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 0fe3adb..fca2a18c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -19,8 +19,8 @@
 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
 
 import static com.android.systemui.DejankUtils.whitelistIpcs;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_MEDIA_CONTROLS;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_MEDIA_CONTROLS;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
 
 import android.app.ActivityManager;
 import android.app.KeyguardManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 6369a7e..d56938a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -31,7 +31,7 @@
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
 
 import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_ALERTING;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_ALERTING;
 
 import static java.util.Objects.requireNonNull;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 122fb1c..3730524 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -52,6 +52,7 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
 import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
+import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
 import com.android.systemui.util.Assert;
 import com.android.systemui.util.time.SystemClock;
 
@@ -738,7 +739,7 @@
             if (entry instanceof GroupEntry) {
                 GroupEntry parent = (GroupEntry) entry;
                 for (NotificationEntry child : parent.getChildren()) {
-                    child.getAttachState().setSection(section);
+                    setEntrySection(child, section);
                 }
                 parent.sortChildren(sChildComparator);
             }
@@ -957,10 +958,18 @@
             }
         }
 
-        entry.getAttachState().setSection(finalSection);
+        setEntrySection(entry, finalSection);
         return finalSection;
     }
 
+    private void setEntrySection(ListEntry entry, NotifSection finalSection) {
+        entry.getAttachState().setSection(finalSection);
+        NotificationEntry representativeEntry = entry.getRepresentativeEntry();
+        if (representativeEntry != null && finalSection != null) {
+            representativeEntry.setBucket(finalSection.getBucket());
+        }
+    }
+
     @NonNull
     private NotifSection findSection(ListEntry entry) {
         for (int i = 0; i < mNotifSections.size(); i++) {
@@ -1039,13 +1048,13 @@
         void onRenderList(@NonNull List<ListEntry> entries);
     }
 
-    private static final NotifSectioner DEFAULT_SECTIONER =
-            new NotifSectioner("UnknownSection") {
-                @Override
-                public boolean isInSection(ListEntry entry) {
-                    return true;
-                }
-            };
+    private static final NotifSectioner DEFAULT_SECTIONER = new NotifSectioner("UnknownSection",
+            NotificationPriorityBucketKt.BUCKET_UNKNOWN) {
+        @Override
+        public boolean isInSection(ListEntry entry) {
+            return true;
+        }
+    };
 
     private static final int MIN_CHILDREN_FOR_GROUP = 2;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
index 3a87f68..301b185 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
@@ -30,6 +30,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
+import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 
 import javax.inject.Inject;
@@ -102,7 +103,8 @@
     /**
      * Puts foreground service notifications into its own section.
      */
-    private final NotifSectioner mNotifSectioner = new NotifSectioner("ForegroundService") {
+    private final NotifSectioner mNotifSectioner = new NotifSectioner("ForegroundService",
+            NotificationPriorityBucketKt.BUCKET_FOREGROUND_SERVICE) {
         @Override
         public boolean isInSection(ListEntry entry) {
             NotificationEntry notificationEntry = entry.getRepresentativeEntry();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
index efec94f..c385836 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.statusbar.notification.dagger.PeopleHeader
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
+import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE
 import javax.inject.Inject
 
 /**
@@ -45,7 +46,7 @@
         }
     }
 
-    val sectioner = object : NotifSectioner("People") {
+    val sectioner = object : NotifSectioner("People", BUCKET_PEOPLE) {
         override fun isInSection(entry: ListEntry): Boolean =
                 isConversation(entry.representativeEntry!!)
         override fun getHeaderNodeController() =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
index 1bde312..4d36251 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
@@ -34,6 +34,7 @@
 import com.android.systemui.statusbar.notification.dagger.IncomingHeader;
 import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
+import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 
@@ -196,7 +197,8 @@
         }
     };
 
-    private final NotifSectioner mNotifSectioner = new NotifSectioner("HeadsUp") {
+    private final NotifSectioner mNotifSectioner = new NotifSectioner("HeadsUp",
+            NotificationPriorityBucketKt.BUCKET_HEADS_UP) {
         @Override
         public boolean isInSection(ListEntry entry) {
             return isCurrentlyShowingHun(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
index c62214c..1a6a63a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
@@ -31,6 +31,7 @@
 import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
 import com.android.systemui.statusbar.notification.dagger.AlertingHeader;
 import com.android.systemui.statusbar.notification.dagger.SilentHeader;
+import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
 
 import java.util.List;
 
@@ -82,7 +83,8 @@
         return mSilentNotifSectioner;
     }
 
-    private final NotifSectioner mAlertingNotifSectioner = new NotifSectioner("Alerting") {
+    private final NotifSectioner mAlertingNotifSectioner = new NotifSectioner("Alerting",
+            NotificationPriorityBucketKt.BUCKET_ALERTING) {
         @Override
         public boolean isInSection(ListEntry entry) {
             return mHighPriorityProvider.isHighPriority(entry);
@@ -99,7 +101,8 @@
         }
     };
 
-    private final NotifSectioner mSilentNotifSectioner = new NotifSectioner("Silent") {
+    private final NotifSectioner mSilentNotifSectioner = new NotifSectioner("Silent",
+            NotificationPriorityBucketKt.BUCKET_SILENT) {
         @Override
         public boolean isInSection(ListEntry entry) {
             return !mHighPriorityProvider.isHighPriority(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
index c9fc992..6424e37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
@@ -18,14 +18,17 @@
 
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
 import com.android.systemui.statusbar.notification.collection.render.NodeController
+import com.android.systemui.statusbar.notification.stack.PriorityBucket
 
 data class NotifSection(
     val sectioner: NotifSectioner,
     val index: Int
 ) {
     val label: String
-        get() = "Section($index, \"${sectioner.name}\")"
+        get() = "Section($index, $bucket, \"${sectioner.name}\")"
 
     val headerController: NodeController?
         get() = sectioner.headerNodeController
+
+    @PriorityBucket val bucket: Int = sectioner.bucket
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
index 58afca8..ef9ee11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
@@ -22,15 +22,28 @@
 import com.android.systemui.statusbar.notification.collection.ShadeListBuilder;
 import com.android.systemui.statusbar.notification.collection.render.NodeController;
 import com.android.systemui.statusbar.notification.collection.render.NodeSpec;
+import com.android.systemui.statusbar.notification.stack.PriorityBucket;
 
 import java.util.List;
 
 /**
- * Pluggable for participating in notif sectioning. See {@link ShadeListBuilder#setSections}.
+ * Pluggable for participating in notif sectioning. See {@link ShadeListBuilder#setSectioners}.
  */
 public abstract class NotifSectioner extends Pluggable<NotifSectioner> {
-    protected NotifSectioner(String name) {
+    @PriorityBucket
+    private final int mBucket;
+
+    protected NotifSectioner(String name, @PriorityBucket int bucket) {
         super(name);
+        mBucket = bucket;
+    }
+
+    /**
+     * @return the "bucket" value to apply to entries in this section
+     */
+    @PriorityBucket
+    public final int getBucket() {
+        return mBucket;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
index c147023..9faef1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
@@ -16,12 +16,12 @@
 
 package com.android.systemui.statusbar.notification.logging;
 
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_ALERTING;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_FOREGROUND_SERVICE;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_HEADS_UP;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_MEDIA_CONTROLS;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_PEOPLE;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_ALERTING;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_FOREGROUND_SERVICE;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_HEADS_UP;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_MEDIA_CONTROLS;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PEOPLE;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
 
 import android.annotation.Nullable;
 import android.service.notification.StatusBarNotification;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
new file mode 100644
index 0000000..31f4857
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
@@ -0,0 +1,25 @@
+package com.android.systemui.statusbar.notification.stack
+
+import android.annotation.IntDef
+
+/**
+ * For now, declare the available notification buckets (sections) here so that other
+ * presentation code can decide what to do based on an entry's buckets
+ */
+@Retention(AnnotationRetention.SOURCE)
+@IntDef(
+        prefix = ["BUCKET_"],
+        value = [
+            BUCKET_UNKNOWN, BUCKET_MEDIA_CONTROLS, BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE,
+            BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT
+        ]
+)
+annotation class PriorityBucket
+
+const val BUCKET_UNKNOWN = 0
+const val BUCKET_MEDIA_CONTROLS = 1
+const val BUCKET_HEADS_UP = 2
+const val BUCKET_FOREGROUND_SERVICE = 3
+const val BUCKET_PEOPLE = 4
+const val BUCKET_ALERTING = 5
+const val BUCKET_SILENT = 6
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
index ab39de0..bc172ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.statusbar.notification.stack;
 
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_MEDIA_CONTROLS;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_MEDIA_CONTROLS;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index 6ee14b5..5f157a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -16,7 +16,6 @@
 package com.android.systemui.statusbar.notification.stack
 
 import android.annotation.ColorInt
-import android.annotation.IntDef
 import android.annotation.LayoutRes
 import android.util.Log
 import android.view.LayoutInflater
@@ -448,25 +447,3 @@
         private const val DEBUG = false
     }
 }
-
-/**
- * For now, declare the available notification buckets (sections) here so that other
- * presentation code can decide what to do based on an entry's buckets
- */
-@Retention(AnnotationRetention.SOURCE)
-@IntDef(
-        prefix = ["BUCKET_"],
-        value = [
-            BUCKET_UNKNOWN, BUCKET_MEDIA_CONTROLS, BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE,
-            BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT
-        ]
-)
-annotation class PriorityBucket
-
-const val BUCKET_UNKNOWN = 0
-const val BUCKET_MEDIA_CONTROLS = 1
-const val BUCKET_HEADS_UP = 2
-const val BUCKET_FOREGROUND_SERVICE = 3
-const val BUCKET_PEOPLE = 4
-const val BUCKET_ALERTING = 5
-const val BUCKET_SILENT = 6
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index e6d109f..5c5dd6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -17,7 +17,7 @@
 package com.android.systemui.statusbar.notification.stack;
 
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
 import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE;
 import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
 import static com.android.systemui.util.Utils.shouldUseSplitNotificationShade;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 6312f61..c9033b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -173,6 +173,7 @@
     private final NotificationLockscreenUserManager mLockscreenUserManager;
     // TODO: StatusBar should be encapsulated behind a Controller
     private final StatusBar mStatusBar;
+    private final NotificationGroupManagerLegacy mLegacyGroupManager;
     private final SectionHeaderController mSilentHeaderController;
     private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
 
@@ -663,6 +664,8 @@
                 mStatusBar.requestNotificationUpdate("onGroupsChanged");
             }
         });
+        mLegacyGroupManager = featureFlags.isNewNotifPipelineRenderingEnabled()
+                ? null : legacyGroupManager;
         mSilentHeaderController = silentHeaderController;
         mFeatureFlags = featureFlags;
         mNotifPipeline = notifPipeline;
@@ -1224,7 +1227,11 @@
             final boolean inSection =
                     NotificationStackScrollLayout.matchesSelection(row, selection);
             if (matchClearable && inSection) {
-                return true;
+                if (mLegacyGroupManager == null
+                        || !mLegacyGroupManager.isSummaryOfSuppressedGroup(
+                        row.getEntry().getSbn())) {
+                    return true;
+                }
             }
         }
         return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
index aeb2efd..b3f8612 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
@@ -171,4 +171,23 @@
 
         return false;
     }
+
+    /**
+     * Injectable factory for creating a {@link AutoHideController}.
+     */
+    public static class Factory {
+        private final Handler mHandler;
+        private final IWindowManager mIWindowManager;
+
+        @Inject
+        public Factory(@Main Handler handler, IWindowManager iWindowManager) {
+            mHandler = handler;
+            mIWindowManager = iWindowManager;
+        }
+
+        /** Create an {@link AutoHideController} */
+        public AutoHideController create(Context context) {
+            return new AutoHideController(context, mHandler, mIWindowManager);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index abee7a5..3679682 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -298,4 +298,33 @@
             pw.println();
         }
     }
+
+    /**
+     * Injectable factory for creating a {@link LightBarController}.
+     */
+    public static class Factory {
+        private final DarkIconDispatcher mDarkIconDispatcher;
+        private final BatteryController mBatteryController;
+        private final NavigationModeController mNavModeController;
+        private final DumpManager mDumpManager;
+
+        @Inject
+        public Factory(
+                DarkIconDispatcher darkIconDispatcher,
+                BatteryController batteryController,
+                NavigationModeController navModeController,
+                DumpManager dumpManager) {
+
+            mDarkIconDispatcher = darkIconDispatcher;
+            mBatteryController = batteryController;
+            mNavModeController = navModeController;
+            mDumpManager = dumpManager;
+        }
+
+        /** Create an {@link LightBarController} */
+        public LightBarController create(Context context) {
+            return new LightBarController(context, mDarkIconDispatcher, mBatteryController,
+                    mNavModeController, mDumpManager);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index f8765c8..dd6b1c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -3931,6 +3931,9 @@
     @Override
     protected TouchHandler createTouchHandler() {
         return new TouchHandler() {
+
+            private long mLastTouchDownTime = -1L;
+
             @Override
             public boolean onInterceptTouchEvent(MotionEvent event) {
                 if (mBlockTouches || mQs.disallowPanelTouches()) {
@@ -3962,6 +3965,19 @@
 
             @Override
             public boolean onTouch(View v, MotionEvent event) {
+                if (event.getAction() == MotionEvent.ACTION_DOWN) {
+                    if (event.getDownTime() == mLastTouchDownTime) {
+                        // An issue can occur when swiping down after unlock, where multiple down
+                        // events are received in this handler with identical downTimes. Until the
+                        // source of the issue can be located, detect this case and ignore.
+                        // see b/193350347
+                        Log.w(TAG, "Duplicate down event detected... ignoring");
+                        return true;
+                    }
+                    mLastTouchDownTime = event.getDownTime();
+                }
+
+
                 if (mBlockTouches || (mQsFullyExpanded && mQs != null
                         && mQs.disallowPanelTouches())) {
                     return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index eca91a3..e775e96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -182,8 +182,7 @@
         }
         boolean fullyClosed = true;
         boolean fullyOpened = false;
-        if (SPEW) LOG("panelExpansionChanged: start state=%d", mState);
-        PanelViewController pv = mPanel;
+        if (SPEW) LOG("panelExpansionChanged: start state=%d, f=%.1f", mState, frac);
         mExpanded = expanded;
         mPanelFraction = frac;
         updateVisibility();
@@ -194,9 +193,7 @@
                 onPanelPeeked();
             }
             fullyClosed = false;
-            final float thisFrac = pv.getExpandedFraction();
-            if (SPEW) LOG("panelExpansionChanged:  -> %s: f=%.1f", pv.getName(), thisFrac);
-            fullyOpened = thisFrac >= 1f;
+            fullyOpened = frac >= 1f;
         }
         if (fullyOpened && !mTracking) {
             go(STATE_OPEN);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 62ba56a..eeff010 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -103,7 +103,16 @@
             }
         }
 
+        // Fix for b/199600334
+        override fun onEntryCleanUp(entry: NotificationEntry) {
+            removeChipIfNeeded(entry)
+        }
+
         override fun onEntryRemoved(entry: NotificationEntry, reason: Int) {
+            removeChipIfNeeded(entry)
+        }
+
+        private fun removeChipIfNeeded(entry: NotificationEntry) {
             if (entry.sbn.key == callNotificationInfo?.key) {
                 removeChip()
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java
index d38284a..2dd4128 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java
@@ -14,7 +14,6 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.content.Context;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
@@ -35,13 +34,13 @@
     private final AccessibilityManager mAccessibilityManager;
 
     @Inject
-    public AccessibilityManagerWrapper(Context context) {
-        mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
+    public AccessibilityManagerWrapper(AccessibilityManager accessibilityManager) {
+        mAccessibilityManager = accessibilityManager;
     }
 
     @Override
     public void addCallback(@NonNull AccessibilityServicesStateChangeListener listener) {
-        mAccessibilityManager.addAccessibilityServicesStateChangeListener(listener, null);
+        mAccessibilityManager.addAccessibilityServicesStateChangeListener(listener);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/util/AlphaTintDrawableWrapper.java b/packages/SystemUI/src/com/android/systemui/util/AlphaTintDrawableWrapper.java
index a22793b..516efc0 100644
--- a/packages/SystemUI/src/com/android/systemui/util/AlphaTintDrawableWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/util/AlphaTintDrawableWrapper.java
@@ -109,6 +109,12 @@
         }
     }
 
+    @Override
+    public void setTintList(ColorStateList tint) {
+        super.setTintList(tint);
+        mTint = tint;
+    }
+
     private void applyTint() {
         if (getDrawable() != null && mTint != null) {
             getDrawable().mutate().setTintList(mTint);
diff --git a/packages/SystemUI/src/com/android/systemui/util/CarrierConfigTracker.java b/packages/SystemUI/src/com/android/systemui/util/CarrierConfigTracker.java
index de5a363..14190fa 100644
--- a/packages/SystemUI/src/com/android/systemui/util/CarrierConfigTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/util/CarrierConfigTracker.java
@@ -23,8 +23,9 @@
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
-import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 
 import javax.inject.Inject;
@@ -34,39 +35,54 @@
  */
 @SysUISingleton
 public class CarrierConfigTracker extends BroadcastReceiver {
-    private final SparseArray<Boolean> mCallStrengthConfigs = new SparseArray<>();
-    private final SparseArray<Boolean> mNoCallingConfigs = new SparseArray<>();
+    private final SparseBooleanArray mCallStrengthConfigs = new SparseBooleanArray();
+    private final SparseBooleanArray mNoCallingConfigs = new SparseBooleanArray();
+    private final SparseBooleanArray mCarrierProvisionsWifiMergedNetworks =
+            new SparseBooleanArray();
     private final CarrierConfigManager mCarrierConfigManager;
     private boolean mDefaultCallStrengthConfigLoaded;
     private boolean mDefaultCallStrengthConfig;
     private boolean mDefaultNoCallingConfigLoaded;
     private boolean mDefaultNoCallingConfig;
+    private boolean mDefaultCarrierProvisionsWifiMergedNetworksLoaded;
+    private boolean mDefaultCarrierProvisionsWifiMergedNetworks;
 
     @Inject
-    public CarrierConfigTracker(Context context) {
+    public CarrierConfigTracker(Context context, BroadcastDispatcher broadcastDispatcher) {
         mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
-        context.registerReceiver(
+        broadcastDispatcher.registerReceiver(
                 this, new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
     }
 
     @Override
     public void onReceive(Context context, Intent intent) {
-        if (intent.getAction() == CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED) {
-            int subId = intent.getIntExtra(
-                    CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
-                    SubscriptionManager.INVALID_SUBSCRIPTION_ID);
-            if (!SubscriptionManager.isValidSubscriptionId(subId)) {
-                return;
-            }
-            PersistableBundle b = mCarrierConfigManager.getConfigForSubId(subId);
-            if (b != null) {
-                boolean hideNoCallingConfig = b.getBoolean(
-                        CarrierConfigManager.KEY_USE_IP_FOR_CALLING_INDICATOR_BOOL);
-                boolean displayCallStrengthIcon = b.getBoolean(
-                        CarrierConfigManager.KEY_DISPLAY_CALL_STRENGTH_INDICATOR_BOOL);
-                mCallStrengthConfigs.put(subId, displayCallStrengthIcon);
-                mNoCallingConfigs.put(subId, hideNoCallingConfig);
-            }
+        if (!CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
+            return;
+        }
+
+        final int subId = intent.getIntExtra(
+                CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            return;
+        }
+
+        final PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId);
+        if (config == null) {
+            return;
+        }
+
+        synchronized (mCallStrengthConfigs) {
+            mCallStrengthConfigs.put(subId, config.getBoolean(
+                    CarrierConfigManager.KEY_DISPLAY_CALL_STRENGTH_INDICATOR_BOOL));
+        }
+        synchronized (mNoCallingConfigs) {
+            mNoCallingConfigs.put(subId, config.getBoolean(
+                    CarrierConfigManager.KEY_USE_IP_FOR_CALLING_INDICATOR_BOOL));
+        }
+        synchronized (mCarrierProvisionsWifiMergedNetworks) {
+            mCarrierProvisionsWifiMergedNetworks.put(subId, config.getBoolean(
+                    CarrierConfigManager.KEY_CARRIER_PROVISIONS_WIFI_MERGED_NETWORKS_BOOL));
         }
     }
 
@@ -74,8 +90,10 @@
      * Returns the KEY_DISPLAY_CALL_STRENGTH_INDICATOR_BOOL value for the given subId.
      */
     public boolean getCallStrengthConfig(int subId) {
-        if (mCallStrengthConfigs.indexOfKey(subId) >= 0) {
-            return mCallStrengthConfigs.get(subId);
+        synchronized (mCallStrengthConfigs) {
+            if (mCallStrengthConfigs.indexOfKey(subId) >= 0) {
+                return mCallStrengthConfigs.get(subId);
+            }
         }
         if (!mDefaultCallStrengthConfigLoaded) {
             mDefaultCallStrengthConfig =
@@ -90,8 +108,10 @@
      * Returns the KEY_USE_IP_FOR_CALLING_INDICATOR_BOOL value for the given subId.
      */
     public boolean getNoCallingConfig(int subId) {
-        if (mNoCallingConfigs.indexOfKey(subId) >= 0) {
-            return mNoCallingConfigs.get(subId);
+        synchronized (mNoCallingConfigs) {
+            if (mNoCallingConfigs.indexOfKey(subId) >= 0) {
+                return mNoCallingConfigs.get(subId);
+            }
         }
         if (!mDefaultNoCallingConfigLoaded) {
             mDefaultNoCallingConfig =
@@ -101,4 +121,22 @@
         }
         return mDefaultNoCallingConfig;
     }
+
+    /**
+     * Returns the KEY_CARRIER_PROVISIONS_WIFI_MERGED_NETWORKS_BOOL value for the given subId.
+     */
+    public boolean getCarrierProvisionsWifiMergedNetworksBool(int subId) {
+        synchronized (mCarrierProvisionsWifiMergedNetworks) {
+            if (mCarrierProvisionsWifiMergedNetworks.indexOfKey(subId) >= 0) {
+                return mCarrierProvisionsWifiMergedNetworks.get(subId);
+            }
+        }
+        if (!mDefaultCarrierProvisionsWifiMergedNetworksLoaded) {
+            mDefaultCarrierProvisionsWifiMergedNetworks =
+                    CarrierConfigManager.getDefaultConfig().getBoolean(
+                            CarrierConfigManager.KEY_CARRIER_PROVISIONS_WIFI_MERGED_NETWORKS_BOOL);
+            mDefaultCarrierProvisionsWifiMergedNetworksLoaded = true;
+        }
+        return mDefaultCarrierProvisionsWifiMergedNetworks;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt b/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt
index 3b64f9f..1059d6c 100644
--- a/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt
@@ -69,6 +69,10 @@
         return super.getChangingConfigurations() or ActivityInfo.CONFIG_DENSITY
     }
 
+    override fun canApplyTheme(): Boolean {
+        return (drawable?.canApplyTheme() ?: false) || super.canApplyTheme()
+    }
+
     private class RoundedCornerState(private val wrappedState: ConstantState) : ConstantState() {
         override fun newDrawable(): Drawable {
             return newDrawable(null, null)
@@ -82,5 +86,9 @@
         override fun getChangingConfigurations(): Int {
             return wrappedState.changingConfigurations
         }
+
+        override fun canApplyTheme(): Boolean {
+            return true
+        }
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt b/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt
index db2aca8..a981045 100644
--- a/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt
@@ -40,8 +40,8 @@
         this.wallpaperInfo = wallpaperInfo
     }
 
-    private val shouldUseDefaultUnfoldTransition: Boolean
-        get() = wallpaperInfo?.shouldUseDefaultUnfoldTransition()
+    private val shouldUseDefaultDeviceStateChangeTransition: Boolean
+        get() = wallpaperInfo?.shouldUseDefaultDeviceStateChangeTransition()
             ?: true
 
     fun setNotificationShadeZoom(zoomOut: Float) {
@@ -50,7 +50,7 @@
     }
 
     fun setUnfoldTransitionZoom(zoomOut: Float) {
-        if (shouldUseDefaultUnfoldTransition) {
+        if (shouldUseDefaultDeviceStateChangeTransition) {
             unfoldTransitionZoomOut = zoomOut
             updateZoom()
         }
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
index d44fb76..9917777 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
@@ -116,7 +116,7 @@
         if (toolbar != null) {
             setActionBar(toolbar);
         }
-        setTitle("");
+        getActionBar().setDisplayShowTitleEnabled(false);
         getActionBar().setDisplayHomeAsUpEnabled(true);
         getActionBar().setHomeAsUpIndicator(getHomeIndicatorDrawable());
         getActionBar().setHomeActionContentDescription(R.string.accessibility_desc_close);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index b27f5b1..4098677 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -38,7 +38,6 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -277,27 +276,29 @@
         final int newRotation = (currentRotation + 1) % 4;
         when(display.getRotation()).thenReturn(newRotation);
         when(mContext.getDisplay()).thenReturn(display);
-        mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
-                    Float.NaN);
-        });
-        final PointF expectedCenter = new PointF(mWindowMagnificationController.getCenterY(),
-                mWindowMagnificationController.getCenterX());
         final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
+        final float center = Math.min(windowBounds.exactCenterX(), windowBounds.exactCenterY());
+        final PointF magnifiedCenter = new PointF(center, center + 5f);
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnification(Float.NaN, magnifiedCenter.x,
+                    magnifiedCenter.y);
+            // Get the center again in case the center we set is out of screen.
+            magnifiedCenter.set(mWindowMagnificationController.getCenterX(),
+                    mWindowMagnificationController.getCenterY());
+        });
         // Rotate the window clockwise 90 degree.
         windowBounds.set(windowBounds.top, windowBounds.left, windowBounds.bottom,
                 windowBounds.right);
         mWindowManager.setWindowBounds(windowBounds);
 
-        mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION);
-        });
+        mInstrumentation.runOnMainSync(() -> mWindowMagnificationController.onConfigurationChanged(
+                ActivityInfo.CONFIG_ORIENTATION));
 
         assertEquals(newRotation, mWindowMagnificationController.mRotation);
+        final PointF expectedCenter = new PointF(magnifiedCenter.y, magnifiedCenter.x);
         final PointF actualCenter = new PointF(mWindowMagnificationController.getCenterX(),
                 mWindowMagnificationController.getCenterY());
         assertEquals(expectedCenter, actualCenter);
-        verify(mWindowManager, times(2)).updateViewLayout(any(), any());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java
index 7bc5f86..9616042 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java
@@ -16,11 +16,14 @@
 
 package com.android.systemui.flags;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -32,6 +35,7 @@
 
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.util.wrapper.BuildInfo;
 
@@ -40,10 +44,15 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
 @SmallTest
 public class FeatureFlagReaderTest extends SysuiTestCase {
     @Mock private Resources mResources;
     @Mock private BuildInfo mBuildInfo;
+    @Mock private DumpManager mDumpManager;
     @Mock private PluginManager mPluginManager;
     @Mock private SystemPropertiesHelper mSystemPropertiesHelper;
 
@@ -66,7 +75,7 @@
         when(mBuildInfo.isDebuggable()).thenReturn(isDebuggable);
         when(mResources.getBoolean(R.bool.are_flags_overrideable)).thenReturn(isOverrideable);
         mReader = new FeatureFlagReader(
-                mResources, mBuildInfo, mPluginManager, mSystemPropertiesHelper);
+                mResources, mBuildInfo, mDumpManager, mPluginManager, mSystemPropertiesHelper);
     }
 
     @Test
@@ -127,9 +136,29 @@
                 .getBoolean(fakeStorageKey(FLAG_RESID_0), false);
     }
 
+    @Test
+    public void testDump() {
+        // GIVEN that the flag 0 (by override) and 1 (by default) are both true
+        overrideFlag(FLAG_RESID_0, true);
+
+        // WHEN the flags have been accessed
+        assertTrue(mReader.isEnabled(FLAG_RESID_0));
+        assertTrue(mReader.isEnabled(FLAG_RESID_1));
+
+        // THEN the dump contains the flags and their correct values
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        mReader.dump(mock(FileDescriptor.class), pw, new String[0]);
+        pw.flush();
+        String dump = sw.toString();
+        assertThat(dump).contains(" flag_testname_" + FLAG_RESID_0 + ": true\n");
+        assertThat(dump).contains(" flag_testname_" + FLAG_RESID_1 + ": true\n");
+        assertThat(dump).contains("AreFlagsOverrideable: true\n");
+    }
+
     private void defineFlag(int resId, boolean value) {
         when(mResources.getBoolean(resId)).thenReturn(value);
-        when(mResources.getResourceEntryName(resId)).thenReturn(fakeStorageKey(resId));
+        when(mResources.getResourceEntryName(resId)).thenReturn(fakeResourceEntryName(resId));
     }
 
     private void overrideFlag(int resId, boolean value) {
@@ -137,6 +166,10 @@
                 .thenReturn(value);
     }
 
+    private String fakeResourceEntryName(@BoolRes int resId) {
+        return "flag_testname_" + resId;
+    }
+
     private String fakeStorageKey(@BoolRes int resId) {
         return "persist.systemui.flag_testname_" + resId;
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
index af6dee7..c464cad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
@@ -32,6 +32,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.DisplayMetrics;
+import android.util.Pair;
 import android.view.View;
 import android.view.accessibility.AccessibilityManager;
 
@@ -128,20 +129,7 @@
     @Test
     public void testUpdateFingerprintLocationOnInit() {
         // GIVEN fp sensor location is available pre-attached
-        final PointF udfpsLocation = new PointF(50, 75);
-        final int radius = 33;
-        final FingerprintSensorPropertiesInternal fpProps =
-                new FingerprintSensorPropertiesInternal(
-                        /* sensorId */ 0,
-                        /* strength */ 0,
-                        /* max enrollments per user */ 5,
-                        /* component info */ new ArrayList<>(),
-                        /* sensorType */ 3,
-                        /* resetLockoutRequiresHwToken */ false,
-                        List.of(new SensorLocationInternal("" /* displayId */,
-                                (int) udfpsLocation.x, (int) udfpsLocation.y, radius)));
-        when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation);
-        when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps));
+        Pair<Integer, PointF> udfps = setupUdfps();
 
         // WHEN lock icon view controller is initialized and attached
         mLockIconViewController.init();
@@ -149,8 +137,8 @@
         mAttachListener.onViewAttachedToWindow(mLockIconView);
 
         // THEN lock icon view location is updated with the same coordinates as fpProps
-        verify(mLockIconView).setCenterLocation(mPointCaptor.capture(), eq(radius));
-        assertEquals(udfpsLocation, mPointCaptor.getValue());
+        verify(mLockIconView).setCenterLocation(mPointCaptor.capture(), eq(udfps.first));
+        assertEquals(udfps.second, mPointCaptor.getValue());
     }
 
     @Test
@@ -164,6 +152,47 @@
 
         // GIVEN fp sensor location is available post-atttached
         captureAuthControllerCallback();
+        Pair<Integer, PointF> udfps = setupUdfps();
+
+        // WHEN all authenticators are registered
+        mAuthControllerCallback.onAllAuthenticatorsRegistered();
+
+        // THEN lock icon view location is updated with the same coordinates as fpProps
+        verify(mLockIconView).setCenterLocation(mPointCaptor.capture(), eq(udfps.first));
+        assertEquals(udfps.second, mPointCaptor.getValue());
+    }
+
+    @Test
+    public void testLockIconViewBackgroundEnabledWhenUdfpsIsAvailable() {
+        // GIVEN Udpfs sensor location is available
+        setupUdfps();
+
+        mLockIconViewController.init();
+        captureAttachListener();
+
+        // WHEN the view is attached
+        mAttachListener.onViewAttachedToWindow(mLockIconView);
+
+        // THEN the lock icon view background should be enabled
+        verify(mLockIconView).setUseBackground(true);
+    }
+
+    @Test
+    public void testLockIconViewBackgroundDisabledWhenUdfpsIsUnavailable() {
+        // GIVEN Udfps sensor location is not available
+        when(mAuthController.getUdfpsSensorLocation()).thenReturn(null);
+
+        mLockIconViewController.init();
+        captureAttachListener();
+
+        // WHEN the view is attached
+        mAttachListener.onViewAttachedToWindow(mLockIconView);
+
+        // THEN the lock icon view background should be disabled
+        verify(mLockIconView).setUseBackground(false);
+    }
+
+    private Pair<Integer, PointF> setupUdfps() {
         final PointF udfpsLocation = new PointF(50, 75);
         final int radius = 33;
         final FingerprintSensorPropertiesInternal fpProps =
@@ -179,12 +208,7 @@
         when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation);
         when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps));
 
-        // WHEN all authenticators are registered
-        mAuthControllerCallback.onAllAuthenticatorsRegistered();
-
-        // THEN lock icon view location is updated with the same coordinates as fpProps
-        verify(mLockIconView).setCenterLocation(mPointCaptor.capture(), eq(radius));
-        assertEquals(udfpsLocation, mPointCaptor.getValue());
+        return new Pair(radius, udfpsLocation);
     }
 
     private void captureAuthControllerCallback() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index c1a9739..83493aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -35,42 +35,23 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 import android.util.SparseArray;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityManager;
 
 import androidx.test.filters.SmallTest;
 
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
-import com.android.systemui.accessibility.SystemActions;
-import com.android.systemui.assist.AssistManager;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.model.SysUiState;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.recents.OverviewProxyService;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.NotificationShadeDepthController;
-import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
-import com.android.wm.shell.pip.Pip;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-
-import java.util.Optional;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 /** atest NavigationBarControllerTest */
 @RunWith(AndroidTestingRunner.class)
@@ -78,46 +59,31 @@
 @SmallTest
 public class NavigationBarControllerTest extends SysuiTestCase {
 
+    private static final int SECONDARY_DISPLAY = 1;
+
     private NavigationBarController mNavigationBarController;
     private NavigationBar mDefaultNavBar;
     private NavigationBar mSecondaryNavBar;
 
-    private CommandQueue mCommandQueue = mock(CommandQueue.class);
-
-    private static final int SECONDARY_DISPLAY = 1;
+    @Mock
+    private CommandQueue mCommandQueue;
+    @Mock
+    private NavigationBar.Factory mNavigationBarFactory;
 
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
         mNavigationBarController = spy(
                 new NavigationBarController(mContext,
-                        mock(WindowManager.class),
-                        () -> mock(AssistManager.class),
-                        mock(AccessibilityManager.class),
-                        mock(AccessibilityManagerWrapper.class),
-                        mock(DeviceProvisionedController.class),
-                        mock(MetricsLogger.class),
                         mock(OverviewProxyService.class),
                         mock(NavigationModeController.class),
-                        mock(AccessibilityButtonModeObserver.class),
-                        mock(StatusBarStateController.class),
                         mock(SysUiState.class),
-                        mock(BroadcastDispatcher.class),
                         mCommandQueue,
-                        Optional.of(mock(Pip.class)),
-                        Optional.of(mock(LegacySplitScreen.class)),
-                        Optional.of(mock(Recents.class)),
-                        () -> Optional.of(mock(StatusBar.class)),
-                        mock(ShadeController.class),
-                        mock(NotificationRemoteInputManager.class),
-                        mock(NotificationShadeDepthController.class),
-                        mock(SystemActions.class),
                         Dependency.get(Dependency.MAIN_HANDLER),
-                        mock(UiEventLogger.class),
-                        mock(NavigationBarOverlayController.class),
                         mock(ConfigurationController.class),
                         mock(NavigationBarA11yHelper.class),
                         mock(TaskbarDelegate.class),
-                        mock(UserTracker.class),
+                        mNavigationBarFactory,
                         mock(DumpManager.class)));
         initializeNavigationBars();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index ed3c473..422db1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -19,6 +19,7 @@
 import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
 import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
 import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
+import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
 import static android.inputmethodservice.InputMethodService.IME_VISIBLE;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
@@ -28,7 +29,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -45,26 +45,27 @@
 import android.content.IntentFilter;
 import android.hardware.display.DisplayManagerGlobal;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
+import android.telecom.TelecomManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.MotionEvent;
+import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowMetrics;
 import android.view.accessibility.AccessibilityManager;
+import android.view.inputmethod.InputMethodManager;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.SysuiTestableContext;
 import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
@@ -80,9 +81,10 @@
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
+import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
@@ -109,7 +111,13 @@
     private NavigationBar mExternalDisplayNavigationBar;
 
     private SysuiTestableContext mSysuiTestableContextExternal;
+    @Mock
     private OverviewProxyService mOverviewProxyService;
+    @Mock
+    private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private NavigationModeController mNavigationModeController;
+    @Mock
     private CommandQueue mCommandQueue;
     private SysUiState mMockSysUiState;
     @Mock
@@ -122,11 +130,27 @@
     EdgeBackGestureHandler.Factory mEdgeBackGestureHandlerFactory;
     @Mock
     EdgeBackGestureHandler mEdgeBackGestureHandler;
+    @Mock
+    NavigationBarA11yHelper mNavigationBarA11yHelper;
+    @Mock
+    private LightBarController mLightBarController;
+    @Mock
+    private LightBarController.Factory mLightBarcontrollerFactory;
+    @Mock
+    private AutoHideController mAutoHideController;
+    @Mock
+    private AutoHideController.Factory mAutoHideControllerFactory;
+    @Mock
+    private WindowManager mWindowManager;
+    @Mock
+    private TelecomManager mTelecomManager;
+    @Mock
+    private InputMethodManager mInputMethodManager;
+    @Mock
+    private AssistManager mAssistManager;
 
     @Rule
     public final LeakCheckedTest.SysuiLeakCheck mLeakCheck = new LeakCheckedTest.SysuiLeakCheck();
-    private AccessibilityManagerWrapper mAccessibilityWrapper =
-            new AccessibilityManagerWrapper(mContext);
 
     @Before
     public void setup() throws Exception {
@@ -134,15 +158,19 @@
 
         when(mEdgeBackGestureHandlerFactory.create(any(Context.class)))
                 .thenReturn(mEdgeBackGestureHandler);
-        mCommandQueue = new CommandQueue(mContext);
+        when(mLightBarcontrollerFactory.create(any(Context.class))).thenReturn(mLightBarController);
+        when(mAutoHideControllerFactory.create(any(Context.class))).thenReturn(mAutoHideController);
         setupSysuiDependency();
-        mDependency.injectMockDependency(AssistManager.class);
+        // This class inflates views that call Dependency.get, thus these injections are still
+        // necessary.
+        mDependency.injectTestDependency(AssistManager.class, mAssistManager);
         mDependency.injectMockDependency(KeyguardStateController.class);
-        mDependency.injectMockDependency(StatusBarStateController.class);
+        mDependency.injectTestDependency(StatusBarStateController.class, mStatusBarStateController);
         mDependency.injectMockDependency(NavigationBarController.class);
-        mOverviewProxyService = mDependency.injectMockDependency(OverviewProxyService.class);
         mDependency.injectTestDependency(EdgeBackGestureHandler.Factory.class,
                 mEdgeBackGestureHandlerFactory);
+        mDependency.injectTestDependency(OverviewProxyService.class, mOverviewProxyService);
+        mDependency.injectTestDependency(NavigationModeController.class, mNavigationModeController);
         TestableLooper.get(this).runWithLooper(() -> {
             mNavigationBar = createNavBar(mContext);
             mExternalDisplayNavigationBar = createNavBar(mSysuiTestableContextExternal);
@@ -161,20 +189,13 @@
         mSysuiTestableContextExternal = (SysuiTestableContext) getContext().createDisplayContext(
                 display);
 
-        WindowManager windowManager = mock(WindowManager.class);
-        Display defaultDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay();
-        when(windowManager.getDefaultDisplay()).thenReturn(
-                defaultDisplay);
+        Display defaultDisplay = mContext.getDisplay();
+        when(mWindowManager.getDefaultDisplay()).thenReturn(defaultDisplay);
         WindowMetrics metrics = mContext.getSystemService(WindowManager.class)
                 .getMaximumWindowMetrics();
-        when(windowManager.getMaximumWindowMetrics()).thenReturn(metrics);
-        doNothing().when(windowManager).addView(any(), any());
-        mContext.addMockSystemService(Context.WINDOW_SERVICE, windowManager);
-        mSysuiTestableContextExternal.addMockSystemService(Context.WINDOW_SERVICE, windowManager);
-
-        mDependency.injectTestDependency(Dependency.BG_LOOPER, Looper.getMainLooper());
-        mDependency.injectTestDependency(AccessibilityManagerWrapper.class, mAccessibilityWrapper);
-
+        when(mWindowManager.getMaximumWindowMetrics()).thenReturn(metrics);
+        doNothing().when(mWindowManager).addView(any(), any());
+        doNothing().when(mWindowManager).removeViewImmediate(any());
         mMockSysUiState = mock(SysUiState.class);
         when(mMockSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mMockSysUiState);
     }
@@ -233,10 +254,8 @@
         defaultNavBar.createView(null);
         externalNavBar.createView(null);
 
-        // Set IME window status for default NavBar.
-        mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE,
-                BACK_DISPOSITION_DEFAULT, true, false);
-        processAllMessages();
+        defaultNavBar.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE,
+                BACK_DISPOSITION_DEFAULT, true);
 
         // Verify IME window state will be updated in default NavBar & external NavBar state reset.
         assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN,
@@ -244,11 +263,10 @@
         assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0);
         assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0);
 
-        // Set IME window status for external NavBar.
-        mCommandQueue.setImeWindowStatus(EXTERNAL_DISPLAY_ID, null,
-                IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true, false);
-        processAllMessages();
-
+        externalNavBar.setImeWindowStatus(EXTERNAL_DISPLAY_ID, null, IME_VISIBLE,
+                BACK_DISPOSITION_DEFAULT, true);
+        defaultNavBar.setImeWindowStatus(
+                DEFAULT_DISPLAY, null, IME_INVISIBLE, BACK_DISPOSITION_DEFAULT, false);
         // Verify IME window state will be updated in external NavBar & default NavBar state reset.
         assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN,
                 externalNavBar.getNavigationIconHints());
@@ -256,23 +274,34 @@
         assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0);
     }
 
+    @Test
+    public void testA11yEventAfterDetach() {
+        View v = mNavigationBar.createView(null);
+        mNavigationBar.onViewAttachedToWindow(v);
+        verify(mNavigationBarA11yHelper).registerA11yEventListener(any(
+                NavigationBarA11yHelper.NavA11yEventListener.class));
+        mNavigationBar.onViewDetachedFromWindow(v);
+        verify(mNavigationBarA11yHelper).removeA11yEventListener(any(
+                NavigationBarA11yHelper.NavA11yEventListener.class));
+
+        // Should be safe even though the internal view is now null.
+        mNavigationBar.updateAccessibilityServicesState();
+    }
+
     private NavigationBar createNavBar(Context context) {
         DeviceProvisionedController deviceProvisionedController =
                 mock(DeviceProvisionedController.class);
         when(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
-        assertNotNull(mAccessibilityWrapper);
-        return spy(new NavigationBar(context,
-                mock(WindowManager.class),
-                () -> mock(AssistManager.class),
+        NavigationBar.Factory factory = new NavigationBar.Factory(
+                mWindowManager,
+                () -> mAssistManager,
                 mock(AccessibilityManager.class),
-                context.getDisplayId() == DEFAULT_DISPLAY ? mAccessibilityWrapper
-                        : mock(AccessibilityManagerWrapper.class),
                 deviceProvisionedController,
                 new MetricsLogger(),
                 mOverviewProxyService,
-                mock(NavigationModeController.class),
+                mNavigationModeController,
                 mock(AccessibilityButtonModeObserver.class),
-                mock(StatusBarStateController.class),
+                mStatusBarStateController,
                 mMockSysUiState,
                 mBroadcastDispatcher,
                 mCommandQueue,
@@ -287,8 +316,15 @@
                 mHandler,
                 mock(NavigationBarOverlayController.class),
                 mUiEventLogger,
-                mock(NavigationBarA11yHelper.class),
-                mock(UserTracker.class)));
+                mNavigationBarA11yHelper,
+                mock(UserTracker.class),
+                mLightBarController,
+                mLightBarcontrollerFactory,
+                mAutoHideController,
+                mAutoHideControllerFactory,
+                Optional.of(mTelecomManager),
+                mInputMethodManager);
+        return spy(factory.create(context));
     }
 
     private void processAllMessages() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index 6ff5aa0..2e1fb07 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -95,11 +96,11 @@
     Resources mResources;
     @Mock
     Configuration mConfiguration;
+    @Mock
+    Runnable mHorizontalLayoutListener;
 
     private QSPanelControllerBase<QSPanel> mController;
 
-
-
     /** Implementation needed to ensure we have a reflectively-available class name. */
     private class TestableQSPanelControllerBase extends QSPanelControllerBase<QSPanel> {
         protected TestableQSPanelControllerBase(QSPanel view, QSTileHost host,
@@ -239,17 +240,43 @@
         when(mMediaHost.getVisible()).thenReturn(true);
 
         when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(false);
+        when(mQSPanel.getDumpableTag()).thenReturn("QSPanelLandscape");
         mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
                 mQSCustomizerController, mMediaHost,
                 mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
+        mController.init();
 
         assertThat(mController.shouldUseHorizontalLayout()).isTrue();
 
         when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(true);
+        when(mQSPanel.getDumpableTag()).thenReturn("QSPanelPortrait");
         mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
                 mQSCustomizerController, mMediaHost,
                 mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
+        mController.init();
 
         assertThat(mController.shouldUseHorizontalLayout()).isFalse();
     }
+
+    @Test
+    public void testChangeConfiguration_shouldUseHorizontalLayout() {
+        when(mMediaHost.getVisible()).thenReturn(true);
+        mController.setUsingHorizontalLayoutChangeListener(mHorizontalLayoutListener);
+
+        // When device is rotated to landscape
+        mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        mController.mOnConfigurationChangedListener.onConfigurationChange(mConfiguration);
+
+        // Then the layout changes
+        assertThat(mController.shouldUseHorizontalLayout()).isTrue();
+        verify(mHorizontalLayoutListener).run(); // not invoked
+
+        // When it is rotated back to portrait
+        mConfiguration.orientation = Configuration.ORIENTATION_PORTRAIT;
+        mController.mOnConfigurationChangedListener.onConfigurationChange(mConfiguration);
+
+        // Then the layout changes back
+        assertThat(mController.shouldUseHorizontalLayout()).isFalse();
+        verify(mHorizontalLayoutListener, times(2)).run();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
index a21f488..06a4ae0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
@@ -23,6 +23,8 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 
@@ -98,6 +100,10 @@
     @Mock
     CommandQueue mCommandQueue;
     FalsingManagerFake mFalsingManager = new FalsingManagerFake();
+    @Mock
+    Resources mResources;
+    @Mock
+    Configuration mConfiguration;
 
     private QSPanelController mController;
 
@@ -109,7 +115,8 @@
         when(mQSPanel.getDumpableTag()).thenReturn("QSPanel");
         when(mQSPanel.getOrCreateTileLayout()).thenReturn(mPagedTileLayout);
         when(mQSPanel.getTileLayout()).thenReturn(mPagedTileLayout);
-        when(mQSPanel.getResources()).thenReturn(mContext.getResources());
+        when(mQSPanel.getResources()).thenReturn(mResources);
+        when(mResources.getConfiguration()).thenReturn(mConfiguration);
         when(mQSTileHost.getTiles()).thenReturn(Collections.singleton(mQSTile));
         when(mQSTileHost.createTileView(any(), eq(mQSTile), anyBoolean())).thenReturn(mQSTileView);
         when(mToggleSliderViewControllerFactory.create(any(), any()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt
index 5e2d8fd..b4a66297 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt
@@ -3,6 +3,7 @@
 import android.app.AlarmManager
 import android.app.PendingIntent
 import android.os.Handler
+import android.provider.AlarmClock
 import android.service.quicksettings.Tile
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
@@ -98,6 +99,11 @@
     }
 
     @Test
+    fun testDefaultIntentShowAlarms() {
+        assertThat(tile.defaultIntent.action).isEqualTo(AlarmClock.ACTION_SHOW_ALARMS)
+    }
+
+    @Test
     fun testInactiveByDefault() {
         assertThat(tile.state.state).isEqualTo(Tile.STATE_INACTIVE)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index 18f48a3..f9d5be6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -1,11 +1,15 @@
 package com.android.systemui.qs.tiles.dialog;
 
+import static com.android.systemui.qs.tiles.dialog.InternetDialogController.TOAST_PARAMS_HORIZONTAL_WEIGHT;
+import static com.android.systemui.qs.tiles.dialog.InternetDialogController.TOAST_PARAMS_VERTICAL_WEIGHT;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -14,8 +18,10 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.animation.Animator;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
@@ -25,7 +31,11 @@
 import android.telephony.TelephonyManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.testing.TestableResources;
 import android.text.TextUtils;
+import android.view.Gravity;
+import android.view.View;
+import android.view.WindowManager;
 
 import androidx.annotation.Nullable;
 import androidx.test.filters.SmallTest;
@@ -41,14 +51,19 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
+import com.android.systemui.toast.SystemUIToast;
+import com.android.systemui.toast.ToastFactory;
+import com.android.systemui.util.CarrierConfigTracker;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.settings.GlobalSettings;
 import com.android.systemui.util.time.FakeSystemClock;
+import com.android.wifitrackerlib.MergedCarrierEntry;
 import com.android.wifitrackerlib.WifiEntry;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -65,6 +80,11 @@
     private static final String CONNECTED_TITLE = "Connected Wi-Fi Title";
     private static final String CONNECTED_SUMMARY = "Connected Wi-Fi Summary";
 
+    //SystemUIToast
+    private static final int GRAVITY_FLAGS = Gravity.FILL_HORIZONTAL | Gravity.FILL_VERTICAL;
+    private static final int TOAST_MESSAGE_STRING_ID = 1;
+    private static final String TOAST_MESSAGE_STRING = "toast message";
+
     @Mock
     private WifiManager mWifiManager;
     @Mock
@@ -74,6 +94,8 @@
     @Mock
     private Handler mHandler;
     @Mock
+    private Handler mWorkerHandler;
+    @Mock
     private ActivityStarter mActivityStarter;
     @Mock
     private GlobalSettings mGlobalSettings;
@@ -92,6 +114,8 @@
     @Mock
     private WifiEntry mWifiEntry4;
     @Mock
+    private MergedCarrierEntry mMergedCarrierEntry;
+    @Mock
     private ServiceState mServiceState;
     @Mock
     private BroadcastDispatcher mBroadcastDispatcher;
@@ -99,7 +123,20 @@
     private WifiUtils.InternetIconInjector mWifiIconInjector;
     @Mock
     InternetDialogController.InternetDialogCallback mInternetDialogCallback;
+    @Mock
+    private WindowManager mWindowManager;
+    @Mock
+    private ToastFactory mToastFactory;
+    @Mock
+    private SystemUIToast mSystemUIToast;
+    @Mock
+    private View mToastView;
+    @Mock
+    private Animator mAnimator;
+    @Mock
+    private CarrierConfigTracker mCarrierConfigTracker;
 
+    private TestableResources mTestableResources;
     private MockInternetDialogController mInternetDialogController;
     private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
     private List<WifiEntry> mAccessPoints = new ArrayList<>();
@@ -108,6 +145,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        mTestableResources = mContext.getOrCreateTestableResources();
         doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
         when(mKeyguardStateController.isUnlocked()).thenReturn(true);
         when(mConnectedEntry.isDefaultNetwork()).thenReturn(true);
@@ -118,13 +156,21 @@
         when(mWifiEntry4.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_DISCONNECTED);
         mAccessPoints.add(mConnectedEntry);
         mAccessPoints.add(mWifiEntry1);
+        when(mAccessPointController.getMergedCarrierEntry()).thenReturn(mMergedCarrierEntry);
         when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(new int[]{SUB_ID});
+        when(mAccessPointController.getMergedCarrierEntry()).thenReturn(mMergedCarrierEntry);
+        when(mToastFactory.createToast(any(), anyString(), anyString(), anyInt(), anyInt()))
+            .thenReturn(mSystemUIToast);
+        when(mSystemUIToast.getView()).thenReturn(mToastView);
+        when(mSystemUIToast.getGravity()).thenReturn(GRAVITY_FLAGS);
+        when(mSystemUIToast.getInAnimation()).thenReturn(mAnimator);
 
         mInternetDialogController = new MockInternetDialogController(mContext,
                 mock(UiEventLogger.class), mock(ActivityStarter.class), mAccessPointController,
                 mSubscriptionManager, mTelephonyManager, mWifiManager,
                 mock(ConnectivityManager.class), mHandler, mExecutor, mBroadcastDispatcher,
-                mock(KeyguardUpdateMonitor.class), mGlobalSettings, mKeyguardStateController);
+                mock(KeyguardUpdateMonitor.class), mGlobalSettings, mKeyguardStateController,
+                mWindowManager, mToastFactory, mWorkerHandler, mCarrierConfigTracker);
         mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor,
                 mInternetDialogController.mOnSubscriptionsChangedListener);
         mInternetDialogController.onStart(mInternetDialogCallback, true);
@@ -134,6 +180,44 @@
     }
 
     @Test
+    public void connectCarrierNetwork_mergedCarrierEntryCanConnect_connectAndCreateSysUiToast() {
+        when(mMergedCarrierEntry.canConnect()).thenReturn(true);
+        mTestableResources.addOverride(R.string.wifi_wont_autoconnect_for_now,
+            TOAST_MESSAGE_STRING);
+
+        mInternetDialogController.connectCarrierNetwork();
+
+        verify(mMergedCarrierEntry).connect(null /* callback */, false /* showToast */);
+        verify(mToastFactory).createToast(any(), eq(TOAST_MESSAGE_STRING), anyString(), anyInt(),
+            anyInt());
+    }
+
+    @Test
+    public void makeOverlayToast_withGravityFlags_addViewWithLayoutParams() {
+        mTestableResources.addOverride(TOAST_MESSAGE_STRING_ID, TOAST_MESSAGE_STRING);
+
+        mInternetDialogController.makeOverlayToast(TOAST_MESSAGE_STRING_ID);
+
+        ArgumentCaptor<WindowManager.LayoutParams> paramsCaptor = ArgumentCaptor.forClass(
+            WindowManager.LayoutParams.class);
+        verify(mWindowManager).addView(eq(mToastView), paramsCaptor.capture());
+        WindowManager.LayoutParams params = paramsCaptor.getValue();
+        assertThat(params.format).isEqualTo(PixelFormat.TRANSLUCENT);
+        assertThat(params.type).isEqualTo(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
+        assertThat(params.horizontalWeight).isEqualTo(TOAST_PARAMS_HORIZONTAL_WEIGHT);
+        assertThat(params.verticalWeight).isEqualTo(TOAST_PARAMS_VERTICAL_WEIGHT);
+    }
+
+    @Test
+    public void makeOverlayToast_withAnimation_verifyAnimatorStart() {
+        mTestableResources.addOverride(TOAST_MESSAGE_STRING_ID, TOAST_MESSAGE_STRING);
+
+        mInternetDialogController.makeOverlayToast(TOAST_MESSAGE_STRING_ID);
+
+        verify(mAnimator).start();
+    }
+
+    @Test
     public void getDialogTitleText_withAirplaneModeOn_returnAirplaneMode() {
         mInternetDialogController.setAirplaneModeEnabled(true);
 
@@ -485,6 +569,39 @@
                 .onAccessPointsChanged(mWifiEntries, null /* connectedEntry */);
     }
 
+    @Test
+    public void setMergedCarrierWifiEnabledIfNeed_carrierProvisionsEnabled_doNothing() {
+        when(mCarrierConfigTracker.getCarrierProvisionsWifiMergedNetworksBool(SUB_ID))
+                .thenReturn(true);
+
+        mInternetDialogController.setMergedCarrierWifiEnabledIfNeed(SUB_ID, true);
+
+        verify(mMergedCarrierEntry, never()).setEnabled(anyBoolean());
+    }
+
+    @Test
+    public void setMergedCarrierWifiEnabledIfNeed_mergedCarrierEntryEmpty_doesntCrash() {
+        when(mCarrierConfigTracker.getCarrierProvisionsWifiMergedNetworksBool(SUB_ID))
+                .thenReturn(false);
+        when(mAccessPointController.getMergedCarrierEntry()).thenReturn(null);
+
+        mInternetDialogController.setMergedCarrierWifiEnabledIfNeed(SUB_ID, true);
+    }
+
+    @Test
+    public void setMergedCarrierWifiEnabledIfNeed_neededSetMergedCarrierEntry_setTogether() {
+        when(mCarrierConfigTracker.getCarrierProvisionsWifiMergedNetworksBool(SUB_ID))
+                .thenReturn(false);
+
+        mInternetDialogController.setMergedCarrierWifiEnabledIfNeed(SUB_ID, true);
+
+        verify(mMergedCarrierEntry).setEnabled(true);
+
+        mInternetDialogController.setMergedCarrierWifiEnabledIfNeed(SUB_ID, false);
+
+        verify(mMergedCarrierEntry).setEnabled(false);
+    }
+
     private String getResourcesString(String name) {
         return mContext.getResources().getString(getResourcesId(name));
     }
@@ -506,11 +623,14 @@
                 @Main Handler handler, @Main Executor mainExecutor,
                 BroadcastDispatcher broadcastDispatcher,
                 KeyguardUpdateMonitor keyguardUpdateMonitor, GlobalSettings globalSettings,
-                KeyguardStateController keyguardStateController) {
+                KeyguardStateController keyguardStateController, WindowManager windowManager,
+                ToastFactory toastFactory, Handler workerHandler,
+                CarrierConfigTracker carrierConfigTracker) {
             super(context, uiEventLogger, starter, accessPointController, subscriptionManager,
                     telephonyManager, wifiManager, connectivityManager, handler, mainExecutor,
                     broadcastDispatcher, keyguardUpdateMonitor, globalSettings,
-                    keyguardStateController);
+                    keyguardStateController, windowManager, toastFactory, workerHandler,
+                    carrierConfigTracker);
             mGlobalSettings = globalSettings;
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 2416132..af624ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -15,6 +15,8 @@
 package com.android.systemui.statusbar;
 
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
+import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
+import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
@@ -188,8 +190,13 @@
 
     @Test
     public void testShowImeButtonForSecondaryDisplay() {
+        // First show in default display to update the "last updated ime display"
+        testShowImeButton();
+
         mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, null, 1, 2, true, false);
         waitForIdleSync();
+        verify(mCallbacks).setImeWindowStatus(eq(DEFAULT_DISPLAY), eq(null), eq(IME_INVISIBLE),
+                eq(BACK_DISPOSITION_DEFAULT), eq(false));
         verify(mCallbacks).setImeWindowStatus(
                 eq(SECONDARY_DISPLAY), eq(null), eq(1), eq(2), eq(true));
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 09a3d35..f5cab1d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -23,6 +23,7 @@
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_RESTING;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRANSIENT;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRUST;
@@ -725,6 +726,20 @@
         verify(mIndicationAreaBottom).announceForAccessibility(eq(faceHelpMsg));
     }
 
+    @Test
+    public void testEmptyOwnerInfoHidesIndicationArea() {
+        createController();
+
+        // GIVEN the owner info is set to an empty string
+        when(mLockPatternUtils.getDeviceOwnerInfo()).thenReturn("");
+
+        // WHEN asked to update the indication area
+        mController.setVisible(true);
+
+        // THEN the owner info should be hidden
+        verifyHideIndication(INDICATION_TYPE_OWNER_INFO);
+    }
+
     private void sendUpdateDisclosureBroadcast() {
         mBroadcastReceiver.onReceive(mContext, new Intent());
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index ea21aa9..23cca72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -20,10 +20,10 @@
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.content.Intent.ACTION_USER_SWITCHED;
 
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_ALERTING;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_MEDIA_CONTROLS;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_PEOPLE;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_ALERTING;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_MEDIA_CONTROLS;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PEOPLE;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
 
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index c862f97..e9e6718 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -1660,7 +1660,7 @@
         private final String mPackage;
 
         PackageSectioner(String pkg) {
-            super("PackageSection_" + pkg);
+            super("PackageSection_" + pkg, 0);
             mPackage = pkg;
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
index 2e676bb..ed48452 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
@@ -26,6 +26,10 @@
 import com.android.systemui.statusbar.notification.collection.getAttachState
 import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
+import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
+import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE
+import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
+import com.android.systemui.statusbar.notification.stack.PriorityBucket
 import com.android.systemui.util.mockito.any
 import org.junit.Before
 import org.junit.Test
@@ -45,11 +49,15 @@
     private var headerController1: NodeController = buildFakeController("header1")
     private var headerController2: NodeController = buildFakeController("header2")
 
-    private val section0 = buildSection(0, headerController0)
-    private val section0NoHeader = buildSection(0, null)
-    private val section1 = buildSection(1, headerController1)
-    private val section1NoHeader = buildSection(1, null)
-    private val section2 = buildSection(2, headerController2)
+    private val section0Bucket = BUCKET_PEOPLE
+    private val section1Bucket = BUCKET_ALERTING
+    private val section2Bucket = BUCKET_SILENT
+
+    private val section0 = buildSection(0, section0Bucket, headerController0)
+    private val section0NoHeader = buildSection(0, section0Bucket, null)
+    private val section1 = buildSection(1, section1Bucket, headerController1)
+    private val section1NoHeader = buildSection(1, section1Bucket, null)
+    private val section2 = buildSection(2, section2Bucket, headerController2)
 
     private val fakeViewBarn = FakeViewBarn()
 
@@ -297,8 +305,12 @@
     return controller
 }
 
-private fun buildSection(index: Int, nodeController: NodeController?): NotifSection {
-    return NotifSection(object : NotifSectioner("Section $index") {
+private fun buildSection(
+    index: Int,
+    @PriorityBucket bucket: Int,
+    nodeController: NodeController?
+): NotifSection {
+    return NotifSection(object : NotifSectioner("Section $index (bucket=$bucket)", bucket) {
 
         override fun isInSection(entry: ListEntry?): Boolean {
             throw NotImplementedError("This should never be called")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index c1d2ea8..f11f8c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -18,11 +18,11 @@
 
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_ALERTING;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_FOREGROUND_SERVICE;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_HEADS_UP;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_PEOPLE;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_ALERTING;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_FOREGROUND_SERVICE;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_HEADS_UP;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PEOPLE;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -64,7 +64,6 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
@@ -608,7 +607,7 @@
         }
     }
 
-    private View mockNotification(int bucket, boolean isGone) {
+    private View mockNotification(@PriorityBucket int bucket, boolean isGone) {
         ExpandableNotificationRow notifRow =
                 mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
         when(notifRow.getVisibility()).thenReturn(View.VISIBLE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index 4476fd8..efe2c17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -221,6 +221,18 @@
         verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean())
     }
 
+    /** Regression test for b/201097913. */
+    @Test
+    fun onEntryCleanUp_callNotifAddedThenRemoved_listenerNotified() {
+        val ongoingCallNotifEntry = createOngoingCallNotifEntry()
+        notifCollectionListener.onEntryAdded(ongoingCallNotifEntry)
+        reset(mockOngoingCallListener)
+
+        notifCollectionListener.onEntryCleanUp(ongoingCallNotifEntry)
+
+        verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean())
+    }
+
     /** Regression test for b/188491504. */
     @Test
     fun onEntryRemoved_removedNotifHasSameKeyAsAddedNotif_listenerNotified() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt
index 3cb19e3..de86821 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt
@@ -91,7 +91,7 @@
     @Test
     fun setUnfoldTransitionZoom_defaultUnfoldTransitionIsDisabled_doesNotUpdateWallpaperZoom() {
         wallaperController.onWallpaperInfoUpdated(createWallpaperInfo(
-            useDefaultUnfoldTransition = false
+            useDefaultTransition = false
         ))
 
         wallaperController.setUnfoldTransitionZoom(0.5f)
@@ -136,9 +136,10 @@
         verify(wallpaperManager).setWallpaperZoomOut(any(), anyFloat())
     }
 
-    private fun createWallpaperInfo(useDefaultUnfoldTransition: Boolean = true): WallpaperInfo {
+    private fun createWallpaperInfo(useDefaultTransition: Boolean = true): WallpaperInfo {
         val info = mock(WallpaperInfo::class.java)
-        whenever(info.shouldUseDefaultUnfoldTransition()).thenReturn(useDefaultUnfoldTransition)
+        whenever(info.shouldUseDefaultDeviceStateChangeTransition())
+            .thenReturn(useDefaultTransition)
         return info
     }
 }
diff --git a/packages/VpnDialogs/res/values-as/strings.xml b/packages/VpnDialogs/res/values-as/strings.xml
index 13c5cc9..3f2e234 100644
--- a/packages/VpnDialogs/res/values-as/strings.xml
+++ b/packages/VpnDialogs/res/values-as/strings.xml
@@ -29,7 +29,7 @@
     <string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g>ক সকলো সময়তে সংযুক্ত হৈ থাকিবলৈ ছেট কৰি থোৱা হৈছে, কিন্তু ই বৰ্তমান সংযোগ কৰিবপৰা নাই। আপোনাৰ ফ\'নটোৱে <xliff:g id="VPN_APP_1">%1$s</xliff:g>ৰ সৈতে সংযোগ কৰিব নোৱাৰালৈকে এটা ৰাজহুৱা নেটৱৰ্ক ব্যৱহাৰ কৰিব।"</string>
     <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g>ক সকলো সময়তে সংযুক্ত হৈ থাকিবলৈ ছেট কৰি থোৱা হৈছে, কিন্তু ই বৰ্তমান সংযোগ কৰিবপৰা নাই। ভিপিএনটোৰ সৈতে পুনৰ সংযুক্ত নোহোৱালৈকে আপোনাৰ কোনো সংযোগ নাথাকিব।"</string>
     <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
-    <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"ভিপিএন ছেটিংসমূহ সলনি কৰক"</string>
+    <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"ভিপিএন ছেটিং সলনি কৰক"</string>
     <string name="configure" msgid="4905518375574791375">"কনফিগাৰ কৰক"</string>
     <string name="disconnect" msgid="971412338304200056">"সংযোগ বিচ্ছিন্ন কৰক"</string>
     <string name="open_app" msgid="3717639178595958667">"এপ্ খোলক"</string>
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 20ad9e1..e3b7fdd 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -98,8 +98,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.permission.PermissionControllerManager;
-import android.provider.Settings;
-import android.provider.SettingsStringUtil.ComponentNameSet;
 import android.text.BidiFormatter;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -632,6 +630,12 @@
             registerDevicePresenceListenerActive(packageName, deviceAddress, false);
         }
 
+        @Override
+        public void dispatchMessage(int messageId, int associationId, byte[] message)
+                throws RemoteException {
+            //TODO: b/199427116
+        }
+
         private void registerDevicePresenceListenerActive(String packageName, String deviceAddress,
                 boolean active) throws RemoteException {
             getContext().enforceCallingOrSelfPermission(
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
index 9f3045e..3a90a95 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
@@ -87,7 +87,7 @@
         mId = sessionId;
         mUid = uid;
         mContentCaptureContext = new ContentCaptureContext(/* clientContext= */ null,
-                activityId, appComponentName, displayId, flags);
+                activityId, appComponentName, displayId, activityToken, flags);
         mSessionStateReceiver = sessionStateReceiver;
         try {
             sessionStateReceiver.asBinder().linkToDeath(() -> onClientDeath(), 0);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index fd5fd35..216224c 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -150,7 +150,7 @@
         "android.hardware.biometrics.fingerprint-V2.3-java",
         "android.hardware.biometrics.fingerprint-V1-java",
         "android.hardware.oemlock-V1.0-java",
-        "android.hardware.configstore-V1.0-java",
+        "android.hardware.configstore-V1.1-java",
         "android.hardware.contexthub-V1.0-java",
         "android.hardware.rebootescrow-V1-java",
         "android.hardware.soundtrigger-V2.3-java",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index c3bf03c..d92b65b4 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -667,6 +667,12 @@
      */
     public abstract @Nullable AndroidPackage getPackage(int uid);
 
+
+    /**
+     * Returns all packages for the given app ID.
+     */
+    public abstract @NonNull List<AndroidPackage> getPackagesForAppId(int appId);
+
     /**
      * Returns a list without a change observer.
      *
diff --git a/services/core/java/com/android/server/Dumpable.java b/services/core/java/com/android/server/Dumpable.java
index d2bd66f..866f81c 100644
--- a/services/core/java/com/android/server/Dumpable.java
+++ b/services/core/java/com/android/server/Dumpable.java
@@ -21,6 +21,8 @@
 
 /**
  * Interface used to dump {@link SystemServer} state that is not associated with any service.
+ *
+ * <p>See {@link SystemServer.SystemServerDumper} for usage example.
  */
 public interface Dumpable {
 
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 483250a..68fd0c1 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -92,6 +92,8 @@
 27533 notification_autogrouped (key|3)
 # notification was removed from an autogroup
 275534 notification_unautogrouped (key|3)
+# when a notification is adjusted via assistant
+27535 notification_adjusted (key|3),(adjustment_type|3),(new_value|3)
 
 # ---------------------------
 # Watchdog.java
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index 3a03573..ba0266e 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -420,9 +420,12 @@
             }
 
             synchronized (mLock) {
-                if (mSuppressReminders.containsKey(new Pair<>(sensor, user))) {
+                UserHandle parentUser = UserHandle.of(mUserManagerInternal
+                        .getProfileParentId(user.getIdentifier()));
+                if (mSuppressReminders.containsKey(new Pair<>(sensor, parentUser))) {
                     Log.d(TAG,
-                            "Suppressed sensor privacy reminder for " + packageName + "/" + user);
+                            "Suppressed sensor privacy reminder for " + packageName + "/"
+                                    + parentUser);
                     return;
                 }
             }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index cb1f744..3a6d9a2 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -4369,8 +4369,13 @@
                 packageName = packagesForUid[0];
             }
 
-            if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) {
-                return StorageManager.MOUNT_MODE_EXTERNAL_NONE;
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) {
+                    return StorageManager.MOUNT_MODE_EXTERNAL_NONE;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
 
             if (mStorageManagerInternal.isExternalStorageService(uid)) {
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index d1e56a0..a6b265b 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -69,10 +69,12 @@
 import static com.android.server.am.ActivityManagerService.TAG_OOM_ADJ;
 import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS;
 import static com.android.server.am.AppProfiler.TAG_PSS;
+import static com.android.server.am.PlatformCompatCache.CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY;
+import static com.android.server.am.PlatformCompatCache.CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY;
+import static com.android.server.am.PlatformCompatCache.CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME;
 import static com.android.server.am.ProcessList.TAG_PROCESS_OBSERVERS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
 
-import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
@@ -93,31 +95,23 @@
 import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.Trace;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.LongSparseArray;
-import android.util.Pair;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.CompositeRWLock;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.compat.IPlatformCompat;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
-import com.android.server.compat.CompatChange;
-import com.android.server.compat.PlatformCompat;
+import com.android.server.am.PlatformCompatCache.CachedCompatChangeId;
 import com.android.server.wm.ActivityServiceConnectionsHolder;
 import com.android.server.wm.WindowProcessController;
 
 import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -174,27 +168,6 @@
     @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
     static final long USE_SHORT_FGS_USAGE_INTERACTION_TIME = 183972877L;
 
-    static final int CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY = 0;
-    static final int CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY = 1;
-    static final int CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME = 2;
-
-    @IntDef(prefix = { "CACHED_COMPAT_CHANGE_" }, value = {
-        CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY,
-        CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY,
-        CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    static @interface CachedCompatChangeId{}
-
-    /**
-     * Mapping from CACHED_COMPAT_CHANGE_* to the actual compat change id.
-     */
-    static final long[] CACHED_COMPAT_CHANGE_IDS_MAPPING = new long[] {
-        PROCESS_CAPABILITY_CHANGE_ID,
-        CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID,
-        USE_SHORT_FGS_USAGE_INTERACTION_TIME,
-    };
-
     /**
      * For some direct access we need to power manager.
      */
@@ -280,150 +253,12 @@
     @GuardedBy("mService")
     private boolean mPendingFullOomAdjUpdate = false;
 
-    final PlatformCompatCache mPlatformCompatCache;
-
     /** Overrideable by a test */
     @VisibleForTesting
-    static class PlatformCompatCache {
-        private final PlatformCompat mPlatformCompat;
-        private final IPlatformCompat mIPlatformCompatProxy;
-        private final LongSparseArray<CacheItem> mCaches = new LongSparseArray<>();
-        private final boolean mCacheEnabled;
-
-        PlatformCompatCache(long[] compatChanges) {
-            IBinder b = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
-            if (b instanceof PlatformCompat) {
-                mPlatformCompat = (PlatformCompat) ServiceManager.getService(
-                        Context.PLATFORM_COMPAT_SERVICE);
-                for (long changeId: compatChanges) {
-                    mCaches.put(changeId, new CacheItem(mPlatformCompat, changeId));
-                }
-                mIPlatformCompatProxy = null;
-                mCacheEnabled = true;
-            } else {
-                // we are in UT where the platform_compat is not running within the same process
-                mIPlatformCompatProxy = IPlatformCompat.Stub.asInterface(b);
-                mPlatformCompat = null;
-                mCacheEnabled = false;
-            }
-        }
-
-        boolean isChangeEnabled(long changeId, ApplicationInfo app) throws RemoteException {
-            return mCacheEnabled ? mCaches.get(changeId).isChangeEnabled(app)
-                    : mIPlatformCompatProxy.isChangeEnabled(changeId, app);
-        }
-
-        /**
-         * Same as {@link #isChangeEnabled(long, ApplicationInfo)} but instead of throwing a
-         * RemoteException from platform compat, it returns the default value provided.
-         */
-        boolean isChangeEnabled(long changeId, ApplicationInfo app, boolean defaultValue) {
-            try {
-                return mCacheEnabled ? mCaches.get(changeId).isChangeEnabled(app)
-                        : mIPlatformCompatProxy.isChangeEnabled(changeId, app);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Error reading platform compat change " + changeId, e);
-                return defaultValue;
-            }
-        }
-
-        void invalidate(ApplicationInfo app) {
-            for (int i = mCaches.size() - 1; i >= 0; i--) {
-                mCaches.valueAt(i).invalidate(app);
-            }
-        }
-
-        void onApplicationInfoChanged(ApplicationInfo app) {
-            for (int i = mCaches.size() - 1; i >= 0; i--) {
-                mCaches.valueAt(i).onApplicationInfoChanged(app);
-            }
-        }
-
-        static class CacheItem implements CompatChange.ChangeListener {
-            private final PlatformCompat mPlatformCompat;
-            private final long mChangeId;
-            private final Object mLock = new Object();
-
-            private final ArrayMap<String, Pair<Boolean, WeakReference<ApplicationInfo>>> mCache =
-                    new ArrayMap<>();
-
-            CacheItem(PlatformCompat platformCompat, long changeId) {
-                mPlatformCompat = platformCompat;
-                mChangeId = changeId;
-                mPlatformCompat.registerListener(changeId, this);
-            }
-
-            boolean isChangeEnabled(ApplicationInfo app) {
-                synchronized (mLock) {
-                    final int index = mCache.indexOfKey(app.packageName);
-                    Pair<Boolean, WeakReference<ApplicationInfo>> p;
-                    if (index < 0) {
-                        return fetchLocked(app, index);
-                    }
-                    p = mCache.valueAt(index);
-                    if (p.second.get() == app) {
-                        return p.first;
-                    }
-                    // Cache is invalid, regenerate it
-                    return fetchLocked(app, index);
-                }
-            }
-
-            void invalidate(ApplicationInfo app) {
-                synchronized (mLock) {
-                    mCache.remove(app.packageName);
-                }
-            }
-
-            @GuardedBy("mLock")
-            boolean fetchLocked(ApplicationInfo app, int index) {
-                final Pair<Boolean, WeakReference<ApplicationInfo>> p = new Pair<>(
-                        mPlatformCompat.isChangeEnabledInternalNoLogging(mChangeId, app),
-                        new WeakReference<>(app));
-                if (index >= 0) {
-                    mCache.setValueAt(index, p);
-                } else {
-                    mCache.put(app.packageName, p);
-                }
-                return p.first;
-            }
-
-            void onApplicationInfoChanged(ApplicationInfo app) {
-                synchronized (mLock) {
-                    final int index = mCache.indexOfKey(app.packageName);
-                    if (index >= 0) {
-                        fetchLocked(app, index);
-                    }
-                }
-            }
-
-            @Override
-            public void onCompatChange(String packageName) {
-                synchronized (mLock) {
-                    final int index = mCache.indexOfKey(packageName);
-                    if (index >= 0) {
-                        final ApplicationInfo app = mCache.valueAt(index).second.get();
-                        if (app != null) {
-                            fetchLocked(app, index);
-                        } else {
-                            mCache.removeAt(index);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /** Overrideable by a test */
-    @VisibleForTesting
-    protected PlatformCompatCache getPlatformCompatCache() {
-        return mPlatformCompatCache;
-    }
-
-    boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId, ApplicationInfo app,
-            boolean defaultValue) {
-        return getPlatformCompatCache().isChangeEnabled(
-                CACHED_COMPAT_CHANGE_IDS_MAPPING[cachedCompatChangeId], app, defaultValue);
+    protected boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId,
+            ApplicationInfo app, boolean defaultValue) {
+        return PlatformCompatCache.getInstance()
+                .isChangeEnabled(cachedCompatChangeId, app, defaultValue);
     }
 
     OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) {
@@ -477,10 +312,6 @@
         mTmpQueue = new ArrayDeque<ProcessRecord>(mConstants.CUR_MAX_CACHED_PROCESSES << 1);
         mNumSlots = ((ProcessList.CACHED_APP_MAX_ADJ - ProcessList.CACHED_APP_MIN_ADJ + 1) >> 1)
                 / ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
-        mPlatformCompatCache = new PlatformCompatCache(new long[] {
-                PROCESS_CAPABILITY_CHANGE_ID, CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID,
-                USE_SHORT_FGS_USAGE_INTERACTION_TIME
-        });
     }
 
     void initSettings() {
@@ -827,7 +658,7 @@
         if (app != null) {
             mPendingProcessSet.remove(app);
             if (procDied) {
-                getPlatformCompatCache().invalidate(app.info);
+                PlatformCompatCache.getInstance().invalidate(app.info);
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 175da9c..81a8680 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -310,6 +310,22 @@
                 requiredPermission, null, null, 0, 0, 0, options);
     }
 
+    public static boolean isPendingIntentBalAllowedByCaller(
+            @Nullable ActivityOptions activityOptions) {
+        if (activityOptions == null) {
+            return ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT;
+        }
+        return isPendingIntentBalAllowedByCaller(activityOptions.toBundle());
+    }
+
+    private static boolean isPendingIntentBalAllowedByCaller(@Nullable Bundle options) {
+        if (options == null) {
+            return ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT;
+        }
+        return options.getBoolean(ActivityOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED,
+                ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT);
+    }
+
     public int sendInner(int code, Intent intent, String resolvedType, IBinder allowlistToken,
             IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo,
             String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options) {
@@ -431,7 +447,8 @@
             // temporarily allow receivers and services to open activities from background if the
             // PendingIntent.send() caller was foreground at the time of sendInner() call
             final boolean allowTrampoline = uid != callingUid
-                    && controller.mAtmInternal.isUidForeground(callingUid);
+                    && controller.mAtmInternal.isUidForeground(callingUid)
+                    && isPendingIntentBalAllowedByCaller(options);
 
             // note: we on purpose don't pass in the information about the PendingIntent's creator,
             // like pid or ProcessRecord, to the ActivityTaskManagerInternal calls below, because
diff --git a/services/core/java/com/android/server/am/PlatformCompatCache.java b/services/core/java/com/android/server/am/PlatformCompatCache.java
new file mode 100644
index 0000000..15bee33
--- /dev/null
+++ b/services/core/java/com/android/server/am/PlatformCompatCache.java
@@ -0,0 +1,216 @@
+/*
+ * 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.am;
+
+import static com.android.server.am.ActivityManagerService.TAG;
+import static com.android.server.am.OomAdjuster.CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID;
+import static com.android.server.am.OomAdjuster.PROCESS_CAPABILITY_CHANGE_ID;
+import static com.android.server.am.OomAdjuster.USE_SHORT_FGS_USAGE_INTERACTION_TIME;
+
+import android.annotation.IntDef;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.ArrayMap;
+import android.util.LongSparseArray;
+import android.util.Pair;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.compat.IPlatformCompat;
+import com.android.server.compat.CompatChange;
+import com.android.server.compat.PlatformCompat;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+
+/**
+ * Local platform compat cache.
+ */
+final class PlatformCompatCache {
+
+    static final int CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY = 0;
+    static final int CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY = 1;
+    static final int CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME = 2;
+
+    @IntDef(prefix = { "CACHED_COMPAT_CHANGE_" }, value = {
+        CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY,
+        CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY,
+        CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    static @interface CachedCompatChangeId{}
+
+    /**
+     * Mapping from CACHED_COMPAT_CHANGE_* to the actual compat change id.
+     */
+    static final long[] CACHED_COMPAT_CHANGE_IDS_MAPPING = new long[] {
+        PROCESS_CAPABILITY_CHANGE_ID,
+        CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID,
+        USE_SHORT_FGS_USAGE_INTERACTION_TIME,
+    };
+
+    private final PlatformCompat mPlatformCompat;
+    private final IPlatformCompat mIPlatformCompatProxy;
+    private final LongSparseArray<CacheItem> mCaches = new LongSparseArray<>();
+    private final boolean mCacheEnabled;
+
+    private static PlatformCompatCache sPlatformCompatCache;
+
+    private PlatformCompatCache(long[] compatChanges) {
+        IBinder b = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
+        if (b instanceof PlatformCompat) {
+            mPlatformCompat = (PlatformCompat) ServiceManager.getService(
+                    Context.PLATFORM_COMPAT_SERVICE);
+            for (long changeId: compatChanges) {
+                mCaches.put(changeId, new CacheItem(mPlatformCompat, changeId));
+            }
+            mIPlatformCompatProxy = null;
+            mCacheEnabled = true;
+        } else {
+            // we are in UT where the platform_compat is not running within the same process
+            mIPlatformCompatProxy = IPlatformCompat.Stub.asInterface(b);
+            mPlatformCompat = null;
+            mCacheEnabled = false;
+        }
+    }
+
+    static PlatformCompatCache getInstance() {
+        if (sPlatformCompatCache == null) {
+            sPlatformCompatCache = new PlatformCompatCache(new long[] {
+                PROCESS_CAPABILITY_CHANGE_ID,
+                CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID,
+                USE_SHORT_FGS_USAGE_INTERACTION_TIME,
+            });
+        }
+        return sPlatformCompatCache;
+    }
+
+    private boolean isChangeEnabled(long changeId, ApplicationInfo app, boolean defaultValue) {
+        try {
+            return mCacheEnabled ? mCaches.get(changeId).isChangeEnabled(app)
+                    : mIPlatformCompatProxy.isChangeEnabled(changeId, app);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Error reading platform compat change " + changeId, e);
+            return defaultValue;
+        }
+    }
+
+    /**
+     * @return If the given cached compat change id is enabled.
+     */
+    static boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId,
+            ApplicationInfo app, boolean defaultValue) {
+        return getInstance().isChangeEnabled(
+                CACHED_COMPAT_CHANGE_IDS_MAPPING[cachedCompatChangeId], app, defaultValue);
+    }
+
+    /**
+     * Invalidate the cache for the given app.
+     */
+    void invalidate(ApplicationInfo app) {
+        for (int i = mCaches.size() - 1; i >= 0; i--) {
+            mCaches.valueAt(i).invalidate(app);
+        }
+    }
+
+    /**
+     * Update the cache due to application info changes.
+     */
+    void onApplicationInfoChanged(ApplicationInfo app) {
+        for (int i = mCaches.size() - 1; i >= 0; i--) {
+            mCaches.valueAt(i).onApplicationInfoChanged(app);
+        }
+    }
+
+    static class CacheItem implements CompatChange.ChangeListener {
+        private final PlatformCompat mPlatformCompat;
+        private final long mChangeId;
+        private final Object mLock = new Object();
+
+        private final ArrayMap<String, Pair<Boolean, WeakReference<ApplicationInfo>>> mCache =
+                new ArrayMap<>();
+
+        CacheItem(PlatformCompat platformCompat, long changeId) {
+            mPlatformCompat = platformCompat;
+            mChangeId = changeId;
+            mPlatformCompat.registerListener(changeId, this);
+        }
+
+        boolean isChangeEnabled(ApplicationInfo app) {
+            synchronized (mLock) {
+                final int index = mCache.indexOfKey(app.packageName);
+                Pair<Boolean, WeakReference<ApplicationInfo>> p;
+                if (index < 0) {
+                    return fetchLocked(app, index);
+                }
+                p = mCache.valueAt(index);
+                if (p.second.get() == app) {
+                    return p.first;
+                }
+                // Cache is invalid, regenerate it
+                return fetchLocked(app, index);
+            }
+        }
+
+        void invalidate(ApplicationInfo app) {
+            synchronized (mLock) {
+                mCache.remove(app.packageName);
+            }
+        }
+
+        @GuardedBy("mLock")
+        boolean fetchLocked(ApplicationInfo app, int index) {
+            final Pair<Boolean, WeakReference<ApplicationInfo>> p = new Pair<>(
+                    mPlatformCompat.isChangeEnabledInternalNoLogging(mChangeId, app),
+                    new WeakReference<>(app));
+            if (index >= 0) {
+                mCache.setValueAt(index, p);
+            } else {
+                mCache.put(app.packageName, p);
+            }
+            return p.first;
+        }
+
+        void onApplicationInfoChanged(ApplicationInfo app) {
+            synchronized (mLock) {
+                final int index = mCache.indexOfKey(app.packageName);
+                if (index >= 0) {
+                    fetchLocked(app, index);
+                }
+            }
+        }
+
+        @Override
+        public void onCompatChange(String packageName) {
+            synchronized (mLock) {
+                final int index = mCache.indexOfKey(packageName);
+                if (index >= 0) {
+                    final ApplicationInfo app = mCache.valueAt(index).second.get();
+                    if (app != null) {
+                        fetchLocked(app, index);
+                    } else {
+                        mCache.removeAt(index);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index cf8be63..ca32e08 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -4753,7 +4753,7 @@
                         if (ai != null) {
                             if (ai.packageName.equals(app.info.packageName)) {
                                 app.info = ai;
-                                mService.mOomAdjuster.mPlatformCompatCache
+                                PlatformCompatCache.getInstance()
                                         .onApplicationInfoChanged(ai);
                             }
                             app.getThread().scheduleApplicationInfoChanged(ai);
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index c4ce873..b08f6c1 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -21,7 +21,6 @@
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
-import static com.android.server.am.OomAdjuster.CachedCompatChangeId;
 import static com.android.server.am.ProcessRecord.TAG;
 
 import android.annotation.ElapsedRealtimeLong;
@@ -35,6 +34,7 @@
 import com.android.internal.annotations.CompositeRWLock;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.am.PlatformCompatCache.CachedCompatChangeId;
 
 import java.io.PrintWriter;
 
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 3003c52..456a758 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -852,7 +852,7 @@
      * @hide
      */
     @VisibleForTesting
-    public void updateConfigsForUser(int userId, String ...packageNames) {
+    void updateConfigsForUser(int userId, String ...packageNames) {
         try {
             synchronized (mDeviceConfigLock) {
                 for (final String packageName : packageNames) {
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 19dcee4..bd066ff 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -269,16 +269,16 @@
         getContext().enforceCallingOrSelfPermission(
                 android.Manifest.permission.MANAGE_APP_HIBERNATION,
                 "Caller does not have MANAGE_APP_HIBERNATION permission.");
-        userId = handleIncomingUser(userId, methodName);
-        if (!checkUserStatesExist(userId, methodName)) {
+        final int realUserId = handleIncomingUser(userId, methodName);
+        if (!checkUserStatesExist(realUserId, methodName)) {
             return;
         }
         synchronized (mLock) {
-            final Map<String, UserLevelState> packageStates = mUserStates.get(userId);
+            final Map<String, UserLevelState> packageStates = mUserStates.get(realUserId);
             final UserLevelState pkgState = packageStates.get(packageName);
             if (pkgState == null) {
                 Slog.e(TAG, String.format("Package %s is not installed for user %s",
-                        packageName, userId));
+                        packageName, realUserId));
                 return;
             }
 
@@ -286,13 +286,17 @@
                 return;
             }
 
+            pkgState.hibernated = isHibernating;
             if (isHibernating) {
-                hibernatePackageForUser(packageName, userId, pkgState);
+                mBackgroundExecutor.execute(() -> hibernatePackageForUser(packageName, realUserId));
             } else {
-                unhibernatePackageForUser(packageName, userId, pkgState);
+                mBackgroundExecutor.execute(
+                        () -> unhibernatePackageForUser(packageName, realUserId));
+                pkgState.lastUnhibernatedMs = System.currentTimeMillis();
             }
+
             final UserLevelState stateSnapshot = new UserLevelState(pkgState);
-            final int userIdSnapshot = userId;
+            final int userIdSnapshot = realUserId;
             mBackgroundExecutor.execute(() -> {
                 FrameworkStatsLog.write(
                         FrameworkStatsLog.USER_LEVEL_HIBERNATION_STATE_CHANGED,
@@ -300,8 +304,8 @@
                         userIdSnapshot,
                         stateSnapshot.hibernated);
             });
-            List<UserLevelState> states = new ArrayList<>(mUserStates.get(userId).values());
-            mUserDiskStores.get(userId).scheduleWriteHibernationStates(states);
+            List<UserLevelState> states = new ArrayList<>(mUserStates.get(realUserId).values());
+            mUserDiskStores.get(realUserId).scheduleWriteHibernationStates(states);
         }
     }
 
@@ -326,10 +330,12 @@
                 return;
             }
             if (state.hibernated != isHibernating) {
+                state.hibernated = isHibernating;
                 if (isHibernating) {
-                    hibernatePackageGlobally(packageName, state);
+                    mBackgroundExecutor.execute(() -> hibernatePackageGlobally(packageName, state));
                 } else {
-                    unhibernatePackageGlobally(packageName, state);
+                    state.savedByte = 0;
+                    state.lastUnhibernatedMs = System.currentTimeMillis();
                 }
                 List<GlobalLevelState> states = new ArrayList<>(mGlobalHibernationStates.values());
                 mGlobalLevelHibernationDiskStore.scheduleWriteHibernationStates(states);
@@ -366,20 +372,16 @@
     }
 
     /**
-     * Put an app into hibernation for a given user, allowing user-level optimizations to occur.
-     *
-     * @param pkgState package hibernation state
+     * Put an app into hibernation for a given user, allowing user-level optimizations to occur. Do
+     * not hold {@link #mLock} while calling this to avoid deadlock scenarios.
      */
-    @GuardedBy("mLock")
-    private void hibernatePackageForUser(@NonNull String packageName, int userId,
-            @NonNull UserLevelState pkgState) {
+    private void hibernatePackageForUser(@NonNull String packageName, int userId) {
         Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackage");
         final long caller = Binder.clearCallingIdentity();
         try {
             mIActivityManager.forceStopPackage(packageName, userId);
             mIPackageManager.deleteApplicationCacheFilesAsUser(packageName, userId,
                     null /* observer */);
-            pkgState.hibernated = true;
         } catch (RemoteException e) {
             throw new IllegalStateException(
                     "Failed to hibernate due to manager not being available", e);
@@ -390,16 +392,11 @@
     }
 
     /**
-     * Remove a package from hibernation for a given user.
-     *
-     * @param pkgState package hibernation state
+     * Remove a package from hibernation for a given user. Do not hold {@link #mLock} while calling
+     * this.
      */
-    @GuardedBy("mLock")
-    private void unhibernatePackageForUser(@NonNull String packageName, int userId,
-            UserLevelState pkgState) {
+    private void unhibernatePackageForUser(@NonNull String packageName, int userId) {
         Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage");
-        pkgState.hibernated = false;
-        pkgState.lastUnhibernatedMs = System.currentTimeMillis();
         final long caller = Binder.clearCallingIdentity();
         // Deliver LOCKED_BOOT_COMPLETE AND BOOT_COMPLETE broadcast so app can re-register
         // their alarms/jobs/etc.
@@ -450,29 +447,20 @@
     }
 
     /**
-     * Put a package into global hibernation, optimizing its storage at a package / APK level.
+     * Put a package into global hibernation, optimizing its storage at a package / APK level. Do
+     * not hold {@link #mLock} while calling this.
      */
-    @GuardedBy("mLock")
     private void hibernatePackageGlobally(@NonNull String packageName, GlobalLevelState state) {
         Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackageGlobally");
+        long savedBytes = 0;
         if (mOatArtifactDeletionEnabled) {
-            state.savedByte = Math.max(
+            savedBytes = Math.max(
                     mPackageManagerInternal.deleteOatArtifactsOfPackage(packageName),
                     0);
         }
-        state.hibernated = true;
-        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-    }
-
-    /**
-     * Unhibernate a package from global hibernation.
-     */
-    @GuardedBy("mLock")
-    private void unhibernatePackageGlobally(@NonNull String packageName, GlobalLevelState state) {
-        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackageGlobally");
-        state.hibernated = false;
-        state.savedByte = 0;
-        state.lastUnhibernatedMs = System.currentTimeMillis();
+        synchronized (mLock) {
+            state.savedByte = savedBytes;
+        }
         Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
     }
 
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index fe6a5a3..587b5d2 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -4562,8 +4562,9 @@
         }
         if (pkgUid != Process.INVALID_UID) {
             if (pkgUid != UserHandle.getAppId(uid)) {
-                //TODO 195339480: replace true with debug
-                String otherUidMessage = true ? " but it is really " + pkgUid : " but it is not";
+                Slog.e(TAG, "Bad call made by uid " + callingUid + ". "
+                        + "Package \"" + packageName + "\" does not belong to uid " + uid + ".");
+                String otherUidMessage = DEBUG ? " but it is really " + pkgUid : " but it is not";
                 throw new SecurityException("Specified package \"" + packageName + "\" under uid "
                         +  UserHandle.getAppId(uid) + otherUidMessage);
             }
@@ -4619,8 +4620,9 @@
         }
 
         if (pkgUid != uid) {
-            //TODO 195339480: replace true with debug
-            String otherUidMessage = true ? " but it is really " + pkgUid : " but it is not";
+            Slog.e(TAG, "Bad call made by uid " + callingUid + ". "
+                    + "Package \"" + packageName + "\" does not belong to uid " + uid + ".");
+            String otherUidMessage = DEBUG ? " but it is really " + pkgUid : " but it is not";
             throw new SecurityException("Specified package \"" + packageName + "\" under uid " + uid
                     + otherUidMessage);
         }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 1c4b9ce..289396e 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -244,7 +244,7 @@
      */
     private static final int FLAG_ADJUST_VOLUME = 1;
 
-    private final Context mContext;
+    final Context mContext;
     private final ContentResolver mContentResolver;
     private final AppOpsManager mAppOps;
 
@@ -319,6 +319,8 @@
     private static final int MSG_A2DP_DEV_CONFIG_CHANGE = 39;
     private static final int MSG_DISPATCH_AUDIO_MODE = 40;
     private static final int MSG_ROUTING_UPDATED = 41;
+    private static final int MSG_INIT_HEADTRACKING_SENSORS = 42;
+    private static final int MSG_PERSIST_SPATIAL_AUDIO_ENABLED = 43;
 
     // start of messages handled under wakelock
     //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
@@ -1039,12 +1041,13 @@
 
         mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
 
+        mHasSpatializerEffect = SystemProperties.getBoolean("ro.audio.spatializer_enabled", false);
+
         // done with service initialization, continue additional work in our Handler thread
         queueMsgUnderWakeLock(mAudioHandler, MSG_INIT_STREAMS_VOLUMES,
                 0 /* arg1 */,  0 /* arg2 */, null /* obj */,  0 /* delay */);
         queueMsgUnderWakeLock(mAudioHandler, MSG_INIT_SPATIALIZER,
-                0 /* arg1 */,  0 /* arg2 */, null /* obj */,  0 /* delay */);
-
+                0 /* arg1 */, 0 /* arg2 */, null /* obj */, 0 /* delay */);
     }
 
     /**
@@ -1238,6 +1241,9 @@
     // routing monitoring from AudioSystemAdapter
     @Override
     public void onRoutingUpdatedFromNative() {
+        if (!mHasSpatializerEffect) {
+            return;
+        }
         sendMsg(mAudioHandler,
                 MSG_ROUTING_UPDATED,
                 SENDMSG_REPLACE, 0, 0, null,
@@ -1434,8 +1440,10 @@
             }
         }
 
-        // TODO check property if feature enabled
-        mSpatializerHelper.reset(/* featureEnabled */ SPATIALIZER_FEATURE_ENABLED_DEFAULT);
+        if (mHasSpatializerEffect) {
+            mSpatializerHelper.reset(/* featureEnabled */ isSpatialAudioEnabled());
+            monitorRoutingChanges(true);
+        }
 
         onIndicateSystemReady();
         // indicate the end of reconfiguration phase to audio HAL
@@ -2628,18 +2636,19 @@
             case KeyEvent.KEYCODE_VOLUME_UP:
                     adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE,
                             AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller,
-                            Binder.getCallingUid(), true, keyEventMode);
+                            Binder.getCallingUid(), Binder.getCallingPid(), true, keyEventMode);
                 break;
             case KeyEvent.KEYCODE_VOLUME_DOWN:
                     adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER,
                             AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller,
-                            Binder.getCallingUid(), true, keyEventMode);
+                            Binder.getCallingUid(), Binder.getCallingPid(), true, keyEventMode);
                 break;
             case KeyEvent.KEYCODE_VOLUME_MUTE:
                 if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
                     adjustSuggestedStreamVolume(AudioManager.ADJUST_TOGGLE_MUTE,
                             AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller,
-                            Binder.getCallingUid(), true, VOL_ADJUST_NORMAL);
+                            Binder.getCallingUid(), Binder.getCallingPid(),
+                            true, VOL_ADJUST_NORMAL);
                 }
                 break;
             default:
@@ -2672,7 +2681,7 @@
 
     /** All callers come from platform apps/system server, so no attribution tag is needed */
     private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
-            String callingPackage, String caller, int uid, boolean hasModifyAudioSettings,
+            String callingPackage, String caller, int uid, int pid, boolean hasModifyAudioSettings,
             int keyEventMode) {
         if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
                 + ", flags=" + flags + ", caller=" + caller
@@ -2745,7 +2754,7 @@
             if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
         }
 
-        adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid,
+        adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid, pid,
                 null, hasModifyAudioSettings, keyEventMode);
     }
 
@@ -2783,12 +2792,12 @@
         sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_STREAM_VOL, streamType,
                 direction/*val1*/, flags/*val2*/, callingPackage));
         adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
-                Binder.getCallingUid(), attributionTag, callingHasAudioSettingsPermission(),
-                VOL_ADJUST_NORMAL);
+                Binder.getCallingUid(), Binder.getCallingPid(), attributionTag,
+                callingHasAudioSettingsPermission(), VOL_ADJUST_NORMAL);
     }
 
     protected void adjustStreamVolume(int streamType, int direction, int flags,
-            String callingPackage, String caller, int uid, String attributionTag,
+            String callingPackage, String caller, int uid, int pid, String attributionTag,
             boolean hasModifyAudioSettings, int keyEventMode) {
         if (mUseFixedVolume) {
             return;
@@ -2810,8 +2819,7 @@
         if (isMuteAdjust &&
             (streamType == AudioSystem.STREAM_VOICE_CALL ||
                 streamType == AudioSystem.STREAM_BLUETOOTH_SCO) &&
-            mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.MODIFY_PHONE_STATE)
+                mContext.checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, pid, uid)
                     != PackageManager.PERMISSION_GRANTED) {
             Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: adjustStreamVolume from pid="
                     + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
@@ -2821,8 +2829,8 @@
         // If the stream is STREAM_ASSISTANT,
         // make sure that the calling app have the MODIFY_AUDIO_ROUTING permission.
         if (streamType == AudioSystem.STREAM_ASSISTANT &&
-            mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+                mContext.checkPermission(
+                android.Manifest.permission.MODIFY_AUDIO_ROUTING, pid, uid)
                     != PackageManager.PERMISSION_GRANTED) {
             Log.w(TAG, "MODIFY_AUDIO_ROUTING Permission Denial: adjustStreamVolume from pid="
                     + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
@@ -3979,7 +3987,7 @@
     }
 
     private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid,
-            int userId, String attributionTag) {
+            int userId, int pid, String attributionTag) {
         // If we are being called by the system check for user we are going to change
         // so we handle user restrictions correctly.
         if (uid == android.os.Process.SYSTEM_UID) {
@@ -3991,8 +3999,8 @@
             return;
         }
         if (userId != UserHandle.getCallingUserId() &&
-                mContext.checkCallingOrSelfPermission(
-                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+                mContext.checkPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                        pid, uid)
                 != PackageManager.PERMISSION_GRANTED) {
             return;
         }
@@ -4033,7 +4041,7 @@
             String attributionTag) {
         enforceModifyAudioRoutingPermission();
         setMasterMuteInternal(mute, flags, callingPackage,
-                Binder.getCallingUid(), userId, attributionTag);
+                Binder.getCallingUid(), userId, Binder.getCallingPid(), attributionTag);
     }
 
     /** @see AudioManager#getStreamVolume(int) */
@@ -4936,8 +4944,8 @@
 
         // direction and stream type swap here because the public
         // adjustSuggested has a different order than the other methods.
-        adjustSuggestedStreamVolume(direction, streamType, flags, packageName, packageName, uid,
-                hasAudioSettingsPermission(uid, pid), VOL_ADJUST_NORMAL);
+        adjustSuggestedStreamVolume(direction, streamType, flags, packageName, packageName,
+                uid, pid, hasAudioSettingsPermission(uid, pid), VOL_ADJUST_NORMAL);
     }
 
     /** @see AudioManager#adjustStreamVolumeForUid(int, int, int, String, int, int, int) */
@@ -4956,7 +4964,7 @@
                     .toString()));
         }
 
-        adjustStreamVolume(streamType, direction, flags, packageName, packageName, uid,
+        adjustStreamVolume(streamType, direction, flags, packageName, packageName, uid, pid,
                 null, hasAudioSettingsPermission(uid, pid), VOL_ADJUST_NORMAL);
     }
 
@@ -7579,12 +7587,18 @@
                     break;
 
                 case MSG_INIT_SPATIALIZER:
-                    mSpatializerHelper.init();
-                    // TODO read property to see if enabled
-                    mSpatializerHelper.setFeatureEnabled(SPATIALIZER_FEATURE_ENABLED_DEFAULT);
+                    mSpatializerHelper.init(/*effectExpected*/ mHasSpatializerEffect);
+                    if (mHasSpatializerEffect) {
+                        mSpatializerHelper.setFeatureEnabled(isSpatialAudioEnabled());
+                        monitorRoutingChanges(true);
+                    }
                     mAudioEventWakeLock.release();
                     break;
 
+                case MSG_INIT_HEADTRACKING_SENSORS:
+                    mSpatializerHelper.onInitSensors(/*init*/ msg.arg1 == 1);
+                    break;
+
                 case MSG_CHECK_MUSIC_ACTIVE:
                     onCheckMusicActive((String) msg.obj);
                     break;
@@ -7721,6 +7735,10 @@
                 case MSG_ROUTING_UPDATED:
                     mSpatializerHelper.onRoutingUpdated();
                     break;
+
+                case MSG_PERSIST_SPATIAL_AUDIO_ENABLED:
+                    onPersistSpatialAudioEnabled(msg.arg1 == 1);
+                    break;
             }
         }
     }
@@ -8290,7 +8308,40 @@
 
     //==========================================================================================
     private final @NonNull SpatializerHelper mSpatializerHelper;
-    private static final boolean SPATIALIZER_FEATURE_ENABLED_DEFAULT = false;
+    /**
+     * Initialized from property ro.audio.spatializer_enabled
+     * Should only be 1 when the device ships with a Spatializer effect
+     */
+    private final boolean mHasSpatializerEffect;
+    /**
+     * Default value for the spatial audio feature
+     */
+    private static final boolean SPATIAL_AUDIO_ENABLED_DEFAULT = true;
+
+    /**
+     * persist in user settings whether the feature is enabled.
+     * Can change when {@link Spatializer#setEnabled(boolean)} is called and successfully
+     * changes the state of the feature
+     * @param featureEnabled
+     */
+    void persistSpatialAudioEnabled(boolean featureEnabled) {
+        sendMsg(mAudioHandler,
+                MSG_PERSIST_SPATIAL_AUDIO_ENABLED,
+                SENDMSG_REPLACE, featureEnabled ? 1 : 0, 0, null,
+                /*delay ms*/ 100);
+    }
+
+    void onPersistSpatialAudioEnabled(boolean enabled) {
+        Settings.Secure.putIntForUser(mContentResolver,
+                Settings.Secure.SPATIAL_AUDIO_ENABLED, enabled ? 1 : 0,
+                UserHandle.USER_CURRENT);
+    }
+
+    boolean isSpatialAudioEnabled() {
+        return Settings.Secure.getIntForUser(mContentResolver,
+                Settings.Secure.SPATIAL_AUDIO_ENABLED, SPATIAL_AUDIO_ENABLED_DEFAULT ? 1 : 0,
+                UserHandle.USER_CURRENT) == 1;
+    }
 
     private void enforceModifyDefaultAudioEffectsPermission() {
         if (mContext.checkCallingOrSelfPermission(
@@ -8457,6 +8508,18 @@
         mSpatializerHelper.getEffectParameter(key, value);
     }
 
+    /**
+     * post a message to schedule init/release of head tracking sensors
+     * @param init initialization if true, release if false
+     */
+    void postInitSpatializerHeadTrackingSensors(boolean init) {
+        sendMsg(mAudioHandler,
+                MSG_INIT_HEADTRACKING_SENSORS,
+                SENDMSG_REPLACE,
+                /*arg1*/ init ? 1 : 0,
+                0, TAG, /*delay*/ 0);
+    }
+
     //==========================================================================================
     private boolean readCameraSoundForced() {
         return SystemProperties.getBoolean("audio.camerasound.force", false) ||
@@ -8797,7 +8860,7 @@
         updateDefaultStreamOverrideDelay(accessibilityManager.isTouchExplorationEnabled());
         updateA11yVolumeAlias(accessibilityManager.isAccessibilityVolumeStreamActive());
         accessibilityManager.addTouchExplorationStateChangeListener(this, null);
-        accessibilityManager.addAccessibilityServicesStateChangeListener(this, null);
+        accessibilityManager.addAccessibilityServicesStateChangeListener(this);
     }
 
     //---------------------------------------------------------------------------------
@@ -9037,6 +9100,12 @@
         sVolumeLogger.dump(pw);
         pw.println("\n");
         dumpSupportedSystemUsage(pw);
+
+        pw.println("\n");
+        pw.println("\nSpatial audio:");
+        pw.println("mHasSpatializerEffect:" + mHasSpatializerEffect);
+        pw.println("isSpatializerEnabled:" + isSpatializerEnabled());
+        pw.println("isSpatialAudioEnabled:" + isSpatialAudioEnabled());
     }
 
     private void dumpSupportedSystemUsage(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/audio/FadeOutManager.java b/services/core/java/com/android/server/audio/FadeOutManager.java
index bb627e5..00cb280 100644
--- a/services/core/java/com/android/server/audio/FadeOutManager.java
+++ b/services/core/java/com/android/server/audio/FadeOutManager.java
@@ -36,7 +36,16 @@
 
     public static final String TAG = "AudioService.FadeOutManager";
 
+    /** duration of the fade out curve */
     /*package*/ static final long FADE_OUT_DURATION_MS = 2000;
+    /**
+     * delay after which a faded out player will be faded back in. This will be heard by the user
+     * only in the case of unmuting players that didn't respect audio focus and didn't stop/pause
+     * when their app lost focus.
+     * This is the amount of time between the app being notified of
+     * the focus loss (when its muted by the fade out), and the time fade in (to unmute) starts
+     */
+    /*package*/ static final long DELAY_FADE_IN_OFFENDERS_MS = 2000;
 
     private static final boolean DEBUG = PlaybackActivityMonitor.DEBUG;
 
@@ -148,6 +157,11 @@
         }
     }
 
+    /**
+     * Remove the app for the given UID from the list of faded out apps, unfade out its players
+     * @param uid the uid for the app to unfade out
+     * @param players map of current available players (so we can get an APC from piid)
+     */
     synchronized void unfadeOutUid(int uid, HashMap<Integer, AudioPlaybackConfiguration> players) {
         Log.i(TAG, "unfadeOutUid() uid:" + uid);
         final FadedOutApp fa = mFadedApps.remove(uid);
@@ -157,12 +171,6 @@
         fa.removeUnfadeAll(players);
     }
 
-    synchronized void forgetUid(int uid) {
-        //Log.v(TAG, "forget() uid:" + uid);
-        //mFadedApps.remove(uid);
-        // TODO unfade all players later in case they are reused or the app continued to play
-    }
-
     // pre-condition: apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
     //   see {@link PlaybackActivityMonitor#playerEvent}
     synchronized void checkFade(@NonNull AudioPlaybackConfiguration apc) {
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index 6fe1295..bf49ac8 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -131,6 +131,11 @@
     @Override
     public void restoreVShapedPlayers(@NonNull FocusRequester winner) {
         mFocusEnforcer.restoreVShapedPlayers(winner);
+        // remove scheduled events to unfade out offending players (if any) corresponding to
+        // this uid, as we're removing any effects of muting/ducking/fade out now
+        mFocusHandler.removeEqualMessages(MSL_L_FORGET_UID,
+                new ForgetFadeUidInfo(winner.getClientUid()));
+
     }
 
     @Override
@@ -1183,6 +1188,13 @@
                 mFocusHandler.obtainMessage(MSG_L_FOCUS_LOSS_AFTER_FADE, focusLoser),
                 FadeOutManager.FADE_OUT_DURATION_MS);
     }
+
+    private void postForgetUidLater(int uid) {
+        mFocusHandler.sendMessageDelayed(
+                mFocusHandler.obtainMessage(MSL_L_FORGET_UID, new ForgetFadeUidInfo(uid)),
+                FadeOutManager.DELAY_FADE_IN_OFFENDERS_MS);
+    }
+
     //=================================================================
     // Message handling
     private Handler mFocusHandler;
@@ -1197,6 +1209,8 @@
      */
     private static final int MSG_L_FOCUS_LOSS_AFTER_FADE = 1;
 
+    private static final int MSL_L_FORGET_UID = 2;
+
     private void initFocusThreading() {
         mFocusThread = new HandlerThread(TAG);
         mFocusThread.start();
@@ -1214,15 +1228,56 @@
                             if (loser.isInFocusLossLimbo()) {
                                 loser.dispatchFocusChange(AudioManager.AUDIOFOCUS_LOSS);
                                 loser.release();
-                                mFocusEnforcer.forgetUid(loser.getClientUid());
+                                postForgetUidLater(loser.getClientUid());
                             }
                         }
                         break;
+
+                    case MSL_L_FORGET_UID:
+                        final int uid = ((ForgetFadeUidInfo) msg.obj).mUid;
+                        if (DEBUG) {
+                            Log.d(TAG, "MSL_L_FORGET_UID uid=" + uid);
+                        }
+                        mFocusEnforcer.forgetUid(uid);
+                        break;
                     default:
                         break;
                 }
             }
         };
+    }
 
+    /**
+     * Class to associate a UID with a scheduled event to "forget" a UID for the fade out behavior.
+     * Having a class with an equals() override allows using Handler.removeEqualsMessage() to
+     * unschedule events when needed. Here we need to unschedule the "unfading out" == "forget uid"
+     * whenever a new, more recent, focus related event happens before this one is handled.
+     */
+    private static final class ForgetFadeUidInfo {
+        private final int mUid;
+
+        ForgetFadeUidInfo(int uid) {
+            mUid = uid;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            final ForgetFadeUidInfo f = (ForgetFadeUidInfo) o;
+            if (f.mUid != mUid) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            return mUid;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index a13b2eb..b94cea4 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -747,7 +747,11 @@
 
     @Override
     public void forgetUid(int uid) {
-        mFadingManager.forgetUid(uid);
+        final HashMap<Integer, AudioPlaybackConfiguration> players;
+        synchronized (mPlayerLock) {
+            players = (HashMap<Integer, AudioPlaybackConfiguration>) mPlayers.clone();
+        }
+        mFadingManager.unfadeOutUid(uid, players);
     }
 
     //=================================================================
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index ccaa96d..b2fa86b 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -18,6 +18,9 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
 import android.media.AudioAttributes;
 import android.media.AudioDeviceAttributes;
 import android.media.AudioFormat;
@@ -28,6 +31,7 @@
 import android.media.ISpatializerHeadToSoundStagePoseCallback;
 import android.media.ISpatializerHeadTrackingCallback;
 import android.media.ISpatializerHeadTrackingModeCallback;
+import android.media.SpatializationLevel;
 import android.media.Spatializer;
 import android.media.SpatializerHeadTrackingMode;
 import android.os.RemoteCallbackList;
@@ -45,6 +49,7 @@
 
     private static final String TAG = "AS.SpatializerHelper";
     private static final boolean DEBUG = true;
+    private static final boolean DEBUG_MORE = false;
 
     private static void logd(String s) {
         if (DEBUG) {
@@ -54,6 +59,7 @@
 
     private final @NonNull AudioSystemAdapter mASA;
     private final @NonNull AudioService mAudioService;
+    private @Nullable SensorManager mSensorManager;
 
     //------------------------------------------------------------
     // Spatializer state machine
@@ -100,8 +106,13 @@
         mASA = asa;
     }
 
-    synchronized void init() {
+    synchronized void init(boolean effectExpected) {
         Log.i(TAG, "Initializing");
+        if (!effectExpected) {
+            Log.i(TAG, "Setting state to STATE_NOT_SUPPORTED due to effect not expected");
+            mState = STATE_NOT_SUPPORTED;
+            return;
+        }
         if (mState != STATE_UNINITIALIZED) {
             throw new IllegalStateException(("init() called in state:" + mState));
         }
@@ -127,7 +138,7 @@
             for (byte level : levels) {
                 logd("found support for level: " + level);
                 if (level == Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL) {
-                    logd("Setting Spatializer to LEVEL_MULTICHANNEL");
+                    logd("Setting capable level to LEVEL_MULTICHANNEL");
                     mCapableSpatLevel = level;
                     break;
                 }
@@ -159,7 +170,7 @@
         mSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
         mCapableSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
         mActualHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED;
-        init();
+        init(true);
         setFeatureEnabled(featureEnabled);
     }
 
@@ -191,9 +202,16 @@
         public void onLevelChanged(byte level) {
             logd("SpatializerCallback.onLevelChanged level:" + level);
             synchronized (SpatializerHelper.this) {
-                mSpatLevel = level;
+                mSpatLevel = spatializationLevelToSpatializerInt(level);
             }
             // TODO use reported spat level to change state
+
+            // init sensors
+            if (level == SpatializationLevel.NONE) {
+                initSensors(/*init*/false);
+            } else {
+                postInitSensors(true);
+            }
         }
     };
 
@@ -224,7 +242,7 @@
                         + " invalid transform length" + headToStage.length);
                 return;
             }
-            if (DEBUG) {
+            if (DEBUG_MORE) {
                 // 6 values * (4 digits + 1 dot + 2 brackets) = 42 characters
                 StringBuilder t = new StringBuilder(42);
                 for (float val : headToStage) {
@@ -378,7 +396,7 @@
             }
         }
         mStateCallbacks.finishBroadcast();
-        // TODO persist enabled state
+        mAudioService.persistSpatialAudioEnabled(featureEnabled);
     }
 
     private synchronized void setDispatchAvailableState(boolean available) {
@@ -641,36 +659,6 @@
         }
     }
 
-    private int headTrackingModeTypeToSpatializerInt(byte mode) {
-        switch (mode) {
-            case SpatializerHeadTrackingMode.OTHER:
-                return Spatializer.HEAD_TRACKING_MODE_OTHER;
-            case SpatializerHeadTrackingMode.DISABLED:
-                return Spatializer.HEAD_TRACKING_MODE_DISABLED;
-            case SpatializerHeadTrackingMode.RELATIVE_WORLD:
-                return Spatializer.HEAD_TRACKING_MODE_RELATIVE_WORLD;
-            case SpatializerHeadTrackingMode.RELATIVE_SCREEN:
-                return Spatializer.HEAD_TRACKING_MODE_RELATIVE_DEVICE;
-            default:
-                throw(new IllegalArgumentException("Unexpected head tracking mode:" + mode));
-        }
-    }
-
-    private byte spatializerIntToHeadTrackingModeType(int sdkMode) {
-        switch (sdkMode) {
-            case Spatializer.HEAD_TRACKING_MODE_OTHER:
-                return SpatializerHeadTrackingMode.OTHER;
-            case Spatializer.HEAD_TRACKING_MODE_DISABLED:
-                return SpatializerHeadTrackingMode.DISABLED;
-            case Spatializer.HEAD_TRACKING_MODE_RELATIVE_WORLD:
-                return SpatializerHeadTrackingMode.RELATIVE_WORLD;
-            case Spatializer.HEAD_TRACKING_MODE_RELATIVE_DEVICE:
-                return SpatializerHeadTrackingMode.RELATIVE_SCREEN;
-            default:
-                throw(new IllegalArgumentException("Unexpected head tracking mode:" + sdkMode));
-        }
-    }
-
     private boolean checkSpatForHeadTracking(String funcName) {
         switch (mState) {
             case STATE_UNINITIALIZED:
@@ -792,4 +780,101 @@
             Log.e(TAG, "Error in getParameter for key:" + key, e);
         }
     }
+
+    //------------------------------------------------------
+    // sensors
+    private void initSensors(boolean init) {
+        if (mSensorManager == null) {
+            mSensorManager = (SensorManager)
+                    mAudioService.mContext.getSystemService(Context.SENSOR_SERVICE);
+        }
+        final int headHandle;
+        final int screenHandle;
+        if (init) {
+            if (mSensorManager == null) {
+                Log.e(TAG, "Null SensorManager, can't init sensors");
+                return;
+            }
+            // TODO replace with dynamic association of sensor for headtracker
+            Sensor headSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR);
+            headHandle = headSensor.getHandle();
+            //Sensor screenSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
+            //screenHandle = deviceSensor.getHandle();
+            screenHandle = -1;
+        } else {
+            // -1 is disable value
+            screenHandle = -1;
+            headHandle = -1;
+        }
+        try {
+            Log.i(TAG, "setScreenSensor:" + screenHandle);
+            mSpat.setScreenSensor(screenHandle);
+        } catch (Exception e) {
+            Log.e(TAG, "Error calling setScreenSensor:" + screenHandle, e);
+        }
+        try {
+            Log.i(TAG, "setHeadSensor:" + headHandle);
+            mSpat.setHeadSensor(headHandle);
+        } catch (Exception e) {
+            Log.e(TAG, "Error calling setHeadSensor:" + headHandle, e);
+        }
+    }
+
+    private void postInitSensors(boolean init) {
+        mAudioService.postInitSpatializerHeadTrackingSensors(init);
+    }
+
+    synchronized void onInitSensors(boolean init) {
+        final int[] modes = getSupportedHeadTrackingModes();
+        if (modes.length == 0) {
+            Log.i(TAG, "not initializing sensors, no headtracking supported");
+            return;
+        }
+        initSensors(init);
+    }
+
+    //------------------------------------------------------
+    // SDK <-> AIDL converters
+    private static int headTrackingModeTypeToSpatializerInt(byte mode) {
+        switch (mode) {
+            case SpatializerHeadTrackingMode.OTHER:
+                return Spatializer.HEAD_TRACKING_MODE_OTHER;
+            case SpatializerHeadTrackingMode.DISABLED:
+                return Spatializer.HEAD_TRACKING_MODE_DISABLED;
+            case SpatializerHeadTrackingMode.RELATIVE_WORLD:
+                return Spatializer.HEAD_TRACKING_MODE_RELATIVE_WORLD;
+            case SpatializerHeadTrackingMode.RELATIVE_SCREEN:
+                return Spatializer.HEAD_TRACKING_MODE_RELATIVE_DEVICE;
+            default:
+                throw(new IllegalArgumentException("Unexpected head tracking mode:" + mode));
+        }
+    }
+
+    private static byte spatializerIntToHeadTrackingModeType(int sdkMode) {
+        switch (sdkMode) {
+            case Spatializer.HEAD_TRACKING_MODE_OTHER:
+                return SpatializerHeadTrackingMode.OTHER;
+            case Spatializer.HEAD_TRACKING_MODE_DISABLED:
+                return SpatializerHeadTrackingMode.DISABLED;
+            case Spatializer.HEAD_TRACKING_MODE_RELATIVE_WORLD:
+                return SpatializerHeadTrackingMode.RELATIVE_WORLD;
+            case Spatializer.HEAD_TRACKING_MODE_RELATIVE_DEVICE:
+                return SpatializerHeadTrackingMode.RELATIVE_SCREEN;
+            default:
+                throw(new IllegalArgumentException("Unexpected head tracking mode:" + sdkMode));
+        }
+    }
+
+    private static int spatializationLevelToSpatializerInt(byte level) {
+        switch (level) {
+            case SpatializationLevel.NONE:
+                return Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
+            case SpatializationLevel.SPATIALIZER_MULTICHANNEL:
+                return Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL;
+            case SpatializationLevel.SPATIALIZER_MCHAN_BED_PLUS_OBJECTS:
+                return Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_MCHAN_BED_PLUS_OBJECTS;
+            default:
+                throw(new IllegalArgumentException("Unexpected spatializer level:" + level));
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java
index a81213d..11dc1db 100644
--- a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java
+++ b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java
@@ -175,29 +175,25 @@
 
     /**
      * Parses the given {@code configStr}, that is expected to be a comma separated list of changes
-     * overrides, and returns a {@link PackageOverrides}.
+     * overrides, and returns a map from change ID to {@link PackageOverride} instances to add.
      *
      * <p>Each change override is in the following format:
-     * '<change-id>:<min-version-code?>:<max-version-code?>:<enabled?>'. If <enabled> is empty,
-     * this indicates that any override for the specified change ID should be removed.
+     * '<change-id>:<min-version-code?>:<max-version-code?>:<enabled>'.
      *
      * <p>If there are multiple overrides that should be added with the same change ID, the one
      * that best fits the given {@code versionCode} is added.
      *
      * <p>Any overrides whose change ID is in {@code changeIdsToSkip} are ignored.
      *
-     * <p>If a change override entry in {@code configStr} is invalid, it will be ignored. If the
-     * same change ID is both added and removed, i.e., has a change override entry with an empty
-     * enabled and another with a non-empty enabled, the change ID will only be removed.
+     * <p>If a change override entry in {@code configStr} is invalid, it will be ignored.
      */
-    static PackageOverrides parsePackageOverrides(
-            String configStr, long versionCode, Set<Long> changeIdsToSkip) {
+    static Map<Long, PackageOverride> parsePackageOverrides(String configStr, long versionCode,
+            Set<Long> changeIdsToSkip) {
         if (configStr.isEmpty()) {
-            return new PackageOverrides();
+            return emptyMap();
         }
         PackageOverrideComparator comparator = new PackageOverrideComparator(versionCode);
         Map<Long, PackageOverride> overridesToAdd = new ArrayMap<>();
-        Set<Long> overridesToRemove = new ArraySet<>();
         for (String overrideEntryString : configStr.split(",")) {
             List<String> changeIdAndVersions = Arrays.asList(overrideEntryString.split(":", 4));
             if (changeIdAndVersions.size() != 4) {
@@ -220,16 +216,6 @@
             String maxVersionCodeStr = changeIdAndVersions.get(2);
 
             String enabledStr = changeIdAndVersions.get(3);
-            if (enabledStr.isEmpty()) {
-                if (!minVersionCodeStr.isEmpty() || !maxVersionCodeStr.isEmpty()) {
-                    Slog.w(
-                            TAG,
-                            "min/max version code should be empty if enabled is empty: "
-                                    + overrideEntryString);
-                }
-                overridesToRemove.add(changeId);
-                continue;
-            }
             if (!BOOLEAN_PATTERN.matcher(enabledStr).matches()) {
                 Slog.w(TAG, "Invalid enabled string in override entry: " + overrideEntryString);
                 continue;
@@ -262,39 +248,7 @@
             }
         }
 
-        for (Long changeId : overridesToRemove) {
-            if (overridesToAdd.containsKey(changeId)) {
-                Slog.w(
-                        TAG,
-                        "Change ID ["
-                                + changeId
-                                + "] is both added and removed in package override flag: "
-                                + configStr);
-                overridesToAdd.remove(changeId);
-            }
-        }
-
-        return new PackageOverrides(overridesToAdd, overridesToRemove);
-    }
-
-    /**
-     * A container for a map from change ID to {@link PackageOverride} to add and a set of change
-     * IDs to remove overrides for.
-     *
-     * <p>The map of overrides to add and the set of overrides to remove are mutually exclusive.
-     */
-    static final class PackageOverrides {
-        public final Map<Long, PackageOverride> overridesToAdd;
-        public final Set<Long> overridesToRemove;
-
-        PackageOverrides() {
-            this(emptyMap(), emptySet());
-        }
-
-        PackageOverrides(Map<Long, PackageOverride> overridesToAdd, Set<Long> overridesToRemove) {
-            this.overridesToAdd = overridesToAdd;
-            this.overridesToRemove = overridesToRemove;
-        }
+        return overridesToAdd;
     }
 
     /**
diff --git a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
index 63ae1af..6aed4b0 100644
--- a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
+++ b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
@@ -49,7 +49,6 @@
 import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
 import com.android.internal.compat.IPlatformCompat;
 import com.android.server.SystemService;
-import com.android.server.compat.overrides.AppCompatOverridesParser.PackageOverrides;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -128,20 +127,25 @@
     }
 
     /**
-     * Same as {@link #applyOverrides(Properties, Map)} except all properties of the given {@code
-     * namespace} are fetched via {@link DeviceConfig#getProperties}.
+     * Same as {@link #applyOverrides(Properties, Set, Map)} except all properties of the given
+     * {@code namespace} are fetched via {@link DeviceConfig#getProperties}.
      */
-    private void applyAllOverrides(String namespace,
+    private void applyAllOverrides(String namespace, Set<Long> ownedChangeIds,
             Map<String, Set<Long>> packageToChangeIdsToSkip) {
-        applyOverrides(DeviceConfig.getProperties(namespace), packageToChangeIdsToSkip);
+        applyOverrides(DeviceConfig.getProperties(namespace), ownedChangeIds,
+                packageToChangeIdsToSkip);
     }
 
     /**
      * Iterates all package override flags in the given {@code properties}, and for each flag whose
-     * package is installed on the device, parses its value and applies the overrides in it with
+     * package is installed on the device, parses its value and adds the overrides in it with
      * respect to the package's current installed version.
+     *
+     * <p>In addition, for each package, removes any override that wasn't just added, whose change
+     * ID is in {@code ownedChangeIds} but not in the respective set in {@code
+     * packageToChangeIdsToSkip}.
      */
-    private void applyOverrides(Properties properties,
+    private void applyOverrides(Properties properties, Set<Long> ownedChangeIds,
             Map<String, Set<Long>> packageToChangeIdsToSkip) {
         Set<String> packageNames = new ArraySet<>(properties.getKeyset());
         packageNames.remove(FLAG_OWNED_CHANGE_IDS);
@@ -154,15 +158,16 @@
             }
 
             applyPackageOverrides(properties.getString(packageName, /* defaultValue= */ ""),
-                    packageName, versionCode,
-                    packageToChangeIdsToSkip.getOrDefault(packageName, emptySet()));
+                    packageName, versionCode, ownedChangeIds,
+                    packageToChangeIdsToSkip.getOrDefault(packageName, emptySet()),
+                    /* removeOtherOwnedOverrides= */ true);
         }
     }
 
     /**
-     * Applies all overrides in all supported namespaces for the given {@code packageName}.
+     * Adds all overrides in all supported namespaces for the given {@code packageName}.
      */
-    private void applyAllPackageOverrides(String packageName) {
+    private void addAllPackageOverrides(String packageName) {
         Long versionCode = getVersionCodeOrNull(packageName);
         if (versionCode == null) {
             return;
@@ -171,26 +176,40 @@
         for (String namespace : mSupportedNamespaces) {
             // We apply overrides for each namespace separately so that if there is a failure for
             // one namespace, the other namespaces won't be affected.
+            Set<Long> ownedChangeIds = getOwnedChangeIds(namespace);
             applyPackageOverrides(
                     DeviceConfig.getString(namespace, packageName, /* defaultValue= */ ""),
-                    packageName, versionCode,
-                    getOverridesToRemove(namespace).getOrDefault(packageName, emptySet()));
+                    packageName, versionCode, ownedChangeIds,
+                    getOverridesToRemove(namespace, ownedChangeIds).getOrDefault(packageName,
+                            emptySet()), /* removeOtherOwnedOverrides */ false);
         }
     }
 
     /**
-     * Calls {@link AppCompatOverridesParser#parsePackageOverrides} on the given arguments, adds the
-     * resulting {@link PackageOverrides#overridesToAdd} via {@link
-     * IPlatformCompat#putOverridesOnReleaseBuilds}, and removes the resulting {@link
-     * PackageOverrides#overridesToRemove} via {@link
-     * IPlatformCompat#removeOverridesOnReleaseBuilds}.
+     * Calls {@link AppCompatOverridesParser#parsePackageOverrides} on the given arguments and adds
+     * the resulting overrides via {@link IPlatformCompat#putOverridesOnReleaseBuilds}.
+     *
+     * <p>In addition, if {@code removeOtherOwnedOverrides} is true, removes any override that
+     * wasn't just added, whose change ID is in {@code ownedChangeIds} but not in {@code
+     * changeIdsToSkip}, via {@link IPlatformCompat#removeOverridesOnReleaseBuilds}.
      */
-    private void applyPackageOverrides(String configStr, String packageName,
-            long versionCode, Set<Long> changeIdsToSkip) {
-        PackageOverrides packageOverrides = AppCompatOverridesParser.parsePackageOverrides(
+    private void applyPackageOverrides(String configStr, String packageName, long versionCode,
+            Set<Long> ownedChangeIds, Set<Long> changeIdsToSkip,
+            boolean removeOtherOwnedOverrides) {
+        Map<Long, PackageOverride> overridesToAdd = AppCompatOverridesParser.parsePackageOverrides(
                 configStr, versionCode, changeIdsToSkip);
-        putPackageOverrides(packageName, packageOverrides.overridesToAdd);
-        removePackageOverrides(packageName, packageOverrides.overridesToRemove);
+        putPackageOverrides(packageName, overridesToAdd);
+
+        if (!removeOtherOwnedOverrides) {
+            return;
+        }
+        Set<Long> overridesToRemove = new ArraySet<>();
+        for (Long changeId : ownedChangeIds) {
+            if (!overridesToAdd.containsKey(changeId) && !changeIdsToSkip.contains(changeId)) {
+                overridesToRemove.add(changeId);
+            }
+        }
+        removePackageOverrides(packageName, overridesToRemove);
     }
 
     /**
@@ -227,10 +246,11 @@
      * {@code namespace} and parses it into a map from package name to a set of change IDs to
      * remove for that package.
      */
-    private Map<String, Set<Long>> getOverridesToRemove(String namespace) {
+    private Map<String, Set<Long>> getOverridesToRemove(String namespace,
+            Set<Long> ownedChangeIds) {
         return mOverridesParser.parseRemoveOverrides(
                 DeviceConfig.getString(namespace, FLAG_REMOVE_OVERRIDES, /* defaultValue= */ ""),
-                getOwnedChangeIds(namespace));
+                ownedChangeIds);
     }
 
     /**
@@ -333,7 +353,9 @@
             boolean ownedChangedIdsFlagChanged = properties.getKeyset().contains(
                     FLAG_OWNED_CHANGE_IDS);
 
-            Map<String, Set<Long>> overridesToRemove = getOverridesToRemove(mNamespace);
+            Set<Long> ownedChangeIds = getOwnedChangeIds(mNamespace);
+            Map<String, Set<Long>> overridesToRemove = getOverridesToRemove(mNamespace,
+                    ownedChangeIds);
             if (removeOverridesFlagChanged || ownedChangedIdsFlagChanged) {
                 // In both cases it's possible that overrides that weren't removed before should
                 // now be removed.
@@ -343,9 +365,9 @@
             if (removeOverridesFlagChanged) {
                 // We need to re-apply all overrides in the namespace since the remove overrides
                 // flag might have blocked some of them from being applied before.
-                applyAllOverrides(mNamespace, overridesToRemove);
+                applyAllOverrides(mNamespace, ownedChangeIds, overridesToRemove);
             } else {
-                applyOverrides(properties, overridesToRemove);
+                applyOverrides(properties, ownedChangeIds, overridesToRemove);
             }
         }
     }
@@ -392,7 +414,7 @@
             switch (action) {
                 case ACTION_PACKAGE_ADDED:
                 case ACTION_PACKAGE_CHANGED:
-                    applyAllPackageOverrides(packageName);
+                    addAllPackageOverrides(packageName);
                     break;
                 case ACTION_PACKAGE_REMOVED:
                     if (!isInstalledForAnyUser(packageName)) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index abbe13a..1063481 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -721,13 +721,13 @@
         final IBinder token = device.getDisplayTokenLocked();
         final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
         mHandler.post(() -> {
-            if (mDisplayDevice == device) {
-                return;
+            if (mDisplayDevice != device) {
+                mDisplayDevice = device;
+                mUniqueDisplayId = uniqueId;
+                mDisplayDeviceConfig = config;
+                loadFromDisplayDeviceConfig(token, info);
+                updatePowerState();
             }
-            mDisplayDevice = device;
-            mUniqueDisplayId = uniqueId;
-            mDisplayDeviceConfig = config;
-            loadFromDisplayDeviceConfig(token, info);
         });
     }
 
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 973dcc4..0fbc3e8 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -22,6 +22,8 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PowerManager;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.text.TextUtils;
 import android.util.ArraySet;
@@ -69,7 +71,7 @@
     public static final int DISPLAY_GROUP_EVENT_CHANGED = 2;
     public static final int DISPLAY_GROUP_EVENT_REMOVED = 3;
 
-    private static final int TIMEOUT_STATE_TRANSITION_MILLIS = 500;
+    private static final int TIMEOUT_STATE_TRANSITION_MILLIS = 300;
 
     private static final int MSG_TRANSITION_TO_PENDING_DEVICE_STATE = 1;
 
@@ -98,6 +100,11 @@
     private final boolean mSupportsConcurrentInternalDisplays;
 
     /**
+     * Wake the device when transitioning into this device state.
+     */
+    private final int mDeviceStateOnWhichToWakeUp;
+
+    /**
      * Map of all logical displays indexed by logical display id.
      * Any modification to mLogicalDisplays must invalidate the DisplayManagerGlobal cache.
      * TODO: multi-display - Move the aforementioned comment?
@@ -113,6 +120,7 @@
     private final Listener mListener;
     private final DisplayManagerService.SyncRoot mSyncRoot;
     private final LogicalDisplayMapperHandler mHandler;
+    private final PowerManager mPowerManager;
 
     /**
      * Has an entry for every logical display that the rest of the system has been notified about.
@@ -150,12 +158,15 @@
             @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot,
             @NonNull Handler handler) {
         mSyncRoot = syncRoot;
+        mPowerManager = context.getSystemService(PowerManager.class);
         mHandler = new LogicalDisplayMapperHandler(handler.getLooper());
         mDisplayDeviceRepo = repo;
         mListener = listener;
         mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
         mSupportsConcurrentInternalDisplays = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_supportsConcurrentInternalDisplays);
+        mDeviceStateOnWhichToWakeUp = context.getResources().getInteger(
+                com.android.internal.R.integer.config_deviceStateOnWhichToWakeUp);
         mDisplayDeviceRepo.addListener(this);
         mDeviceStateToLayoutMap = new DeviceStateToLayoutMap();
     }
@@ -318,6 +329,7 @@
 
         ipw.println("mSingleDisplayDemoMode=" + mSingleDisplayDemoMode);
         ipw.println("mCurrentLayout=" + mCurrentLayout);
+        ipw.println("mDeviceStateOnWhichToWakeUp=" + mDeviceStateOnWhichToWakeUp);
 
         final int logicalDisplayCount = mLogicalDisplays.size();
         ipw.println();
@@ -335,7 +347,9 @@
     }
 
     void setDeviceStateLocked(int state) {
-        Slog.i(TAG, "Requesting Transition to state: " + state);
+        final boolean isInteractive  = mPowerManager.isInteractive();
+        Slog.i(TAG, "Requesting Transition to state: " + state + ", from state=" + mDeviceState
+                + ", interactive=" + isInteractive);
         // As part of a state transition, we may need to turn off some displays temporarily so that
         // the transition is smooth. Plus, on some devices, only one internal displays can be
         // on at a time. We use DISPLAY_PHASE_LAYOUT_TRANSITION to mark a display that needs to be
@@ -344,8 +358,13 @@
             resetLayoutLocked(mDeviceState, state, LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION);
         }
         mPendingDeviceState = state;
-        if (areAllTransitioningDisplaysOffLocked()) {
-            // Nothing to wait on, we're good to go
+        final boolean wakeDevice = mPendingDeviceState == mDeviceStateOnWhichToWakeUp
+                && !isInteractive;
+
+        // If all displays are off already, we can just transition here, unless the device is asleep
+        // and we plan on waking it up. In that case, fall through to the call to wakeUp, and defer
+        // the final transition until later once the device is awake.
+        if (areAllTransitioningDisplaysOffLocked() && !wakeDevice) {
             transitionToPendingStateLocked();
             return;
         }
@@ -356,6 +375,14 @@
         // Send the transitioning phase updates to DisplayManager so that the displays can
         // start turning OFF in preparation for the new layout.
         updateLogicalDisplaysLocked();
+
+        if (wakeDevice) {
+            // We already told the displays to turn off, now we need to wake the device as
+            // we transition to this new state. We do it here so that the waking happens between the
+            // transition from one layout to another.
+            mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_UNFOLD_DEVICE,
+                    "server.display:unfold");
+        }
         mHandler.sendEmptyMessageDelayed(MSG_TRANSITION_TO_PENDING_DEVICE_STATE,
                 TIMEOUT_STATE_TRANSITION_MILLIS);
     }
@@ -482,6 +509,7 @@
                 assignDisplayGroupLocked(display);
                 mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED);
 
+            // The display is involved in a display layout transition
             } else if (updateState == UPDATE_STATE_TRANSITION) {
                 mLogicalDisplaysToUpdate.put(displayId,
                         LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION);
@@ -672,14 +700,14 @@
 
             // We consider a display-device as changing/transition if
             // 1) It's already marked as transitioning
-            // 2) It's going from enabled to disabled
+            // 2) It's going from enabled to disabled, or vice versa
             // 3) It's enabled, but it's mapped to a new logical display ID. To the user this
             //    would look like apps moving from one screen to another since task-stacks stay
             //    with the logical display [ID].
             final boolean isTransitioning =
                     (logicalDisplay.getPhase() == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION)
-                    || (wasEnabled && !willBeEnabled)
-                    || (wasEnabled && deviceHasNewLogicalDisplayId);
+                    || (wasEnabled != willBeEnabled)
+                    || deviceHasNewLogicalDisplayId;
 
             if (isTransitioning) {
                 setDisplayPhase(logicalDisplay, phase);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index 5802e53..8a727c6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -254,7 +254,7 @@
         mValidationInfo.append(opcode, new ValidationInfo(validator, addrType));
     }
 
-    int isValid(HdmiCecMessage message) {
+    int isValid(HdmiCecMessage message, boolean isMessageReceived) {
         int opcode = message.getOpcode();
         ValidationInfo info = mValidationInfo.get(opcode);
         if (info == null) {
@@ -268,6 +268,22 @@
             HdmiLogger.warning("Unexpected source: " + message);
             return ERROR_SOURCE;
         }
+
+        if (isMessageReceived) {
+            // Check if the source's logical address and local device's logical
+            // address are the same.
+            for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) {
+                synchronized (device.mLock) {
+                    if (message.getSource() == device.getDeviceInfo().getLogicalAddress()
+                            && message.getSource() != Constants.ADDR_UNREGISTERED) {
+                        HdmiLogger.warning(
+                                "Unexpected source: message sent from device itself, " + message);
+                        return ERROR_SOURCE;
+                    }
+                }
+            }
+        }
+
         // Check the destination field.
         if (message.getDestination() == Constants.ADDR_BROADCAST) {
             if ((info.addressType & DEST_BROADCAST) == 0) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 6920c4b..362db16 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1159,7 +1159,7 @@
     @ServiceThreadOnly
     void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) {
         assertRunOnServiceThread();
-        if (mMessageValidator.isValid(command) == HdmiCecMessageValidator.OK) {
+        if (mMessageValidator.isValid(command, false) == HdmiCecMessageValidator.OK) {
             mCecController.sendCommand(command, callback);
         } else {
             HdmiLogger.error("Invalid message type:" + command);
@@ -1192,7 +1192,7 @@
     @Constants.HandleMessageResult
     protected int handleCecCommand(HdmiCecMessage message) {
         assertRunOnServiceThread();
-        int errorCode = mMessageValidator.isValid(message);
+        int errorCode = mMessageValidator.isValid(message, true);
         if (errorCode != HdmiCecMessageValidator.OK) {
             // We'll not response on the messages with the invalid source or destination
             // or with parameter length shorter than specified in the standard.
@@ -3590,8 +3590,8 @@
         invokeInputChangeListener(info);
     }
 
-   void setMhlInputChangeEnabled(boolean enabled) {
-       mMhlController.setOption(OPTION_MHL_INPUT_SWITCHING, toInt(enabled));
+    void setMhlInputChangeEnabled(boolean enabled) {
+        mMhlController.setOption(OPTION_MHL_INPUT_SWITCHING, toInt(enabled));
 
         synchronized (mLock) {
             mMhlInputChangeEnabled = enabled;
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index a25392a..686926f 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -293,7 +293,7 @@
                     }, UserHandle.USER_ALL);
         }
 
-        if (mContextHubWrapper.supportsMicrophoneDisableSettingNotifications()) {
+        if (mContextHubWrapper.supportsMicrophoneSettingNotifications()) {
             sendMicrophoneDisableSettingUpdateForCurrentUser();
 
             mSensorPrivacyManagerInternal.addSensorPrivacyListenerForAllUsers(
@@ -1100,7 +1100,10 @@
      */
     private void sendMicrophoneDisableSettingUpdate(boolean enabled) {
         Log.d(TAG, "Mic Disabled Setting: " + enabled);
-        mContextHubWrapper.onMicrophoneDisableSettingChanged(enabled);
+        // The SensorPrivacyManager reports if microphone privacy was enabled,
+        // which translates to microphone access being disabled (and vice-versa).
+        // With this in mind, we flip the argument before piping it to CHRE.
+        mContextHubWrapper.onMicrophoneSettingChanged(!enabled);
     }
 
     /**
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index 13bcc9b..74630d1 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -228,15 +228,15 @@
     public abstract void onAirplaneModeSettingChanged(boolean enabled);
 
     /**
-     * @return True if this version of the Contexthub HAL supports microphone disable setting
+     * @return True if this version of the Contexthub HAL supports microphone setting
      * notifications.
      */
-    public abstract boolean supportsMicrophoneDisableSettingNotifications();
+    public abstract boolean supportsMicrophoneSettingNotifications();
 
     /**
-     * Notifies the Contexthub implementation of a microphone disable setting change.
+     * Notifies the Contexthub implementation of a microphone setting change.
      */
-    public abstract void onMicrophoneDisableSettingChanged(boolean enabled);
+    public abstract void onMicrophoneSettingChanged(boolean enabled);
 
     /**
      * Sends a message to the Context Hub.
@@ -380,7 +380,7 @@
             return true;
         }
 
-        public boolean supportsMicrophoneDisableSettingNotifications() {
+        public boolean supportsMicrophoneSettingNotifications() {
             return true;
         }
 
@@ -395,7 +395,7 @@
             onSettingChanged(android.hardware.contexthub.Setting.AIRPLANE_MODE, enabled);
         }
 
-        public void onMicrophoneDisableSettingChanged(boolean enabled) {
+        public void onMicrophoneSettingChanged(boolean enabled) {
             onSettingChanged(android.hardware.contexthub.Setting.MICROPHONE, enabled);
         }
 
@@ -615,7 +615,7 @@
             return false;
         }
 
-        public boolean supportsMicrophoneDisableSettingNotifications() {
+        public boolean supportsMicrophoneSettingNotifications() {
             return false;
         }
 
@@ -628,7 +628,7 @@
         public void onAirplaneModeSettingChanged(boolean enabled) {
         }
 
-        public void onMicrophoneDisableSettingChanged(boolean enabled) {
+        public void onMicrophoneSettingChanged(boolean enabled) {
         }
     }
 
@@ -660,7 +660,7 @@
             return false;
         }
 
-        public boolean supportsMicrophoneDisableSettingNotifications() {
+        public boolean supportsMicrophoneSettingNotifications() {
             return false;
         }
 
@@ -679,7 +679,7 @@
         public void onAirplaneModeSettingChanged(boolean enabled) {
         }
 
-        public void onMicrophoneDisableSettingChanged(boolean enabled) {
+        public void onMicrophoneSettingChanged(boolean enabled) {
         }
     }
 
@@ -721,7 +721,7 @@
             return true;
         }
 
-        public boolean supportsMicrophoneDisableSettingNotifications() {
+        public boolean supportsMicrophoneSettingNotifications() {
             return true;
         }
 
@@ -740,12 +740,9 @@
                     enabled ? SettingValue.ENABLED : SettingValue.DISABLED);
         }
 
-        public void onMicrophoneDisableSettingChanged(boolean enabled) {
-            // The SensorPrivacyManager reports if microphone privacy was enabled,
-            // which translates to microphone access being disabled (and vice-versa).
-            // With this in mind, we flip the argument before piping it to CHRE.
+        public void onMicrophoneSettingChanged(boolean enabled) {
             sendSettingChanged(android.hardware.contexthub.V1_2.Setting.MICROPHONE,
-                    enabled ? SettingValue.DISABLED : SettingValue.ENABLED);
+                    enabled ? SettingValue.ENABLED : SettingValue.DISABLED);
         }
 
         public void registerCallback(int contextHubId, ICallback callback) throws RemoteException {
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 8750e2a..7d0b98e 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -67,7 +67,6 @@
 import android.location.provider.ProviderProperties;
 import android.location.provider.ProviderRequest;
 import android.location.util.identity.CallerIdentity;
-import android.os.AsyncTask;
 import android.os.BatteryStats;
 import android.os.Bundle;
 import android.os.Handler;
@@ -112,6 +111,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.Executors;
 
 /**
  * A GNSS implementation of LocationProvider used by LocationManager.
@@ -636,7 +636,7 @@
             mDownloadPsdsWakeLock.acquire(DOWNLOAD_PSDS_DATA_TIMEOUT_MS);
         }
         Log.i(TAG, "WakeLock acquired by handleDownloadPsdsData()");
-        AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
+        Executors.newSingleThreadExecutor().execute(() -> {
             GnssPsdsDownloader psdsDownloader = new GnssPsdsDownloader(
                     mGnssConfiguration.getProperties());
             byte[] data = psdsDownloader.downloadPsdsData(psdsType);
diff --git a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
index 2227506..4d9253e 100644
--- a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
+++ b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
@@ -444,12 +444,11 @@
         capabilities = networkAttributes.mCapabilities;
         Log.i(TAG, String.format(
                 "updateNetworkState, state=%s, connected=%s, network=%s, capabilities=%s"
-                        + ", apn: %s, availableNetworkCount: %d",
+                        + ", availableNetworkCount: %d",
                 agpsDataConnStateAsString(),
                 isConnected,
                 network,
                 capabilities,
-                apn,
                 mAvailableNetworkAttributes.size()));
 
         if (native_is_agps_ril_supported()) {
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 62d8c32..345dc21 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -243,15 +243,24 @@
                 intent.putExtra(KEY_LOCATIONS, locationResult.asList().toArray(new Location[0]));
             }
 
+            // send() SHOULD only run the completion callback if it completes successfully. however,
+            // b/199464864 (which could not be fixed in the S timeframe) means that it's possible
+            // for send() to throw an exception AND run the completion callback. if this happens, we
+            // would over-release the wakelock... we take matters into our own hands to ensure that
+            // the completion callback can only be run if send() completes successfully. this means
+            // the completion callback may be run inline - but as we've never specified what thread
+            // the callback is run on, this is fine.
+            GatedCallback gatedCallback = new GatedCallback(onCompleteCallback);
+
             mPendingIntent.send(
                     mContext,
                     0,
                     intent,
-                    onCompleteCallback != null ? (pI, i, rC, rD, rE) -> onCompleteCallback.run()
-                            : null,
+                    (pI, i, rC, rD, rE) -> gatedCallback.run(),
                     null,
                     null,
                     options.toBundle());
+            gatedCallback.allow();
         }
 
         @Override
@@ -1960,11 +1969,6 @@
             Preconditions.checkState(Thread.holdsLock(mLock));
         }
 
-        if (mDelayedRegister != null) {
-            mAlarmHelper.cancel(mDelayedRegister);
-            mDelayedRegister = null;
-        }
-
         // calculate how long the new request should be delayed before sending it off to the
         // provider, under the assumption that once we send the request off, the provider will
         // immediately attempt to deliver a new location satisfying that request.
@@ -1997,8 +2001,8 @@
                 public void onAlarm() {
                     synchronized (mLock) {
                         if (mDelayedRegister == this) {
-                            setProviderRequest(newRequest);
                             mDelayedRegister = null;
+                            setProviderRequest(newRequest);
                         }
                     }
                 }
@@ -2025,6 +2029,11 @@
 
     @GuardedBy("mLock")
     void setProviderRequest(ProviderRequest request) {
+        if (mDelayedRegister != null) {
+            mAlarmHelper.cancel(mDelayedRegister);
+            mDelayedRegister = null;
+        }
+
         EVENT_LOG.logProviderUpdateRequest(mName, request);
         mProvider.getController().setRequest(request);
 
@@ -2734,4 +2743,49 @@
             }
         }
     }
+
+    private static class GatedCallback implements Runnable {
+
+        private @Nullable Runnable mCallback;
+
+        @GuardedBy("this")
+        private boolean mGate;
+        @GuardedBy("this")
+        private boolean mRun;
+
+        GatedCallback(Runnable callback) {
+            mCallback = callback;
+        }
+
+        public void allow() {
+            Runnable callback = null;
+            synchronized (this) {
+                mGate = true;
+                if (mRun && mCallback != null) {
+                    callback = mCallback;
+                    mCallback = null;
+                }
+            }
+
+            if (callback != null) {
+                callback.run();
+            }
+        }
+
+        @Override
+        public void run() {
+            Runnable callback = null;
+            synchronized (this) {
+                mRun = true;
+                if (mGate && mCallback != null) {
+                    callback = mCallback;
+                    mCallback = null;
+                }
+            }
+
+            if (callback != null) {
+                callback.run();
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java b/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
index 22a675a..ad87c45 100644
--- a/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
@@ -105,20 +105,15 @@
 
         synchronized (mLock) {
             mDeviceIdleHelper.addListener(this);
-            mDeviceIdle = mDeviceIdleHelper.isDeviceIdle();
-            mDeviceStationaryHelper.addListener(this);
-            mDeviceStationary = false;
-            mDeviceStationaryRealtimeMs = Long.MIN_VALUE;
-
-            onThrottlingChangedLocked(false);
+            onDeviceIdleChanged(mDeviceIdleHelper.isDeviceIdle());
         }
     }
 
     @Override
     protected void onStop() {
         synchronized (mLock) {
-            mDeviceStationaryHelper.removeListener(this);
             mDeviceIdleHelper.removeListener(this);
+            onDeviceIdleChanged(false);
 
             mIncomingRequest = ProviderRequest.EMPTY_REQUEST;
             mOutgoingRequest = ProviderRequest.EMPTY_REQUEST;
@@ -151,13 +146,26 @@
             }
 
             mDeviceIdle = deviceIdle;
-            onThrottlingChangedLocked(false);
+
+            if (deviceIdle) {
+                // device stationary helper will deliver an immediate listener update
+                mDeviceStationaryHelper.addListener(this);
+            } else {
+                mDeviceStationaryHelper.removeListener(this);
+                mDeviceStationary = false;
+                mDeviceStationaryRealtimeMs = Long.MIN_VALUE;
+            }
         }
     }
 
     @Override
     public void onDeviceStationaryChanged(boolean deviceStationary) {
         synchronized (mLock) {
+            if (!mDeviceIdle) {
+                // stationary detection is only registered while idle - ignore late notifications
+                return;
+            }
+
             if (mDeviceStationary == deviceStationary) {
                 return;
             }
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index bccc52f..ddaaa1e 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -1536,7 +1536,7 @@
                 @Override
                 public void onNullBinding(ComponentName name) {
                     Slog.v(TAG, "onNullBinding() called with: name = [" + name + "]");
-                    mServicesBound.remove(servicesBindingTag);
+                    mContext.unbindService(this);
                 }
             };
             if (!mContext.bindServiceAsUser(intent,
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index bd2a407..b7744c7e 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -5399,6 +5399,7 @@
                                     == IMPORTANCE_NONE) {
                                 cancelNotificationsFromListener(token, new String[]{r.getKey()});
                             } else {
+                                r.setPendingLogUpdate(true);
                                 needsSort = true;
                             }
                         }
@@ -8059,64 +8060,151 @@
         }
     }
 
+    static class NotificationRecordExtractorData {
+        // Class that stores any field in a NotificationRecord that can change via an extractor.
+        // Used to cache previous data used in a sort.
+        int mPosition;
+        int mVisibility;
+        boolean mShowBadge;
+        boolean mAllowBubble;
+        boolean mIsBubble;
+        NotificationChannel mChannel;
+        String mGroupKey;
+        ArrayList<String> mOverridePeople;
+        ArrayList<SnoozeCriterion> mSnoozeCriteria;
+        Integer mUserSentiment;
+        Integer mSuppressVisually;
+        ArrayList<Notification.Action> mSystemSmartActions;
+        ArrayList<CharSequence> mSmartReplies;
+        int mImportance;
+
+        // These fields may not trigger a reranking but diffs here may be logged.
+        float mRankingScore;
+        boolean mIsConversation;
+
+        NotificationRecordExtractorData(int position, int visibility, boolean showBadge,
+                boolean allowBubble, boolean isBubble, NotificationChannel channel, String groupKey,
+                ArrayList<String> overridePeople, ArrayList<SnoozeCriterion> snoozeCriteria,
+                Integer userSentiment, Integer suppressVisually,
+                ArrayList<Notification.Action> systemSmartActions,
+                ArrayList<CharSequence> smartReplies, int importance, float rankingScore,
+                boolean isConversation) {
+            mPosition = position;
+            mVisibility = visibility;
+            mShowBadge = showBadge;
+            mAllowBubble = allowBubble;
+            mIsBubble = isBubble;
+            mChannel = channel;
+            mGroupKey = groupKey;
+            mOverridePeople = overridePeople;
+            mSnoozeCriteria = snoozeCriteria;
+            mUserSentiment = userSentiment;
+            mSuppressVisually = suppressVisually;
+            mSystemSmartActions = systemSmartActions;
+            mSmartReplies = smartReplies;
+            mImportance = importance;
+            mRankingScore = rankingScore;
+            mIsConversation = isConversation;
+        }
+
+        // Returns whether the provided NotificationRecord differs from the cached data in any way.
+        // Should be guarded by mNotificationLock; not annotated here as this class is static.
+        boolean hasDiffForRankingLocked(NotificationRecord r, int newPosition) {
+            return mPosition != newPosition
+                    || mVisibility != r.getPackageVisibilityOverride()
+                    || mShowBadge != r.canShowBadge()
+                    || mAllowBubble != r.canBubble()
+                    || mIsBubble != r.getNotification().isBubbleNotification()
+                    || !Objects.equals(mChannel, r.getChannel())
+                    || !Objects.equals(mGroupKey, r.getGroupKey())
+                    || !Objects.equals(mOverridePeople, r.getPeopleOverride())
+                    || !Objects.equals(mSnoozeCriteria, r.getSnoozeCriteria())
+                    || !Objects.equals(mUserSentiment, r.getUserSentiment())
+                    || !Objects.equals(mSuppressVisually, r.getSuppressedVisualEffects())
+                    || !Objects.equals(mSystemSmartActions, r.getSystemGeneratedSmartActions())
+                    || !Objects.equals(mSmartReplies, r.getSmartReplies())
+                    || mImportance != r.getImportance();
+        }
+
+        // Returns whether the NotificationRecord has a change from this data for which we should
+        // log an update. This method specifically targets fields that may be changed via
+        // adjustments from the assistant.
+        //
+        // Fields here are the union of things in NotificationRecordLogger.shouldLogReported
+        // and NotificationRecord.applyAdjustments.
+        //
+        // Should be guarded by mNotificationLock; not annotated here as this class is static.
+        boolean hasDiffForLoggingLocked(NotificationRecord r, int newPosition) {
+            return mPosition != newPosition
+                    || !Objects.equals(mChannel, r.getChannel())
+                    || !Objects.equals(mGroupKey, r.getGroupKey())
+                    || !Objects.equals(mOverridePeople, r.getPeopleOverride())
+                    || !Objects.equals(mSnoozeCriteria, r.getSnoozeCriteria())
+                    || !Objects.equals(mUserSentiment, r.getUserSentiment())
+                    || !Objects.equals(mSystemSmartActions, r.getSystemGeneratedSmartActions())
+                    || !Objects.equals(mSmartReplies, r.getSmartReplies())
+                    || mImportance != r.getImportance()
+                    || !r.rankingScoreMatches(mRankingScore)
+                    || mIsConversation != r.isConversation();
+        }
+    }
+
     void handleRankingSort() {
         if (mRankingHelper == null) return;
         synchronized (mNotificationLock) {
             final int N = mNotificationList.size();
             // Any field that can change via one of the extractors needs to be added here.
-            ArrayList<String> orderBefore = new ArrayList<>(N);
-            int[] visibilities = new int[N];
-            boolean[] showBadges = new boolean[N];
-            boolean[] allowBubbles = new boolean[N];
-            boolean[] isBubble = new boolean[N];
-            ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
-            ArrayList<String> groupKeyBefore = new ArrayList<>(N);
-            ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
-            ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
-            ArrayList<Integer> userSentimentBefore = new ArrayList<>(N);
-            ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N);
-            ArrayList<ArrayList<Notification.Action>> systemSmartActionsBefore = new ArrayList<>(N);
-            ArrayList<ArrayList<CharSequence>> smartRepliesBefore = new ArrayList<>(N);
-            int[] importancesBefore = new int[N];
+            ArrayMap<String, NotificationRecordExtractorData> extractorDataBefore =
+                    new ArrayMap<>(N);
             for (int i = 0; i < N; i++) {
                 final NotificationRecord r = mNotificationList.get(i);
-                orderBefore.add(r.getKey());
-                visibilities[i] = r.getPackageVisibilityOverride();
-                showBadges[i] = r.canShowBadge();
-                allowBubbles[i] = r.canBubble();
-                isBubble[i] = r.getNotification().isBubbleNotification();
-                channelBefore.add(r.getChannel());
-                groupKeyBefore.add(r.getGroupKey());
-                overridePeopleBefore.add(r.getPeopleOverride());
-                snoozeCriteriaBefore.add(r.getSnoozeCriteria());
-                userSentimentBefore.add(r.getUserSentiment());
-                suppressVisuallyBefore.add(r.getSuppressedVisualEffects());
-                systemSmartActionsBefore.add(r.getSystemGeneratedSmartActions());
-                smartRepliesBefore.add(r.getSmartReplies());
-                importancesBefore[i] = r.getImportance();
+                NotificationRecordExtractorData extractorData = new NotificationRecordExtractorData(
+                        i,
+                        r.getPackageVisibilityOverride(),
+                        r.canShowBadge(),
+                        r.canBubble(),
+                        r.getNotification().isBubbleNotification(),
+                        r.getChannel(),
+                        r.getGroupKey(),
+                        r.getPeopleOverride(),
+                        r.getSnoozeCriteria(),
+                        r.getUserSentiment(),
+                        r.getSuppressedVisualEffects(),
+                        r.getSystemGeneratedSmartActions(),
+                        r.getSmartReplies(),
+                        r.getImportance(),
+                        r.getRankingScore(),
+                        r.isConversation());
+                extractorDataBefore.put(r.getKey(), extractorData);
                 mRankingHelper.extractSignals(r);
             }
             mRankingHelper.sort(mNotificationList);
             for (int i = 0; i < N; i++) {
                 final NotificationRecord r = mNotificationList.get(i);
-                if (!orderBefore.get(i).equals(r.getKey())
-                        || visibilities[i] != r.getPackageVisibilityOverride()
-                        || showBadges[i] != r.canShowBadge()
-                        || allowBubbles[i] != r.canBubble()
-                        || isBubble[i] != r.getNotification().isBubbleNotification()
-                        || !Objects.equals(channelBefore.get(i), r.getChannel())
-                        || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
-                        || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
-                        || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())
-                        || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment())
-                        || !Objects.equals(suppressVisuallyBefore.get(i),
-                        r.getSuppressedVisualEffects())
-                        || !Objects.equals(systemSmartActionsBefore.get(i),
-                                r.getSystemGeneratedSmartActions())
-                        || !Objects.equals(smartRepliesBefore.get(i), r.getSmartReplies())
-                        || importancesBefore[i] != r.getImportance()) {
+                if (!extractorDataBefore.containsKey(r.getKey())) {
+                    // This shouldn't happen given that we just built this with all the
+                    // notifications, but check just to be safe.
+                    continue;
+                }
+                if (extractorDataBefore.get(r.getKey()).hasDiffForRankingLocked(r, i)) {
                     mHandler.scheduleSendRankingUpdate();
-                    return;
+                }
+
+                // If this notification is one for which we wanted to log an update, and
+                // sufficient relevant bits are different, log update.
+                if (r.hasPendingLogUpdate()) {
+                    // We need to acquire the previous data associated with this specific
+                    // notification, as the one at the current index may be unrelated if
+                    // notification order has changed.
+                    NotificationRecordExtractorData prevData = extractorDataBefore.get(r.getKey());
+                    if (prevData.hasDiffForLoggingLocked(r, i)) {
+                        mNotificationRecordLogger.logNotificationAdjusted(r, i, 0,
+                                getGroupInstanceId(r.getSbn().getGroupKey()));
+                    }
+
+                    // Remove whether there was a diff or not; we've sorted the key, so if it
+                    // turns out there was nothing to log, that's fine too.
+                    r.setPendingLogUpdate(false);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 7a00b86..7e94f0d 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -200,6 +200,10 @@
     private boolean mIsAppImportanceLocked;
     private ArraySet<Uri> mGrantableUris;
 
+    // Whether this notification record should have an update logged the next time notifications
+    // are sorted.
+    private boolean mPendingLogUpdate = false;
+
     public NotificationRecord(Context context, StatusBarNotification sbn,
             NotificationChannel channel) {
         this.sbn = sbn;
@@ -662,17 +666,23 @@
                     final ArrayList<String> people =
                             adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE);
                     setPeopleOverride(people);
+                    EventLogTags.writeNotificationAdjusted(
+                            getKey(), Adjustment.KEY_PEOPLE, people.toString());
                 }
                 if (signals.containsKey(Adjustment.KEY_SNOOZE_CRITERIA)) {
                     final ArrayList<SnoozeCriterion> snoozeCriterionList =
                             adjustment.getSignals().getParcelableArrayList(
                                     Adjustment.KEY_SNOOZE_CRITERIA);
                     setSnoozeCriteria(snoozeCriterionList);
+                    EventLogTags.writeNotificationAdjusted(getKey(), Adjustment.KEY_SNOOZE_CRITERIA,
+                            snoozeCriterionList.toString());
                 }
                 if (signals.containsKey(Adjustment.KEY_GROUP_KEY)) {
                     final String groupOverrideKey =
                             adjustment.getSignals().getString(Adjustment.KEY_GROUP_KEY);
                     setOverrideGroupKey(groupOverrideKey);
+                    EventLogTags.writeNotificationAdjusted(getKey(), Adjustment.KEY_GROUP_KEY,
+                            groupOverrideKey);
                 }
                 if (signals.containsKey(Adjustment.KEY_USER_SENTIMENT)) {
                     // Only allow user sentiment update from assistant if user hasn't already
@@ -681,27 +691,42 @@
                             && (getChannel().getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0) {
                         setUserSentiment(adjustment.getSignals().getInt(
                                 Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEUTRAL));
+                        EventLogTags.writeNotificationAdjusted(getKey(),
+                                Adjustment.KEY_USER_SENTIMENT,
+                                Integer.toString(getUserSentiment()));
                     }
                 }
                 if (signals.containsKey(Adjustment.KEY_CONTEXTUAL_ACTIONS)) {
                     setSystemGeneratedSmartActions(
                             signals.getParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS));
+                    EventLogTags.writeNotificationAdjusted(getKey(),
+                            Adjustment.KEY_CONTEXTUAL_ACTIONS,
+                            getSystemGeneratedSmartActions().toString());
                 }
                 if (signals.containsKey(Adjustment.KEY_TEXT_REPLIES)) {
                     setSmartReplies(signals.getCharSequenceArrayList(Adjustment.KEY_TEXT_REPLIES));
+                    EventLogTags.writeNotificationAdjusted(getKey(), Adjustment.KEY_TEXT_REPLIES,
+                            getSmartReplies().toString());
                 }
                 if (signals.containsKey(Adjustment.KEY_IMPORTANCE)) {
                     int importance = signals.getInt(Adjustment.KEY_IMPORTANCE);
                     importance = Math.max(IMPORTANCE_UNSPECIFIED, importance);
                     importance = Math.min(IMPORTANCE_HIGH, importance);
                     setAssistantImportance(importance);
+                    EventLogTags.writeNotificationAdjusted(getKey(), Adjustment.KEY_IMPORTANCE,
+                            Integer.toString(importance));
                 }
                 if (signals.containsKey(Adjustment.KEY_RANKING_SCORE)) {
                     mRankingScore = signals.getFloat(Adjustment.KEY_RANKING_SCORE);
+                    EventLogTags.writeNotificationAdjusted(getKey(), Adjustment.KEY_RANKING_SCORE,
+                            Float.toString(mRankingScore));
                 }
                 if (signals.containsKey(Adjustment.KEY_NOT_CONVERSATION)) {
                     mIsNotConversationOverride = signals.getBoolean(
                             Adjustment.KEY_NOT_CONVERSATION);
+                    EventLogTags.writeNotificationAdjusted(getKey(),
+                            Adjustment.KEY_NOT_CONVERSATION,
+                            Boolean.toString(mIsNotConversationOverride));
                 }
                 if (!signals.isEmpty() && adjustment.getIssuer() != null) {
                     mAdjustmentIssuer = adjustment.getIssuer();
@@ -1492,6 +1517,24 @@
         return sbn;
     }
 
+    /**
+     * Returns whether this record's ranking score is approximately equal to otherScore
+     * (the difference must be within 0.0001).
+     */
+    public boolean rankingScoreMatches(float otherScore) {
+        return Math.abs(mRankingScore - otherScore) < 0.0001;
+    }
+
+    protected void setPendingLogUpdate(boolean pendingLogUpdate) {
+        mPendingLogUpdate = pendingLogUpdate;
+    }
+
+    // If a caller of this function subsequently logs the update, they should also call
+    // setPendingLogUpdate to false to make sure other callers don't also do so.
+    protected boolean hasPendingLogUpdate() {
+        return mPendingLogUpdate;
+    }
+
     @VisibleForTesting
     static final class Light {
         public final int color;
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
index 3ca6a0d..f3dc2dd 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
@@ -59,6 +59,20 @@
             InstanceId groupId);
 
     /**
+     * Logs a NotificationReported atom reflecting an adjustment to a notification.
+     * Unlike maybeLogNotificationPosted, this method is guaranteed to log a notification update,
+     * so the caller must take responsibility for checking that that logging update is necessary,
+     * and that the notification is meaningfully changed.
+     * @param r The NotificationRecord. If null, no action is taken.
+     * @param position The position at which this notification is ranked.
+     * @param buzzBeepBlink Logging code reflecting whether this notification alerted the user.
+     * @param groupId The instance Id of the group summary notification, or null.
+     */
+    void logNotificationAdjusted(@Nullable NotificationRecord r,
+            int position, int buzzBeepBlink,
+            InstanceId groupId);
+
+    /**
      * Logs a notification cancel / dismiss event using UiEventReported (event ids from the
      * NotificationCancelledEvents enum).
      * @param r The NotificationRecord. If null, no action is taken.
@@ -96,7 +110,9 @@
         @UiEvent(doc = "New notification enqueued to post")
         NOTIFICATION_POSTED(162),
         @UiEvent(doc = "Notification substantially updated, or alerted again.")
-        NOTIFICATION_UPDATED(163);
+        NOTIFICATION_UPDATED(163),
+        @UiEvent(doc = "Notification adjusted by assistant.")
+        NOTIFICATION_ADJUSTED(908);
 
         private final int mId;
         NotificationReportedEvent(int id) {
@@ -349,7 +365,8 @@
                     && Objects.equals(r.getSbn().getNotification().category,
                         old.getSbn().getNotification().category)
                     && (r.getImportance() == old.getImportance())
-                    && (getLoggingImportance(r) == getLoggingImportance(old)));
+                    && (getLoggingImportance(r) == getLoggingImportance(old))
+                    && r.rankingScoreMatches(old.getRankingScore()));
         }
 
         /**
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
index 249910d..17c6c46 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.server.notification;
 
+import android.annotation.Nullable;
+
 import com.android.internal.logging.InstanceId;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.UiEventLoggerImpl;
@@ -37,38 +39,54 @@
         if (!p.shouldLogReported(buzzBeepBlink)) {
             return;
         }
+        writeNotificationReportedAtom(p, NotificationReportedEvent.fromRecordPair(p),
+                position, buzzBeepBlink, groupId);
+    }
+
+    @Override
+    public void logNotificationAdjusted(@Nullable NotificationRecord r,
+            int position, int buzzBeepBlink,
+            InstanceId groupId) {
+        NotificationRecordPair p = new NotificationRecordPair(r, null);
+        writeNotificationReportedAtom(p, NotificationReportedEvent.NOTIFICATION_ADJUSTED,
+                position, buzzBeepBlink, groupId);
+    }
+
+    private void writeNotificationReportedAtom(NotificationRecordPair p,
+            NotificationReportedEvent eventType, int position, int buzzBeepBlink,
+            InstanceId groupId) {
         FrameworkStatsLog.write(FrameworkStatsLog.NOTIFICATION_REPORTED,
-                /* int32 event_id = 1 */ NotificationReportedEvent.fromRecordPair(p).getId(),
-                /* int32 uid = 2 */ r.getUid(),
-                /* string package_name = 3 */ r.getSbn().getPackageName(),
+                /* int32 event_id = 1 */ eventType.getId(),
+                /* int32 uid = 2 */ p.r.getUid(),
+                /* string package_name = 3 */ p.r.getSbn().getPackageName(),
                 /* int32 instance_id = 4 */ p.getInstanceId(),
                 /* int32 notification_id_hash = 5 */ p.getNotificationIdHash(),
                 /* int32 channel_id_hash = 6 */ p.getChannelIdHash(),
                 /* string group_id_hash = 7 */ p.getGroupIdHash(),
                 /* int32 group_instance_id = 8 */ (groupId == null) ? 0 : groupId.getId(),
-                /* bool is_group_summary = 9 */ r.getSbn().getNotification().isGroupSummary(),
-                /* string category = 10 */ r.getSbn().getNotification().category,
+                /* bool is_group_summary = 9 */ p.r.getSbn().getNotification().isGroupSummary(),
+                /* string category = 10 */ p.r.getSbn().getNotification().category,
                 /* int32 style = 11 */ p.getStyle(),
                 /* int32 num_people = 12 */ p.getNumPeople(),
                 /* int32 position = 13 */ position,
                 /* android.stats.sysui.NotificationImportance importance = 14 */
-                NotificationRecordLogger.getLoggingImportance(r),
+                NotificationRecordLogger.getLoggingImportance(p.r),
                 /* int32 alerting = 15 */ buzzBeepBlink,
                 /* NotificationImportanceExplanation importance_source = 16 */
-                r.getImportanceExplanationCode(),
+                p.r.getImportanceExplanationCode(),
                 /* android.stats.sysui.NotificationImportance importance_initial = 17 */
-                r.getInitialImportance(),
+                p.r.getInitialImportance(),
                 /* NotificationImportanceExplanation importance_initial_source = 18 */
-                r.getInitialImportanceExplanationCode(),
+                p.r.getInitialImportanceExplanationCode(),
                 /* android.stats.sysui.NotificationImportance importance_asst = 19 */
-                r.getAssistantImportance(),
+                p.r.getAssistantImportance(),
                 /* int32 assistant_hash = 20 */ p.getAssistantHash(),
-                /* float assistant_ranking_score = 21 */ r.getRankingScore(),
-                /* bool is_ongoing = 22 */ r.getSbn().isOngoing(),
+                /* float assistant_ranking_score = 21 */ p.r.getRankingScore(),
+                /* bool is_ongoing = 22 */ p.r.getSbn().isOngoing(),
                 /* bool is_foreground_service = 23 */
-                NotificationRecordLogger.isForegroundService(r),
+                NotificationRecordLogger.isForegroundService(p.r),
                 /* optional int64 timeout_millis = 24 */
-                r.getSbn().getNotification().getTimeoutAfter()
+                p.r.getSbn().getNotification().getTimeoutAfter()
         );
     }
 
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index ae683d4..047a701 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -719,6 +719,11 @@
         if (overlayIdmap == null) {
             pw.println("Default overlays: " + TextUtils.join(";", mDefaultOverlays));
         }
+
+        // overlay configurations
+        if (dumpState.getPackageName() == null) {
+            mOverlayConfig.dump(pw);
+        }
     }
 
     @NonNull String[] getDefaultOverlayPackages() {
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
new file mode 100644
index 0000000..5b7013b
--- /dev/null
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -0,0 +1,274 @@
+/*
+ * 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;
+
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.SigningDetails;
+import android.content.pm.UserInfo;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.PackageState;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.List;
+
+/**
+ * A {@link Computer} provides a set of functions that can operate on live data or snapshot
+ * data.  At this time, the {@link Computer} is implemented by the
+ * {@link ComputerEngine}, which is in turn extended by {@link ComputerLocked}.
+ *
+ * New functions must be added carefully.
+ * <ol>
+ * <li> New functions must be true functions with respect to data collected in a
+ * {@link PackageManagerService.Snapshot}.  Such data may never be modified from inside a {@link Computer}
+ * function.
+ * </li>
+ *
+ * <li> A new function must be implemented in {@link ComputerEngine}.
+ * </li>
+ *
+ * <li> A new function must be overridden in {@link ComputerLocked} if the function
+ * cannot safely access live data without holding the PackageManagerService lock.  The
+ * form of the {@link ComputerLocked} function must be a single call to the
+ * {@link ComputerEngine} implementation, wrapped in a <code>synchronized</code>
+ * block.  Functions in {@link ComputerLocked} should never include any other code.
+ * </li>
+ *
+ * Care must be taken when deciding if a function should be overridden in
+ * {@link ComputerLocked}.  The complex lock relationships of PackageManagerService
+ * and other managers (like PermissionManager) mean deadlock is possible.  On the
+ * other hand, not overriding in {@link ComputerLocked} may leave a function walking
+ * unstable data.
+ *
+ * To coax developers to consider such issues carefully, all methods in
+ * {@link Computer} must be annotated with <code>@LiveImplementation(override =
+ * MANDATORY)</code> or <code>LiveImplementation(locked = NOT_ALLOWED)</code>.  A unit
+ * test verifies the annotation and that the annotation corresponds to the code in
+ * {@link ComputerEngine} and {@link ComputerLocked}.
+ */
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+public interface Computer {
+    /**
+     * Every method must be annotated.
+     */
+    @Target({ ElementType.METHOD })
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface LiveImplementation {
+        // A Computer method must be annotated with one of the following values:
+        //   MANDATORY - the method must be overridden in ComputerEngineLive.  The
+        //     format of the override is a call to the super method, wrapped in a
+        //     synchronization block.
+        //   NOT_ALLOWED - the method may not appear in the live computer.  It must
+        //     be final in the ComputerEngine.
+        int MANDATORY = 1;
+        int NOT_ALLOWED = 2;
+        int override() default MANDATORY;
+        String rationale() default "";
+    }
+
+    /**
+     * Administrative statistics: record that the snapshot has been used.  Every call
+     * to use() increments the usage counter.
+     */
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    default void use() {
+    }
+    /**
+     * Fetch the snapshot usage counter.
+     * @return The number of times this snapshot was used.
+     */
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    default int getUsed() {
+        return 0;
+    }
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType,
+            int flags, @PackageManagerInternal.PrivateResolveFlags int privateResolveFlags,
+            int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType,
+            int flags, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent, String resolvedType,
+            int flags, int userId, int callingUid, boolean includeInstantApps);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
+    @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(Intent intent,
+            String resolvedType, int flags, int filterCallingUid, int userId,
+            boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
+            String instantAppPkgName);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    ActivityInfo getActivityInfo(ComponentName component, int flags, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
+            int filterCallingUid, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
+    AndroidPackage getPackage(String packageName);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
+    AndroidPackage getPackage(int uid);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
+            int filterCallingUid, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    ApplicationInfo getApplicationInfo(String packageName, int flags, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
+            int filterCallingUid, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    ComponentName getDefaultHomeActivity(int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType,
+            int flags, int sourceUserId, int parentUserId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    Intent getHomeIntent();
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent,
+            String resolvedType, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    List<ResolveInfo> applyPostResolutionFilter(@NonNull List<ResolveInfo> resolveInfos,
+            String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
+            boolean resolveForStart, int userId, Intent intent);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    PackageInfo getPackageInfo(String packageName, int flags, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    PackageInfo getPackageInfoInternal(String packageName, long versionCode, int flags,
+            int filterCallingUid, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    PackageSetting getPackageSetting(String packageName);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
+    PackageSetting getPackageSettingInternal(String packageName, int callingUid);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
+    @Nullable PackageState getPackageState(@NonNull String packageName);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
+            int sourceUserId, int targetUserId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    ServiceInfo getServiceInfo(ComponentName component, int flags, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
+    String getInstantAppPackageName(int callingUid);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    String resolveExternalPackageNameLPr(AndroidPackage pkg);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    String resolveInternalPackageNameLPr(String packageName, long versionCode);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    String[] getPackagesForUid(int uid);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    UserInfo getProfileParent(int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    boolean canViewInstantApps(int callingUid, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId,
+            int flags);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    boolean isCallerSameApp(String packageName, int uid);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    boolean isComponentVisibleToInstantApp(@Nullable ComponentName component);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    boolean isComponentVisibleToInstantApp(@Nullable ComponentName component,
+            @PackageManager.ComponentType int type);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
+            String resolvedType, int flags);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    boolean isInstantApp(String packageName, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    boolean isInstantAppInternal(String packageName, @UserIdInt int userId, int callingUid);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid,
+            @Nullable ComponentName component, @PackageManager.ComponentType int componentType,
+            int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid,
+            int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus, int callingUid,
+            int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    int checkUidPermission(String permName, int uid);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
+    int getPackageUidInternal(String packageName, int flags, int userId, int callingUid);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    int updateFlagsForApplication(int flags, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    int updateFlagsForComponent(int flags, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    int updateFlagsForPackage(int flags, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps,
+            boolean isImplicitImageCaptureIntentAndNotSetByDpc);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps,
+            boolean onlyExposedExplicitly, boolean isImplicitImageCaptureIntentAndNotSetByDpc);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
+            boolean requireFullPermission, boolean checkShell, String message);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
+            boolean requireFullPermission, boolean checkShell, String message);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
+            boolean requireFullPermission, boolean checkShell,
+            boolean requirePermissionWhenSameUser, String message);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
+    SigningDetails getSigningDetails(@NonNull String packageName);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
+    SigningDetails getSigningDetails(int uid);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
+    boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
+    boolean filterAppAccess(String packageName, int callingUid, int userId);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
+    boolean filterAppAccess(int uid, int callingUid);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
+    void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityInternal(
+            Intent intent, String resolvedType, int flags, List<ResolveInfo> query, boolean always,
+            boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered);
+    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+    ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, int flags,
+            List<ResolveInfo> query, boolean debug, int userId);
+}
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
new file mode 100644
index 0000000..ff4a8fd
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -0,0 +1,3256 @@
+/*
+ * 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;
+
+import static android.content.Intent.ACTION_MAIN;
+import static android.content.Intent.CATEGORY_DEFAULT;
+import static android.content.Intent.CATEGORY_HOME;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
+import static android.content.pm.PackageManager.MATCH_ALL;
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.content.pm.PackageManager.MATCH_APEX;
+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_DISABLED_COMPONENTS;
+import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
+import static android.content.pm.PackageManager.MATCH_KNOWN_PACKAGES;
+import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.content.pm.PackageManager.TYPE_ACTIVITY;
+import static android.content.pm.PackageManager.TYPE_PROVIDER;
+import static android.content.pm.PackageManager.TYPE_RECEIVER;
+import static android.content.pm.PackageManager.TYPE_SERVICE;
+import static android.content.pm.PackageManager.TYPE_UNKNOWN;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
+import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
+import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
+import static com.android.server.pm.PackageManagerService.DEBUG_DOMAIN_VERIFICATION;
+import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
+import static com.android.server.pm.PackageManagerService.DEBUG_INSTANT;
+import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_INFO;
+import static com.android.server.pm.PackageManagerService.DEBUG_PREFERRED;
+import static com.android.server.pm.PackageManagerService.EMPTY_INT_ARRAY;
+import static com.android.server.pm.PackageManagerService.HIDE_EPHEMERAL_APIS;
+import static com.android.server.pm.PackageManagerService.TAG;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.PermissionChecker;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.AuxiliaryResolveInfo;
+import android.content.pm.ComponentInfo;
+import android.content.pm.InstantAppRequest;
+import android.content.pm.InstantAppResolveInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageUserState;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.SigningDetails;
+import android.content.pm.UserInfo;
+import android.content.pm.parsing.PackageInfoWithoutStateUtils;
+import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedInstrumentation;
+import android.content.pm.parsing.component.ParsedProvider;
+import android.content.pm.parsing.component.ParsedService;
+import android.os.Binder;
+import android.os.PatternMatcher;
+import android.os.Process;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.LogPrinter;
+import android.util.LongSparseLongArray;
+import android.util.MathUtils;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.SparseBooleanArray;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.pm.dex.DexManager;
+import com.android.server.pm.parsing.PackageInfoUtils;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.PackageState;
+import com.android.server.pm.pkg.PackageStateImpl;
+import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
+import com.android.server.pm.verify.domain.DomainVerificationUtils;
+import com.android.server.utils.WatchedArrayMap;
+import com.android.server.utils.WatchedLongSparseArray;
+import com.android.server.utils.WatchedSparseBooleanArray;
+import com.android.server.utils.WatchedSparseIntArray;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+import java.io.BufferedOutputStream;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * This class contains the implementation of the Computer functions.  It
+ * is entirely self-contained - it has no implicit access to
+ * PackageManagerService.
+ */
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+public class ComputerEngine implements Computer {
+
+    // The administrative use counter.
+    private int mUsed = 0;
+
+    // Cached attributes.  The names in this class are the same as the
+    // names in PackageManagerService; see that class for documentation.
+    protected final Settings mSettings;
+    private final WatchedSparseIntArray mIsolatedOwners;
+    private final WatchedArrayMap<String, AndroidPackage> mPackages;
+    private final WatchedArrayMap<ComponentName, ParsedInstrumentation>
+            mInstrumentation;
+    private final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
+            mStaticLibsByDeclaringPackage;
+    private final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
+            mSharedLibraries;
+    private final ComponentName mLocalResolveComponentName;
+    private final ActivityInfo mResolveActivity;
+    private final WatchedSparseBooleanArray mWebInstantAppsDisabled;
+    private final ActivityInfo mLocalInstantAppInstallerActivity;
+    private final ResolveInfo mInstantAppInstallerInfo;
+    private final InstantAppRegistry mInstantAppRegistry;
+    private final ApplicationInfo mLocalAndroidApplication;
+    private final AppsFilter mAppsFilter;
+
+    // Immutable service attribute
+    private final String mAppPredictionServicePackage;
+
+    // The following are not cloned since changes to these have never
+    // been guarded by the PMS lock.
+    private final Context mContext;
+    private final UserManagerService mUserManager;
+    private final PermissionManagerServiceInternal mPermissionManager;
+    private final ApexManager mApexManager;
+    private final PackageManagerService.Injector mInjector;
+    private final ComponentResolver mComponentResolver;
+    private final InstantAppResolverConnection mInstantAppResolverConnection;
+    private final DefaultAppProvider mDefaultAppProvider;
+    private final DomainVerificationManagerInternal mDomainVerificationManager;
+    private final PackageDexOptimizer mPackageDexOptimizer;
+    private final DexManager mDexManager;
+    private final CompilerStats mCompilerStats;
+
+    // PackageManagerService attributes that are primitives are referenced through the
+    // pms object directly.  Primitives are the only attributes so referenced.
+    protected final PackageManagerService mService;
+    private boolean safeMode() {
+        return mService.getSafeMode();
+    }
+    protected ComponentName resolveComponentName() {
+        return mLocalResolveComponentName;
+    }
+    protected ActivityInfo instantAppInstallerActivity() {
+        return mLocalInstantAppInstallerActivity;
+    }
+    protected ApplicationInfo androidApplication() {
+        return mLocalAndroidApplication;
+    }
+
+    ComputerEngine(PackageManagerService.Snapshot args) {
+        mSettings = args.settings;
+        mIsolatedOwners = args.isolatedOwners;
+        mPackages = args.packages;
+        mSharedLibraries = args.sharedLibs;
+        mStaticLibsByDeclaringPackage = args.staticLibs;
+        mInstrumentation = args.instrumentation;
+        mWebInstantAppsDisabled = args.webInstantAppsDisabled;
+        mLocalResolveComponentName = args.resolveComponentName;
+        mResolveActivity = args.resolveActivity;
+        mLocalInstantAppInstallerActivity = args.instantAppInstallerActivity;
+        mInstantAppInstallerInfo = args.instantAppInstallerInfo;
+        mInstantAppRegistry = args.instantAppRegistry;
+        mLocalAndroidApplication = args.androidApplication;
+        mAppsFilter = args.appsFilter;
+        mComponentResolver = args.componentResolver;
+
+        mAppPredictionServicePackage = args.appPredictionServicePackage;
+
+        // The following are not cached copies.  Instead they are
+        // references to outside services.
+        mPermissionManager = args.service.mPermissionManager;
+        mUserManager = args.service.mUserManager;
+        mContext = args.service.mContext;
+        mInjector = args.service.mInjector;
+        mApexManager = args.service.mApexManager;
+        mInstantAppResolverConnection = args.service.mInstantAppResolverConnection;
+        mDefaultAppProvider = args.service.getDefaultAppProvider();
+        mDomainVerificationManager = args.service.mDomainVerificationManager;
+        mPackageDexOptimizer = args.service.mPackageDexOptimizer;
+        mDexManager = args.service.getDexManager();
+        mCompilerStats = args.service.mCompilerStats;
+
+        // Used to reference PMS attributes that are primitives and which are not
+        // updated under control of the PMS lock.
+        mService = args.service;
+    }
+
+    /**
+     * Record that the snapshot was used.
+     */
+    public final void use() {
+        mUsed++;
+    }
+
+    /**
+     * Return the usage counter.
+     */
+    public final int getUsed() {
+        return mUsed;
+    }
+
+    public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
+            String resolvedType, int flags,
+            @PackageManagerInternal.PrivateResolveFlags int privateResolveFlags,
+            int filterCallingUid, int userId, boolean resolveForStart,
+            boolean allowDynamicSplits) {
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
+        final String instantAppPkgName = getInstantAppPackageName(filterCallingUid);
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */,
+                "query intent activities");
+        final String pkgName = intent.getPackage();
+        Intent originalIntent = null;
+        ComponentName comp = intent.getComponent();
+        if (comp == null) {
+            if (intent.getSelector() != null) {
+                originalIntent = intent;
+                intent = intent.getSelector();
+                comp = intent.getComponent();
+            }
+        }
+
+        flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
+                comp != null || pkgName != null /*onlyExposedExplicitly*/,
+                isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+                        flags));
+        List<ResolveInfo> list = Collections.emptyList();
+        boolean skipPostResolution = false;
+        if (comp != null) {
+            final ActivityInfo ai = getActivityInfo(comp, flags, userId);
+            if (ai != null) {
+                // When specifying an explicit component, we prevent the activity from being
+                // used when either 1) the calling package is normal and the activity is within
+                // an ephemeral application or 2) the calling package is ephemeral and the
+                // activity is not visible to ephemeral applications.
+                final boolean matchInstantApp =
+                        (flags & PackageManager.MATCH_INSTANT) != 0;
+                final boolean matchVisibleToInstantAppOnly =
+                        (flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
+                final boolean matchExplicitlyVisibleOnly =
+                        (flags & PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY) != 0;
+                final boolean isCallerInstantApp =
+                        instantAppPkgName != null;
+                final boolean isTargetSameInstantApp =
+                        comp.getPackageName().equals(instantAppPkgName);
+                final boolean isTargetInstantApp =
+                        (ai.applicationInfo.privateFlags
+                                & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0;
+                final boolean isTargetVisibleToInstantApp =
+                        (ai.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+                final boolean isTargetExplicitlyVisibleToInstantApp =
+                        isTargetVisibleToInstantApp
+                                && (ai.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP)
+                                == 0;
+                final boolean isTargetHiddenFromInstantApp =
+                        !isTargetVisibleToInstantApp
+                                || (matchExplicitlyVisibleOnly
+                                && !isTargetExplicitlyVisibleToInstantApp);
+                final boolean blockInstantResolution =
+                        !isTargetSameInstantApp
+                                && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp)
+                                || (matchVisibleToInstantAppOnly && isCallerInstantApp
+                                && isTargetHiddenFromInstantApp));
+                final boolean blockNormalResolution =
+                        !resolveForStart && !isTargetInstantApp && !isCallerInstantApp
+                                && shouldFilterApplicationLocked(
+                                getPackageSettingInternal(ai.applicationInfo.packageName,
+                                        Process.SYSTEM_UID), filterCallingUid, userId);
+                if (!blockInstantResolution && !blockNormalResolution) {
+                    final ResolveInfo ri = new ResolveInfo();
+                    ri.activityInfo = ai;
+                    list = new ArrayList<>(1);
+                    list.add(ri);
+                    PackageManagerServiceUtils.applyEnforceIntentFilterMatching(
+                            mInjector.getCompatibility(), mComponentResolver,
+                            list, false, intent, resolvedType, filterCallingUid);
+                }
+            }
+        } else {
+            QueryIntentActivitiesResult lockedResult =
+                    queryIntentActivitiesInternalBody(
+                            intent, resolvedType, flags, filterCallingUid, userId,
+                            resolveForStart, allowDynamicSplits, pkgName, instantAppPkgName);
+            if (lockedResult.answer != null) {
+                skipPostResolution = true;
+                list = lockedResult.answer;
+            } else {
+                if (lockedResult.addInstant) {
+                    String callingPkgName = getInstantAppPackageName(filterCallingUid);
+                    boolean isRequesterInstantApp = isInstantApp(callingPkgName, userId);
+                    lockedResult.result = maybeAddInstantAppInstaller(
+                            lockedResult.result, intent, resolvedType, flags,
+                            userId, resolveForStart, isRequesterInstantApp);
+                }
+                if (lockedResult.sortResult) {
+                    lockedResult.result.sort(RESOLVE_PRIORITY_SORTER);
+                }
+                list = lockedResult.result;
+            }
+        }
+
+        if (originalIntent != null) {
+            // We also have to ensure all components match the original intent
+            PackageManagerServiceUtils.applyEnforceIntentFilterMatching(
+                    mInjector.getCompatibility(), mComponentResolver,
+                    list, false, originalIntent, resolvedType, filterCallingUid);
+        }
+
+        return skipPostResolution ? list : applyPostResolutionFilter(
+                list, instantAppPkgName, allowDynamicSplits, filterCallingUid,
+                resolveForStart, userId, intent);
+    }
+
+    public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
+            String resolvedType, int flags, int userId) {
+        return queryIntentActivitiesInternal(
+                intent, resolvedType, flags, 0 /*privateResolveFlags*/, Binder.getCallingUid(),
+                userId, false /*resolveForStart*/, true /*allowDynamicSplits*/);
+    }
+
+    public final @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
+            String resolvedType, int flags, int userId, int callingUid,
+            boolean includeInstantApps) {
+        if (!mUserManager.exists(userId)) return Collections.emptyList();
+        enforceCrossUserOrProfilePermission(callingUid,
+                userId,
+                false /*requireFullPermission*/,
+                false /*checkShell*/,
+                "query intent receivers");
+        final String instantAppPkgName = getInstantAppPackageName(callingUid);
+        flags = updateFlagsForResolve(flags, userId, callingUid, includeInstantApps,
+                false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
+        Intent originalIntent = null;
+        ComponentName comp = intent.getComponent();
+        if (comp == null) {
+            if (intent.getSelector() != null) {
+                originalIntent = intent;
+                intent = intent.getSelector();
+                comp = intent.getComponent();
+            }
+        }
+        List<ResolveInfo> list = Collections.emptyList();
+        if (comp != null) {
+            final ServiceInfo si = getServiceInfo(comp, flags, userId);
+            if (si != null) {
+                // When specifying an explicit component, we prevent the service from being
+                // used when either 1) the service is in an instant application and the
+                // caller is not the same instant application or 2) the calling package is
+                // ephemeral and the activity is not visible to ephemeral applications.
+                final boolean matchInstantApp =
+                        (flags & PackageManager.MATCH_INSTANT) != 0;
+                final boolean matchVisibleToInstantAppOnly =
+                        (flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
+                final boolean isCallerInstantApp =
+                        instantAppPkgName != null;
+                final boolean isTargetSameInstantApp =
+                        comp.getPackageName().equals(instantAppPkgName);
+                final boolean isTargetInstantApp =
+                        (si.applicationInfo.privateFlags
+                                & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0;
+                final boolean isTargetHiddenFromInstantApp =
+                        (si.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0;
+                final boolean blockInstantResolution =
+                        !isTargetSameInstantApp
+                                && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp)
+                                || (matchVisibleToInstantAppOnly && isCallerInstantApp
+                                && isTargetHiddenFromInstantApp));
+
+                final boolean blockNormalResolution = !isTargetInstantApp && !isCallerInstantApp
+                        && shouldFilterApplicationLocked(
+                        getPackageSettingInternal(si.applicationInfo.packageName,
+                                Process.SYSTEM_UID), callingUid, userId);
+                if (!blockInstantResolution && !blockNormalResolution) {
+                    final ResolveInfo ri = new ResolveInfo();
+                    ri.serviceInfo = si;
+                    list = new ArrayList<>(1);
+                    list.add(ri);
+                    PackageManagerServiceUtils.applyEnforceIntentFilterMatching(
+                            mInjector.getCompatibility(), mComponentResolver,
+                            list, false, intent, resolvedType, callingUid);
+                }
+            }
+        } else {
+            list = queryIntentServicesInternalBody(intent, resolvedType, flags,
+                    userId, callingUid, instantAppPkgName);
+        }
+
+        if (originalIntent != null) {
+            // We also have to ensure all components match the original intent
+            PackageManagerServiceUtils.applyEnforceIntentFilterMatching(
+                    mInjector.getCompatibility(), mComponentResolver,
+                    list, false, originalIntent, resolvedType, callingUid);
+        }
+
+        return list;
+    }
+
+    protected @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
+            String resolvedType, int flags, int userId, int callingUid,
+            String instantAppPkgName) {
+        // reader
+        String pkgName = intent.getPackage();
+        if (pkgName == null) {
+            final List<ResolveInfo> resolveInfos = mComponentResolver.queryServices(intent,
+                    resolvedType, flags, userId);
+            if (resolveInfos == null) {
+                return Collections.emptyList();
+            }
+            return applyPostServiceResolutionFilter(
+                    resolveInfos, instantAppPkgName, userId, callingUid);
+        }
+        final AndroidPackage pkg = mPackages.get(pkgName);
+        if (pkg != null) {
+            final List<ResolveInfo> resolveInfos = mComponentResolver.queryServices(intent,
+                    resolvedType, flags, pkg.getServices(),
+                    userId);
+            if (resolveInfos == null) {
+                return Collections.emptyList();
+            }
+            return applyPostServiceResolutionFilter(
+                    resolveInfos, instantAppPkgName, userId, callingUid);
+        }
+        return Collections.emptyList();
+    }
+
+    public @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
+            Intent intent, String resolvedType, int flags, int filterCallingUid, int userId,
+            boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
+            String instantAppPkgName) {
+        // reader
+        boolean sortResult = false;
+        boolean addInstant = false;
+        List<ResolveInfo> result = null;
+        if (pkgName == null) {
+            List<CrossProfileIntentFilter> matchingFilters =
+                    getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
+            // Check for results that need to skip the current profile.
+            ResolveInfo skipProfileInfo  = querySkipCurrentProfileIntents(matchingFilters,
+                    intent, resolvedType, flags, userId);
+            if (skipProfileInfo != null) {
+                List<ResolveInfo> xpResult = new ArrayList<>(1);
+                xpResult.add(skipProfileInfo);
+                return new QueryIntentActivitiesResult(
+                        applyPostResolutionFilter(
+                                filterIfNotSystemUser(xpResult, userId), instantAppPkgName,
+                                allowDynamicSplits, filterCallingUid, resolveForStart, userId,
+                                intent));
+            }
+
+            // Check for results in the current profile.
+            result = filterIfNotSystemUser(mComponentResolver.queryActivities(
+                    intent, resolvedType, flags, userId), userId);
+            addInstant = isInstantAppResolutionAllowed(intent, result, userId,
+                    false /*skipPackageCheck*/, flags);
+            // Check for cross profile results.
+            boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
+            CrossProfileDomainInfo specificXpInfo = queryCrossProfileIntents(
+                    matchingFilters, intent, resolvedType, flags, userId,
+                    hasNonNegativePriorityResult);
+            if (intent.hasWebURI()) {
+                CrossProfileDomainInfo generalXpInfo = null;
+                final UserInfo parent = getProfileParent(userId);
+                if (parent != null) {
+                    generalXpInfo = getCrossProfileDomainPreferredLpr(intent, resolvedType,
+                            flags, userId, parent.id);
+                }
+
+                // Generalized cross profile intents take precedence over specific.
+                // Note that this is the opposite of the intuitive order.
+                CrossProfileDomainInfo prioritizedXpInfo =
+                        generalXpInfo != null ? generalXpInfo : specificXpInfo;
+
+                if (!addInstant) {
+                    if (result.isEmpty() && prioritizedXpInfo != null) {
+                        // No result in current profile, but found candidate in parent user.
+                        // And we are not going to add ephemeral app, so we can return the
+                        // result straight away.
+                        result.add(prioritizedXpInfo.mResolveInfo);
+                        return new QueryIntentActivitiesResult(
+                                applyPostResolutionFilter(result, instantAppPkgName,
+                                        allowDynamicSplits, filterCallingUid, resolveForStart,
+                                        userId, intent));
+                    } else if (result.size() <= 1 && prioritizedXpInfo == null) {
+                        // No result in parent user and <= 1 result in current profile, and we
+                        // are not going to add ephemeral app, so we can return the result
+                        // without further processing.
+                        return new QueryIntentActivitiesResult(
+                                applyPostResolutionFilter(result, instantAppPkgName,
+                                        allowDynamicSplits, filterCallingUid, resolveForStart,
+                                        userId, intent));
+                    }
+                }
+
+                // We have more than one candidate (combining results from current and parent
+                // profile), so we need filtering and sorting.
+                result = filterCandidatesWithDomainPreferredActivitiesLPr(
+                        intent, flags, result, prioritizedXpInfo, userId);
+                sortResult = true;
+            } else {
+                // If not web Intent, just add result to candidate set and let ResolverActivity
+                // figure it out.
+                if (specificXpInfo != null) {
+                    result.add(specificXpInfo.mResolveInfo);
+                    sortResult = true;
+                }
+            }
+        } else {
+            final PackageSetting setting =
+                    getPackageSettingInternal(pkgName, Process.SYSTEM_UID);
+            result = null;
+            if (setting != null && setting.pkg != null && (resolveForStart
+                    || !shouldFilterApplicationLocked(setting, filterCallingUid, userId))) {
+                result = filterIfNotSystemUser(mComponentResolver.queryActivities(
+                        intent, resolvedType, flags, setting.pkg.getActivities(), userId),
+                        userId);
+            }
+            if (result == null || result.size() == 0) {
+                // the caller wants to resolve for a particular package; however, there
+                // were no installed results, so, try to find an ephemeral result
+                addInstant = isInstantAppResolutionAllowed(intent, null /*result*/, userId,
+                        true /*skipPackageCheck*/, flags);
+                if (result == null) {
+                    result = new ArrayList<>();
+                }
+            }
+        }
+        return new QueryIntentActivitiesResult(sortResult, addInstant, result);
+    }
+
+    /**
+     * Returns the activity component that can handle install failures.
+     * <p>By default, the instant application installer handles failures. However, an
+     * application may want to handle failures on its own. Applications do this by
+     * creating an activity with an intent filter that handles the action
+     * {@link Intent#ACTION_INSTALL_FAILURE}.
+     */
+    private @Nullable ComponentName findInstallFailureActivity(
+            String packageName, int filterCallingUid, int userId) {
+        final Intent failureActivityIntent = new Intent(Intent.ACTION_INSTALL_FAILURE);
+        failureActivityIntent.setPackage(packageName);
+        // IMPORTANT: disallow dynamic splits to avoid an infinite loop
+        final List<ResolveInfo> result = queryIntentActivitiesInternal(
+                failureActivityIntent, null /*resolvedType*/, 0 /*flags*/,
+                0 /*privateResolveFlags*/, filterCallingUid, userId, false /*resolveForStart*/,
+                false /*allowDynamicSplits*/);
+        final int numResults = result.size();
+        if (numResults > 0) {
+            for (int i = 0; i < numResults; i++) {
+                final ResolveInfo info = result.get(i);
+                if (info.activityInfo.splitName != null) {
+                    continue;
+                }
+                return new ComponentName(packageName, info.activityInfo.name);
+            }
+        }
+        return null;
+    }
+
+    public final ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
+        return getActivityInfoInternal(component, flags, Binder.getCallingUid(), userId);
+    }
+
+    /**
+     * Important: The provided filterCallingUid is used exclusively to filter out activities
+     * that can be seen based on user state. It's typically the original caller uid prior
+     * to clearing. Because it can only be provided by trusted code, its value can be
+     * trusted and will be used as-is; unlike userId which will be validated by this method.
+     */
+    public final ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
+            int filterCallingUid, int userId) {
+        if (!mUserManager.exists(userId)) return null;
+        flags = updateFlagsForComponent(flags, userId);
+
+        if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) {
+            enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                    false /* requireFullPermission */, false /* checkShell */,
+                    "get activity info");
+        }
+
+        return getActivityInfoInternalBody(component, flags, filterCallingUid, userId);
+    }
+
+    protected ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
+            int filterCallingUid, int userId) {
+        ParsedActivity a = mComponentResolver.getActivity(component);
+
+        if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
+
+        AndroidPackage pkg = a == null ? null : mPackages.get(a.getPackageName());
+        if (pkg != null && mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) {
+            PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
+            if (ps == null) return null;
+            if (shouldFilterApplicationLocked(
+                    ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
+                return null;
+            }
+            return PackageInfoUtils.generateActivityInfo(pkg,
+                    a, flags, ps.readUserState(userId), userId, ps);
+        }
+        if (resolveComponentName().equals(component)) {
+            return PackageInfoWithoutStateUtils.generateDelegateActivityInfo(mResolveActivity,
+                    flags, new PackageUserState(), userId);
+        }
+        return null;
+    }
+
+    public AndroidPackage getPackage(String packageName) {
+        packageName = resolveInternalPackageNameLPr(
+                packageName, PackageManager.VERSION_CODE_HIGHEST);
+        return mPackages.get(packageName);
+    }
+
+    public AndroidPackage getPackage(int uid) {
+        final String[] packageNames = getPackagesForUidInternal(uid, Process.SYSTEM_UID);
+        AndroidPackage pkg = null;
+        final int numPackages = packageNames == null ? 0 : packageNames.length;
+        for (int i = 0; pkg == null && i < numPackages; i++) {
+            pkg = mPackages.get(packageNames[i]);
+        }
+        return pkg;
+    }
+
+    public final ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName,
+            int flags, int filterCallingUid, int userId) {
+        if (!mUserManager.exists(userId)) return null;
+        PackageSetting ps = mSettings.getPackageLPr(packageName);
+        if (ps != null) {
+            if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
+                return null;
+            }
+            if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
+                return null;
+            }
+            if (ps.pkg == null) {
+                final PackageInfo pInfo = generatePackageInfo(ps, flags, userId);
+                if (pInfo != null) {
+                    return pInfo.applicationInfo;
+                }
+                return null;
+            }
+            ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, flags,
+                    ps.readUserState(userId), userId, ps);
+            if (ai != null) {
+                ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
+            }
+            return ai;
+        }
+        return null;
+    }
+
+    public final ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
+        return getApplicationInfoInternal(packageName, flags, Binder.getCallingUid(), userId);
+    }
+
+    /**
+     * Important: The provided filterCallingUid is used exclusively to filter out applications
+     * that can be seen based on user state. It's typically the original caller uid prior
+     * to clearing. Because it can only be provided by trusted code, its value can be
+     * trusted and will be used as-is; unlike userId which will be validated by this method.
+     */
+    public final ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
+            int filterCallingUid, int userId) {
+        if (!mUserManager.exists(userId)) return null;
+        flags = updateFlagsForApplication(flags, userId);
+
+        if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) {
+            enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                    false /* requireFullPermission */, false /* checkShell */,
+                    "get application info");
+        }
+
+        return getApplicationInfoInternalBody(packageName, flags, filterCallingUid, userId);
+    }
+
+    protected ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
+            int filterCallingUid, int userId) {
+        // writer
+        // Normalize package name to handle renamed packages and static libs
+        packageName = resolveInternalPackageNameLPr(packageName,
+                PackageManager.VERSION_CODE_HIGHEST);
+
+        AndroidPackage p = mPackages.get(packageName);
+        if (DEBUG_PACKAGE_INFO) {
+            Log.v(
+                    TAG, "getApplicationInfo " + packageName
+                            + ": " + p);
+        }
+        if (p != null) {
+            PackageSetting ps = mSettings.getPackageLPr(packageName);
+            if (ps == null) return null;
+            if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
+                return null;
+            }
+            if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
+                return null;
+            }
+            // Note: isEnabledLP() does not apply here - always return info
+            ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(
+                    p, flags, ps.readUserState(userId), userId, ps);
+            if (ai != null) {
+                ai.packageName = resolveExternalPackageNameLPr(p);
+            }
+            return ai;
+        }
+        if ((flags & PackageManager.MATCH_APEX) != 0) {
+            // For APKs, PackageInfo.applicationInfo is not exactly the same as ApplicationInfo
+            // returned from getApplicationInfo, but for APEX packages difference shouldn't be
+            // very big.
+            // TODO(b/155328545): generate proper application info for APEXes as well.
+            int apexFlags = ApexManager.MATCH_ACTIVE_PACKAGE;
+            if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
+                apexFlags = ApexManager.MATCH_FACTORY_PACKAGE;
+            }
+            final PackageInfo pi = mApexManager.getPackageInfo(packageName, apexFlags);
+            if (pi == null) {
+                return null;
+            }
+            return pi.applicationInfo;
+        }
+        if ("android".equals(packageName) || "system".equals(packageName)) {
+            return androidApplication();
+        }
+        if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
+            // Already generates the external package name
+            return generateApplicationInfoFromSettingsLPw(packageName,
+                    flags, filterCallingUid, userId);
+        }
+        return null;
+    }
+
+    protected ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(
+            Intent intent, int matchFlags, List<ResolveInfo> candidates,
+            CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) {
+        final ArrayList<ResolveInfo> result = new ArrayList<>();
+        final ArrayList<ResolveInfo> matchAllList = new ArrayList<>();
+        final ArrayList<ResolveInfo> undefinedList = new ArrayList<>();
+
+        // Blocking instant apps is usually done in applyPostResolutionFilter, but since
+        // domain verification can resolve to a single result, which can be an instant app,
+        // it will then be filtered to an empty list in that method. Instead, do blocking
+        // here so that instant apps can be ignored for approval filtering and a lower
+        // priority result chosen instead.
+        final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled(userId);
+
+        final int count = candidates.size();
+        // First, try to use approved apps.
+        for (int n = 0; n < count; n++) {
+            ResolveInfo info = candidates.get(n);
+            if (blockInstant && (info.isInstantAppAvailable
+                    || isInstantApp(info.activityInfo.packageName, userId))) {
+                continue;
+            }
+
+            // Add to the special match all list (Browser use case)
+            if (info.handleAllWebDataURI) {
+                matchAllList.add(info);
+            } else {
+                undefinedList.add(info);
+            }
+        }
+
+        // We'll want to include browser possibilities in a few cases
+        boolean includeBrowser = false;
+
+        if (!DomainVerificationUtils.isDomainVerificationIntent(intent, matchFlags)) {
+            result.addAll(undefinedList);
+            // Maybe add one for the other profile.
+            if (xpDomainInfo != null && xpDomainInfo.mHighestApprovalLevel
+                    > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) {
+                result.add(xpDomainInfo.mResolveInfo);
+            }
+            includeBrowser = true;
+        } else {
+            Pair<List<ResolveInfo>, Integer> infosAndLevel = mDomainVerificationManager
+                    .filterToApprovedApp(intent, undefinedList, userId,
+                            mSettings::getPackageLPr);
+            List<ResolveInfo> approvedInfos = infosAndLevel.first;
+            Integer highestApproval = infosAndLevel.second;
+
+            // If no apps are approved for the domain, resolve only to browsers
+            if (approvedInfos.isEmpty()) {
+                includeBrowser = true;
+                if (xpDomainInfo != null && xpDomainInfo.mHighestApprovalLevel
+                        > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) {
+                    result.add(xpDomainInfo.mResolveInfo);
+                }
+            } else {
+                result.addAll(approvedInfos);
+
+                // If the other profile has an app that's higher approval, add it
+                if (xpDomainInfo != null
+                        && xpDomainInfo.mHighestApprovalLevel > highestApproval) {
+                    result.add(xpDomainInfo.mResolveInfo);
+                }
+            }
+        }
+
+        if (includeBrowser) {
+            // Also add browsers (all of them or only the default one)
+            if (DEBUG_DOMAIN_VERIFICATION) {
+                Slog.v(TAG, "   ...including browsers in candidate set");
+            }
+            if ((matchFlags & MATCH_ALL) != 0) {
+                result.addAll(matchAllList);
+            } else {
+                // Browser/generic handling case.  If there's a default browser, go straight
+                // to that (but only if there is no other higher-priority match).
+                final String defaultBrowserPackageName = mDefaultAppProvider.getDefaultBrowser(
+                        userId);
+                int maxMatchPrio = 0;
+                ResolveInfo defaultBrowserMatch = null;
+                final int numCandidates = matchAllList.size();
+                for (int n = 0; n < numCandidates; n++) {
+                    ResolveInfo info = matchAllList.get(n);
+                    // track the highest overall match priority...
+                    if (info.priority > maxMatchPrio) {
+                        maxMatchPrio = info.priority;
+                    }
+                    // ...and the highest-priority default browser match
+                    if (info.activityInfo.packageName.equals(defaultBrowserPackageName)) {
+                        if (defaultBrowserMatch == null
+                                || (defaultBrowserMatch.priority < info.priority)) {
+                            if (debug) {
+                                Slog.v(TAG, "Considering default browser match " + info);
+                            }
+                            defaultBrowserMatch = info;
+                        }
+                    }
+                }
+                if (defaultBrowserMatch != null
+                        && defaultBrowserMatch.priority >= maxMatchPrio
+                        && !TextUtils.isEmpty(defaultBrowserPackageName)) {
+                    if (debug) {
+                        Slog.v(TAG, "Default browser match " + defaultBrowserMatch);
+                    }
+                    result.add(defaultBrowserMatch);
+                } else {
+                    result.addAll(matchAllList);
+                }
+            }
+
+            // If there is nothing selected, add all candidates
+            if (result.size() == 0) {
+                result.addAll(candidates);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Report the 'Home' activity which is currently set as "always use this one". If non is set
+     * then reports the most likely home activity or null if there are more than one.
+     */
+    public final ComponentName getDefaultHomeActivity(int userId) {
+        List<ResolveInfo> allHomeCandidates = new ArrayList<>();
+        ComponentName cn = getHomeActivitiesAsUser(allHomeCandidates, userId);
+        if (cn != null) {
+            return cn;
+        }
+        // TODO: This should not happen since there should always be a default package set for
+        //  ROLE_HOME in RoleManager. Continue with a warning log for now.
+        Slog.w(TAG, "Default package for ROLE_HOME is not set in RoleManager");
+
+        // Find the launcher with the highest priority and return that component if there are no
+        // other home activity with the same priority.
+        int lastPriority = Integer.MIN_VALUE;
+        ComponentName lastComponent = null;
+        final int size = allHomeCandidates.size();
+        for (int i = 0; i < size; i++) {
+            final ResolveInfo ri = allHomeCandidates.get(i);
+            if (ri.priority > lastPriority) {
+                lastComponent = ri.activityInfo.getComponentName();
+                lastPriority = ri.priority;
+            } else if (ri.priority == lastPriority) {
+                // Two components found with same priority.
+                lastComponent = null;
+            }
+        }
+        return lastComponent;
+    }
+
+    public final ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
+            int userId) {
+        Intent intent  = getHomeIntent();
+        List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null,
+                PackageManager.GET_META_DATA, userId);
+        allHomeCandidates.clear();
+        if (resolveInfos == null) {
+            return null;
+        }
+        allHomeCandidates.addAll(resolveInfos);
+
+        String packageName = mDefaultAppProvider.getDefaultHome(userId);
+        if (packageName == null) {
+            // Role changes are not and cannot be atomic because its implementation lives inside
+            // a system app, so when the home role changes, there is a window when the previous
+            // role holder is removed and the new role holder is granted the preferred activity,
+            // but hasn't become the role holder yet. However, this case may be easily hit
+            // because the preferred activity change triggers a broadcast and receivers may try
+            // to get the default home activity there. So we need to fix it for this time
+            // window, and an easy workaround is to fallback to the current preferred activity.
+            final int appId = UserHandle.getAppId(Binder.getCallingUid());
+            final boolean filtered = appId >= Process.FIRST_APPLICATION_UID;
+            PackageManagerService.FindPreferredActivityBodyResult result =
+                    findPreferredActivityInternal(intent, null, 0, resolveInfos, true, false,
+                            false, userId, filtered);
+            ResolveInfo preferredResolveInfo =  result.mPreferredResolveInfo;
+            if (preferredResolveInfo != null && preferredResolveInfo.activityInfo != null) {
+                packageName = preferredResolveInfo.activityInfo.packageName;
+            }
+        }
+        if (packageName == null) {
+            return null;
+        }
+
+        int resolveInfosSize = resolveInfos.size();
+        for (int i = 0; i < resolveInfosSize; i++) {
+            ResolveInfo resolveInfo = resolveInfos.get(i);
+
+            if (resolveInfo.activityInfo != null && TextUtils.equals(
+                    resolveInfo.activityInfo.packageName, packageName)) {
+                return new ComponentName(resolveInfo.activityInfo.packageName,
+                        resolveInfo.activityInfo.name);
+            }
+        }
+        return null;
+    }
+
+    public final CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
+            String resolvedType, int flags, int sourceUserId, int parentUserId) {
+        if (!mUserManager.hasUserRestriction(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING,
+                sourceUserId)) {
+            return null;
+        }
+        List<ResolveInfo> resultTargetUser = mComponentResolver.queryActivities(intent,
+                resolvedType, flags, parentUserId);
+
+        if (resultTargetUser == null || resultTargetUser.isEmpty()) {
+            return null;
+        }
+        CrossProfileDomainInfo result = null;
+        int size = resultTargetUser.size();
+        for (int i = 0; i < size; i++) {
+            ResolveInfo riTargetUser = resultTargetUser.get(i);
+            // Intent filter verification is only for filters that specify a host. So don't
+            //return
+            // those that handle all web uris.
+            if (riTargetUser.handleAllWebDataURI) {
+                continue;
+            }
+            String packageName = riTargetUser.activityInfo.packageName;
+            PackageSetting ps = mSettings.getPackageLPr(packageName);
+            if (ps == null) {
+                continue;
+            }
+
+            int approvalLevel = mDomainVerificationManager
+                    .approvalLevelForDomain(ps, intent, flags, parentUserId);
+
+            if (result == null) {
+                result = new CrossProfileDomainInfo(createForwardingResolveInfoUnchecked(
+                        new WatchedIntentFilter(), sourceUserId, parentUserId), approvalLevel);
+            } else {
+                result.mHighestApprovalLevel =
+                        Math.max(approvalLevel, result.mHighestApprovalLevel);
+            }
+        }
+        if (result != null && result.mHighestApprovalLevel
+                <= DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) {
+            return null;
+        }
+        return result;
+    }
+
+    public final Intent getHomeIntent() {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_HOME);
+        intent.addCategory(Intent.CATEGORY_DEFAULT);
+        return intent;
+    }
+
+    public final List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(
+            Intent intent, String resolvedType, int userId) {
+        CrossProfileIntentResolver resolver = mSettings.getCrossProfileIntentResolver(userId);
+        if (resolver != null) {
+            return resolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, userId);
+        }
+        return null;
+    }
+
+    /**
+     * Filters out ephemeral activities.
+     * <p>When resolving for an ephemeral app, only activities that 1) are defined in the
+     * ephemeral app or 2) marked with {@code visibleToEphemeral} are returned.
+     *
+     * @param resolveInfos The pre-filtered list of resolved activities
+     * @param ephemeralPkgName The ephemeral package name. If {@code null}, no filtering
+     *          is performed.
+     * @param intent
+     * @return A filtered list of resolved activities.
+     */
+    public final List<ResolveInfo> applyPostResolutionFilter(
+            @NonNull List<ResolveInfo> resolveInfos,
+            String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
+            boolean resolveForStart, int userId, Intent intent) {
+        final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled(userId);
+        for (int i = resolveInfos.size() - 1; i >= 0; i--) {
+            final ResolveInfo info = resolveInfos.get(i);
+            // remove locally resolved instant app web results when disabled
+            if (info.isInstantAppAvailable && blockInstant) {
+                resolveInfos.remove(i);
+                continue;
+            }
+            // allow activities that are defined in the provided package
+            if (allowDynamicSplits
+                    && info.activityInfo != null
+                    && info.activityInfo.splitName != null
+                    && !ArrayUtils.contains(info.activityInfo.applicationInfo.splitNames,
+                    info.activityInfo.splitName)) {
+                if (instantAppInstallerActivity() == null) {
+                    if (DEBUG_INSTALL) {
+                        Slog.v(TAG, "No installer - not adding it to the ResolveInfo list");
+                    }
+                    resolveInfos.remove(i);
+                    continue;
+                }
+                if (blockInstant && isInstantApp(info.activityInfo.packageName, userId)) {
+                    resolveInfos.remove(i);
+                    continue;
+                }
+                // requested activity is defined in a split that hasn't been installed yet.
+                // add the installer to the resolve list
+                if (DEBUG_INSTALL) {
+                    Slog.v(TAG, "Adding installer to the ResolveInfo list");
+                }
+                final ResolveInfo installerInfo = new ResolveInfo(
+                        mInstantAppInstallerInfo);
+                final ComponentName installFailureActivity = findInstallFailureActivity(
+                        info.activityInfo.packageName,  filterCallingUid, userId);
+                installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
+                        installFailureActivity,
+                        info.activityInfo.packageName,
+                        info.activityInfo.applicationInfo.longVersionCode,
+                        info.activityInfo.splitName);
+                // add a non-generic filter
+                installerInfo.filter = new IntentFilter();
+
+                // This resolve info may appear in the chooser UI, so let us make it
+                // look as the one it replaces as far as the user is concerned which
+                // requires loading the correct label and icon for the resolve info.
+                installerInfo.resolvePackageName = info.getComponentInfo().packageName;
+                installerInfo.labelRes = info.resolveLabelResId();
+                installerInfo.icon = info.resolveIconResId();
+                installerInfo.isInstantAppAvailable = true;
+                resolveInfos.set(i, installerInfo);
+                continue;
+            }
+            if (ephemeralPkgName == null) {
+                // caller is a full app
+                SettingBase callingSetting =
+                        mSettings.getSettingLPr(UserHandle.getAppId(filterCallingUid));
+                PackageSetting resolvedSetting =
+                        getPackageSettingInternal(info.activityInfo.packageName, 0);
+                if (resolveForStart
+                        || !mAppsFilter.shouldFilterApplication(
+                        filterCallingUid, callingSetting, resolvedSetting, userId)) {
+                    continue;
+                }
+            } else if (ephemeralPkgName.equals(info.activityInfo.packageName)) {
+                // caller is same app; don't need to apply any other filtering
+                continue;
+            } else if (resolveForStart
+                    && (intent.isWebIntent()
+                    || (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0)
+                    && intent.getPackage() == null
+                    && intent.getComponent() == null) {
+                // ephemeral apps can launch other ephemeral apps indirectly
+                continue;
+            } else if (((info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP)
+                    != 0)
+                    && !info.activityInfo.applicationInfo.isInstantApp()) {
+                // allow activities that have been explicitly exposed to ephemeral apps
+                continue;
+            }
+            resolveInfos.remove(i);
+        }
+        return resolveInfos;
+    }
+
+    private List<ResolveInfo> applyPostServiceResolutionFilter(List<ResolveInfo> resolveInfos,
+            String instantAppPkgName, @UserIdInt int userId, int filterCallingUid) {
+        for (int i = resolveInfos.size() - 1; i >= 0; i--) {
+            final ResolveInfo info = resolveInfos.get(i);
+            if (instantAppPkgName == null) {
+                SettingBase callingSetting =
+                        mSettings.getSettingLPr(UserHandle.getAppId(filterCallingUid));
+                PackageSetting resolvedSetting =
+                        getPackageSettingInternal(info.serviceInfo.packageName, 0);
+                if (!mAppsFilter.shouldFilterApplication(
+                        filterCallingUid, callingSetting, resolvedSetting, userId)) {
+                    continue;
+                }
+            }
+            final boolean isEphemeralApp = info.serviceInfo.applicationInfo.isInstantApp();
+            // allow services that are defined in the provided package
+            if (isEphemeralApp && instantAppPkgName.equals(info.serviceInfo.packageName)) {
+                if (info.serviceInfo.splitName != null
+                        && !ArrayUtils.contains(info.serviceInfo.applicationInfo.splitNames,
+                        info.serviceInfo.splitName)) {
+                    if (instantAppInstallerActivity() == null) {
+                        if (DEBUG_INSTANT) {
+                            Slog.v(TAG, "No installer - not adding it to the ResolveInfo"
+                                    + "list");
+                        }
+                        resolveInfos.remove(i);
+                        continue;
+                    }
+                    // requested service is defined in a split that hasn't been installed yet.
+                    // add the installer to the resolve list
+                    if (DEBUG_INSTANT) {
+                        Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
+                    }
+                    final ResolveInfo installerInfo = new ResolveInfo(
+                            mInstantAppInstallerInfo);
+                    installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
+                            null /* installFailureActivity */,
+                            info.serviceInfo.packageName,
+                            info.serviceInfo.applicationInfo.longVersionCode,
+                            info.serviceInfo.splitName);
+                    // add a non-generic filter
+                    installerInfo.filter = new IntentFilter();
+                    // load resources from the correct package
+                    installerInfo.resolvePackageName = info.getComponentInfo().packageName;
+                    resolveInfos.set(i, installerInfo);
+                }
+                continue;
+            }
+            // allow services that have been explicitly exposed to ephemeral apps
+            if (!isEphemeralApp
+                    && ((info.serviceInfo.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP)
+                    != 0)) {
+                continue;
+            }
+            resolveInfos.remove(i);
+        }
+        return resolveInfos;
+    }
+
+    private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(Intent intent,
+            int matchFlags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo,
+            int userId) {
+        final boolean debug = (intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0;
+
+        if (DEBUG_PREFERRED || DEBUG_DOMAIN_VERIFICATION) {
+            Slog.v(TAG, "Filtering results with preferred activities. Candidates count: "
+                    + candidates.size());
+        }
+
+        final ArrayList<ResolveInfo> result =
+                filterCandidatesWithDomainPreferredActivitiesLPrBody(
+                        intent, matchFlags, candidates, xpDomainInfo, userId, debug);
+
+        if (DEBUG_PREFERRED || DEBUG_DOMAIN_VERIFICATION) {
+            Slog.v(TAG, "Filtered results with preferred activities. New candidates count: "
+                    + result.size());
+            for (ResolveInfo info : result) {
+                Slog.v(TAG, "  + " + info.activityInfo);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Filter out activities with systemUserOnly flag set, when current user is not System.
+     *
+     * @return filtered list
+     */
+    private List<ResolveInfo> filterIfNotSystemUser(List<ResolveInfo> resolveInfos,
+            int userId) {
+        if (userId == UserHandle.USER_SYSTEM) {
+            return resolveInfos;
+        }
+        for (int i = resolveInfos.size() - 1; i >= 0; i--) {
+            ResolveInfo info = resolveInfos.get(i);
+            if ((info.activityInfo.flags & ActivityInfo.FLAG_SYSTEM_USER_ONLY) != 0) {
+                resolveInfos.remove(i);
+            }
+        }
+        return resolveInfos;
+    }
+
+    private List<ResolveInfo> maybeAddInstantAppInstaller(List<ResolveInfo> result,
+            Intent intent,
+            String resolvedType, int flags, int userId, boolean resolveForStart,
+            boolean isRequesterInstantApp) {
+        // first, check to see if we've got an instant app already installed
+        final boolean alreadyResolvedLocally = (flags & PackageManager.MATCH_INSTANT) != 0;
+        ResolveInfo localInstantApp = null;
+        boolean blockResolution = false;
+        if (!alreadyResolvedLocally) {
+            final List<ResolveInfo> instantApps = mComponentResolver.queryActivities(
+                    intent,
+                    resolvedType,
+                    flags
+                            | PackageManager.GET_RESOLVED_FILTER
+                            | PackageManager.MATCH_INSTANT
+                            | PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY,
+                    userId);
+            for (int i = instantApps.size() - 1; i >= 0; --i) {
+                final ResolveInfo info = instantApps.get(i);
+                final String packageName = info.activityInfo.packageName;
+                final PackageSetting ps = mSettings.getPackageLPr(packageName);
+                if (ps.getInstantApp(userId)) {
+                    if (PackageManagerServiceUtils.hasAnyDomainApproval(
+                            mDomainVerificationManager, ps, intent, flags, userId)) {
+                        if (DEBUG_INSTANT) {
+                            Slog.v(TAG, "Instant app approved for intent; pkg: "
+                                    + packageName);
+                        }
+                        localInstantApp = info;
+                    } else {
+                        if (DEBUG_INSTANT) {
+                            Slog.v(TAG, "Instant app not approved for intent; pkg: "
+                                    + packageName);
+                        }
+                        blockResolution = true;
+                    }
+                    break;
+                }
+            }
+        }
+        // no app installed, let's see if one's available
+        AuxiliaryResolveInfo auxiliaryResponse = null;
+        if (!blockResolution) {
+            if (localInstantApp == null) {
+                // we don't have an instant app locally, resolve externally
+                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
+                String token = UUID.randomUUID().toString();
+                InstantAppResolveInfo.InstantAppDigest digest =
+                        InstantAppResolver.parseDigest(intent);
+                final InstantAppRequest requestObject =
+                        new InstantAppRequest(null /*responseObj*/,
+                                intent /*origIntent*/, resolvedType, null /*callingPackage*/,
+                                null /*callingFeatureId*/, isRequesterInstantApp, userId,
+                                null /*verificationBundle*/, resolveForStart,
+                                digest.getDigestPrefixSecure(), token);
+                auxiliaryResponse = InstantAppResolver.doInstantAppResolutionPhaseOne(
+                        mInstantAppResolverConnection, requestObject);
+                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            } else {
+                // we have an instant application locally, but, we can't admit that since
+                // callers shouldn't be able to determine prior browsing. create a placeholder
+                // auxiliary response so the downstream code behaves as if there's an
+                // instant application available externally. when it comes time to start
+                // the instant application, we'll do the right thing.
+                final ApplicationInfo ai = localInstantApp.activityInfo.applicationInfo;
+                auxiliaryResponse = new AuxiliaryResolveInfo(null /* failureActivity */,
+                        ai.packageName, ai.longVersionCode,
+                        null /* splitName */);
+            }
+        }
+        if (intent.isWebIntent() && auxiliaryResponse == null) {
+            return result;
+        }
+        final PackageSetting ps =
+                mSettings.getPackageLPr(instantAppInstallerActivity().packageName);
+        if (ps == null
+                || !ps.readUserState(userId).isEnabled(instantAppInstallerActivity(), 0)) {
+            return result;
+        }
+        final ResolveInfo ephemeralInstaller = new ResolveInfo(mInstantAppInstallerInfo);
+        ephemeralInstaller.activityInfo =
+                PackageInfoWithoutStateUtils.generateDelegateActivityInfo(
+                        instantAppInstallerActivity(), 0 /*flags*/, ps.readUserState(userId),
+                        userId);
+        ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
+                | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
+        // add a non-generic filter
+        ephemeralInstaller.filter = new IntentFilter();
+        if (intent.getAction() != null) {
+            ephemeralInstaller.filter.addAction(intent.getAction());
+        }
+        if (intent.getData() != null && intent.getData().getPath() != null) {
+            ephemeralInstaller.filter.addDataPath(
+                    intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
+        }
+        ephemeralInstaller.isInstantAppAvailable = true;
+        // make sure this resolver is the default
+        ephemeralInstaller.isDefault = true;
+        ephemeralInstaller.auxiliaryInfo = auxiliaryResponse;
+        if (DEBUG_INSTANT) {
+            Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
+        }
+
+        result.add(ephemeralInstaller);
+        return result;
+    }
+
+    public final PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
+        if (!mUserManager.exists(userId)) return null;
+        if (ps == null) {
+            return null;
+        }
+        final int callingUid = Binder.getCallingUid();
+        // Filter out ephemeral app metadata:
+        //   * The system/shell/root can see metadata for any app
+        //   * An installed app can see metadata for 1) other installed apps
+        //     and 2) ephemeral apps that have explicitly interacted with it
+        //   * Ephemeral apps can only see their own data and exposed installed apps
+        //   * Holding a signature permission allows seeing instant apps
+        if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
+            return null;
+        }
+
+        if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0
+                && ps.isSystem()) {
+            flags |= MATCH_ANY_USER;
+        }
+
+        final PackageUserState state = ps.readUserState(userId);
+        AndroidPackage p = ps.pkg;
+        if (p != null) {
+            // Compute GIDs only if requested
+            final int[] gids = (flags & PackageManager.GET_GIDS) == 0 ? EMPTY_INT_ARRAY
+                    : mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId));
+            // Compute granted permissions only if package has requested permissions
+            final Set<String> permissions = ((flags & PackageManager.GET_PERMISSIONS) == 0
+                    || ArrayUtils.isEmpty(p.getRequestedPermissions())) ? Collections.emptySet()
+                    : mPermissionManager.getGrantedPermissions(ps.name, userId);
+
+            PackageInfo packageInfo = PackageInfoUtils.generate(p, gids, flags,
+                    ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId, ps);
+
+            if (packageInfo == null) {
+                return null;
+            }
+
+            packageInfo.packageName = packageInfo.applicationInfo.packageName =
+                    resolveExternalPackageNameLPr(p);
+
+            return packageInfo;
+        } else if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0 && state.isAvailable(flags)) {
+            PackageInfo pi = new PackageInfo();
+            pi.packageName = ps.name;
+            pi.setLongVersionCode(ps.versionCode);
+            pi.sharedUserId = (ps.sharedUser != null) ? ps.sharedUser.name : null;
+            pi.firstInstallTime = ps.firstInstallTime;
+            pi.lastUpdateTime = ps.lastUpdateTime;
+
+            ApplicationInfo ai = new ApplicationInfo();
+            ai.packageName = ps.name;
+            ai.uid = UserHandle.getUid(userId, ps.appId);
+            ai.primaryCpuAbi = ps.primaryCpuAbiString;
+            ai.secondaryCpuAbi = ps.secondaryCpuAbiString;
+            ai.setVersionCode(ps.versionCode);
+            ai.flags = ps.pkgFlags;
+            ai.privateFlags = ps.pkgPrivateFlags;
+            pi.applicationInfo = PackageInfoWithoutStateUtils.generateDelegateApplicationInfo(
+                    ai, flags, state, userId);
+
+            if (DEBUG_PACKAGE_INFO) {
+                Log.v(TAG, "ps.pkg is n/a for ["
+                        + ps.name + "]. Provides a minimum info.");
+            }
+            return pi;
+        } else {
+            return null;
+        }
+    }
+
+    public final PackageInfo getPackageInfo(String packageName, int flags, int userId) {
+        return getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST,
+                flags, Binder.getCallingUid(), userId);
+    }
+
+    /**
+     * Important: The provided filterCallingUid is used exclusively to filter out packages
+     * that can be seen based on user state. It's typically the original caller uid prior
+     * to clearing. Because it can only be provided by trusted code, its value can be
+     * trusted and will be used as-is; unlike userId which will be validated by this method.
+     */
+    public final PackageInfo getPackageInfoInternal(String packageName, long versionCode,
+            int flags, int filterCallingUid, int userId) {
+        if (!mUserManager.exists(userId)) return null;
+        flags = updateFlagsForPackage(flags, userId);
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "get package info");
+
+        return getPackageInfoInternalBody(packageName, versionCode, flags, filterCallingUid,
+                userId);
+    }
+
+    protected PackageInfo getPackageInfoInternalBody(String packageName, long versionCode,
+            int flags, int filterCallingUid, int userId) {
+        // reader
+        // Normalize package name to handle renamed packages and static libs
+        packageName = resolveInternalPackageNameLPr(packageName, versionCode);
+
+        final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0;
+        if (matchFactoryOnly) {
+            // Instant app filtering for APEX modules is ignored
+            if ((flags & MATCH_APEX) != 0) {
+                return mApexManager.getPackageInfo(packageName,
+                        ApexManager.MATCH_FACTORY_PACKAGE);
+            }
+            final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
+            if (ps != null) {
+                if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
+                    return null;
+                }
+                if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
+                    return null;
+                }
+                return generatePackageInfo(ps, flags, userId);
+            }
+        }
+
+        AndroidPackage p = mPackages.get(packageName);
+        if (matchFactoryOnly && p != null && !p.isSystem()) {
+            return null;
+        }
+        if (DEBUG_PACKAGE_INFO) {
+            Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
+        }
+        if (p != null) {
+            final PackageSetting ps = getPackageSetting(p.getPackageName());
+            if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
+                return null;
+            }
+            if (ps != null && shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
+                return null;
+            }
+
+            return generatePackageInfo(ps, flags, userId);
+        }
+        if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) {
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
+            if (ps == null) return null;
+            if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
+                return null;
+            }
+            if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
+                return null;
+            }
+            return generatePackageInfo(ps, flags, userId);
+        }
+        if ((flags & MATCH_APEX) != 0) {
+            return mApexManager.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE);
+        }
+        return null;
+    }
+
+    @Nullable
+    public final PackageSetting getPackageSetting(String packageName) {
+        return getPackageSettingInternal(packageName, Binder.getCallingUid());
+    }
+
+    public PackageSetting getPackageSettingInternal(String packageName, int callingUid) {
+        packageName = resolveInternalPackageNameInternalLocked(
+                packageName, PackageManager.VERSION_CODE_HIGHEST, callingUid);
+        return mSettings.getPackageLPr(packageName);
+    }
+
+    @Nullable
+    public PackageState getPackageState(@NonNull String packageName) {
+        int callingUid = Binder.getCallingUid();
+        packageName = resolveInternalPackageNameInternalLocked(
+                packageName, PackageManager.VERSION_CODE_HIGHEST, callingUid);
+        PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
+        return pkgSetting == null ? null : PackageStateImpl.copy(pkgSetting);
+    }
+
+    public final ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        if (getInstantAppPackageName(callingUid) != null) {
+            return ParceledListSlice.emptyList();
+        }
+        if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        flags = updateFlagsForPackage(flags, userId);
+
+        enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
+                false /* checkShell */, "get installed packages");
+
+        return getInstalledPackagesBody(flags, userId, callingUid);
+    }
+
+    protected ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,
+            int callingUid) {
+        // writer
+        final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
+        final boolean listApex = (flags & MATCH_APEX) != 0;
+        final boolean listFactory = (flags & MATCH_FACTORY_ONLY) != 0;
+
+        ArrayList<PackageInfo> list;
+        if (listUninstalled) {
+            list = new ArrayList<>(mSettings.getPackagesLocked().size());
+            for (PackageSetting ps : mSettings.getPackagesLocked().values()) {
+                if (listFactory) {
+                    if (!ps.isSystem()) {
+                        continue;
+                    }
+                    PackageSetting psDisabled = mSettings.getDisabledSystemPkgLPr(ps);
+                    if (psDisabled != null) {
+                        ps = psDisabled;
+                    }
+                }
+                if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
+                    continue;
+                }
+                if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
+                    continue;
+                }
+                final PackageInfo pi = generatePackageInfo(ps, flags, userId);
+                if (pi != null) {
+                    list.add(pi);
+                }
+            }
+        } else {
+            list = new ArrayList<>(mPackages.size());
+            for (AndroidPackage p : mPackages.values()) {
+                PackageSetting ps = getPackageSetting(p.getPackageName());
+                if (listFactory) {
+                    if (!p.isSystem()) {
+                        continue;
+                    }
+                    PackageSetting psDisabled = mSettings.getDisabledSystemPkgLPr(ps);
+                    if (psDisabled != null) {
+                        ps = psDisabled;
+                    }
+                }
+                if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
+                    continue;
+                }
+                if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
+                    continue;
+                }
+                final PackageInfo pi = generatePackageInfo(ps, flags, userId);
+                if (pi != null) {
+                    list.add(pi);
+                }
+            }
+        }
+        if (listApex) {
+            if (listFactory) {
+                list.addAll(mApexManager.getFactoryPackages());
+            } else {
+                list.addAll(mApexManager.getActivePackages());
+            }
+            if (listUninstalled) {
+                list.addAll(mApexManager.getInactivePackages());
+            }
+        }
+        return new ParceledListSlice<>(list);
+    }
+
+    /**
+     * If the filter's target user can handle the intent and is enabled: a [ResolveInfo] that
+     * will forward the intent to the filter's target user, along with the highest approval of
+     * any handler in the target user. Otherwise, returns null.
+     */
+    @Nullable
+    private CrossProfileDomainInfo createForwardingResolveInfo(
+            @NonNull CrossProfileIntentFilter filter, @NonNull Intent intent,
+            @Nullable String resolvedType, int flags, int sourceUserId) {
+        int targetUserId = filter.getTargetUserId();
+        if (!isUserEnabled(targetUserId)) {
+            return null;
+        }
+
+        List<ResolveInfo> resultTargetUser = mComponentResolver.queryActivities(intent,
+                resolvedType, flags, targetUserId);
+        if (CollectionUtils.isEmpty(resultTargetUser)) {
+            return null;
+        }
+
+        ResolveInfo forwardingInfo = null;
+        for (int i = resultTargetUser.size() - 1; i >= 0; i--) {
+            ResolveInfo targetUserResolveInfo = resultTargetUser.get(i);
+            if ((targetUserResolveInfo.activityInfo.applicationInfo.flags
+                    & ApplicationInfo.FLAG_SUSPENDED) == 0) {
+                forwardingInfo = createForwardingResolveInfoUnchecked(filter, sourceUserId,
+                        targetUserId);
+                break;
+            }
+        }
+
+        if (forwardingInfo == null) {
+            // If all the matches in the target profile are suspended, return null.
+            return null;
+        }
+
+        int highestApprovalLevel = DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
+
+        int size = resultTargetUser.size();
+        for (int i = 0; i < size; i++) {
+            ResolveInfo riTargetUser = resultTargetUser.get(i);
+            if (riTargetUser.handleAllWebDataURI) {
+                continue;
+            }
+            String packageName = riTargetUser.activityInfo.packageName;
+            PackageSetting ps = mSettings.getPackageLPr(packageName);
+            if (ps == null) {
+                continue;
+            }
+            highestApprovalLevel = Math.max(highestApprovalLevel, mDomainVerificationManager
+                    .approvalLevelForDomain(ps, intent, flags, targetUserId));
+        }
+
+        return new CrossProfileDomainInfo(forwardingInfo, highestApprovalLevel);
+    }
+
+    public final ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
+            int sourceUserId, int targetUserId) {
+        ResolveInfo forwardingResolveInfo = new ResolveInfo();
+        final long ident = Binder.clearCallingIdentity();
+        boolean targetIsProfile;
+        try {
+            targetIsProfile = mUserManager.getUserInfo(targetUserId).isManagedProfile();
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+        String className;
+        if (targetIsProfile) {
+            className = FORWARD_INTENT_TO_MANAGED_PROFILE;
+        } else {
+            className = FORWARD_INTENT_TO_PARENT;
+        }
+        ComponentName forwardingActivityComponentName = new ComponentName(
+                androidApplication().packageName, className);
+        ActivityInfo forwardingActivityInfo =
+                getActivityInfo(forwardingActivityComponentName, 0,
+                        sourceUserId);
+        if (!targetIsProfile) {
+            forwardingActivityInfo.showUserIcon = targetUserId;
+            forwardingResolveInfo.noResourceId = true;
+        }
+        forwardingResolveInfo.activityInfo = forwardingActivityInfo;
+        forwardingResolveInfo.priority = 0;
+        forwardingResolveInfo.preferredOrder = 0;
+        forwardingResolveInfo.match = 0;
+        forwardingResolveInfo.isDefault = true;
+        forwardingResolveInfo.filter = new IntentFilter(filter.getIntentFilter());
+        forwardingResolveInfo.targetUserId = targetUserId;
+        return forwardingResolveInfo;
+    }
+
+    // Return matching ResolveInfo in target user if any.
+    @Nullable
+    private CrossProfileDomainInfo queryCrossProfileIntents(
+            List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
+            int flags, int sourceUserId, boolean matchInCurrentProfile) {
+        if (matchingFilters == null) {
+            return null;
+        }
+        // Two {@link CrossProfileIntentFilter}s can have the same targetUserId and
+        // match the same intent. For performance reasons, it is better not to
+        // run queryIntent twice for the same userId
+        SparseBooleanArray alreadyTriedUserIds = new SparseBooleanArray();
+
+        CrossProfileDomainInfo resultInfo = null;
+
+        int size = matchingFilters.size();
+        for (int i = 0; i < size; i++) {
+            CrossProfileIntentFilter filter = matchingFilters.get(i);
+            int targetUserId = filter.getTargetUserId();
+            boolean skipCurrentProfile =
+                    (filter.getFlags() & PackageManager.SKIP_CURRENT_PROFILE) != 0;
+            boolean skipCurrentProfileIfNoMatchFound =
+                    (filter.getFlags() & PackageManager.ONLY_IF_NO_MATCH_FOUND) != 0;
+            if (!skipCurrentProfile && !alreadyTriedUserIds.get(targetUserId)
+                    && (!skipCurrentProfileIfNoMatchFound || !matchInCurrentProfile)) {
+                // Checking if there are activities in the target user that can handle the
+                // intent.
+                CrossProfileDomainInfo info = createForwardingResolveInfo(filter, intent,
+                        resolvedType, flags, sourceUserId);
+                if (info != null) {
+                    resultInfo = info;
+                    break;
+                }
+                alreadyTriedUserIds.put(targetUserId, true);
+            }
+        }
+
+        if (resultInfo == null) {
+            return null;
+        }
+
+        ResolveInfo forwardingResolveInfo = resultInfo.mResolveInfo;
+        if (!isUserEnabled(forwardingResolveInfo.targetUserId)) {
+            return null;
+        }
+
+        List<ResolveInfo> filteredResult =
+                filterIfNotSystemUser(Collections.singletonList(forwardingResolveInfo),
+                        sourceUserId);
+        if (filteredResult.isEmpty()) {
+            return null;
+        }
+
+        return resultInfo;
+    }
+
+    private ResolveInfo querySkipCurrentProfileIntents(
+            List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
+            int flags, int sourceUserId) {
+        if (matchingFilters != null) {
+            int size = matchingFilters.size();
+            for (int i = 0; i < size; i++) {
+                CrossProfileIntentFilter filter = matchingFilters.get(i);
+                if ((filter.getFlags() & PackageManager.SKIP_CURRENT_PROFILE) != 0) {
+                    // Checking if there are activities in the target user that can handle the
+                    // intent.
+                    CrossProfileDomainInfo info = createForwardingResolveInfo(filter, intent,
+                            resolvedType, flags, sourceUserId);
+                    if (info != null) {
+                        return info.mResolveInfo;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    public final ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
+        if (!mUserManager.exists(userId)) return null;
+        final int callingUid = Binder.getCallingUid();
+        flags = updateFlagsForComponent(flags, userId);
+        enforceCrossUserOrProfilePermission(callingUid, userId,
+                false /* requireFullPermission */,
+                false /* checkShell */, "get service info");
+        return getServiceInfoBody(component, flags, userId, callingUid);
+    }
+
+    protected ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
+            int callingUid) {
+        ParsedService s = mComponentResolver.getService(component);
+        if (DEBUG_PACKAGE_INFO) {
+            Log.v(
+                    TAG, "getServiceInfo " + component + ": " + s);
+        }
+        if (s == null) {
+            return null;
+        }
+
+        AndroidPackage pkg = mPackages.get(s.getPackageName());
+        if (mSettings.isEnabledAndMatchLPr(pkg, s, flags, userId)) {
+            PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
+            if (ps == null) return null;
+            if (shouldFilterApplicationLocked(
+                    ps, callingUid, component, TYPE_SERVICE, userId)) {
+                return null;
+            }
+            return PackageInfoUtils.generateServiceInfo(pkg,
+                    s, flags, ps.readUserState(userId), userId, ps);
+        }
+        return null;
+    }
+
+    @Nullable
+    public final SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version) {
+        return PackageManagerService.getSharedLibraryInfo(
+                name, version, mSharedLibraries, null);
+    }
+
+    /**
+     * Returns the package name of the calling Uid if it's an instant app. If it isn't
+     * instant, returns {@code null}.
+     */
+    public String getInstantAppPackageName(int callingUid) {
+        // If the caller is an isolated app use the owner's uid for the lookup.
+        if (Process.isIsolated(callingUid)) {
+            callingUid = getIsolatedOwner(callingUid);
+        }
+        final int appId = UserHandle.getAppId(callingUid);
+        final Object obj = mSettings.getSettingLPr(appId);
+        if (obj instanceof PackageSetting) {
+            final PackageSetting ps = (PackageSetting) obj;
+            final boolean isInstantApp = ps.getInstantApp(UserHandle.getUserId(callingUid));
+            return isInstantApp ? ps.pkg.getPackageName() : null;
+        }
+        return null;
+    }
+
+    /**
+     * Finds the owner for the provided isolated UID. Throws IllegalStateException if no such
+     * isolated UID is found.
+     */
+    private int getIsolatedOwner(int isolatedUid) {
+        final int ownerUid = mIsolatedOwners.get(isolatedUid, -1);
+        if (ownerUid == -1) {
+            throw new IllegalStateException(
+                    "No owner UID found for isolated UID " + isolatedUid);
+        }
+        return ownerUid;
+    }
+
+    public final String resolveExternalPackageNameLPr(AndroidPackage pkg) {
+        if (pkg.getStaticSharedLibName() != null) {
+            return pkg.getManifestPackageName();
+        }
+        return pkg.getPackageName();
+    }
+
+    private String resolveInternalPackageNameInternalLocked(
+            String packageName, long versionCode, int callingUid) {
+        // Handle renamed packages
+        String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
+        packageName = normalizedPackageName != null ? normalizedPackageName : packageName;
+
+        // Is this a static library?
+        WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
+                mStaticLibsByDeclaringPackage.get(packageName);
+        if (versionedLib == null || versionedLib.size() <= 0) {
+            return packageName;
+        }
+
+        // Figure out which lib versions the caller can see
+        LongSparseLongArray versionsCallerCanSee = null;
+        final int callingAppId = UserHandle.getAppId(callingUid);
+        if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.SHELL_UID
+                && callingAppId != Process.ROOT_UID) {
+            versionsCallerCanSee = new LongSparseLongArray();
+            String libName = versionedLib.valueAt(0).getName();
+            String[] uidPackages = getPackagesForUidInternal(callingUid, callingUid);
+            if (uidPackages != null) {
+                for (String uidPackage : uidPackages) {
+                    PackageSetting ps = mSettings.getPackageLPr(uidPackage);
+                    final int libIdx = ArrayUtils.indexOf(ps.usesStaticLibraries, libName);
+                    if (libIdx >= 0) {
+                        final long libVersion = ps.usesStaticLibrariesVersions[libIdx];
+                        versionsCallerCanSee.append(libVersion, libVersion);
+                    }
+                }
+            }
+        }
+
+        // Caller can see nothing - done
+        if (versionsCallerCanSee != null && versionsCallerCanSee.size() <= 0) {
+            return packageName;
+        }
+
+        // Find the version the caller can see and the app version code
+        SharedLibraryInfo highestVersion = null;
+        final int versionCount = versionedLib.size();
+        for (int i = 0; i < versionCount; i++) {
+            SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
+            if (versionsCallerCanSee != null && versionsCallerCanSee.indexOfKey(
+                    libraryInfo.getLongVersion()) < 0) {
+                continue;
+            }
+            final long libVersionCode = libraryInfo.getDeclaringPackage().getLongVersionCode();
+            if (versionCode != PackageManager.VERSION_CODE_HIGHEST) {
+                if (libVersionCode == versionCode) {
+                    return libraryInfo.getPackageName();
+                }
+            } else if (highestVersion == null) {
+                highestVersion = libraryInfo;
+            } else if (libVersionCode  > highestVersion
+                    .getDeclaringPackage().getLongVersionCode()) {
+                highestVersion = libraryInfo;
+            }
+        }
+
+        if (highestVersion != null) {
+            return highestVersion.getPackageName();
+        }
+
+        return packageName;
+    }
+
+    public final String resolveInternalPackageNameLPr(String packageName, long versionCode) {
+        final int callingUid = Binder.getCallingUid();
+        return resolveInternalPackageNameInternalLocked(packageName, versionCode,
+                callingUid);
+    }
+
+    /**
+     * <em>IMPORTANT:</em> Not all packages returned by this method may be known
+     * to the system. There are two conditions in which this may occur:
+     * <ol>
+     *   <li>The package is on adoptable storage and the device has been removed</li>
+     *   <li>The package is being removed and the internal structures are partially updated</li>
+     * </ol>
+     * The second is an artifact of the current data structures and should be fixed. See
+     * b/111075456 for one such instance.
+     * This binder API is cached.  If the algorithm in this method changes,
+     * or if the underlying objecs (as returned by getSettingLPr()) change
+     * then the logic that invalidates the cache must be revisited.  See
+     * calls to invalidateGetPackagesForUidCache() to locate the points at
+     * which the cache is invalidated.
+     */
+    public final String[] getPackagesForUid(int uid) {
+        return getPackagesForUidInternal(uid, Binder.getCallingUid());
+    }
+
+    private String[] getPackagesForUidInternal(int uid, int callingUid) {
+        final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
+        final int userId = UserHandle.getUserId(uid);
+        final int appId = UserHandle.getAppId(uid);
+        return getPackagesForUidInternalBody(callingUid, userId, appId, isCallerInstantApp);
+    }
+
+    protected String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId,
+            boolean isCallerInstantApp) {
+        // reader
+        final Object obj = mSettings.getSettingLPr(appId);
+        if (obj instanceof SharedUserSetting) {
+            if (isCallerInstantApp) {
+                return null;
+            }
+            final SharedUserSetting sus = (SharedUserSetting) obj;
+            final int n = sus.packages.size();
+            String[] res = new String[n];
+            int i = 0;
+            for (int index = 0; index < n; index++) {
+                final PackageSetting ps = sus.packages.valueAt(index);
+                if (ps.getInstalled(userId)
+                        && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
+                    res[i++] = ps.name;
+                }
+            }
+            return ArrayUtils.trimToSize(res, i);
+        } else if (obj instanceof PackageSetting) {
+            final PackageSetting ps = (PackageSetting) obj;
+            if (ps.getInstalled(userId)
+                    && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
+                return new String[]{ps.name};
+            }
+        }
+        return null;
+    }
+
+    public final UserInfo getProfileParent(int userId) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return mUserManager.getProfileParent(userId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Returns whether or not instant apps have been disabled remotely.
+     */
+    private boolean areWebInstantAppsDisabled(int userId) {
+        return mWebInstantAppsDisabled.get(userId);
+    }
+
+    /**
+     * Returns whether or not a full application can see an instant application.
+     * <p>
+     * Currently, there are four cases in which this can occur:
+     * <ol>
+     * <li>The calling application is a "special" process. Special processes
+     *     are those with a UID < {@link Process#FIRST_APPLICATION_UID}.</li>
+     * <li>The calling application has the permission
+     *     {@link android.Manifest.permission#ACCESS_INSTANT_APPS}.</li>
+     * <li>The calling application is the default launcher on the
+     *     system partition.</li>
+     * <li>The calling application is the default app prediction service.</li>
+     * </ol>
+     */
+    public final boolean canViewInstantApps(int callingUid, int userId) {
+        if (callingUid < Process.FIRST_APPLICATION_UID) {
+            return true;
+        }
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.ACCESS_INSTANT_APPS) == PERMISSION_GRANTED) {
+            return true;
+        }
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.VIEW_INSTANT_APPS) == PERMISSION_GRANTED) {
+            final ComponentName homeComponent = getDefaultHomeActivity(userId);
+            if (homeComponent != null
+                    && isCallerSameApp(homeComponent.getPackageName(), callingUid)) {
+                return true;
+            }
+            // TODO(b/122900055) Change/Remove this and replace with new permission role.
+            return mAppPredictionServicePackage != null
+                    && isCallerSameApp(mAppPredictionServicePackage, callingUid);
+        }
+        return false;
+    }
+
+    public final boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid,
+            int userId, int flags) {
+        // Callers can access only the libs they depend on, otherwise they need to explicitly
+        // ask for the shared libraries given the caller is allowed to access all static libs.
+        if ((flags & PackageManager.MATCH_STATIC_SHARED_LIBRARIES) != 0) {
+            // System/shell/root get to see all static libs
+            final int appId = UserHandle.getAppId(uid);
+            if (appId == Process.SYSTEM_UID || appId == Process.SHELL_UID
+                    || appId == Process.ROOT_UID) {
+                return false;
+            }
+            // Installer gets to see all static libs.
+            if (PackageManager.PERMISSION_GRANTED
+                    == checkUidPermission(Manifest.permission.INSTALL_PACKAGES, uid)) {
+                return false;
+            }
+        }
+
+        // No package means no static lib as it is always on internal storage
+        if (ps == null || ps.pkg == null || !ps.pkg.isStaticSharedLibrary()) {
+            return false;
+        }
+
+        final SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(
+                ps.pkg.getStaticSharedLibName(), ps.pkg.getStaticSharedLibVersion());
+        if (libraryInfo == null) {
+            return false;
+        }
+
+        final int resolvedUid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
+        final String[] uidPackageNames = getPackagesForUid(resolvedUid);
+        if (uidPackageNames == null) {
+            return true;
+        }
+
+        for (String uidPackageName : uidPackageNames) {
+            if (ps.name.equals(uidPackageName)) {
+                return false;
+            }
+            PackageSetting uidPs = mSettings.getPackageLPr(uidPackageName);
+            if (uidPs != null) {
+                final int index = ArrayUtils.indexOf(uidPs.usesStaticLibraries,
+                        libraryInfo.getName());
+                if (index < 0) {
+                    continue;
+                }
+                if (uidPs.pkg.getUsesStaticLibrariesVersions()[index]
+                        == libraryInfo.getLongVersion()) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    private boolean hasCrossUserPermission(
+            int callingUid, int callingUserId, int userId, boolean requireFullPermission,
+            boolean requirePermissionWhenSameUser) {
+        if (!requirePermissionWhenSameUser && userId == callingUserId) {
+            return true;
+        }
+        if (callingUid == Process.SYSTEM_UID || callingUid == Process.ROOT_UID) {
+            return true;
+        }
+        if (requireFullPermission) {
+            return hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+        }
+        return hasPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+                || hasPermission(Manifest.permission.INTERACT_ACROSS_USERS);
+    }
+
+    /**
+     * @param resolveInfos list of resolve infos in descending priority order
+     * @return if the list contains a resolve info with non-negative priority
+     */
+    private boolean hasNonNegativePriority(List<ResolveInfo> resolveInfos) {
+        return resolveInfos.size() > 0 && resolveInfos.get(0).priority >= 0;
+    }
+
+    private boolean hasPermission(String permission) {
+        return mContext.checkCallingOrSelfPermission(permission)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
+    public final boolean isCallerSameApp(String packageName, int uid) {
+        AndroidPackage pkg = mPackages.get(packageName);
+        return pkg != null
+                && UserHandle.getAppId(uid) == pkg.getUid();
+    }
+
+    public final boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) {
+        if (isComponentVisibleToInstantApp(component, TYPE_ACTIVITY)) {
+            return true;
+        }
+        if (isComponentVisibleToInstantApp(component, TYPE_SERVICE)) {
+            return true;
+        }
+        return isComponentVisibleToInstantApp(component, TYPE_PROVIDER);
+    }
+
+    public final boolean isComponentVisibleToInstantApp(
+            @Nullable ComponentName component, @PackageManager.ComponentType int type) {
+        if (type == TYPE_ACTIVITY) {
+            final ParsedActivity activity = mComponentResolver.getActivity(component);
+            if (activity == null) {
+                return false;
+            }
+            final boolean visibleToInstantApp =
+                    (activity.getFlags() & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+            final boolean explicitlyVisibleToInstantApp =
+                    (activity.getFlags() & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP)
+                            == 0;
+            return visibleToInstantApp && explicitlyVisibleToInstantApp;
+        } else if (type == TYPE_RECEIVER) {
+            final ParsedActivity activity = mComponentResolver.getReceiver(component);
+            if (activity == null) {
+                return false;
+            }
+            final boolean visibleToInstantApp =
+                    (activity.getFlags() & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+            final boolean explicitlyVisibleToInstantApp =
+                    (activity.getFlags() & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP)
+                            == 0;
+            return visibleToInstantApp && !explicitlyVisibleToInstantApp;
+        } else if (type == TYPE_SERVICE) {
+            final ParsedService service = mComponentResolver.getService(component);
+            return service != null
+                    && (service.getFlags() & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+        } else if (type == TYPE_PROVIDER) {
+            final ParsedProvider provider = mComponentResolver.getProvider(component);
+            return provider != null
+                    && (provider.getFlags() & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+        } else if (type == TYPE_UNKNOWN) {
+            return isComponentVisibleToInstantApp(component);
+        }
+        return false;
+    }
+
+    /**
+     * From Android R,
+     *  camera intents have to match system apps. The only exception to this is if
+     * the DPC has set the camera persistent preferred activity. This case was introduced
+     * because it is important that the DPC has the ability to set both system and non-system
+     * camera persistent preferred activities.
+     *
+     * @return {@code true} if the intent is a camera intent and the persistent preferred
+     * activity was not set by the DPC.
+     */
+    public final boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent,
+            int userId, String resolvedType, int flags) {
+        return intent.isImplicitImageCaptureIntent() && !isPersistentPreferredActivitySetByDpm(
+                intent, userId, resolvedType, flags);
+    }
+
+    public final boolean isInstantApp(String packageName, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
+                false /* checkShell */, "isInstantApp");
+
+        return isInstantAppInternal(packageName, userId, callingUid);
+    }
+
+    public final boolean isInstantAppInternal(String packageName, @UserIdInt int userId,
+            int callingUid) {
+        if (HIDE_EPHEMERAL_APIS) {
+            return false;
+        }
+        return isInstantAppInternalBody(packageName, userId, callingUid);
+    }
+
+    protected boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
+            int callingUid) {
+        if (Process.isIsolated(callingUid)) {
+            callingUid = getIsolatedOwner(callingUid);
+        }
+        final PackageSetting ps = mSettings.getPackageLPr(packageName);
+        final boolean returnAllowed =
+                ps != null
+                        && (isCallerSameApp(packageName, callingUid)
+                        || canViewInstantApps(callingUid, userId)
+                        || mInstantAppRegistry.isInstantAccessGranted(
+                        userId, UserHandle.getAppId(callingUid), ps.appId));
+        if (returnAllowed) {
+            return ps.getInstantApp(userId);
+        }
+        return false;
+    }
+
+    private boolean isInstantAppResolutionAllowed(
+            Intent intent, List<ResolveInfo> resolvedActivities, int userId,
+            boolean skipPackageCheck, int flags) {
+        if (mInstantAppResolverConnection == null) {
+            return false;
+        }
+        if (instantAppInstallerActivity() == null) {
+            return false;
+        }
+        if (intent.getComponent() != null) {
+            return false;
+        }
+        if ((intent.getFlags() & Intent.FLAG_IGNORE_EPHEMERAL) != 0) {
+            return false;
+        }
+        if (!skipPackageCheck && intent.getPackage() != null) {
+            return false;
+        }
+        if (!intent.isWebIntent()) {
+            // for non web intents, we should not resolve externally if an app already exists to
+            // handle it or if the caller didn't explicitly request it.
+            if ((resolvedActivities != null && resolvedActivities.size() != 0)
+                    || (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) == 0) {
+                return false;
+            }
+        } else {
+            if (intent.getData() == null || TextUtils.isEmpty(intent.getData().getHost())) {
+                return false;
+            } else if (areWebInstantAppsDisabled(userId)) {
+                return false;
+            }
+        }
+        // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
+        // Or if there's already an ephemeral app installed that handles the action
+        return isInstantAppResolutionAllowedBody(intent, resolvedActivities, userId,
+                skipPackageCheck, flags);
+    }
+
+    // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
+    // Or if there's already an ephemeral app installed that handles the action
+    protected boolean isInstantAppResolutionAllowedBody(
+            Intent intent, List<ResolveInfo> resolvedActivities, int userId,
+            boolean skipPackageCheck, int flags) {
+        final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
+        for (int n = 0; n < count; n++) {
+            final ResolveInfo info = resolvedActivities.get(n);
+            final String packageName = info.activityInfo.packageName;
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
+            if (ps != null) {
+                // only check domain verification status if the app is not a browser
+                if (!info.handleAllWebDataURI) {
+                    if (PackageManagerServiceUtils.hasAnyDomainApproval(
+                            mDomainVerificationManager, ps, intent, flags, userId)) {
+                        if (DEBUG_INSTANT) {
+                            Slog.v(TAG, "DENY instant app;" + " pkg: " + packageName
+                                    + ", approved");
+                        }
+                        return false;
+                    }
+                }
+                if (ps.getInstantApp(userId)) {
+                    if (DEBUG_INSTANT) {
+                        Slog.v(TAG, "DENY instant app installed;"
+                                + " pkg: " + packageName);
+                    }
+                    return false;
+                }
+            }
+        }
+        // We've exhausted all ways to deny ephemeral application; let the system look for them.
+        return true;
+    }
+
+    private boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId,
+            String resolvedType, int flags) {
+        PersistentPreferredIntentResolver ppir =
+                mSettings.getPersistentPreferredActivities(userId);
+        //TODO(b/158003772): Remove double query
+        List<PersistentPreferredActivity> pprefs = ppir != null
+                ? ppir.queryIntent(intent, resolvedType,
+                (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
+                userId)
+                : new ArrayList<>();
+        for (PersistentPreferredActivity ppa : pprefs) {
+            if (ppa.mIsSetByDpm) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isRecentsAccessingChildProfiles(int callingUid, int targetUserId) {
+        if (!mInjector.getLocalService(ActivityTaskManagerInternal.class)
+                .isCallerRecents(callingUid)) {
+            return false;
+        }
+        final long token = Binder.clearCallingIdentity();
+        try {
+            final int callingUserId = UserHandle.getUserId(callingUid);
+            if (ActivityManager.getCurrentUser() != callingUserId) {
+                return false;
+            }
+            return mUserManager.isSameProfileGroup(callingUserId, targetUserId);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    public final boolean isSameProfileGroup(@UserIdInt int callerUserId,
+            @UserIdInt int userId) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return UserManagerService.getInstance().isSameProfileGroup(callerUserId, userId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private boolean isUserEnabled(int userId) {
+        final long callingId = Binder.clearCallingIdentity();
+        try {
+            UserInfo userInfo = mUserManager.getUserInfo(userId);
+            return userInfo != null && userInfo.isEnabled();
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+    }
+
+    /**
+     * Returns whether or not access to the application should be filtered.
+     * <p>
+     * Access may be limited based upon whether the calling or target applications
+     * are instant applications.
+     *
+     * @see #canViewInstantApps(int, int)
+     */
+    public final boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps,
+            int callingUid, @Nullable ComponentName component,
+            @PackageManager.ComponentType int componentType, int userId) {
+        // if we're in an isolated process, get the real calling UID
+        if (Process.isIsolated(callingUid)) {
+            callingUid = getIsolatedOwner(callingUid);
+        }
+        final String instantAppPkgName = getInstantAppPackageName(callingUid);
+        final boolean callerIsInstantApp = instantAppPkgName != null;
+        if (ps == null) {
+            // pretend the application exists, but, needs to be filtered
+            return callerIsInstantApp;
+        }
+        // if the target and caller are the same application, don't filter
+        if (isCallerSameApp(ps.name, callingUid)) {
+            return false;
+        }
+        if (callerIsInstantApp) {
+            // both caller and target are both instant, but, different applications, filter
+            if (ps.getInstantApp(userId)) {
+                return true;
+            }
+            // request for a specific component; if it hasn't been explicitly exposed through
+            // property or instrumentation target, filter
+            if (component != null) {
+                final ParsedInstrumentation instrumentation =
+                        mInstrumentation.get(component);
+                if (instrumentation != null
+                        && isCallerSameApp(instrumentation.getTargetPackage(), callingUid)) {
+                    return false;
+                }
+                return !isComponentVisibleToInstantApp(component, componentType);
+            }
+            // request for application; if no components have been explicitly exposed, filter
+            return !ps.pkg.isVisibleToInstantApps();
+        }
+        if (ps.getInstantApp(userId)) {
+            // caller can see all components of all instant applications, don't filter
+            if (canViewInstantApps(callingUid, userId)) {
+                return false;
+            }
+            // request for a specific instant application component, filter
+            if (component != null) {
+                return true;
+            }
+            // request for an instant application; if the caller hasn't been granted access,
+            //filter
+            return !mInstantAppRegistry.isInstantAccessGranted(
+                    userId, UserHandle.getAppId(callingUid), ps.appId);
+        }
+        int appId = UserHandle.getAppId(callingUid);
+        final SettingBase callingPs = mSettings.getSettingLPr(appId);
+        return mAppsFilter.shouldFilterApplication(callingUid, callingPs, ps, userId);
+    }
+
+    /**
+     * @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int)
+     */
+    public final boolean shouldFilterApplicationLocked(
+            @Nullable PackageSetting ps, int callingUid, int userId) {
+        return shouldFilterApplicationLocked(ps, callingUid, null, TYPE_UNKNOWN, userId);
+    }
+
+    /**
+     * @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int)
+     */
+    public final boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus,
+            int callingUid, int userId) {
+        boolean filterApp = true;
+        for (int index = sus.packages.size() - 1; index >= 0 && filterApp; index--) {
+            filterApp &= shouldFilterApplicationLocked(sus.packages.valueAt(index),
+                    callingUid, /* component */ null, TYPE_UNKNOWN, userId);
+        }
+        return filterApp;
+    }
+
+    /**
+     * Verification statuses are ordered from the worse to the best, except for
+     * INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER, which is the worse.
+     */
+    private int bestDomainVerificationStatus(int status1, int status2) {
+        if (status1 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
+            return status2;
+        }
+        if (status2 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
+            return status1;
+        }
+        return (int) MathUtils.max(status1, status2);
+    }
+
+    // NOTE: Can't remove without a major refactor. Keep around for now.
+    public final int checkUidPermission(String permName, int uid) {
+        return mPermissionManager.checkUidPermission(uid, permName);
+    }
+
+    public int getPackageUidInternal(String packageName, int flags, int userId,
+            int callingUid) {
+        // reader
+        final AndroidPackage p = mPackages.get(packageName);
+        if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) {
+            final PackageSetting ps = getPackageSettingInternal(p.getPackageName(), callingUid);
+            if (ps != null && ps.getInstalled(userId)
+                    && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
+                return UserHandle.getUid(userId, p.getUid());
+            }
+        }
+        if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
+            if (ps != null && ps.isMatch(flags)
+                    && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
+                return UserHandle.getUid(userId, ps.appId);
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * Update given flags based on encryption status of current user.
+     */
+    private int updateFlags(int flags, int userId) {
+        if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                | PackageManager.MATCH_DIRECT_BOOT_AWARE)) != 0) {
+            // Caller expressed an explicit opinion about what encryption
+            // aware/unaware components they want to see, so fall through and
+            // give them what they want
+        } else {
+            final UserManagerInternal umInternal = mInjector.getUserManagerInternal();
+            // Caller expressed no opinion, so match based on user state
+            if (umInternal.isUserUnlockingOrUnlocked(userId)) {
+                flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
+            } else {
+                flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE;
+            }
+        }
+        return flags;
+    }
+
+    /**
+     * Update given flags when being used to request {@link ApplicationInfo}.
+     */
+    public final int updateFlagsForApplication(int flags, int userId) {
+        return updateFlagsForPackage(flags, userId);
+    }
+
+    /**
+     * Update given flags when being used to request {@link ComponentInfo}.
+     */
+    public final int updateFlagsForComponent(int flags, int userId) {
+        return updateFlags(flags, userId);
+    }
+
+    /**
+     * Update given flags when being used to request {@link PackageInfo}.
+     */
+    public final int updateFlagsForPackage(int flags, int userId) {
+        final boolean isCallerSystemUser = UserHandle.getCallingUserId()
+                == UserHandle.USER_SYSTEM;
+        if ((flags & PackageManager.MATCH_ANY_USER) != 0) {
+            // require the permission to be held; the calling uid and given user id referring
+            // to the same user is not sufficient
+            enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false,
+                    !isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId),
+                    "MATCH_ANY_USER flag requires INTERACT_ACROSS_USERS permission");
+        } else if ((flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0
+                && isCallerSystemUser
+                && mUserManager.hasManagedProfile(UserHandle.USER_SYSTEM)) {
+            // If the caller wants all packages and has a restricted profile associated with it,
+            // then match all users. This is to make sure that launchers that need to access
+            //work
+            // profile apps don't start breaking. TODO: Remove this hack when launchers stop
+            //using
+            // MATCH_UNINSTALLED_PACKAGES to query apps in other profiles. b/31000380
+            flags |= PackageManager.MATCH_ANY_USER;
+        }
+        return updateFlags(flags, userId);
+    }
+
+    /**
+     * Update given flags when being used to request {@link ResolveInfo}.
+     * <p>Instant apps are resolved specially, depending upon context. Minimally,
+     * {@code}flags{@code} must have the {@link PackageManager#MATCH_INSTANT}
+     * flag set. However, this flag is only honoured in three circumstances:
+     * <ul>
+     * <li>when called from a system process</li>
+     * <li>when the caller holds the permission {@code
+     * android.permission.ACCESS_INSTANT_APPS}</li>
+     * <li>when resolution occurs to start an activity with a {@code android.intent.action.VIEW}
+     * action and a {@code android.intent.category.BROWSABLE} category</li>
+     * </ul>
+     */
+    public final int updateFlagsForResolve(int flags, int userId, int callingUid,
+            boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
+        return updateFlagsForResolve(flags, userId, callingUid,
+                wantInstantApps, false /*onlyExposedExplicitly*/,
+                isImplicitImageCaptureIntentAndNotSetByDpc);
+    }
+
+    public final int updateFlagsForResolve(int flags, int userId, int callingUid,
+            boolean wantInstantApps, boolean onlyExposedExplicitly,
+            boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
+        // Safe mode means we shouldn't match any third-party components
+        if (safeMode() || isImplicitImageCaptureIntentAndNotSetByDpc) {
+            flags |= PackageManager.MATCH_SYSTEM_ONLY;
+        }
+        if (getInstantAppPackageName(callingUid) != null) {
+            // But, ephemeral apps see both ephemeral and exposed, non-ephemeral components
+            if (onlyExposedExplicitly) {
+                flags |= PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY;
+            }
+            flags |= PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY;
+            flags |= PackageManager.MATCH_INSTANT;
+        } else {
+            final boolean wantMatchInstant = (flags & PackageManager.MATCH_INSTANT) != 0;
+            final boolean allowMatchInstant = wantInstantApps
+                    || (wantMatchInstant && canViewInstantApps(callingUid, userId));
+            flags &= ~(PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY
+                    | PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY);
+            if (!allowMatchInstant) {
+                flags &= ~PackageManager.MATCH_INSTANT;
+            }
+        }
+        return updateFlagsForComponent(flags, userId);
+    }
+
+    /**
+     * Checks if the request is from the system or an app that has the appropriate cross-user
+     * permissions defined as follows:
+     * <ul>
+     * <li>INTERACT_ACROSS_USERS_FULL if {@code requireFullPermission} is true.</li>
+     * <li>INTERACT_ACROSS_USERS if the given {@code userId} is in a different profile group
+     * to the caller.</li>
+     * <li>Otherwise,
+     *  INTERACT_ACROSS_PROFILES if the given {@code userId} is in the same profile
+     * group as the caller.</li>
+     * </ul>
+     *
+     * @param checkShell whether to prevent shell from access if there's a debugging restriction
+     * @param message the message to log on security exception
+     */
+    public final void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
+            boolean requireFullPermission, boolean checkShell, String message) {
+        if (userId < 0) {
+            throw new IllegalArgumentException("Invalid userId " + userId);
+        }
+        if (checkShell) {
+            PackageManagerServiceUtils.enforceShellRestriction(
+                    mInjector.getUserManagerInternal(),
+                    UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
+        }
+        final int callingUserId = UserHandle.getUserId(callingUid);
+        if (hasCrossUserPermission(callingUid, callingUserId, userId, requireFullPermission,
+                /*requirePermissionWhenSameUser= */ false)) {
+            return;
+        }
+        final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, userId);
+        if (isSameProfileGroup && PermissionChecker.checkPermissionForPreflight(
+                mContext,
+                android.Manifest.permission.INTERACT_ACROSS_PROFILES,
+                PermissionChecker.PID_UNKNOWN,
+                callingUid,
+                getPackage(callingUid).getPackageName())
+                == PermissionChecker.PERMISSION_GRANTED) {
+            return;
+        }
+        String errorMessage = buildInvalidCrossUserOrProfilePermissionMessage(
+                callingUid, userId, message, requireFullPermission, isSameProfileGroup);
+        Slog.w(TAG, errorMessage);
+        throw new SecurityException(errorMessage);
+    }
+
+    private static String buildInvalidCrossUserOrProfilePermissionMessage(int callingUid,
+            @UserIdInt int userId, String message, boolean requireFullPermission,
+            boolean isSameProfileGroup) {
+        StringBuilder builder = new StringBuilder();
+        if (message != null) {
+            builder.append(message);
+            builder.append(": ");
+        }
+        builder.append("UID ");
+        builder.append(callingUid);
+        builder.append(" requires ");
+        builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+        if (!requireFullPermission) {
+            builder.append(" or ");
+            builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS);
+            if (isSameProfileGroup) {
+                builder.append(" or ");
+                builder.append(android.Manifest.permission.INTERACT_ACROSS_PROFILES);
+            }
+        }
+        builder.append(" to access user ");
+        builder.append(userId);
+        builder.append(".");
+        return builder.toString();
+    }
+
+    /**
+     * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
+     * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller.
+     *
+     * @param checkShell whether to prevent shell from access if there's a debugging restriction
+     * @param message the message to log on security exception
+     */
+    public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
+            boolean requireFullPermission, boolean checkShell, String message) {
+        enforceCrossUserPermission(callingUid, userId, requireFullPermission, checkShell, false,
+                message);
+    }
+
+    /**
+     * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
+     * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller.
+     *
+     * @param checkShell whether to prevent shell from access if there's a debugging restriction
+     * @param requirePermissionWhenSameUser When {@code true}, still require the cross user
+     *                                      permission to be held even if the callingUid and
+     * userId
+     *                                      reference the same user.
+     * @param message the message to log on security exception
+     */
+    public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
+            boolean requireFullPermission, boolean checkShell,
+            boolean requirePermissionWhenSameUser, String message) {
+        if (userId < 0) {
+            throw new IllegalArgumentException("Invalid userId " + userId);
+        }
+        if (checkShell) {
+            PackageManagerServiceUtils.enforceShellRestriction(
+                    mInjector.getUserManagerInternal(),
+                    UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
+        }
+        final int callingUserId = UserHandle.getUserId(callingUid);
+        if (hasCrossUserPermission(
+                callingUid, callingUserId, userId, requireFullPermission,
+                requirePermissionWhenSameUser)) {
+            return;
+        }
+        String errorMessage = buildInvalidCrossUserPermissionMessage(
+                callingUid, userId, message, requireFullPermission);
+        Slog.w(TAG, errorMessage);
+        throw new SecurityException(errorMessage);
+    }
+
+    private static String buildInvalidCrossUserPermissionMessage(int callingUid,
+            @UserIdInt int userId, String message, boolean requireFullPermission) {
+        StringBuilder builder = new StringBuilder();
+        if (message != null) {
+            builder.append(message);
+            builder.append(": ");
+        }
+        builder.append("UID ");
+        builder.append(callingUid);
+        builder.append(" requires ");
+        builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+        if (!requireFullPermission) {
+            builder.append(" or ");
+            builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS);
+        }
+        builder.append(" to access user ");
+        builder.append(userId);
+        builder.append(".");
+        return builder.toString();
+    }
+
+    public SigningDetails getSigningDetails(@NonNull String packageName) {
+        AndroidPackage p = mPackages.get(packageName);
+        if (p == null) {
+            return null;
+        }
+        return p.getSigningDetails();
+    }
+
+    public SigningDetails getSigningDetails(int uid) {
+        final int appId = UserHandle.getAppId(uid);
+        final Object obj = mSettings.getSettingLPr(appId);
+        if (obj != null) {
+            if (obj instanceof SharedUserSetting) {
+                return ((SharedUserSetting) obj).signatures.mSigningDetails;
+            } else if (obj instanceof PackageSetting) {
+                final PackageSetting ps = (PackageSetting) obj;
+                return ps.signatures.mSigningDetails;
+            }
+        }
+        return SigningDetails.UNKNOWN;
+    }
+
+    public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
+        PackageSetting ps = getPackageSetting(pkg.getPackageName());
+        return shouldFilterApplicationLocked(ps, callingUid,
+                userId);
+    }
+
+    public boolean filterAppAccess(String packageName, int callingUid, int userId) {
+        PackageSetting ps = getPackageSetting(packageName);
+        return shouldFilterApplicationLocked(ps, callingUid,
+                userId);
+    }
+
+    public boolean filterAppAccess(int uid, int callingUid) {
+        final int userId = UserHandle.getUserId(uid);
+        final int appId = UserHandle.getAppId(uid);
+        final Object setting = mSettings.getSettingLPr(appId);
+
+        if (setting instanceof SharedUserSetting) {
+            return shouldFilterApplicationLocked(
+                    (SharedUserSetting) setting, callingUid, userId);
+        } else if (setting == null
+                || setting instanceof PackageSetting) {
+            return shouldFilterApplicationLocked(
+                    (PackageSetting) setting, callingUid, userId);
+        }
+        return false;
+    }
+
+    public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
+        final String packageName = dumpState.getTargetPackageName();
+        final PackageSetting setting = mSettings.getPackageLPr(packageName);
+        final boolean checkin = dumpState.isCheckIn();
+
+        // Return if the package doesn't exist.
+        if (packageName != null && setting == null) {
+            return;
+        }
+
+        switch (type) {
+            case DumpState.DUMP_VERSION:
+            {
+                if (dumpState.onTitlePrinted()) {
+                    pw.println();
+                }
+                pw.println("Database versions:");
+                mSettings.dumpVersionLPr(new IndentingPrintWriter(pw, "  "));
+                break;
+            }
+
+            case DumpState.DUMP_LIBS:
+            {
+                boolean printedHeader = false;
+                final int numSharedLibraries = mSharedLibraries.size();
+                for (int index = 0; index < numSharedLibraries; index++) {
+                    final String libName = mSharedLibraries.keyAt(index);
+                    final WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
+                            mSharedLibraries.get(libName);
+                    if (versionedLib == null) {
+                        continue;
+                    }
+                    final int versionCount = versionedLib.size();
+                    for (int i = 0; i < versionCount; i++) {
+                        SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
+                        if (!checkin) {
+                            if (!printedHeader) {
+                                if (dumpState.onTitlePrinted()) {
+                                    pw.println();
+                                }
+                                pw.println("Libraries:");
+                                printedHeader = true;
+                            }
+                            pw.print("  ");
+                        } else {
+                            pw.print("lib,");
+                        }
+                        pw.print(libraryInfo.getName());
+                        if (libraryInfo.isStatic()) {
+                            pw.print(" version=" + libraryInfo.getLongVersion());
+                        }
+                        if (!checkin) {
+                            pw.print(" -> ");
+                        }
+                        if (libraryInfo.getPath() != null) {
+                            if (libraryInfo.isNative()) {
+                                pw.print(" (so) ");
+                            } else {
+                                pw.print(" (jar) ");
+                            }
+                            pw.print(libraryInfo.getPath());
+                        } else {
+                            pw.print(" (apk) ");
+                            pw.print(libraryInfo.getPackageName());
+                        }
+                        pw.println();
+                    }
+                }
+                break;
+            }
+
+            case DumpState.DUMP_PREFERRED:
+                mSettings.dumpPreferred(pw, dumpState, packageName);
+                break;
+
+            case DumpState.DUMP_PREFERRED_XML:
+            {
+                pw.flush();
+                FileOutputStream fout = new FileOutputStream(fd);
+                BufferedOutputStream str = new BufferedOutputStream(fout);
+                TypedXmlSerializer serializer = Xml.newFastSerializer();
+                try {
+                    serializer.setOutput(str, StandardCharsets.UTF_8.name());
+                    serializer.startDocument(null, true);
+                    serializer.setFeature(
+                            "http://xmlpull.org/v1/doc/features.html#indent-output", true);
+                    mSettings.writePreferredActivitiesLPr(serializer, 0,
+                            dumpState.isFullPreferred());
+                    serializer.endDocument();
+                    serializer.flush();
+                } catch (IllegalArgumentException e) {
+                    pw.println("Failed writing: " + e);
+                } catch (IllegalStateException e) {
+                    pw.println("Failed writing: " + e);
+                } catch (IOException e) {
+                    pw.println("Failed writing: " + e);
+                }
+                break;
+            }
+
+            case DumpState.DUMP_QUERIES:
+            {
+                final Integer filteringAppId = setting == null ? null : setting.appId;
+                mAppsFilter.dumpQueries(
+                        pw, filteringAppId, dumpState, mUserManager.getUserIds(),
+                        this::getPackagesForUidInternalBody);
+                break;
+            }
+
+            case DumpState.DUMP_DOMAIN_PREFERRED:
+            {
+                final android.util.IndentingPrintWriter writer =
+                        new android.util.IndentingPrintWriter(pw);
+                if (dumpState.onTitlePrinted()) {
+                    pw.println();
+                }
+                writer.println("Domain verification status:");
+                writer.increaseIndent();
+                try {
+                    mDomainVerificationManager.printState(writer, packageName,
+                            UserHandle.USER_ALL, mSettings::getPackageLPr);
+                } catch (PackageManager.NameNotFoundException e) {
+                    pw.println("Failure printing domain verification information");
+                    Slog.e(TAG, "Failure printing domain verification information", e);
+                }
+                writer.decreaseIndent();
+                break;
+            }
+
+            case DumpState.DUMP_DEXOPT:
+            {
+                final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
+                if (dumpState.onTitlePrinted()) {
+                    pw.println();
+                }
+                ipw.println("Dexopt state:");
+                ipw.increaseIndent();
+                Collection<PackageSetting> pkgSettings;
+                if (setting != null) {
+                    pkgSettings = Collections.singletonList(setting);
+                } else {
+                    pkgSettings = mSettings.getPackagesLocked().values();
+                }
+
+                for (PackageSetting pkgSetting : pkgSettings) {
+                    final AndroidPackage pkg = pkgSetting.getPkg();
+                    if (pkg == null) {
+                        continue;
+                    }
+                    final String pkgName = pkg.getPackageName();
+                    ipw.println("[" + pkgName + "]");
+                    ipw.increaseIndent();
+
+                    mPackageDexOptimizer.dumpDexoptState(ipw, pkg, pkgSetting,
+                            mDexManager.getPackageUseInfoOrDefault(pkgName));
+                    ipw.decreaseIndent();
+                }
+                break;
+            }
+
+            case DumpState.DUMP_COMPILER_STATS:
+            {
+                final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
+                if (dumpState.onTitlePrinted()) {
+                    pw.println();
+                }
+                ipw.println("Compiler stats:");
+                ipw.increaseIndent();
+                Collection<PackageSetting> pkgSettings;
+                if (setting != null) {
+                    pkgSettings = Collections.singletonList(setting);
+                } else {
+                    pkgSettings = mSettings.getPackagesLocked().values();
+                }
+
+                for (PackageSetting pkgSetting : pkgSettings) {
+                    final AndroidPackage pkg = pkgSetting.getPkg();
+                    if (pkg == null) {
+                        continue;
+                    }
+                    final String pkgName = pkg.getPackageName();
+                    ipw.println("[" + pkgName + "]");
+                    ipw.increaseIndent();
+
+                    final CompilerStats.PackageStats stats =
+                            mCompilerStats.getPackageStats(pkgName);
+                    if (stats == null) {
+                        ipw.println("(No recorded stats)");
+                    } else {
+                        stats.dump(ipw);
+                    }
+                    ipw.decreaseIndent();
+                }
+                break;
+            }
+        } // switch
+    }
+
+    // The body of findPreferredActivity.
+    protected PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityBody(
+            Intent intent, String resolvedType, int flags,
+            List<ResolveInfo> query, boolean always,
+            boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered,
+            int callingUid, boolean isDeviceProvisioned) {
+        PackageManagerService.FindPreferredActivityBodyResult
+                result = new PackageManagerService.FindPreferredActivityBodyResult();
+
+        flags = updateFlagsForResolve(
+                flags, userId, callingUid, false /*includeInstantApps*/,
+                isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
+                        resolvedType, flags));
+        intent = PackageManagerServiceUtils.updateIntentForResolve(intent);
+
+        // Try to find a matching persistent preferred activity.
+        result.mPreferredResolveInfo = findPersistentPreferredActivityLP(intent,
+                resolvedType, flags, query, debug, userId);
+
+        // If a persistent preferred activity matched, use it.
+        if (result.mPreferredResolveInfo != null) {
+            return result;
+        }
+
+        PreferredIntentResolver pir = mSettings.getPreferredActivities(userId);
+        // Get the list of preferred activities that handle the intent
+        if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities...");
+        List<PreferredActivity> prefs = pir != null
+                ? pir.queryIntent(intent, resolvedType,
+                (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
+                userId)
+                : null;
+        if (prefs != null && prefs.size() > 0) {
+
+            // First figure out how good the original match set is.
+            // We will only allow preferred activities that came
+            // from the same match quality.
+            int match = 0;
+
+            if (DEBUG_PREFERRED || debug) {
+                Slog.v(TAG, "Figuring out best match...");
+            }
+
+            final int n = query.size();
+            for (int j = 0; j < n; j++) {
+                final ResolveInfo ri = query.get(j);
+                if (DEBUG_PREFERRED || debug) {
+                    Slog.v(TAG, "Match for " + ri.activityInfo
+                            + ": 0x" + Integer.toHexString(match));
+                }
+                if (ri.match > match) {
+                    match = ri.match;
+                }
+            }
+
+            if (DEBUG_PREFERRED || debug) {
+                Slog.v(TAG, "Best match: 0x" + Integer.toHexString(match));
+            }
+            match &= IntentFilter.MATCH_CATEGORY_MASK;
+            final int m = prefs.size();
+            for (int i = 0; i < m; i++) {
+                final PreferredActivity pa = prefs.get(i);
+                if (DEBUG_PREFERRED || debug) {
+                    Slog.v(TAG, "Checking PreferredActivity ds="
+                            + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "<none>")
+                            + "\n  component=" + pa.mPref.mComponent);
+                    pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
+                }
+                if (pa.mPref.mMatch != match) {
+                    if (DEBUG_PREFERRED || debug) {
+                        Slog.v(TAG, "Skipping bad match "
+                                + Integer.toHexString(pa.mPref.mMatch));
+                    }
+                    continue;
+                }
+                // If it's not an "always" type preferred activity and that's what we're
+                // looking for, skip it.
+                if (always && !pa.mPref.mAlways) {
+                    if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry");
+                    continue;
+                }
+                final ActivityInfo ai = getActivityInfo(
+                        pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS
+                                | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+                        userId);
+                if (DEBUG_PREFERRED || debug) {
+                    Slog.v(TAG, "Found preferred activity:");
+                    if (ai != null) {
+                        ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
+                    } else {
+                        Slog.v(TAG, "  null");
+                    }
+                }
+                final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent)
+                        && !isDeviceProvisioned;
+                final boolean allowSetMutation = !excludeSetupWizardHomeActivity
+                        && !queryMayBeFiltered;
+                if (ai == null) {
+                    // Do not remove launcher's preferred activity during SetupWizard
+                    // due to it may not install yet
+                    if (!allowSetMutation) {
+                        continue;
+                    }
+
+                    // This previously registered preferred activity
+                    // component is no longer known.  Most likely an update
+                    // to the app was installed and in the new version this
+                    // component no longer exists.  Clean it up by removing
+                    // it from the preferred activities list, and skip it.
+                    Slog.w(TAG, "Removing dangling preferred activity: "
+                            + pa.mPref.mComponent);
+                    pir.removeFilter(pa);
+                    result.mChanged = true;
+                    continue;
+                }
+                for (int j = 0; j < n; j++) {
+                    final ResolveInfo ri = query.get(j);
+                    if (!ri.activityInfo.applicationInfo.packageName
+                            .equals(ai.applicationInfo.packageName)) {
+                        continue;
+                    }
+                    if (!ri.activityInfo.name.equals(ai.name)) {
+                        continue;
+                    }
+
+                    if (removeMatches && allowSetMutation) {
+                        pir.removeFilter(pa);
+                        result.mChanged = true;
+                        if (DEBUG_PREFERRED) {
+                            Slog.v(TAG, "Removing match " + pa.mPref.mComponent);
+                        }
+                        break;
+                    }
+
+                    // Okay we found a previously set preferred or last chosen app.
+                    // If the result set is different from when this
+                    // was created, and is not a subset of the preferred set, we need to
+                    // clear it and re-ask the user their preference, if we're looking for
+                    // an "always" type entry.
+
+                    if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) {
+                        if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) {
+                            if (allowSetMutation) {
+                                // some components of the set are no longer present in
+                                // the query, but the preferred activity can still be reused
+                                if (DEBUG_PREFERRED) {
+                                    Slog.i(TAG, "Result set changed, but PreferredActivity"
+                                            + " is still valid as only non-preferred"
+                                            + " components were removed for " + intent
+                                            + " type " + resolvedType);
+                                }
+                                // remove obsolete components and re-add the up-to-date
+                                // filter
+                                PreferredActivity freshPa = new PreferredActivity(pa,
+                                        pa.mPref.mMatch,
+                                        pa.mPref.discardObsoleteComponents(query),
+                                        pa.mPref.mComponent,
+                                        pa.mPref.mAlways);
+                                pir.removeFilter(pa);
+                                pir.addFilter(freshPa);
+                                result.mChanged = true;
+                            } else {
+                                if (DEBUG_PREFERRED) {
+                                    Slog.i(TAG, "Do not remove preferred activity");
+                                }
+                            }
+                        } else {
+                            if (allowSetMutation) {
+                                Slog.i(TAG,
+                                        "Result set changed, dropping preferred activity "
+                                                + "for " + intent + " type "
+                                                + resolvedType);
+                                if (DEBUG_PREFERRED) {
+                                    Slog.v(TAG,
+                                            "Removing preferred activity since set changed "
+                                                    + pa.mPref.mComponent);
+                                }
+                                pir.removeFilter(pa);
+                                // Re-add the filter as a "last chosen" entry (!always)
+                                PreferredActivity lastChosen = new PreferredActivity(
+                                        pa, pa.mPref.mMatch, null, pa.mPref.mComponent,
+                                        false);
+                                pir.addFilter(lastChosen);
+                                result.mChanged = true;
+                            }
+                            result.mPreferredResolveInfo = null;
+                            return result;
+                        }
+                    }
+
+                    // Yay! Either the set matched or we're looking for the last chosen
+                    if (DEBUG_PREFERRED || debug) {
+                        Slog.v(TAG, "Returning preferred activity: "
+                                + ri.activityInfo.packageName + "/" + ri.activityInfo.name);
+                    }
+                    result.mPreferredResolveInfo = ri;
+                    return result;
+                }
+            }
+        }
+        return result;
+    }
+
+    private static boolean isHomeIntent(Intent intent) {
+        return ACTION_MAIN.equals(intent.getAction())
+                && intent.hasCategory(CATEGORY_HOME)
+                && intent.hasCategory(CATEGORY_DEFAULT);
+    }
+
+    public final PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityInternal(
+            Intent intent, String resolvedType, int flags,
+            List<ResolveInfo> query, boolean always,
+            boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
+
+        final int callingUid = Binder.getCallingUid();
+        // Do NOT hold the packages lock; this calls up into the settings provider which
+        // could cause a deadlock.
+        final boolean isDeviceProvisioned =
+                android.provider.Settings.Global.getInt(mContext.getContentResolver(),
+                        android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1;
+        // Find the preferred activity - the lock is held inside the method.
+        return findPreferredActivityBody(
+                intent, resolvedType, flags, query, always, removeMatches, debug,
+                userId, queryMayBeFiltered, callingUid, isDeviceProvisioned);
+    }
+
+    public final ResolveInfo findPersistentPreferredActivityLP(Intent intent,
+            String resolvedType,
+            int flags, List<ResolveInfo> query, boolean debug, int userId) {
+        final int n = query.size();
+        PersistentPreferredIntentResolver ppir =
+                mSettings.getPersistentPreferredActivities(userId);
+        // Get the list of persistent preferred activities that handle the intent
+        if (DEBUG_PREFERRED || debug) {
+            Slog.v(TAG, "Looking for persistent preferred activities...");
+        }
+        List<PersistentPreferredActivity> pprefs = ppir != null
+                ? ppir.queryIntent(intent, resolvedType,
+                (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
+                userId)
+                : null;
+        if (pprefs != null && pprefs.size() > 0) {
+            final int m = pprefs.size();
+            for (int i = 0; i < m; i++) {
+                final PersistentPreferredActivity ppa = pprefs.get(i);
+                if (DEBUG_PREFERRED || debug) {
+                    Slog.v(TAG, "Checking PersistentPreferredActivity ds="
+                            + (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "<none>")
+                            + "\n  component=" + ppa.mComponent);
+                    ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
+                }
+                final ActivityInfo ai = getActivityInfo(ppa.mComponent,
+                        flags | MATCH_DISABLED_COMPONENTS, userId);
+                if (DEBUG_PREFERRED || debug) {
+                    Slog.v(TAG, "Found persistent preferred activity:");
+                    if (ai != null) {
+                        ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
+                    } else {
+                        Slog.v(TAG, "  null");
+                    }
+                }
+                if (ai == null) {
+                    // This previously registered persistent preferred activity
+                    // component is no longer known. Ignore it and do NOT remove it.
+                    continue;
+                }
+                for (int j = 0; j < n; j++) {
+                    final ResolveInfo ri = query.get(j);
+                    if (!ri.activityInfo.applicationInfo.packageName
+                            .equals(ai.applicationInfo.packageName)) {
+                        continue;
+                    }
+                    if (!ri.activityInfo.name.equals(ai.name)) {
+                        continue;
+                    }
+                    //  Found a persistent preference that can handle the intent.
+                    if (DEBUG_PREFERRED || debug) {
+                        Slog.v(TAG, "Returning persistent preferred activity: "
+                                + ri.activityInfo.packageName + "/" + ri.activityInfo.name);
+                    }
+                    return ri;
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ComputerLocked.java b/services/core/java/com/android/server/pm/ComputerLocked.java
new file mode 100644
index 0000000..f63cc4e
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ComputerLocked.java
@@ -0,0 +1,221 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.SigningDetails;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.PackageState;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This subclass is the external interface to the live computer.  Some internal helper
+ * methods are overridden to fetch live data instead of snapshot data.  For each
+ * Computer interface that is overridden in this class, the override takes the PM lock
+ * and then delegates to the live computer engine.  This is required because there are
+ * no locks taken in the engine itself.
+ */
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+public final class ComputerLocked extends ComputerEngine {
+    private final Object mLock;
+
+    ComputerLocked(PackageManagerService.Snapshot args) {
+        super(args);
+        mLock = mService.mLock;
+    }
+
+    protected ComponentName resolveComponentName() {
+        return mService.getResolveComponentName();
+    }
+    protected ActivityInfo instantAppInstallerActivity() {
+        return mService.mInstantAppInstallerActivity;
+    }
+    protected ApplicationInfo androidApplication() {
+        return mService.mAndroidApplication;
+    }
+
+    public @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
+            String resolvedType, int flags, int userId, int callingUid,
+            String instantAppPkgName) {
+        synchronized (mLock) {
+            return super.queryIntentServicesInternalBody(intent, resolvedType, flags, userId,
+                    callingUid, instantAppPkgName);
+        }
+    }
+    public @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
+            Intent intent, String resolvedType, int flags, int filterCallingUid, int userId,
+            boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
+            String instantAppPkgName) {
+        synchronized (mLock) {
+            return super.queryIntentActivitiesInternalBody(intent, resolvedType, flags,
+                    filterCallingUid, userId, resolveForStart, allowDynamicSplits, pkgName,
+                    instantAppPkgName);
+        }
+    }
+    public ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
+            int filterCallingUid, int userId) {
+        synchronized (mLock) {
+            return super.getActivityInfoInternalBody(component, flags, filterCallingUid,
+                    userId);
+        }
+    }
+    public AndroidPackage getPackage(String packageName) {
+        synchronized (mLock) {
+            return super.getPackage(packageName);
+        }
+    }
+    public AndroidPackage getPackage(int uid) {
+        synchronized (mLock) {
+            return super.getPackage(uid);
+        }
+    }
+    public ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
+            int filterCallingUid, int userId) {
+        synchronized (mLock) {
+            return super.getApplicationInfoInternalBody(packageName, flags, filterCallingUid,
+                    userId);
+        }
+    }
+    public ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(
+            Intent intent, int matchFlags, List<ResolveInfo> candidates,
+            CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) {
+        synchronized (mLock) {
+            return super.filterCandidatesWithDomainPreferredActivitiesLPrBody(intent,
+                    matchFlags, candidates, xpDomainInfo, userId, debug);
+        }
+    }
+    public PackageInfo getPackageInfoInternalBody(String packageName, long versionCode,
+            int flags, int filterCallingUid, int userId) {
+        synchronized (mLock) {
+            return super.getPackageInfoInternalBody(packageName, versionCode, flags,
+                    filterCallingUid, userId);
+        }
+    }
+    public PackageSetting getPackageSettingInternal(String packageName, int callingUid) {
+        synchronized (mLock) {
+            return super.getPackageSettingInternal(packageName, callingUid);
+        }
+    }
+
+    @Nullable
+    public PackageState getPackageState(@NonNull String packageName) {
+        synchronized (mLock) {
+            return super.getPackageState(packageName);
+        }
+    }
+
+    public ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,
+            int callingUid) {
+        synchronized (mLock) {
+            return super.getInstalledPackagesBody(flags, userId, callingUid);
+        }
+    }
+    public ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
+            int callingUid) {
+        synchronized (mLock) {
+            return super.getServiceInfoBody(component, flags, userId, callingUid);
+        }
+    }
+    public String getInstantAppPackageName(int callingUid) {
+        synchronized (mLock) {
+            return super.getInstantAppPackageName(callingUid);
+        }
+    }
+    public String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId,
+            boolean isCallerInstantApp) {
+        synchronized (mLock) {
+            return super.getPackagesForUidInternalBody(callingUid, userId, appId,
+                    isCallerInstantApp);
+        }
+    }
+    public boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
+            int callingUid) {
+        synchronized (mLock) {
+            return super.isInstantAppInternalBody(packageName, userId, callingUid);
+        }
+    }
+    public boolean isInstantAppResolutionAllowedBody(Intent intent,
+            List<ResolveInfo> resolvedActivities, int userId, boolean skipPackageCheck,
+            int flags) {
+        synchronized (mLock) {
+            return super.isInstantAppResolutionAllowedBody(intent, resolvedActivities, userId,
+                    skipPackageCheck, flags);
+        }
+    }
+    public int getPackageUidInternal(String packageName, int flags, int userId,
+            int callingUid) {
+        synchronized (mLock) {
+            return super.getPackageUidInternal(packageName, flags, userId, callingUid);
+        }
+    }
+    public SigningDetails getSigningDetails(@NonNull String packageName) {
+        synchronized (mLock) {
+            return super.getSigningDetails(packageName);
+        }
+    }
+    public SigningDetails getSigningDetails(int uid) {
+        synchronized (mLock) {
+            return super.getSigningDetails(uid);
+        }
+    }
+    public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
+        synchronized (mLock) {
+            return super.filterAppAccess(pkg, callingUid, userId);
+        }
+    }
+    public boolean filterAppAccess(String packageName, int callingUid, int userId) {
+        synchronized (mLock) {
+            return super.filterAppAccess(packageName, callingUid, userId);
+        }
+    }
+    public boolean filterAppAccess(int uid, int callingUid) {
+        synchronized (mLock) {
+            return super.filterAppAccess(uid, callingUid);
+        }
+    }
+    public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
+        synchronized (mLock) {
+            super.dump(type, fd, pw, dumpState);
+        }
+    }
+    public PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityBody(
+            Intent intent, String resolvedType, int flags, List<ResolveInfo> query, boolean always,
+            boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered,
+            int callingUid, boolean isDeviceProvisioned) {
+        synchronized (mLock) {
+            return super.findPreferredActivityBody(intent, resolvedType, flags, query, always,
+                    removeMatches, debug, userId, queryMayBeFiltered, callingUid,
+                    isDeviceProvisioned);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ComputerTracker.java b/services/core/java/com/android/server/pm/ComputerTracker.java
new file mode 100644
index 0000000..5c25f67
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ComputerTracker.java
@@ -0,0 +1,651 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.SigningDetails;
+import android.content.pm.UserInfo;
+
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.PackageState;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * This subclass delegates to methods in a Computer after reference-counting the computer.
+ */
+public final class ComputerTracker implements Computer {
+
+    // The number of times a thread reused a computer in its stack instead of fetching
+    // a snapshot computer.
+    private final AtomicInteger mReusedSnapshot = new AtomicInteger(0);
+
+    // The number of times a thread reused a computer in its stack instead of fetching
+    // a live computer.
+    private final AtomicInteger mReusedLive = new AtomicInteger(0);
+
+    private final PackageManagerService mService;
+    ComputerTracker(PackageManagerService s) {
+        mService = s;
+    }
+
+    private ThreadComputer live() {
+        ThreadComputer current = PackageManagerService.sThreadComputer.get();
+        if (current.mRefCount > 0) {
+            current.acquire();
+            mReusedLive.incrementAndGet();
+        } else {
+            current.acquire(mService.liveComputer());
+        }
+        return current;
+    }
+
+    private ThreadComputer snapshot() {
+        ThreadComputer current = PackageManagerService.sThreadComputer.get();
+        if (current.mRefCount > 0) {
+            current.acquire();
+            mReusedSnapshot.incrementAndGet();
+        } else {
+            current.acquire(mService.snapshotComputer());
+        }
+        return current;
+    }
+
+    public @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
+            String resolvedType, int flags,
+            @PackageManagerInternal.PrivateResolveFlags int privateResolveFlags,
+            int filterCallingUid, int userId, boolean resolveForStart,
+            boolean allowDynamicSplits) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.queryIntentActivitiesInternal(intent, resolvedType, flags,
+                    privateResolveFlags, filterCallingUid, userId, resolveForStart,
+                    allowDynamicSplits);
+        } finally {
+            current.release();
+        }
+    }
+    public @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
+            String resolvedType, int flags, int userId) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.queryIntentActivitiesInternal(intent, resolvedType, flags,
+                    userId);
+        } finally {
+            current.release();
+        }
+    }
+    public @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
+            String resolvedType, int flags, int userId, int callingUid,
+            boolean includeInstantApps) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.queryIntentServicesInternal(intent, resolvedType, flags,
+                    userId, callingUid, includeInstantApps);
+        } finally {
+            current.release();
+        }
+    }
+    public @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
+            Intent intent,
+            String resolvedType, int flags, int filterCallingUid, int userId,
+            boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
+            String instantAppPkgName) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.queryIntentActivitiesInternalBody(intent, resolvedType,
+                    flags, filterCallingUid, userId, resolveForStart, allowDynamicSplits,
+                    pkgName, instantAppPkgName);
+        } finally {
+            current.release();
+        }
+    }
+    public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.getActivityInfo(component, flags, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
+            int filterCallingUid, int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.getActivityInfoInternal(component, flags, filterCallingUid,
+                    userId);
+        } finally {
+            current.release();
+        }
+    }
+    public AndroidPackage getPackage(String packageName) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.getPackage(packageName);
+        } finally {
+            current.release();
+        }
+    }
+    public AndroidPackage getPackage(int uid) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.getPackage(uid);
+        } finally {
+            current.release();
+        }
+    }
+    public ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName,
+            int flags, int filterCallingUid, int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.generateApplicationInfoFromSettingsLPw(packageName, flags,
+                    filterCallingUid, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.getApplicationInfo(packageName, flags, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
+            int filterCallingUid, int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.getApplicationInfoInternal(packageName, flags,
+                    filterCallingUid, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public ComponentName getDefaultHomeActivity(int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.getDefaultHomeActivity(userId);
+        } finally {
+            current.release();
+        }
+    }
+    public ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
+            int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.getHomeActivitiesAsUser(allHomeCandidates, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
+            String resolvedType, int flags, int sourceUserId, int parentUserId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.getCrossProfileDomainPreferredLpr(intent, resolvedType,
+                    flags, sourceUserId, parentUserId);
+        } finally {
+            current.release();
+        }
+    }
+    public Intent getHomeIntent() {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.getHomeIntent();
+        } finally {
+            current.release();
+        }
+    }
+    public List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(
+            Intent intent, String resolvedType, int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.getMatchingCrossProfileIntentFilters(intent, resolvedType,
+                    userId);
+        } finally {
+            current.release();
+        }
+    }
+    public List<ResolveInfo> applyPostResolutionFilter(
+            @NonNull List<ResolveInfo> resolveInfos,
+            String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
+            boolean resolveForStart, int userId, Intent intent) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.applyPostResolutionFilter(resolveInfos, ephemeralPkgName,
+                    allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent);
+        } finally {
+            current.release();
+        }
+    }
+    public PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.generatePackageInfo(ps, flags, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.getPackageInfo(packageName, flags, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public PackageInfo getPackageInfoInternal(String packageName, long versionCode,
+            int flags, int filterCallingUid, int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.getPackageInfoInternal(packageName, versionCode, flags,
+                    filterCallingUid, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public PackageSetting getPackageSetting(String packageName) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.getPackageSetting(packageName);
+        } finally {
+            current.release();
+        }
+    }
+    public PackageSetting getPackageSettingInternal(String packageName, int callingUid) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.getPackageSettingInternal(packageName, callingUid);
+        } finally {
+            current.release();
+        }
+    }
+
+    @Nullable
+    public PackageState getPackageState(@NonNull String packageName) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.getPackageState(packageName);
+        } finally {
+            current.release();
+        }
+    }
+
+    public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.getInstalledPackages(flags, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
+            int sourceUserId, int targetUserId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.createForwardingResolveInfoUnchecked(filter, sourceUserId,
+                    targetUserId);
+        } finally {
+            current.release();
+        }
+    }
+    public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.getServiceInfo(component, flags, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.getSharedLibraryInfoLPr(name, version);
+        } finally {
+            current.release();
+        }
+    }
+    public SigningDetails getSigningDetails(@NonNull String packageName) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.getSigningDetails(packageName);
+        } finally {
+            current.release();
+        }
+    }
+    public SigningDetails getSigningDetails(int uid) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.getSigningDetails(uid);
+        } finally {
+            current.release();
+        }
+    }
+    public String getInstantAppPackageName(int callingUid) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.getInstantAppPackageName(callingUid);
+        } finally {
+            current.release();
+        }
+    }
+    public String resolveExternalPackageNameLPr(AndroidPackage pkg) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.resolveExternalPackageNameLPr(pkg);
+        } finally {
+            current.release();
+        }
+    }
+    public String resolveInternalPackageNameLPr(String packageName, long versionCode) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.resolveInternalPackageNameLPr(packageName, versionCode);
+        } finally {
+            current.release();
+        }
+    }
+    public String[] getPackagesForUid(int uid) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.getPackagesForUid(uid);
+        } finally {
+            current.release();
+        }
+    }
+    public UserInfo getProfileParent(int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.getProfileParent(userId);
+        } finally {
+            current.release();
+        }
+    }
+    public boolean canViewInstantApps(int callingUid, int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.canViewInstantApps(callingUid, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.filterAppAccess(pkg, callingUid, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public boolean filterAppAccess(String packageName, int callingUid, int userId) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.filterAppAccess(packageName, callingUid, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public boolean filterAppAccess(int uid, int callingUid) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.filterAppAccess(uid, callingUid);
+        } finally {
+            current.release();
+        }
+    }
+    public boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid,
+            int userId, int flags) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.filterSharedLibPackageLPr(ps, uid, userId, flags);
+        } finally {
+            current.release();
+        }
+    }
+    public boolean isCallerSameApp(String packageName, int uid) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.isCallerSameApp(packageName, uid);
+        } finally {
+            current.release();
+        }
+    }
+    public boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.isComponentVisibleToInstantApp(component);
+        } finally {
+            current.release();
+        }
+    }
+    public boolean isComponentVisibleToInstantApp(@Nullable ComponentName component,
+            @PackageManager.ComponentType int type) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.isComponentVisibleToInstantApp(component, type);
+        } finally {
+            current.release();
+        }
+    }
+    public boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent,
+            int userId, String resolvedType, int flags) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent,
+                    userId, resolvedType, flags);
+        } finally {
+            current.release();
+        }
+    }
+    public boolean isInstantApp(String packageName, int userId) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.isInstantApp(packageName, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public boolean isInstantAppInternal(String packageName, @UserIdInt int userId,
+            int callingUid) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.isInstantAppInternal(packageName, userId, callingUid);
+        } finally {
+            current.release();
+        }
+    }
+    public boolean isSameProfileGroup(@UserIdInt int callerUserId,
+            @UserIdInt int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.isSameProfileGroup(callerUserId, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus,
+            int callingUid, int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.shouldFilterApplicationLocked(sus, callingUid, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps,
+            int callingUid, @Nullable ComponentName component,
+            @PackageManager.ComponentType int componentType, int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.shouldFilterApplicationLocked(ps, callingUid, component,
+                    componentType, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps,
+            int callingUid, int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.shouldFilterApplicationLocked(ps, callingUid, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public int checkUidPermission(String permName, int uid) {
+        ThreadComputer current = snapshot();
+        try {
+            return current.mComputer.checkUidPermission(permName, uid);
+        } finally {
+            current.release();
+        }
+    }
+    public int getPackageUidInternal(String packageName, int flags, int userId,
+            int callingUid) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.getPackageUidInternal(packageName, flags, userId,
+                    callingUid);
+        } finally {
+            current.release();
+        }
+    }
+    public int updateFlagsForApplication(int flags, int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.updateFlagsForApplication(flags, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public int updateFlagsForComponent(int flags, int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.updateFlagsForComponent(flags, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public int updateFlagsForPackage(int flags, int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.updateFlagsForPackage(flags, userId);
+        } finally {
+            current.release();
+        }
+    }
+    public int updateFlagsForResolve(int flags, int userId, int callingUid,
+            boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.updateFlagsForResolve(flags, userId, callingUid,
+                    wantInstantApps, isImplicitImageCaptureIntentAndNotSetByDpc);
+        } finally {
+            current.release();
+        }
+    }
+    public int updateFlagsForResolve(int flags, int userId, int callingUid,
+            boolean wantInstantApps, boolean onlyExposedExplicitly,
+            boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.updateFlagsForResolve(flags, userId, callingUid,
+                    wantInstantApps, onlyExposedExplicitly,
+                    isImplicitImageCaptureIntentAndNotSetByDpc);
+        } finally {
+            current.release();
+        }
+    }
+    public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
+        ThreadComputer current = live();
+        try {
+            current.mComputer.dump(type, fd, pw, dumpState);
+        } finally {
+            current.release();
+        }
+    }
+    public void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
+            boolean requireFullPermission, boolean checkShell, String message) {
+        ThreadComputer current = live();
+        try {
+            current.mComputer.enforceCrossUserOrProfilePermission(callingUid, userId,
+                    requireFullPermission, checkShell, message);
+        } finally {
+            current.release();
+        }
+    }
+    public void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
+            boolean requireFullPermission, boolean checkShell, String message) {
+        ThreadComputer current = live();
+        try {
+            current.mComputer.enforceCrossUserPermission(callingUid, userId,
+                    requireFullPermission, checkShell, message);
+        } finally {
+            current.release();
+        }
+    }
+    public void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
+            boolean requireFullPermission, boolean checkShell,
+            boolean requirePermissionWhenSameUser, String message) {
+        ThreadComputer current = live();
+        try {
+            current.mComputer.enforceCrossUserPermission(callingUid, userId,
+                    requireFullPermission, checkShell, requirePermissionWhenSameUser, message);
+        } finally {
+            current.release();
+        }
+    }
+    public PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityInternal(
+            Intent intent, String resolvedType, int flags, List<ResolveInfo> query, boolean always,
+            boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.findPreferredActivityInternal(intent, resolvedType, flags,
+                    query, always, removeMatches, debug, userId, queryMayBeFiltered);
+        } finally {
+            current.release();
+        }
+    }
+    public ResolveInfo findPersistentPreferredActivityLP(Intent intent,
+            String resolvedType, int flags, List<ResolveInfo> query, boolean debug,
+            int userId) {
+        ThreadComputer current = live();
+        try {
+            return current.mComputer.findPersistentPreferredActivityLP(intent, resolvedType,
+                    flags, query, debug, userId);
+        } finally {
+            current.release();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/CrossProfileDomainInfo.java b/services/core/java/com/android/server/pm/CrossProfileDomainInfo.java
new file mode 100644
index 0000000..31f4fa3
--- /dev/null
+++ b/services/core/java/com/android/server/pm/CrossProfileDomainInfo.java
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+import android.content.pm.ResolveInfo;
+
+public final class CrossProfileDomainInfo {
+    /* ResolveInfo for IntentForwarderActivity to send the intent to the other profile */
+    ResolveInfo mResolveInfo;
+    int mHighestApprovalLevel;
+
+    CrossProfileDomainInfo(ResolveInfo resolveInfo, int highestApprovalLevel) {
+        this.mResolveInfo = resolveInfo;
+        this.mHighestApprovalLevel = highestApprovalLevel;
+    }
+
+    @Override
+    public String toString() {
+        return "CrossProfileDomainInfo{"
+                + "resolveInfo=" + mResolveInfo
+                + ", highestApprovalLevel=" + mHighestApprovalLevel
+                + '}';
+    }
+}
diff --git a/services/core/java/com/android/server/pm/DomainVerificationConnection.java b/services/core/java/com/android/server/pm/DomainVerificationConnection.java
new file mode 100644
index 0000000..1a3f422
--- /dev/null
+++ b/services/core/java/com/android/server/pm/DomainVerificationConnection.java
@@ -0,0 +1,154 @@
+/*
+ * 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;
+
+import static com.android.server.pm.PackageManagerService.DOMAIN_VERIFICATION;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.pm.PackageManagerInternal;
+import android.os.Binder;
+import android.os.Message;
+import android.os.UserHandle;
+
+import com.android.internal.util.FunctionalUtils;
+import com.android.server.DeviceIdleInternal;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.verify.domain.DomainVerificationService;
+import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
+import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV2;
+
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+public final class DomainVerificationConnection implements DomainVerificationService.Connection,
+        DomainVerificationProxyV1.Connection, DomainVerificationProxyV2.Connection {
+    final PackageManagerService mPm;
+    final PackageManagerInternal mPmInternal;
+    final UserManagerInternal mUmInternal;
+    final VerificationHelper mVerificationHelper;
+
+    // TODO(b/198166813): remove PMS dependency
+    DomainVerificationConnection(PackageManagerService pm) {
+        mPm = pm;
+        mPmInternal = mPm.mInjector.getLocalService(PackageManagerInternal.class);
+        mUmInternal = mPm.mInjector.getLocalService(UserManagerInternal.class);
+        mVerificationHelper = new VerificationHelper(mPm.mContext);
+    }
+
+    @Override
+    public void scheduleWriteSettings() {
+        synchronized (mPm.mLock) {
+            mPm.scheduleWriteSettingsLocked();
+        }
+    }
+
+    @Override
+    public int getCallingUid() {
+        return Binder.getCallingUid();
+    }
+
+    @UserIdInt
+    @Override
+    public int getCallingUserId() {
+        return UserHandle.getCallingUserId();
+    }
+
+    @Override
+    public void schedule(int code, @Nullable Object object) {
+        Message message = mPm.mHandler.obtainMessage(DOMAIN_VERIFICATION);
+        message.arg1 = code;
+        message.obj = object;
+        mPm.mHandler.sendMessage(message);
+    }
+
+    @Override
+    public long getPowerSaveTempWhitelistAppDuration() {
+        return mVerificationHelper.getVerificationTimeout();
+    }
+
+    @Override
+    public DeviceIdleInternal getDeviceIdleInternal() {
+        return mPm.mInjector.getLocalService(DeviceIdleInternal.class);
+    }
+
+    @Override
+    public boolean isCallerPackage(int callingUid, @NonNull String packageName) {
+        final int callingUserId = UserHandle.getUserId(callingUid);
+        return callingUid == mPmInternal.getPackageUid(packageName, 0, callingUserId);
+    }
+
+    @Nullable
+    @Override
+    public AndroidPackage getPackage(@NonNull String packageName) {
+        return mPmInternal.getPackage(packageName);
+    }
+
+    @Override
+    public boolean filterAppAccess(String packageName, int callingUid, int userId) {
+        return mPmInternal.filterAppAccess(packageName, callingUid, userId);
+    }
+
+    @Override
+    public int[] getAllUserIds() {
+        return mUmInternal.getUserIds();
+    }
+
+    @Override
+    public boolean doesUserExist(@UserIdInt int userId) {
+        return mUmInternal.exists(userId);
+    }
+
+    @Override
+    public void withPackageSettingsSnapshot(
+            @NonNull Consumer<Function<String, PackageSetting>> block) {
+        mPmInternal.withPackageSettingsSnapshot(block);
+    }
+
+    @Override
+    public <Output> Output withPackageSettingsSnapshotReturning(
+            @NonNull FunctionalUtils.ThrowingFunction<Function<String, PackageSetting>, Output>
+                    block) {
+        return mPmInternal.withPackageSettingsSnapshotReturning(block);
+    }
+
+    @Override
+    public <ExceptionType extends Exception> void withPackageSettingsSnapshotThrowing(
+            @NonNull FunctionalUtils.ThrowingCheckedConsumer<Function<String, PackageSetting>,
+                    ExceptionType> block) throws ExceptionType {
+        mPmInternal.withPackageSettingsSnapshotThrowing(block);
+    }
+
+    @Override
+    public <ExceptionOne extends Exception, ExceptionTwo extends Exception> void
+            withPackageSettingsSnapshotThrowing2(
+                    @NonNull FunctionalUtils.ThrowingChecked2Consumer<
+                            Function<String, PackageSetting>, ExceptionOne, ExceptionTwo> block)
+            throws ExceptionOne, ExceptionTwo {
+        mPmInternal.withPackageSettingsSnapshotThrowing2(block);
+    }
+
+    @Override
+    public <Output, ExceptionType extends Exception> Output
+            withPackageSettingsSnapshotReturningThrowing(
+            @NonNull FunctionalUtils.ThrowingCheckedFunction<
+                    Function<String, PackageSetting>, Output, ExceptionType> block)
+            throws ExceptionType {
+        return mPmInternal.withPackageSettingsSnapshotReturningThrowing(block);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/FileInstallArgs.java b/services/core/java/com/android/server/pm/FileInstallArgs.java
index 3e18374..e492a9c 100644
--- a/services/core/java/com/android/server/pm/FileInstallArgs.java
+++ b/services/core/java/com/android/server/pm/FileInstallArgs.java
@@ -147,7 +147,7 @@
 
         final File targetDir = resolveTargetDir();
         final File beforeCodeFile = mCodeFile;
-        final File afterCodeFile = PackageManagerService.getNextCodePath(targetDir,
+        final File afterCodeFile = PackageManagerServiceUtils.getNextCodePath(targetDir,
                 parsedPackage.getPackageName());
 
         if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
diff --git a/services/core/java/com/android/server/pm/HandlerParams.java b/services/core/java/com/android/server/pm/HandlerParams.java
index ab24ee5..36d41c8 100644
--- a/services/core/java/com/android/server/pm/HandlerParams.java
+++ b/services/core/java/com/android/server/pm/HandlerParams.java
@@ -40,11 +40,13 @@
     int mTraceCookie;
     @NonNull
     final PackageManagerService mPm;
+    final VerificationHelper mVerificationHelper;
 
     // TODO(b/198166813): remove PMS dependency
     HandlerParams(UserHandle user, PackageManagerService pm) {
         mUser = user;
         mPm = pm;
+        mVerificationHelper = new VerificationHelper(mPm.mContext);
     }
 
     UserHandle getUser() {
diff --git a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
index bf241d4..4bbdd4c 100644
--- a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
@@ -50,6 +50,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.parsing.ParsingPackageUtils;
 import android.os.Environment;
+import android.os.Process;
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -575,6 +576,7 @@
                         Slog.w(TAG, "updateAllSharedLibrariesLPw failed: ", e);
                     }
                     mPm.mPermissionManager.onPackageInstalled(pkg,
+                            Process.INVALID_UID /* previousAppId */,
                             PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
                             UserHandle.USER_ALL);
                     mPm.writeSettingsLPrTEMP();
@@ -663,7 +665,7 @@
             return null;
         }
         final File dstCodePath =
-                PackageManagerService.getNextCodePath(Environment.getDataAppDirectory(null),
+                PackageManagerServiceUtils.getNextCodePath(Environment.getDataAppDirectory(null),
                         packageName);
         int ret = PackageManager.INSTALL_SUCCEEDED;
         try {
@@ -907,6 +909,7 @@
             // The method below will take care of removing obsolete permissions and granting
             // install permissions.
             mPm.mPermissionManager.onPackageInstalled(pkg,
+                    Process.INVALID_UID /* previousAppId */,
                     PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
                     UserHandle.USER_ALL);
             for (final int userId : allUserHandles) {
diff --git a/services/core/java/com/android/server/pm/InstallParams.java b/services/core/java/com/android/server/pm/InstallParams.java
index bc7d95e..cb2c99d 100644
--- a/services/core/java/com/android/server/pm/InstallParams.java
+++ b/services/core/java/com/android/server/pm/InstallParams.java
@@ -445,7 +445,8 @@
                     // processInstallRequestAsync. In that case just notify the observer about the
                     // failure.
                     InstallRequest request = apexInstallRequests.get(0);
-                    mPm.notifyInstallObserver(request.mInstallResult, request.mArgs.mObserver);
+                    mPm.notifyInstallObserver(request.mInstallResult,
+                            request.mArgs.mObserver);
                 }
                 return;
             }
@@ -662,7 +663,7 @@
                     final int verificationId = mPm.mPendingVerificationToken++;
                     final String rootHashString = PackageManagerServiceUtils
                             .buildVerificationRootHashString(baseCodePath, splitCodePaths);
-                    mPm.broadcastPackageVerified(verificationId, originUri,
+                    mVerificationHelper.broadcastPackageVerified(verificationId, originUri,
                             PackageManager.VERIFICATION_ALLOW, rootHashString,
                             args.mDataLoaderType, args.getUser());
                 }
@@ -1622,7 +1623,7 @@
 
             AndroidPackage pkg = mPm.commitReconciledScanResultLocked(reconciledPkg,
                     request.mAllUsers);
-            updateSettingsLI(pkg, reconciledPkg.mInstallArgs, request.mAllUsers, res);
+            updateSettingsLI(pkg, reconciledPkg, request.mAllUsers, res);
 
             final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
             if (ps != null) {
@@ -1642,17 +1643,18 @@
         return mPm.mSettings.disableSystemPackageLPw(oldPkg.getPackageName(), true);
     }
 
-    private void updateSettingsLI(AndroidPackage newPackage, InstallArgs installArgs,
+    private void updateSettingsLI(AndroidPackage newPackage, ReconciledPackage reconciledPkg,
             int[] allUsers, PackageInstalledInfo res) {
-        updateSettingsInternalLI(newPackage, installArgs, allUsers, res);
+        updateSettingsInternalLI(newPackage, reconciledPkg, allUsers, res);
     }
 
-    private void updateSettingsInternalLI(AndroidPackage pkg, InstallArgs installArgs,
+    private void updateSettingsInternalLI(AndroidPackage pkg, ReconciledPackage reconciledPkg,
             int[] allUsers, PackageInstalledInfo res) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
 
         final String pkgName = pkg.getPackageName();
         final int[] installedForUsers = res.mOrigUsers;
+        final InstallArgs installArgs = reconciledPkg.mInstallArgs;
         final int installReason = installArgs.mInstallReason;
         InstallSource installSource = installArgs.mInstallSource;
         final String installerPackageName = installSource.installerPackageName;
@@ -1808,8 +1810,9 @@
                 }
                 final int autoRevokePermissionsMode = installArgs.mAutoRevokePermissionsMode;
                 permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode);
-                mPm.mPermissionManager.onPackageInstalled(pkg, permissionParamsBuilder.build(),
-                        userId);
+                final ScanResult scanResult = reconciledPkg.mScanResult;
+                mPm.mPermissionManager.onPackageInstalled(pkg, scanResult.mPreviousAppId,
+                        permissionParamsBuilder.build(), userId);
             }
             res.mName = pkgName;
             res.mUid = pkg.getUid();
diff --git a/services/core/java/com/android/server/pm/MovePackageHelper.java b/services/core/java/com/android/server/pm/MovePackageHelper.java
new file mode 100644
index 0000000..4ebf3af4
--- /dev/null
+++ b/services/core/java/com/android/server/pm/MovePackageHelper.java
@@ -0,0 +1,450 @@
+/*
+ * 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;
+
+import static android.content.pm.PackageManager.INSTALL_INTERNAL;
+import static android.content.pm.PackageManager.MOVE_FAILED_3RD_PARTY_NOT_ALLOWED_ON_INTERNAL;
+import static android.content.pm.PackageManager.MOVE_FAILED_DEVICE_ADMIN;
+import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST;
+import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR;
+import static android.content.pm.PackageManager.MOVE_FAILED_LOCKED_USER;
+import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
+import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
+
+import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
+import static com.android.server.pm.PackageManagerService.TAG;
+
+import android.content.Intent;
+import android.content.pm.IPackageInstallObserver2;
+import android.content.pm.IPackageMoveObserver;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageStats;
+import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.PackageLite;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.util.MathUtils;
+import android.util.Slog;
+import android.util.SparseIntArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.SomeArgs;
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+
+import java.io.File;
+import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public final class MovePackageHelper {
+    final PackageManagerService mPm;
+
+    // TODO(b/198166813): remove PMS dependency
+    public MovePackageHelper(PackageManagerService pm) {
+        mPm = pm;
+    }
+
+    public void movePackageInternal(final String packageName, final String volumeUuid,
+            final int moveId, final int callingUid, UserHandle user)
+            throws PackageManagerException {
+        final StorageManager storage = mPm.mInjector.getSystemService(StorageManager.class);
+        final PackageManager pm = mPm.mContext.getPackageManager();
+
+        final String currentVolumeUuid;
+        final File codeFile;
+        final InstallSource installSource;
+        final String packageAbiOverride;
+        final int appId;
+        final String seinfo;
+        final String label;
+        final int targetSdkVersion;
+        final PackageFreezer freezer;
+        final int[] installedUserIds;
+        final boolean isCurrentLocationExternal;
+        final String fromCodePath;
+
+        // reader
+        synchronized (mPm.mLock) {
+            final AndroidPackage pkg = mPm.mPackages.get(packageName);
+            final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
+            if (pkg == null
+                    || ps == null
+                    || mPm.shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) {
+                throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
+            }
+            if (pkg.isSystem()) {
+                throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
+                        "Cannot move system application");
+            }
+
+            final boolean isInternalStorage = VolumeInfo.ID_PRIVATE_INTERNAL.equals(volumeUuid);
+            final boolean allow3rdPartyOnInternal = mPm.mContext.getResources().getBoolean(
+                    com.android.internal.R.bool.config_allow3rdPartyAppOnInternal);
+            if (isInternalStorage && !allow3rdPartyOnInternal) {
+                throw new PackageManagerException(MOVE_FAILED_3RD_PARTY_NOT_ALLOWED_ON_INTERNAL,
+                        "3rd party apps are not allowed on internal storage");
+            }
+
+            currentVolumeUuid = ps.volumeUuid;
+
+            final File probe = new File(pkg.getPath());
+            final File probeOat = new File(probe, "oat");
+            if (!probe.isDirectory() || !probeOat.isDirectory()) {
+                throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+                        "Move only supported for modern cluster style installs");
+            }
+
+            if (Objects.equals(currentVolumeUuid, volumeUuid)) {
+                throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+                        "Package already moved to " + volumeUuid);
+            }
+            if (!pkg.isExternalStorage() && mPm.isPackageDeviceAdminOnAnyUser(packageName)) {
+                throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN,
+                        "Device admin cannot be moved");
+            }
+
+            if (mPm.mFrozenPackages.contains(packageName)) {
+                throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
+                        "Failed to move already frozen package");
+            }
+
+            isCurrentLocationExternal = pkg.isExternalStorage();
+            codeFile = new File(pkg.getPath());
+            installSource = ps.installSource;
+            packageAbiOverride = ps.cpuAbiOverrideString;
+            appId = UserHandle.getAppId(pkg.getUid());
+            seinfo = AndroidPackageUtils.getSeInfo(pkg, ps);
+            label = String.valueOf(pm.getApplicationLabel(
+                    AndroidPackageUtils.generateAppInfoWithoutState(pkg)));
+            targetSdkVersion = pkg.getTargetSdkVersion();
+            freezer = mPm.freezePackage(packageName, "movePackageInternal");
+            installedUserIds = ps.queryInstalledUsers(mPm.mUserManager.getUserIds(), true);
+            if (codeFile.getParentFile().getName().startsWith(
+                    PackageManagerService.RANDOM_DIR_PREFIX)) {
+                fromCodePath = codeFile.getParentFile().getAbsolutePath();
+            } else {
+                fromCodePath = codeFile.getAbsolutePath();
+            }
+        }
+
+        final Bundle extras = new Bundle();
+        extras.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
+        extras.putString(Intent.EXTRA_TITLE, label);
+        mPm.mMoveCallbacks.notifyCreated(moveId, extras);
+
+        int installFlags;
+        final boolean moveCompleteApp;
+        final File measurePath;
+
+        installFlags = INSTALL_INTERNAL;
+        if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
+            moveCompleteApp = true;
+            measurePath = Environment.getDataAppDirectory(volumeUuid);
+        } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
+            moveCompleteApp = false;
+            measurePath = storage.getPrimaryPhysicalVolume().getPath();
+        } else {
+            final VolumeInfo volume = storage.findVolumeByUuid(volumeUuid);
+            if (volume == null || volume.getType() != VolumeInfo.TYPE_PRIVATE
+                    || !volume.isMountedWritable()) {
+                freezer.close();
+                throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+                        "Move location not mounted private volume");
+            }
+
+            moveCompleteApp = true;
+            measurePath = Environment.getDataAppDirectory(volumeUuid);
+        }
+
+        // If we're moving app data around, we need all the users unlocked
+        if (moveCompleteApp) {
+            for (int userId : installedUserIds) {
+                if (StorageManager.isFileEncryptedNativeOrEmulated()
+                        && !StorageManager.isUserKeyUnlocked(userId)) {
+                    throw new PackageManagerException(MOVE_FAILED_LOCKED_USER,
+                            "User " + userId + " must be unlocked");
+                }
+            }
+        }
+
+        final PackageStats stats = new PackageStats(null, -1);
+        synchronized (mPm.mInstallLock) {
+            for (int userId : installedUserIds) {
+                if (!getPackageSizeInfoLI(packageName, userId, stats)) {
+                    freezer.close();
+                    throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+                            "Failed to measure package size");
+                }
+            }
+        }
+
+        if (DEBUG_INSTALL) {
+            Slog.d(TAG, "Measured code size " + stats.codeSize + ", data size "
+                    + stats.dataSize);
+        }
+
+        final long startFreeBytes = measurePath.getUsableSpace();
+        final long sizeBytes;
+        if (moveCompleteApp) {
+            sizeBytes = stats.codeSize + stats.dataSize;
+        } else {
+            sizeBytes = stats.codeSize;
+        }
+
+        if (sizeBytes > storage.getStorageBytesUntilLow(measurePath)) {
+            freezer.close();
+            throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+                    "Not enough free space to move");
+        }
+
+        mPm.mMoveCallbacks.notifyStatusChanged(moveId, 10);
+
+        final CountDownLatch installedLatch = new CountDownLatch(1);
+        final IPackageInstallObserver2 installObserver = new IPackageInstallObserver2.Stub() {
+            @Override
+            public void onUserActionRequired(Intent intent) throws RemoteException {
+                throw new IllegalStateException();
+            }
+
+            @Override
+            public void onPackageInstalled(String basePackageName, int returnCode, String msg,
+                    Bundle extras) throws RemoteException {
+                if (DEBUG_INSTALL) {
+                    Slog.d(TAG, "Install result for move: "
+                            + PackageManager.installStatusToString(returnCode, msg));
+                }
+
+                installedLatch.countDown();
+                freezer.close();
+
+                final int status = PackageManager.installStatusToPublicStatus(returnCode);
+                switch (status) {
+                    case PackageInstaller.STATUS_SUCCESS:
+                        mPm.mMoveCallbacks.notifyStatusChanged(moveId,
+                                PackageManager.MOVE_SUCCEEDED);
+                        logAppMovedStorage(packageName, isCurrentLocationExternal);
+                        break;
+                    case PackageInstaller.STATUS_FAILURE_STORAGE:
+                        mPm.mMoveCallbacks.notifyStatusChanged(moveId,
+                                PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE);
+                        break;
+                    default:
+                        mPm.mMoveCallbacks.notifyStatusChanged(moveId,
+                                PackageManager.MOVE_FAILED_INTERNAL_ERROR);
+                        break;
+                }
+            }
+        };
+
+        final MoveInfo move;
+        if (moveCompleteApp) {
+            // Kick off a thread to report progress estimates
+            new Thread(() -> {
+                while (true) {
+                    try {
+                        if (installedLatch.await(1, TimeUnit.SECONDS)) {
+                            break;
+                        }
+                    } catch (InterruptedException ignored) {
+                    }
+
+                    final long deltaFreeBytes = startFreeBytes - measurePath.getUsableSpace();
+                    final int progress = 10 + (int) MathUtils.constrain(
+                            ((deltaFreeBytes * 80) / sizeBytes), 0, 80);
+                    mPm.mMoveCallbacks.notifyStatusChanged(moveId, progress);
+                }
+            }).start();
+
+            move = new MoveInfo(moveId, currentVolumeUuid, volumeUuid, packageName,
+                    appId, seinfo, targetSdkVersion, fromCodePath);
+        } else {
+            move = null;
+        }
+
+        installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
+
+        final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
+        final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+        final ParseResult<PackageLite> ret = ApkLiteParseUtils.parsePackageLite(input,
+                new File(origin.mResolvedPath), /* flags */ 0);
+        final PackageLite lite = ret.isSuccess() ? ret.getResult() : null;
+        final InstallParams params = new InstallParams(origin, move, installObserver, installFlags,
+                installSource, volumeUuid, user, packageAbiOverride, lite, mPm);
+        params.movePackage();
+    }
+
+    /**
+     * Logs that an app has been moved from internal to external storage and vice versa.
+     * @param packageName The package that was moved.
+     */
+    private void logAppMovedStorage(String packageName, boolean isPreviousLocationExternal) {
+        final AndroidPackage pkg;
+        synchronized (mPm.mLock) {
+            pkg = mPm.mPackages.get(packageName);
+        }
+        if (pkg == null) {
+            return;
+        }
+
+        final StorageManager storage = mPm.mInjector.getSystemService(StorageManager.class);
+        VolumeInfo volume = storage.findVolumeByUuid(
+                StorageManager.convert(pkg.getVolumeUuid()).toString());
+        int packageExternalStorageType = PackageManagerServiceUtils.getPackageExternalStorageType(
+                volume, pkg.isExternalStorage());
+
+        if (!isPreviousLocationExternal && pkg.isExternalStorage()) {
+            // Move from internal to external storage.
+            FrameworkStatsLog.write(FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED,
+                    packageExternalStorageType,
+                    FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_EXTERNAL,
+                    packageName);
+        } else if (isPreviousLocationExternal && !pkg.isExternalStorage()) {
+            // Move from external to internal storage.
+            FrameworkStatsLog.write(FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED,
+                    packageExternalStorageType,
+                    FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_INTERNAL,
+                    packageName);
+        }
+    }
+
+    @GuardedBy("mPm.mInstallLock")
+    private boolean getPackageSizeInfoLI(String packageName, int userId, PackageStats stats) {
+        final PackageSetting ps;
+        synchronized (mPm.mLock) {
+            ps = mPm.mSettings.getPackageLPr(packageName);
+            if (ps == null) {
+                Slog.w(TAG, "Failed to find settings for " + packageName);
+                return false;
+            }
+        }
+
+        final String[] packageNames = { packageName };
+        final long[] ceDataInodes = { ps.getCeDataInode(userId) };
+        final String[] codePaths = { ps.getPathString() };
+
+        try {
+            mPm.mInstaller.getAppSize(ps.volumeUuid, packageNames, userId, 0,
+                    ps.appId, ceDataInodes, codePaths, stats);
+
+            // For now, ignore code size of packages on system partition
+            if (PackageManagerServiceUtils.isSystemApp(ps)
+                    && !PackageManagerServiceUtils.isUpdatedSystemApp(ps)) {
+                stats.codeSize = 0;
+            }
+
+            // External clients expect these to be tracked separately
+            stats.dataSize -= stats.cacheSize;
+
+        } catch (Installer.InstallerException e) {
+            Slog.w(TAG, String.valueOf(e));
+            return false;
+        }
+
+        return true;
+    }
+
+    public static class MoveCallbacks extends Handler {
+        private static final int MSG_CREATED = 1;
+        private static final int MSG_STATUS_CHANGED = 2;
+
+        private final RemoteCallbackList<IPackageMoveObserver>
+                mCallbacks = new RemoteCallbackList<>();
+
+        public final SparseIntArray mLastStatus = new SparseIntArray();
+
+        public MoveCallbacks(Looper looper) {
+            super(looper);
+        }
+
+        public void register(IPackageMoveObserver callback) {
+            mCallbacks.register(callback);
+        }
+
+        public void unregister(IPackageMoveObserver callback) {
+            mCallbacks.unregister(callback);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            final SomeArgs args = (SomeArgs) msg.obj;
+            final int n = mCallbacks.beginBroadcast();
+            for (int i = 0; i < n; i++) {
+                final IPackageMoveObserver callback = mCallbacks.getBroadcastItem(i);
+                try {
+                    invokeCallback(callback, msg.what, args);
+                } catch (RemoteException ignored) {
+                }
+            }
+            mCallbacks.finishBroadcast();
+            args.recycle();
+        }
+
+        private void invokeCallback(IPackageMoveObserver callback, int what, SomeArgs args)
+                throws RemoteException {
+            switch (what) {
+                case MSG_CREATED: {
+                    callback.onCreated(args.argi1, (Bundle) args.arg2);
+                    break;
+                }
+                case MSG_STATUS_CHANGED: {
+                    callback.onStatusChanged(args.argi1, args.argi2, (long) args.arg3);
+                    break;
+                }
+            }
+        }
+
+        public void notifyCreated(int moveId, Bundle extras) {
+            Slog.v(TAG, "Move " + moveId + " created " + extras.toString());
+
+            final SomeArgs args = SomeArgs.obtain();
+            args.argi1 = moveId;
+            args.arg2 = extras;
+            obtainMessage(MSG_CREATED, args).sendToTarget();
+        }
+
+        public void notifyStatusChanged(int moveId, int status) {
+            notifyStatusChanged(moveId, status, -1);
+        }
+
+        public void notifyStatusChanged(int moveId, int status, long estMillis) {
+            Slog.v(TAG, "Move " + moveId + " status " + status);
+
+            final SomeArgs args = SomeArgs.obtain();
+            args.argi1 = moveId;
+            args.argi2 = status;
+            args.arg3 = estMillis;
+            obtainMessage(MSG_STATUS_CHANGED, args).sendToTarget();
+
+            synchronized (mLastStatus) {
+                mLastStatus.put(moveId, status);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageHandler.java b/services/core/java/com/android/server/pm/PackageHandler.java
index a5a6cae..65acc91 100644
--- a/services/core/java/com/android/server/pm/PackageHandler.java
+++ b/services/core/java/com/android/server/pm/PackageHandler.java
@@ -27,6 +27,7 @@
 import static com.android.server.pm.PackageManagerService.DEFAULT_VERIFICATION_RESPONSE;
 import static com.android.server.pm.PackageManagerService.DEFERRED_NO_KILL_INSTALL_OBSERVER;
 import static com.android.server.pm.PackageManagerService.DEFERRED_NO_KILL_POST_DELETE;
+import static com.android.server.pm.PackageManagerService.DEFERRED_NO_KILL_POST_DELETE_DELAY_MS;
 import static com.android.server.pm.PackageManagerService.DOMAIN_VERIFICATION;
 import static com.android.server.pm.PackageManagerService.EMPTY_INT_ARRAY;
 import static com.android.server.pm.PackageManagerService.ENABLE_ROLLBACK_STATUS;
@@ -84,11 +85,14 @@
 /**
  * Part of PackageManagerService that handles events.
  */
-public class PackageHandler extends Handler {
-    final PackageManagerService mPm;
+public final class PackageHandler extends Handler {
+    private final PackageManagerService mPm;
+    private final VerificationHelper mVerificationHelper;
+
     PackageHandler(Looper looper, PackageManagerService pm) {
         super(looper);
         mPm = pm;
+        mVerificationHelper = new VerificationHelper(mPm.mContext);
     }
 
     @Override
@@ -256,11 +260,11 @@
                         Slog.i(TAG, "Continuing with installation of " + originUri);
                         state.setVerifierResponse(Binder.getCallingUid(),
                                 PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
-                        mPm.broadcastPackageVerified(verificationId, originUri,
+                        mVerificationHelper.broadcastPackageVerified(verificationId, originUri,
                                 PackageManager.VERIFICATION_ALLOW, null, params.mDataLoaderType,
                                 user);
                     } else {
-                        mPm.broadcastPackageVerified(verificationId, originUri,
+                        mVerificationHelper.broadcastPackageVerified(verificationId, originUri,
                                 PackageManager.VERIFICATION_REJECT, null,
                                 params.mDataLoaderType, user);
                         params.setReturnCode(
@@ -337,7 +341,7 @@
                     final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
 
                     if (state.isInstallAllowed()) {
-                        mPm.broadcastPackageVerified(verificationId, originUri,
+                        mVerificationHelper.broadcastPackageVerified(verificationId, originUri,
                                 response.code, null, params.mDataLoaderType, params.getUser());
                     } else {
                         params.setReturnCode(
@@ -659,7 +663,7 @@
                                         StorageManager.convert(
                                                 res.mPkg.getVolumeUuid()).toString());
                         int packageExternalStorageType =
-                                PackageManagerService.getPackageExternalStorageType(volume,
+                                PackageManagerServiceUtils.getPackageExternalStorageType(volume,
                                         res.mPkg.isExternalStorage());
                         // If the package was installed externally, log it.
                         if (packageExternalStorageType != StorageEnums.UNKNOWN) {
@@ -712,7 +716,7 @@
                     // they may still be in use by the running application. This mitigates problems
                     // in cases where resources or code is loaded by a new Activity before
                     // ApplicationInfo changes have propagated to all application threads.
-                    mPm.scheduleDeferredNoKillPostDelete(args);
+                    scheduleDeferredNoKillPostDelete(args);
                 } else {
                     synchronized (mPm.mInstallLock) {
                         args.doPostDeleteLI(true);
@@ -781,4 +785,9 @@
                 android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS,
                 -1, UserHandle.USER_SYSTEM);
     }
+
+    private void scheduleDeferredNoKillPostDelete(InstallArgs args) {
+        Message message = obtainMessage(DEFERRED_NO_KILL_POST_DELETE, args);
+        sendMessageDelayed(message, DEFERRED_NO_KILL_POST_DELETE_DELAY_MS);
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 314cd69..b34a3a2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -135,8 +135,6 @@
     private static final long MAX_ACTIVE_SESSIONS_NO_PERMISSION = 50;
     /** Upper bound on number of historical sessions for a UID */
     private static final long MAX_HISTORICAL_SESSIONS = 1048576;
-    /** Destroy sessions older than this on storage free request */
-    private static final long MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS = 8 * DateUtils.HOUR_IN_MILLIS;
 
     /**
      * Allow verification-skipping if it's a development app installed through ADB with
@@ -341,28 +339,22 @@
 
     @GuardedBy("mSessions")
     private void reconcileStagesLocked(String volumeUuid) {
-        final ArraySet<File> unclaimedStages = getStagingDirsOnVolume(volumeUuid);
+        final File stagingDir = getTmpSessionDir(volumeUuid);
+        final ArraySet<File> unclaimedStages = newArraySet(
+                stagingDir.listFiles(sStageFilter));
+
+        // We also need to clean up orphaned staging directory for staged sessions
+        final File stagedSessionStagingDir = Environment.getDataStagingDirectory(volumeUuid);
+        unclaimedStages.addAll(newArraySet(stagedSessionStagingDir.listFiles()));
+
         // Ignore stages claimed by active sessions
         for (int i = 0; i < mSessions.size(); i++) {
             final PackageInstallerSession session = mSessions.valueAt(i);
             unclaimedStages.remove(session.stageDir);
         }
-        removeStagingDirs(unclaimedStages);
-    }
 
-    private ArraySet<File> getStagingDirsOnVolume(String volumeUuid) {
-        final File stagingDir = getTmpSessionDir(volumeUuid);
-        final ArraySet<File> stagingDirs = newArraySet(stagingDir.listFiles(sStageFilter));
-
-        // We also need to clean up orphaned staging directory for staged sessions
-        final File stagedSessionStagingDir = Environment.getDataStagingDirectory(volumeUuid);
-        stagingDirs.addAll(newArraySet(stagedSessionStagingDir.listFiles()));
-        return stagingDirs;
-    }
-
-    private void removeStagingDirs(ArraySet<File> stagingDirsToRemove) {
         // Clean up orphaned staging directories
-        for (File stage : stagingDirsToRemove) {
+        for (File stage : unclaimedStages) {
             Slog.w(TAG, "Deleting orphan stage " + stage);
             synchronized (mPm.mInstallLock) {
                 mPm.removeCodePathLI(stage);
@@ -376,33 +368,6 @@
         }
     }
 
-    /**
-     * Called to free up some storage space from obsolete installation files
-     */
-    public void freeStageDirs(String volumeUuid) {
-        final ArraySet<File> unclaimedStagingDirsOnVolume = getStagingDirsOnVolume(volumeUuid);
-        final long currentTimeMillis = System.currentTimeMillis();
-        synchronized (mSessions) {
-            for (int i = 0; i < mSessions.size(); i++) {
-                final PackageInstallerSession session = mSessions.valueAt(i);
-                if (!unclaimedStagingDirsOnVolume.contains(session.stageDir)) {
-                    // Only handles sessions stored on the target volume
-                    continue;
-                }
-                final long age = currentTimeMillis - session.createdMillis;
-                if (age >= MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS) {
-                    // Aggressively close old sessions because we are running low on storage
-                    // Their staging dirs will be removed too
-                    session.abandon();
-                } else {
-                    // Session is new enough, so it deserves to be kept even on low storage
-                    unclaimedStagingDirsOnVolume.remove(session.stageDir);
-                }
-            }
-        }
-        removeStagingDirs(unclaimedStagingDirsOnVolume);
-    }
-
     public static boolean isStageName(String name) {
         final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
         final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b2035b8..e76668f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -22,9 +22,7 @@
 import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
 import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
 import static android.app.AppOpsManager.MODE_IGNORED;
-import static android.content.Intent.ACTION_MAIN;
 import static android.content.Intent.CATEGORY_DEFAULT;
-import static android.content.Intent.CATEGORY_HOME;
 import static android.content.pm.PackageManager.CERT_INPUT_RAW_X509;
 import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
@@ -34,12 +32,7 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
 import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
-import static android.content.pm.PackageManager.INSTALL_INTERNAL;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
-import static android.content.pm.PackageManager.MATCH_ALL;
-import static android.content.pm.PackageManager.MATCH_ANY_USER;
-import static android.content.pm.PackageManager.MATCH_APEX;
 import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
@@ -47,20 +40,11 @@
 import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
 import static android.content.pm.PackageManager.MATCH_KNOWN_PACKAGES;
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
-import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
-import static android.content.pm.PackageManager.MOVE_FAILED_3RD_PARTY_NOT_ALLOWED_ON_INTERNAL;
-import static android.content.pm.PackageManager.MOVE_FAILED_DEVICE_ADMIN;
-import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST;
-import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR;
-import static android.content.pm.PackageManager.MOVE_FAILED_LOCKED_USER;
-import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
-import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.pm.PackageManager.RESTRICTION_NONE;
 import static android.content.pm.PackageManager.TYPE_ACTIVITY;
 import static android.content.pm.PackageManager.TYPE_PROVIDER;
 import static android.content.pm.PackageManager.TYPE_RECEIVER;
-import static android.content.pm.PackageManager.TYPE_SERVICE;
 import static android.content.pm.PackageManager.TYPE_UNKNOWN;
 import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
 import static android.content.pm.PackageManagerInternal.LAST_KNOWN_PACKAGE;
@@ -74,10 +58,7 @@
 import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility;
-import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
-import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
 import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME;
-import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
 import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
@@ -119,7 +100,6 @@
 import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
-import android.content.PermissionChecker;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.AuxiliaryResolveInfo;
@@ -147,7 +127,6 @@
 import android.content.pm.InstallSourceInfo;
 import android.content.pm.InstantAppInfo;
 import android.content.pm.InstantAppRequest;
-import android.content.pm.InstantAppResolveInfo.InstantAppDigest;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
@@ -166,7 +145,6 @@
 import android.content.pm.PackageManagerInternal.PackageListObserver;
 import android.content.pm.PackageManagerInternal.PrivateResolveFlags;
 import android.content.pm.PackagePartitions;
-import android.content.pm.PackageStats;
 import android.content.pm.PackageUserState;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.PermissionGroupInfo;
@@ -189,18 +167,12 @@
 import android.content.pm.dex.ArtManager;
 import android.content.pm.dex.IArtManager;
 import android.content.pm.overlay.OverlayPaths;
-import android.content.pm.parsing.ApkLiteParseUtils;
-import android.content.pm.parsing.PackageInfoWithoutStateUtils;
-import android.content.pm.parsing.PackageLite;
 import android.content.pm.parsing.ParsingPackageUtils;
 import android.content.pm.parsing.ParsingPackageUtils.ParseFlags;
 import android.content.pm.parsing.component.ParsedActivity;
 import android.content.pm.parsing.component.ParsedInstrumentation;
 import android.content.pm.parsing.component.ParsedMainComponent;
 import android.content.pm.parsing.component.ParsedProvider;
-import android.content.pm.parsing.component.ParsedService;
-import android.content.pm.parsing.result.ParseResult;
-import android.content.pm.parsing.result.ParseTypeImpl;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
@@ -215,15 +187,12 @@
 import android.os.HandlerExecutor;
 import android.os.HandlerThread;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
 import android.os.ParcelableException;
-import android.os.PatternMatcher;
 import android.os.PersistableBundle;
 import android.os.PowerWhitelistManager;
 import android.os.Process;
-import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
@@ -235,7 +204,6 @@
 import android.os.UserManager;
 import android.os.incremental.IncrementalManager;
 import android.os.incremental.PerUidReadTimeouts;
-import android.os.storage.DiskInfo;
 import android.os.storage.IStorageManager;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageManagerInternal;
@@ -248,28 +216,22 @@
 import android.provider.Settings.Secure;
 import android.security.KeyStore;
 import android.service.pm.PackageServiceDumpProto;
-import android.stats.storage.StorageEnums;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.Base64;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.ExceptionUtils;
 import android.util.IntArray;
 import android.util.Log;
 import android.util.LogPrinter;
-import android.util.LongSparseLongArray;
-import android.util.MathUtils;
 import android.util.PackageUtils;
 import android.util.Pair;
 import android.util.PrintStreamPrinter;
-import android.util.Printer;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
 import android.util.TimingsTraceLog;
 import android.util.TypedXmlPullParser;
 import android.util.TypedXmlSerializer;
@@ -285,7 +247,6 @@
 import com.android.internal.content.PackageHelper;
 import com.android.internal.content.om.OverlayConfig;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.os.SomeArgs;
 import com.android.internal.telephony.CarrierAppUtils;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
@@ -296,10 +257,8 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.permission.persistence.RuntimePermissionsPersistence;
-import com.android.server.DeviceIdleInternal;
 import com.android.server.EventLogTags;
 import com.android.server.FgThread;
-import com.android.server.IntentResolver;
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
 import com.android.server.PackageWatchdog;
@@ -337,10 +296,8 @@
 import com.android.server.pm.pkg.PackageStateImpl;
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
 import com.android.server.pm.verify.domain.DomainVerificationService;
-import com.android.server.pm.verify.domain.DomainVerificationUtils;
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
-import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV2;
 import com.android.server.rollback.RollbackManagerInternal;
 import com.android.server.storage.DeviceStorageMonitorInternal;
 import com.android.server.uri.UriGrantsManagerInternal;
@@ -363,23 +320,18 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
-import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
 import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
@@ -397,9 +349,7 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
-import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
@@ -461,8 +411,8 @@
     public static final boolean DEBUG_INSTALL = false;
     public static final boolean DEBUG_REMOVE = false;
     private static final boolean DEBUG_BROADCASTS = false;
-    private static final boolean DEBUG_PACKAGE_INFO = false;
-    private static final boolean DEBUG_INTENT_MATCHING = false;
+    static final boolean DEBUG_PACKAGE_INFO = false;
+    static final boolean DEBUG_INTENT_MATCHING = false;
     public static final boolean DEBUG_PACKAGE_SCANNING = false;
     static final boolean DEBUG_VERIFY = false;
     public static final boolean DEBUG_PERMISSIONS = false;
@@ -483,7 +433,7 @@
     /** REMOVE. According to Svet, this was only used to reset permissions during development. */
     static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
 
-    private static final boolean HIDE_EPHEMERAL_APIS = false;
+    static final boolean HIDE_EPHEMERAL_APIS = false;
 
     static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts";
 
@@ -674,20 +624,6 @@
     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
     private static final long ENFORCE_NATIVE_SHARED_LIBRARY_DEPENDENCIES = 142191088;
 
-    /**
-     * Components of apps targeting Android T and above will stop receiving intents from
-     * external callers that do not match its declared intent filters.
-     *
-     * When an app registers an exported component in its manifest and adds an <intent-filter>,
-     * the component can be started by any intent - even those that do not match the intent filter.
-     * This has proven to be something that many developers find counterintuitive.
-     * Without checking the intent when the component is started, in some circumstances this can
-     * allow 3P apps to trigger internal-only functionality.
-     */
-    @ChangeId
-    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S)
-    private static final long ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS = 161252188;
-
     public static final String PLATFORM_PACKAGE_NAME = "android";
 
     static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
@@ -733,7 +669,7 @@
     private static final String[] INSTANT_APP_BROADCAST_PERMISSION =
             new String[] { android.Manifest.permission.ACCESS_INSTANT_APPS };
 
-    private static final String RANDOM_DIR_PREFIX = "~~";
+    static final String RANDOM_DIR_PREFIX = "~~";
 
     final Handler mHandler;
 
@@ -835,7 +771,6 @@
     private final PackageManagerInternal mPmInternal;
     private final TestUtilityService mTestUtilityService;
 
-
     @Watched
     @GuardedBy("mLock")
     final Settings mSettings;
@@ -861,7 +796,6 @@
     private final boolean mIsUserDebugBuild;
     private final String mIncrementalVersion;
 
-
     PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy;
 
     @GuardedBy("mAvailableFeatures")
@@ -963,7 +897,6 @@
         private final Executor mBackgroundExecutor;
         private final List<ScanPartition> mSystemPartitions;
 
-
         // ----- producers -----
         private final Singleton<ComponentResolver> mComponentResolverProducer;
         private final Singleton<PermissionManagerServiceInternal> mPermissionManagerServiceProducer;
@@ -1282,7 +1215,7 @@
         public LegacyPermissionManagerInternal legacyPermissionManagerInternal;
         public DisplayMetrics Metrics;
         public ModuleInfoProvider moduleInfoProvider;
-        public MoveCallbacks moveCallbacks;
+        public MovePackageHelper.MoveCallbacks moveCallbacks;
         public boolean onlyCore;
         public OverlayConfig overlayConfig;
         public PackageDexOptimizer packageDexOptimizer;
@@ -1349,7 +1282,6 @@
             new SnapshotCache.Auto<>(mInstrumentation, mInstrumentation,
                                      "PackageManagerService.mInstrumentation");
 
-
     // Packages whose data we have transfered into another package, thus
     // should no longer exist.
     final ArraySet<String> mTransferredPackages = new ArraySet<>();
@@ -1376,7 +1308,7 @@
     final ViewCompiler mViewCompiler;
 
     private final AtomicInteger mNextMoveId = new AtomicInteger();
-    private final MoveCallbacks mMoveCallbacks;
+    final MovePackageHelper.MoveCallbacks mMoveCallbacks;
 
     // Cache of users who need badging.
     private final SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray();
@@ -1537,7 +1469,7 @@
     static final int SNAPSHOT_UNCORK = 28;
 
     static final int DEFERRED_NO_KILL_POST_DELETE_DELAY_MS = 3 * 1000;
-    static final int DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS = 500;
+    private static final int DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS = 500;
 
     static final int WRITE_SETTINGS_DELAY = 10*1000;  // 10 seconds
 
@@ -1599,115 +1531,9 @@
 
     @GuardedBy("mLock")
     private final PackageUsage mPackageUsage = new PackageUsage();
-    private final CompilerStats mCompilerStats = new CompilerStats();
+    final CompilerStats mCompilerStats = new CompilerStats();
 
-    private final DomainVerificationConnection mDomainVerificationConnection =
-            new DomainVerificationConnection();
-
-    private class DomainVerificationConnection implements DomainVerificationService.Connection,
-            DomainVerificationProxyV1.Connection, DomainVerificationProxyV2.Connection {
-
-        @Override
-        public void scheduleWriteSettings() {
-            synchronized (mLock) {
-                PackageManagerService.this.scheduleWriteSettingsLocked();
-            }
-        }
-
-        @Override
-        public int getCallingUid() {
-            return Binder.getCallingUid();
-        }
-
-        @UserIdInt
-        @Override
-        public int getCallingUserId() {
-            return UserHandle.getCallingUserId();
-        }
-
-        @Override
-        public void schedule(int code, @Nullable Object object) {
-            Message message = mHandler.obtainMessage(DOMAIN_VERIFICATION);
-            message.arg1 = code;
-            message.obj = object;
-            mHandler.sendMessage(message);
-        }
-
-        @Override
-        public long getPowerSaveTempWhitelistAppDuration() {
-            return PackageManagerService.this.getVerificationTimeout();
-        }
-
-        @Override
-        public DeviceIdleInternal getDeviceIdleInternal() {
-            return mInjector.getLocalService(DeviceIdleInternal.class);
-        }
-
-        @Override
-        public boolean isCallerPackage(int callingUid, @NonNull String packageName) {
-            final int callingUserId = UserHandle.getUserId(callingUid);
-            return callingUid == getPackageUid(packageName, 0, callingUserId);
-        }
-
-        @Nullable
-        @Override
-        public AndroidPackage getPackage(@NonNull String packageName) {
-            return PackageManagerService.this.getPackage(packageName);
-        }
-
-        @Override
-        public boolean filterAppAccess(String packageName, int callingUid, int userId) {
-            return mPmInternal.filterAppAccess(packageName, callingUid, userId);
-        }
-
-        @Override
-        public int[] getAllUserIds() {
-            return mUserManager.getUserIds();
-        }
-
-        @Override
-        public boolean doesUserExist(@UserIdInt int userId) {
-            return mUserManager.exists(userId);
-        }
-
-        @Override
-        public void withPackageSettingsSnapshot(
-                @NonNull Consumer<Function<String, PackageSetting>> block) {
-            mPmInternal.withPackageSettingsSnapshot(block);
-        }
-
-        @Override
-        public <Output> Output withPackageSettingsSnapshotReturning(
-                @NonNull FunctionalUtils.ThrowingFunction<Function<String, PackageSetting>, Output>
-                        block) {
-            return mPmInternal.withPackageSettingsSnapshotReturning(block);
-        }
-
-        @Override
-        public <ExceptionType extends Exception> void withPackageSettingsSnapshotThrowing(
-                @NonNull FunctionalUtils.ThrowingCheckedConsumer<Function<String, PackageSetting>,
-                        ExceptionType> block) throws ExceptionType {
-            mPmInternal.withPackageSettingsSnapshotThrowing(block);
-        }
-
-        @Override
-        public <ExceptionOne extends Exception, ExceptionTwo extends Exception> void
-                withPackageSettingsSnapshotThrowing2(
-                        @NonNull FunctionalUtils.ThrowingChecked2Consumer<
-                                Function<String, PackageSetting>, ExceptionOne, ExceptionTwo> block)
-                throws ExceptionOne, ExceptionTwo {
-            mPmInternal.withPackageSettingsSnapshotThrowing2(block);
-        }
-
-        @Override
-        public <Output, ExceptionType extends Exception> Output
-                withPackageSettingsSnapshotReturningThrowing(
-                        @NonNull FunctionalUtils.ThrowingCheckedFunction<
-                                Function<String, PackageSetting>, Output, ExceptionType> block)
-                throws ExceptionType {
-            return mPmInternal.withPackageSettingsSnapshotReturningThrowing(block);
-        }
-    }
+    private final DomainVerificationConnection mDomainVerificationConnection;
 
     /**
      * Invalidate the package info cache, which includes updating the cached computer.
@@ -1730,7 +1556,7 @@
      * or snapped.  Live snapshots directly reference PackageManagerService attributes.
      * Snapped snapshots contain deep copies of the attributes.
      */
-    private class Snapshot {
+    class Snapshot {
         public static final int LIVE = 1;
         public static final int SNAPPED = 2;
 
@@ -1800,4087 +1626,6 @@
         }
     }
 
-    /**
-     * A {@link Computer} provides a set of functions that can operate on live data or snapshot
-     * data.  At this time, the {@link Computer} is implemented by the
-     * {@link ComputerEngine}, which is in turn extended by {@link ComputerLocked}.
-     *
-     * New functions must be added carefully.
-     * <ol>
-     * <li> New functions must be true functions with respect to data collected in a
-     * {@link Snapshot}.  Such data may never be modified from inside a {@link Computer}
-     * function.
-     * </li>
-     *
-     * <li> A new function must be implemented in {@link ComputerEngine}.
-     * </li>
-     *
-     * <li> A new function must be overridden in {@link ComputerLocked} if the function
-     * cannot safely access live data without holding the PackageManagerService lock.  The
-     * form of the {@link ComputerLocked} function must be a single call to the
-     * {@link ComputerEngine} implementation, wrapped in a <code>synchronized</code>
-     * block.  Functions in {@link ComputerLocked} should never include any other code.
-     * </li>
-     *
-     * Care must be taken when deciding if a function should be overridden in
-     * {@link ComputerLocked}.  The complex lock relationships of PackageManagerService
-     * and other managers (like PermissionManager) mean deadlock is possible.  On the
-     * other hand, not overriding in {@link ComputerLocked} may leave a function walking
-     * unstable data.
-     *
-     * To coax developers to consider such issues carefully, all methods in
-     * {@link Computer} must be annotated with <code>@LiveImplementation(override =
-     * MANDATORY)</code> or <code>LiveImplementation(locked = NOT_ALLOWED)</code>.  A unit
-     * test verifies the annotation and that the annotation corresponds to the code in
-     * {@link ComputerEngine} and {@link ComputerLocked}.
-     */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
-    protected interface Computer {
-
-        @Nullable
-        PackageState getPackageState(@NonNull String packageName);
-
-        /**
-         * Every method must be annotated.
-         */
-        @Target({ ElementType.METHOD })
-        @Retention(RetentionPolicy.RUNTIME)
-        @interface LiveImplementation {
-            // A Computer method must be annotated with one of the following values:
-            //   MANDATORY - the method must be overridden in ComputerEngineLive.  The
-            //     format of the override is a call to the super method, wrapped in a
-            //     synchronization block.
-            //   NOT_ALLOWED - the method may not appear in the live computer.  It must
-            //     be final in the ComputerEngine.
-            int MANDATORY = 1;
-            int NOT_ALLOWED = 2;
-            int override() default MANDATORY;
-            String rationale() default "";
-        }
-
-        /**
-         * Administrative statistics: record that the snapshot has been used.  Every call
-         * to use() increments the usage counter.
-         */
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        default void use() {
-        }
-
-        /**
-         * Fetch the snapshot usage counter.
-         * @return The number of times this snapshot was used.
-         */
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        default int getUsed() {
-            return 0;
-        }
-
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType,
-                int flags, @PrivateResolveFlags int privateResolveFlags, int filterCallingUid,
-                int userId, boolean resolveForStart, boolean allowDynamicSplits);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType,
-                int flags, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent, String resolvedType,
-                int flags, int userId, int callingUid, boolean includeInstantApps);
-        @LiveImplementation(override = LiveImplementation.MANDATORY)
-        @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(Intent intent,
-                String resolvedType, int flags, int filterCallingUid, int userId,
-                boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
-                String instantAppPkgName);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        ActivityInfo getActivityInfo(ComponentName component, int flags, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
-                int filterCallingUid, int userId);
-        @LiveImplementation(override = LiveImplementation.MANDATORY)
-        AndroidPackage getPackage(String packageName);
-        @LiveImplementation(override = LiveImplementation.MANDATORY)
-        AndroidPackage getPackage(int uid);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
-                int filterCallingUid, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        ApplicationInfo getApplicationInfo(String packageName, int flags, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
-                int filterCallingUid, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        ComponentName getDefaultHomeActivity(int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType,
-                int flags, int sourceUserId, int parentUserId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        Intent getHomeIntent();
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent,
-                String resolvedType, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        List<ResolveInfo> applyPostResolutionFilter(@NonNull List<ResolveInfo> resolveInfos,
-                String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
-                boolean resolveForStart, int userId, Intent intent);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        PackageInfo getPackageInfo(String packageName, int flags, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        PackageInfo getPackageInfoInternal(String packageName, long versionCode, int flags,
-                int filterCallingUid, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        PackageSetting getPackageSetting(String packageName);
-        @LiveImplementation(override = LiveImplementation.MANDATORY)
-        PackageSetting getPackageSettingInternal(String packageName, int callingUid);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
-                int sourceUserId, int targetUserId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        ServiceInfo getServiceInfo(ComponentName component, int flags, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version);
-        @LiveImplementation(override = LiveImplementation.MANDATORY)
-        String getInstantAppPackageName(int callingUid);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        String resolveExternalPackageNameLPr(AndroidPackage pkg);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        String resolveInternalPackageNameLPr(String packageName, long versionCode);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        String[] getPackagesForUid(int uid);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        UserInfo getProfileParent(int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        boolean canViewInstantApps(int callingUid, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId,
-                int flags);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        boolean isCallerSameApp(String packageName, int uid);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        boolean isComponentVisibleToInstantApp(@Nullable ComponentName component);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        boolean isComponentVisibleToInstantApp(@Nullable ComponentName component,
-                @ComponentType int type);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
-                String resolvedType, int flags);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        boolean isInstantApp(String packageName, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        boolean isInstantAppInternal(String packageName, @UserIdInt int userId, int callingUid);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid,
-                @Nullable ComponentName component, @ComponentType int componentType, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid,
-                int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus, int callingUid,
-                int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        int checkUidPermission(String permName, int uid);
-        @LiveImplementation(override = LiveImplementation.MANDATORY)
-        int getPackageUidInternal(String packageName, int flags, int userId, int callingUid);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        int updateFlagsForApplication(int flags, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        int updateFlagsForComponent(int flags, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        int updateFlagsForPackage(int flags, int userId);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps,
-                boolean isImplicitImageCaptureIntentAndNotSetByDpc);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps,
-                boolean onlyExposedExplicitly, boolean isImplicitImageCaptureIntentAndNotSetByDpc);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
-                boolean requireFullPermission, boolean checkShell, String message);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
-                boolean requireFullPermission, boolean checkShell, String message);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
-                boolean requireFullPermission, boolean checkShell,
-                boolean requirePermissionWhenSameUser, String message);
-        @LiveImplementation(override = LiveImplementation.MANDATORY)
-        SigningDetails getSigningDetails(@NonNull String packageName);
-        @LiveImplementation(override = LiveImplementation.MANDATORY)
-        SigningDetails getSigningDetails(int uid);
-        @LiveImplementation(override = LiveImplementation.MANDATORY)
-        boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId);
-        @LiveImplementation(override = LiveImplementation.MANDATORY)
-        boolean filterAppAccess(String packageName, int callingUid, int userId);
-        @LiveImplementation(override = LiveImplementation.MANDATORY)
-        boolean filterAppAccess(int uid, int callingUid);
-        @LiveImplementation(override = LiveImplementation.MANDATORY)
-        void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent,
-                String resolvedType, int flags, List<ResolveInfo> query, boolean always,
-                boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered);
-        @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
-        ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, int flags,
-                List<ResolveInfo> query, boolean debug, int userId);
-    }
-
-    /**
-     * This class contains the implementation of the Computer functions.  It
-     * is entirely self-contained - it has no implicit access to
-     * PackageManagerService.
-     */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
-    protected static class ComputerEngine implements Computer {
-
-        // The administrative use counter.
-        private int mUsed = 0;
-
-        // Cached attributes.  The names in this class are the same as the
-        // names in PackageManagerService; see that class for documentation.
-        protected final Settings mSettings;
-        private final WatchedSparseIntArray mIsolatedOwners;
-        private final WatchedArrayMap<String, AndroidPackage> mPackages;
-        private final WatchedArrayMap<ComponentName, ParsedInstrumentation>
-                mInstrumentation;
-        private final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
-                mStaticLibsByDeclaringPackage;
-        private final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
-                mSharedLibraries;
-        private final ComponentName mLocalResolveComponentName;
-        private final ActivityInfo mResolveActivity;
-        private final WatchedSparseBooleanArray mWebInstantAppsDisabled;
-        private final ActivityInfo mLocalInstantAppInstallerActivity;
-        private final ResolveInfo mInstantAppInstallerInfo;
-        private final InstantAppRegistry mInstantAppRegistry;
-        private final ApplicationInfo mLocalAndroidApplication;
-        private final AppsFilter mAppsFilter;
-
-        // Immutable service attribute
-        private final String mAppPredictionServicePackage;
-
-        // The following are not cloned since changes to these have never
-        // been guarded by the PMS lock.
-        private final Context mContext;
-        private final UserManagerService mUserManager;
-        private final PermissionManagerServiceInternal mPermissionManager;
-        private final ApexManager mApexManager;
-        private final Injector mInjector;
-        private final ComponentResolver mComponentResolver;
-        private final InstantAppResolverConnection mInstantAppResolverConnection;
-        private final DefaultAppProvider mDefaultAppProvider;
-        private final DomainVerificationManagerInternal mDomainVerificationManager;
-        private final PackageDexOptimizer mPackageDexOptimizer;
-        private final DexManager mDexManager;
-        private final CompilerStats mCompilerStats;
-
-        // PackageManagerService attributes that are primitives are referenced through the
-        // pms object directly.  Primitives are the only attributes so referenced.
-        protected final PackageManagerService mService;
-        private boolean safeMode() {
-            return mService.mSafeMode;
-        }
-        protected ComponentName resolveComponentName() {
-            return mLocalResolveComponentName;
-        }
-        protected ActivityInfo instantAppInstallerActivity() {
-            return mLocalInstantAppInstallerActivity;
-        }
-        protected ApplicationInfo androidApplication() {
-            return mLocalAndroidApplication;
-        }
-
-        ComputerEngine(Snapshot args) {
-            mSettings = args.settings;
-            mIsolatedOwners = args.isolatedOwners;
-            mPackages = args.packages;
-            mSharedLibraries = args.sharedLibs;
-            mStaticLibsByDeclaringPackage = args.staticLibs;
-            mInstrumentation = args.instrumentation;
-            mWebInstantAppsDisabled = args.webInstantAppsDisabled;
-            mLocalResolveComponentName = args.resolveComponentName;
-            mResolveActivity = args.resolveActivity;
-            mLocalInstantAppInstallerActivity = args.instantAppInstallerActivity;
-            mInstantAppInstallerInfo = args.instantAppInstallerInfo;
-            mInstantAppRegistry = args.instantAppRegistry;
-            mLocalAndroidApplication = args.androidApplication;
-            mAppsFilter = args.appsFilter;
-            mComponentResolver = args.componentResolver;
-
-            mAppPredictionServicePackage = args.appPredictionServicePackage;
-
-            // The following are not cached copies.  Instead they are
-            // references to outside services.
-            mPermissionManager = args.service.mPermissionManager;
-            mUserManager = args.service.mUserManager;
-            mContext = args.service.mContext;
-            mInjector = args.service.mInjector;
-            mApexManager = args.service.mApexManager;
-            mInstantAppResolverConnection = args.service.mInstantAppResolverConnection;
-            mDefaultAppProvider = args.service.mDefaultAppProvider;
-            mDomainVerificationManager = args.service.mDomainVerificationManager;
-            mPackageDexOptimizer = args.service.mPackageDexOptimizer;
-            mDexManager = args.service.mDexManager;
-            mCompilerStats = args.service.mCompilerStats;
-
-            // Used to reference PMS attributes that are primitives and which are not
-            // updated under control of the PMS lock.
-            mService = args.service;
-        }
-
-        /**
-         * Record that the snapshot was used.
-         */
-        public final void use() {
-            mUsed++;
-        }
-
-        /**
-         * Return the usage counter.
-         */
-        public final int getUsed() {
-            return mUsed;
-        }
-
-        public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
-                String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags,
-                int filterCallingUid, int userId, boolean resolveForStart,
-                boolean allowDynamicSplits) {
-            if (!mUserManager.exists(userId)) return Collections.emptyList();
-            final String instantAppPkgName = getInstantAppPackageName(filterCallingUid);
-            enforceCrossUserPermission(Binder.getCallingUid(), userId,
-                    false /* requireFullPermission */, false /* checkShell */,
-                    "query intent activities");
-            final String pkgName = intent.getPackage();
-            Intent originalIntent = null;
-            ComponentName comp = intent.getComponent();
-            if (comp == null) {
-                if (intent.getSelector() != null) {
-                    originalIntent = intent;
-                    intent = intent.getSelector();
-                    comp = intent.getComponent();
-                }
-            }
-
-            flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
-                    comp != null || pkgName != null /*onlyExposedExplicitly*/,
-                    isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
-                            flags));
-            List<ResolveInfo> list = Collections.emptyList();
-            boolean skipPostResolution = false;
-            if (comp != null) {
-                final ActivityInfo ai = getActivityInfo(comp, flags, userId);
-                if (ai != null) {
-                    // When specifying an explicit component, we prevent the activity from being
-                    // used when either 1) the calling package is normal and the activity is within
-                    // an ephemeral application or 2) the calling package is ephemeral and the
-                    // activity is not visible to ephemeral applications.
-                    final boolean matchInstantApp =
-                            (flags & PackageManager.MATCH_INSTANT) != 0;
-                    final boolean matchVisibleToInstantAppOnly =
-                            (flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
-                    final boolean matchExplicitlyVisibleOnly =
-                            (flags & PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY) != 0;
-                    final boolean isCallerInstantApp =
-                            instantAppPkgName != null;
-                    final boolean isTargetSameInstantApp =
-                            comp.getPackageName().equals(instantAppPkgName);
-                    final boolean isTargetInstantApp =
-                            (ai.applicationInfo.privateFlags
-                                    & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0;
-                    final boolean isTargetVisibleToInstantApp =
-                            (ai.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
-                    final boolean isTargetExplicitlyVisibleToInstantApp =
-                            isTargetVisibleToInstantApp
-                            && (ai.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP)
-                            == 0;
-                    final boolean isTargetHiddenFromInstantApp =
-                            !isTargetVisibleToInstantApp
-                            || (matchExplicitlyVisibleOnly
-                                    && !isTargetExplicitlyVisibleToInstantApp);
-                    final boolean blockInstantResolution =
-                            !isTargetSameInstantApp
-                            && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp)
-                                    || (matchVisibleToInstantAppOnly && isCallerInstantApp
-                                            && isTargetHiddenFromInstantApp));
-                    final boolean blockNormalResolution =
-                            !resolveForStart && !isTargetInstantApp && !isCallerInstantApp
-                                    && shouldFilterApplicationLocked(
-                                    getPackageSettingInternal(ai.applicationInfo.packageName,
-                                            Process.SYSTEM_UID), filterCallingUid, userId);
-                    if (!blockInstantResolution && !blockNormalResolution) {
-                        final ResolveInfo ri = new ResolveInfo();
-                        ri.activityInfo = ai;
-                        list = new ArrayList<>(1);
-                        list.add(ri);
-                        applyEnforceIntentFilterMatching(
-                                mInjector.getCompatibility(), mComponentResolver,
-                                list, false, intent, resolvedType, filterCallingUid);
-                    }
-                }
-            } else {
-                QueryIntentActivitiesResult lockedResult =
-                        queryIntentActivitiesInternalBody(
-                                intent, resolvedType, flags, filterCallingUid, userId,
-                                resolveForStart, allowDynamicSplits, pkgName, instantAppPkgName);
-                if (lockedResult.answer != null) {
-                    skipPostResolution = true;
-                    list = lockedResult.answer;
-                } else {
-                    if (lockedResult.addInstant) {
-                        String callingPkgName = getInstantAppPackageName(filterCallingUid);
-                        boolean isRequesterInstantApp = isInstantApp(callingPkgName, userId);
-                        lockedResult.result = maybeAddInstantAppInstaller(
-                                lockedResult.result, intent, resolvedType, flags,
-                                userId, resolveForStart, isRequesterInstantApp);
-                    }
-                    if (lockedResult.sortResult) {
-                        lockedResult.result.sort(RESOLVE_PRIORITY_SORTER);
-                    }
-                    list = lockedResult.result;
-                }
-            }
-
-            if (originalIntent != null) {
-                // We also have to ensure all components match the original intent
-                applyEnforceIntentFilterMatching(
-                        mInjector.getCompatibility(), mComponentResolver,
-                        list, false, originalIntent, resolvedType, filterCallingUid);
-            }
-
-            return skipPostResolution ? list : applyPostResolutionFilter(
-                    list, instantAppPkgName, allowDynamicSplits, filterCallingUid,
-                    resolveForStart, userId, intent);
-        }
-
-        public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
-                String resolvedType, int flags, int userId) {
-            return queryIntentActivitiesInternal(
-                    intent, resolvedType, flags, 0 /*privateResolveFlags*/, Binder.getCallingUid(),
-                    userId, false /*resolveForStart*/, true /*allowDynamicSplits*/);
-        }
-
-        public final @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
-                String resolvedType, int flags, int userId, int callingUid,
-                boolean includeInstantApps) {
-            if (!mUserManager.exists(userId)) return Collections.emptyList();
-            enforceCrossUserOrProfilePermission(callingUid,
-                    userId,
-                    false /*requireFullPermission*/,
-                    false /*checkShell*/,
-                    "query intent receivers");
-            final String instantAppPkgName = getInstantAppPackageName(callingUid);
-            flags = updateFlagsForResolve(flags, userId, callingUid, includeInstantApps,
-                    false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
-            Intent originalIntent = null;
-            ComponentName comp = intent.getComponent();
-            if (comp == null) {
-                if (intent.getSelector() != null) {
-                    originalIntent = intent;
-                    intent = intent.getSelector();
-                    comp = intent.getComponent();
-                }
-            }
-            List<ResolveInfo> list = Collections.emptyList();
-            if (comp != null) {
-                final ServiceInfo si = getServiceInfo(comp, flags, userId);
-                if (si != null) {
-                    // When specifying an explicit component, we prevent the service from being
-                    // used when either 1) the service is in an instant application and the
-                    // caller is not the same instant application or 2) the calling package is
-                    // ephemeral and the activity is not visible to ephemeral applications.
-                    final boolean matchInstantApp =
-                            (flags & PackageManager.MATCH_INSTANT) != 0;
-                    final boolean matchVisibleToInstantAppOnly =
-                            (flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
-                    final boolean isCallerInstantApp =
-                            instantAppPkgName != null;
-                    final boolean isTargetSameInstantApp =
-                            comp.getPackageName().equals(instantAppPkgName);
-                    final boolean isTargetInstantApp =
-                            (si.applicationInfo.privateFlags
-                                    & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0;
-                    final boolean isTargetHiddenFromInstantApp =
-                            (si.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0;
-                    final boolean blockInstantResolution =
-                            !isTargetSameInstantApp
-                            && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp)
-                                    || (matchVisibleToInstantAppOnly && isCallerInstantApp
-                                            && isTargetHiddenFromInstantApp));
-
-                    final boolean blockNormalResolution = !isTargetInstantApp && !isCallerInstantApp
-                            && shouldFilterApplicationLocked(
-                            getPackageSettingInternal(si.applicationInfo.packageName,
-                                    Process.SYSTEM_UID), callingUid, userId);
-                    if (!blockInstantResolution && !blockNormalResolution) {
-                        final ResolveInfo ri = new ResolveInfo();
-                        ri.serviceInfo = si;
-                        list = new ArrayList<>(1);
-                        list.add(ri);
-                        applyEnforceIntentFilterMatching(
-                                mInjector.getCompatibility(), mComponentResolver,
-                                list, false, intent, resolvedType, callingUid);
-                    }
-                }
-            } else {
-                list = queryIntentServicesInternalBody(intent, resolvedType, flags,
-                        userId, callingUid, instantAppPkgName);
-            }
-
-            if (originalIntent != null) {
-                // We also have to ensure all components match the original intent
-                applyEnforceIntentFilterMatching(
-                        mInjector.getCompatibility(), mComponentResolver,
-                        list, false, originalIntent, resolvedType, callingUid);
-            }
-
-            return list;
-        }
-
-        protected @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
-                String resolvedType, int flags, int userId, int callingUid,
-                String instantAppPkgName) {
-            // reader
-            String pkgName = intent.getPackage();
-            if (pkgName == null) {
-                final List<ResolveInfo> resolveInfos = mComponentResolver.queryServices(intent,
-                        resolvedType, flags, userId);
-                if (resolveInfos == null) {
-                    return Collections.emptyList();
-                }
-                return applyPostServiceResolutionFilter(
-                        resolveInfos, instantAppPkgName, userId, callingUid);
-            }
-            final AndroidPackage pkg = mPackages.get(pkgName);
-            if (pkg != null) {
-                final List<ResolveInfo> resolveInfos = mComponentResolver.queryServices(intent,
-                        resolvedType, flags, pkg.getServices(),
-                        userId);
-                if (resolveInfos == null) {
-                    return Collections.emptyList();
-                }
-                return applyPostServiceResolutionFilter(
-                        resolveInfos, instantAppPkgName, userId, callingUid);
-            }
-            return Collections.emptyList();
-        }
-
-        public @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
-                Intent intent, String resolvedType, int flags, int filterCallingUid, int userId,
-                boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
-                String instantAppPkgName) {
-            // reader
-            boolean sortResult = false;
-            boolean addInstant = false;
-            List<ResolveInfo> result = null;
-            if (pkgName == null) {
-                List<CrossProfileIntentFilter> matchingFilters =
-                        getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
-                // Check for results that need to skip the current profile.
-                ResolveInfo skipProfileInfo  = querySkipCurrentProfileIntents(matchingFilters,
-                        intent, resolvedType, flags, userId);
-                if (skipProfileInfo != null) {
-                    List<ResolveInfo> xpResult = new ArrayList<>(1);
-                    xpResult.add(skipProfileInfo);
-                    return new QueryIntentActivitiesResult(
-                            applyPostResolutionFilter(
-                                    filterIfNotSystemUser(xpResult, userId), instantAppPkgName,
-                                    allowDynamicSplits, filterCallingUid, resolveForStart, userId,
-                                    intent));
-                }
-
-                // Check for results in the current profile.
-                result = filterIfNotSystemUser(mComponentResolver.queryActivities(
-                        intent, resolvedType, flags, userId), userId);
-                addInstant = isInstantAppResolutionAllowed(intent, result, userId,
-                        false /*skipPackageCheck*/, flags);
-                // Check for cross profile results.
-                boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
-                CrossProfileDomainInfo specificXpInfo = queryCrossProfileIntents(
-                        matchingFilters, intent, resolvedType, flags, userId,
-                        hasNonNegativePriorityResult);
-                if (intent.hasWebURI()) {
-                    CrossProfileDomainInfo generalXpInfo = null;
-                    final UserInfo parent = getProfileParent(userId);
-                    if (parent != null) {
-                        generalXpInfo = getCrossProfileDomainPreferredLpr(intent, resolvedType,
-                                flags, userId, parent.id);
-                    }
-
-                    // Generalized cross profile intents take precedence over specific.
-                    // Note that this is the opposite of the intuitive order.
-                    CrossProfileDomainInfo prioritizedXpInfo =
-                            generalXpInfo != null ? generalXpInfo : specificXpInfo;
-
-                    if (!addInstant) {
-                        if (result.isEmpty() && prioritizedXpInfo != null) {
-                            // No result in current profile, but found candidate in parent user.
-                            // And we are not going to add ephemeral app, so we can return the
-                            // result straight away.
-                            result.add(prioritizedXpInfo.resolveInfo);
-                            return new QueryIntentActivitiesResult(
-                                    applyPostResolutionFilter(result, instantAppPkgName,
-                                            allowDynamicSplits, filterCallingUid, resolveForStart,
-                                            userId, intent));
-                        } else if (result.size() <= 1 && prioritizedXpInfo == null) {
-                            // No result in parent user and <= 1 result in current profile, and we
-                            // are not going to add ephemeral app, so we can return the result
-                            // without further processing.
-                            return new QueryIntentActivitiesResult(
-                                    applyPostResolutionFilter(result, instantAppPkgName,
-                                            allowDynamicSplits, filterCallingUid, resolveForStart,
-                                            userId, intent));
-                        }
-                    }
-
-                    // We have more than one candidate (combining results from current and parent
-                    // profile), so we need filtering and sorting.
-                    result = filterCandidatesWithDomainPreferredActivitiesLPr(
-                            intent, flags, result, prioritizedXpInfo, userId);
-                    sortResult = true;
-                } else {
-                    // If not web Intent, just add result to candidate set and let ResolverActivity
-                    // figure it out.
-                    if (specificXpInfo != null) {
-                        result.add(specificXpInfo.resolveInfo);
-                        sortResult = true;
-                    }
-                }
-            } else {
-                final PackageSetting setting =
-                        getPackageSettingInternal(pkgName, Process.SYSTEM_UID);
-                result = null;
-                if (setting != null && setting.pkg != null && (resolveForStart
-                        || !shouldFilterApplicationLocked(setting, filterCallingUid, userId))) {
-                    result = filterIfNotSystemUser(mComponentResolver.queryActivities(
-                            intent, resolvedType, flags, setting.pkg.getActivities(), userId),
-                            userId);
-                }
-                if (result == null || result.size() == 0) {
-                    // the caller wants to resolve for a particular package; however, there
-                    // were no installed results, so, try to find an ephemeral result
-                    addInstant = isInstantAppResolutionAllowed(intent, null /*result*/, userId,
-                            true /*skipPackageCheck*/, flags);
-                    if (result == null) {
-                        result = new ArrayList<>();
-                    }
-                }
-            }
-            return new QueryIntentActivitiesResult(sortResult, addInstant, result);
-        }
-
-        /**
-         * Returns the activity component that can handle install failures.
-         * <p>By default, the instant application installer handles failures. However, an
-         * application may want to handle failures on its own. Applications do this by
-         * creating an activity with an intent filter that handles the action
-         * {@link Intent#ACTION_INSTALL_FAILURE}.
-         */
-        private @Nullable ComponentName findInstallFailureActivity(
-                String packageName, int filterCallingUid, int userId) {
-            final Intent failureActivityIntent = new Intent(Intent.ACTION_INSTALL_FAILURE);
-            failureActivityIntent.setPackage(packageName);
-            // IMPORTANT: disallow dynamic splits to avoid an infinite loop
-            final List<ResolveInfo> result = queryIntentActivitiesInternal(
-                    failureActivityIntent, null /*resolvedType*/, 0 /*flags*/,
-                    0 /*privateResolveFlags*/, filterCallingUid, userId, false /*resolveForStart*/,
-                    false /*allowDynamicSplits*/);
-            final int NR = result.size();
-            if (NR > 0) {
-                for (int i = 0; i < NR; i++) {
-                    final ResolveInfo info = result.get(i);
-                    if (info.activityInfo.splitName != null) {
-                        continue;
-                    }
-                    return new ComponentName(packageName, info.activityInfo.name);
-                }
-            }
-            return null;
-        }
-
-        public final ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
-            return getActivityInfoInternal(component, flags, Binder.getCallingUid(), userId);
-        }
-
-        /**
-         * Important: The provided filterCallingUid is used exclusively to filter out activities
-         * that can be seen based on user state. It's typically the original caller uid prior
-         * to clearing. Because it can only be provided by trusted code, its value can be
-         * trusted and will be used as-is; unlike userId which will be validated by this method.
-         */
-        public final ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
-                int filterCallingUid, int userId) {
-            if (!mUserManager.exists(userId)) return null;
-            flags = updateFlagsForComponent(flags, userId);
-
-            if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) {
-                enforceCrossUserPermission(Binder.getCallingUid(), userId,
-                        false /* requireFullPermission */, false /* checkShell */,
-                        "get activity info");
-            }
-
-            return getActivityInfoInternalBody(component, flags, filterCallingUid, userId);
-        }
-
-        protected ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
-                int filterCallingUid, int userId) {
-            ParsedActivity a = mComponentResolver.getActivity(component);
-
-            if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
-
-            AndroidPackage pkg = a == null ? null : mPackages.get(a.getPackageName());
-            if (pkg != null && mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) {
-                PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
-                if (ps == null) return null;
-                if (shouldFilterApplicationLocked(
-                        ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
-                    return null;
-                }
-                return PackageInfoUtils.generateActivityInfo(pkg,
-                        a, flags, ps.readUserState(userId), userId, ps);
-            }
-            if (resolveComponentName().equals(component)) {
-                return PackageInfoWithoutStateUtils.generateDelegateActivityInfo(mResolveActivity,
-                        flags, new PackageUserState(), userId);
-            }
-            return null;
-        }
-
-        public AndroidPackage getPackage(String packageName) {
-            packageName = resolveInternalPackageNameLPr(
-                    packageName, PackageManager.VERSION_CODE_HIGHEST);
-            return mPackages.get(packageName);
-        }
-
-        public AndroidPackage getPackage(int uid) {
-            final String[] packageNames = getPackagesForUidInternal(uid, Process.SYSTEM_UID);
-            AndroidPackage pkg = null;
-            final int numPackages = packageNames == null ? 0 : packageNames.length;
-            for (int i = 0; pkg == null && i < numPackages; i++) {
-                pkg = mPackages.get(packageNames[i]);
-            }
-            return pkg;
-        }
-
-        public final ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName,
-                int flags, int filterCallingUid, int userId) {
-            if (!mUserManager.exists(userId)) return null;
-            PackageSetting ps = mSettings.getPackageLPr(packageName);
-            if (ps != null) {
-                if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
-                    return null;
-                }
-                if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
-                    return null;
-                }
-                if (ps.pkg == null) {
-                    final PackageInfo pInfo = generatePackageInfo(ps, flags, userId);
-                    if (pInfo != null) {
-                        return pInfo.applicationInfo;
-                    }
-                    return null;
-                }
-                ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, flags,
-                        ps.readUserState(userId), userId, ps);
-                if (ai != null) {
-                    ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
-                }
-                return ai;
-            }
-            return null;
-        }
-
-        public final ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
-            return getApplicationInfoInternal(packageName, flags, Binder.getCallingUid(), userId);
-        }
-
-        /**
-         * Important: The provided filterCallingUid is used exclusively to filter out applications
-         * that can be seen based on user state. It's typically the original caller uid prior
-         * to clearing. Because it can only be provided by trusted code, its value can be
-         * trusted and will be used as-is; unlike userId which will be validated by this method.
-         */
-        public final ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
-                int filterCallingUid, int userId) {
-            if (!mUserManager.exists(userId)) return null;
-            flags = updateFlagsForApplication(flags, userId);
-
-            if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) {
-                enforceCrossUserPermission(Binder.getCallingUid(), userId,
-                        false /* requireFullPermission */, false /* checkShell */,
-                        "get application info");
-            }
-
-            return getApplicationInfoInternalBody(packageName, flags, filterCallingUid, userId);
-        }
-
-        protected ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
-                int filterCallingUid, int userId) {
-            // writer
-            // Normalize package name to handle renamed packages and static libs
-            packageName = resolveInternalPackageNameLPr(packageName,
-                    PackageManager.VERSION_CODE_HIGHEST);
-
-            AndroidPackage p = mPackages.get(packageName);
-            if (DEBUG_PACKAGE_INFO) Log.v(
-                    TAG, "getApplicationInfo " + packageName
-                    + ": " + p);
-            if (p != null) {
-                PackageSetting ps = mSettings.getPackageLPr(packageName);
-                if (ps == null) return null;
-                if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
-                    return null;
-                }
-                if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
-                    return null;
-                }
-                // Note: isEnabledLP() does not apply here - always return info
-                ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(
-                        p, flags, ps.readUserState(userId), userId, ps);
-                if (ai != null) {
-                    ai.packageName = resolveExternalPackageNameLPr(p);
-                }
-                return ai;
-            }
-            if ((flags & PackageManager.MATCH_APEX) != 0) {
-                // For APKs, PackageInfo.applicationInfo is not exactly the same as ApplicationInfo
-                // returned from getApplicationInfo, but for APEX packages difference shouldn't be
-                // very big.
-                // TODO(b/155328545): generate proper application info for APEXes as well.
-                int apexFlags = ApexManager.MATCH_ACTIVE_PACKAGE;
-                if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
-                    apexFlags = ApexManager.MATCH_FACTORY_PACKAGE;
-                }
-                final PackageInfo pi = mApexManager.getPackageInfo(packageName, apexFlags);
-                if (pi == null) {
-                    return null;
-                }
-                return pi.applicationInfo;
-            }
-            if ("android".equals(packageName)||"system".equals(packageName)) {
-                return androidApplication();
-            }
-            if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
-                // Already generates the external package name
-                return generateApplicationInfoFromSettingsLPw(packageName,
-                        flags, filterCallingUid, userId);
-            }
-            return null;
-        }
-
-        protected ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(
-                Intent intent, int matchFlags, List<ResolveInfo> candidates,
-                CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) {
-            final ArrayList<ResolveInfo> result = new ArrayList<>();
-            final ArrayList<ResolveInfo> matchAllList = new ArrayList<>();
-            final ArrayList<ResolveInfo> undefinedList = new ArrayList<>();
-
-            // Blocking instant apps is usually done in applyPostResolutionFilter, but since
-            // domain verification can resolve to a single result, which can be an instant app,
-            // it will then be filtered to an empty list in that method. Instead, do blocking
-            // here so that instant apps can be ignored for approval filtering and a lower
-            // priority result chosen instead.
-            final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled(userId);
-
-            final int count = candidates.size();
-            // First, try to use approved apps.
-            for (int n = 0; n < count; n++) {
-                ResolveInfo info = candidates.get(n);
-                if (blockInstant && (info.isInstantAppAvailable
-                        || isInstantApp(info.activityInfo.packageName, userId))) {
-                    continue;
-                }
-
-                // Add to the special match all list (Browser use case)
-                if (info.handleAllWebDataURI) {
-                    matchAllList.add(info);
-                } else {
-                    undefinedList.add(info);
-                }
-            }
-
-            // We'll want to include browser possibilities in a few cases
-            boolean includeBrowser = false;
-
-            if (!DomainVerificationUtils.isDomainVerificationIntent(intent, matchFlags)) {
-                result.addAll(undefinedList);
-                // Maybe add one for the other profile.
-                if (xpDomainInfo != null && xpDomainInfo.highestApprovalLevel
-                        > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) {
-                    result.add(xpDomainInfo.resolveInfo);
-                }
-                includeBrowser = true;
-            } else {
-                Pair<List<ResolveInfo>, Integer> infosAndLevel = mDomainVerificationManager
-                        .filterToApprovedApp(intent, undefinedList, userId,
-                                mSettings::getPackageLPr);
-                List<ResolveInfo> approvedInfos = infosAndLevel.first;
-                Integer highestApproval = infosAndLevel.second;
-
-                // If no apps are approved for the domain, resolve only to browsers
-                if (approvedInfos.isEmpty()) {
-                    includeBrowser = true;
-                    if (xpDomainInfo != null && xpDomainInfo.highestApprovalLevel
-                            > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) {
-                        result.add(xpDomainInfo.resolveInfo);
-                    }
-                } else {
-                    result.addAll(approvedInfos);
-
-                    // If the other profile has an app that's higher approval, add it
-                    if (xpDomainInfo != null
-                            && xpDomainInfo.highestApprovalLevel > highestApproval) {
-                        result.add(xpDomainInfo.resolveInfo);
-                    }
-                }
-            }
-
-            if (includeBrowser) {
-                // Also add browsers (all of them or only the default one)
-                if (DEBUG_DOMAIN_VERIFICATION) {
-                    Slog.v(TAG, "   ...including browsers in candidate set");
-                }
-                if ((matchFlags & MATCH_ALL) != 0) {
-                    result.addAll(matchAllList);
-                } else {
-                    // Browser/generic handling case.  If there's a default browser, go straight
-                    // to that (but only if there is no other higher-priority match).
-                    final String defaultBrowserPackageName = mDefaultAppProvider.getDefaultBrowser(
-                            userId);
-                    int maxMatchPrio = 0;
-                    ResolveInfo defaultBrowserMatch = null;
-                    final int numCandidates = matchAllList.size();
-                    for (int n = 0; n < numCandidates; n++) {
-                        ResolveInfo info = matchAllList.get(n);
-                        // track the highest overall match priority...
-                        if (info.priority > maxMatchPrio) {
-                            maxMatchPrio = info.priority;
-                        }
-                        // ...and the highest-priority default browser match
-                        if (info.activityInfo.packageName.equals(defaultBrowserPackageName)) {
-                            if (defaultBrowserMatch == null
-                                    || (defaultBrowserMatch.priority < info.priority)) {
-                                if (debug) {
-                                    Slog.v(TAG, "Considering default browser match " + info);
-                                }
-                                defaultBrowserMatch = info;
-                            }
-                        }
-                    }
-                    if (defaultBrowserMatch != null
-                            && defaultBrowserMatch.priority >= maxMatchPrio
-                            && !TextUtils.isEmpty(defaultBrowserPackageName))
-                    {
-                        if (debug) {
-                            Slog.v(TAG, "Default browser match " + defaultBrowserMatch);
-                        }
-                        result.add(defaultBrowserMatch);
-                    } else {
-                        result.addAll(matchAllList);
-                    }
-                }
-
-                // If there is nothing selected, add all candidates
-                if (result.size() == 0) {
-                    result.addAll(candidates);
-                }
-            }
-            return result;
-        }
-
-        /**
-         * Report the 'Home' activity which is currently set as "always use this one". If non is set
-         * then reports the most likely home activity or null if there are more than one.
-         */
-        public final ComponentName getDefaultHomeActivity(int userId) {
-            List<ResolveInfo> allHomeCandidates = new ArrayList<>();
-            ComponentName cn = getHomeActivitiesAsUser(allHomeCandidates, userId);
-            if (cn != null) {
-                return cn;
-            }
-            // TODO: This should not happen since there should always be a default package set for
-            //  ROLE_HOME in RoleManager. Continue with a warning log for now.
-            Slog.w(TAG, "Default package for ROLE_HOME is not set in RoleManager");
-
-            // Find the launcher with the highest priority and return that component if there are no
-            // other home activity with the same priority.
-            int lastPriority = Integer.MIN_VALUE;
-            ComponentName lastComponent = null;
-            final int size = allHomeCandidates.size();
-            for (int i = 0; i < size; i++) {
-                final ResolveInfo ri = allHomeCandidates.get(i);
-                if (ri.priority > lastPriority) {
-                    lastComponent = ri.activityInfo.getComponentName();
-                    lastPriority = ri.priority;
-                } else if (ri.priority == lastPriority) {
-                    // Two components found with same priority.
-                    lastComponent = null;
-                }
-            }
-            return lastComponent;
-        }
-
-        public final ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
-                int userId) {
-            Intent intent  = getHomeIntent();
-            List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null,
-                    PackageManager.GET_META_DATA, userId);
-            allHomeCandidates.clear();
-            if (resolveInfos == null) {
-                return null;
-            }
-            allHomeCandidates.addAll(resolveInfos);
-
-            String packageName = mDefaultAppProvider.getDefaultHome(userId);
-            if (packageName == null) {
-                // Role changes are not and cannot be atomic because its implementation lives inside
-                // a system app, so when the home role changes, there is a window when the previous
-                // role holder is removed and the new role holder is granted the preferred activity,
-                // but hasn't become the role holder yet. However, this case may be easily hit
-                // because the preferred activity change triggers a broadcast and receivers may try
-                // to get the default home activity there. So we need to fix it for this time
-                // window, and an easy workaround is to fallback to the current preferred activity.
-                final int appId = UserHandle.getAppId(Binder.getCallingUid());
-                final boolean filtered = appId >= Process.FIRST_APPLICATION_UID;
-                FindPreferredActivityBodyResult result = findPreferredActivityInternal(
-                        intent, null, 0, resolveInfos, true, false, false, userId, filtered);
-                ResolveInfo preferredResolveInfo =  result.mPreferredResolveInfo;
-                if (preferredResolveInfo != null && preferredResolveInfo.activityInfo != null) {
-                    packageName = preferredResolveInfo.activityInfo.packageName;
-                }
-            }
-            if (packageName == null) {
-                return null;
-            }
-
-            int resolveInfosSize = resolveInfos.size();
-            for (int i = 0; i < resolveInfosSize; i++) {
-                ResolveInfo resolveInfo = resolveInfos.get(i);
-
-                if (resolveInfo.activityInfo != null && TextUtils.equals(
-                        resolveInfo.activityInfo.packageName, packageName)) {
-                    return new ComponentName(resolveInfo.activityInfo.packageName,
-                            resolveInfo.activityInfo.name);
-                }
-            }
-            return null;
-        }
-
-        public final CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
-                String resolvedType, int flags, int sourceUserId, int parentUserId) {
-            if (!mUserManager.hasUserRestriction(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING,
-                    sourceUserId)) {
-                return null;
-            }
-            List<ResolveInfo> resultTargetUser = mComponentResolver.queryActivities(intent,
-                    resolvedType, flags, parentUserId);
-
-            if (resultTargetUser == null || resultTargetUser.isEmpty()) {
-                return null;
-            }
-            CrossProfileDomainInfo result = null;
-            int size = resultTargetUser.size();
-            for (int i = 0; i < size; i++) {
-                ResolveInfo riTargetUser = resultTargetUser.get(i);
-                // Intent filter verification is only for filters that specify a host. So don't
-                //return
-                // those that handle all web uris.
-                if (riTargetUser.handleAllWebDataURI) {
-                    continue;
-                }
-                String packageName = riTargetUser.activityInfo.packageName;
-                PackageSetting ps = mSettings.getPackageLPr(packageName);
-                if (ps == null) {
-                    continue;
-                }
-
-                int approvalLevel = mDomainVerificationManager
-                        .approvalLevelForDomain(ps, intent, flags, parentUserId);
-
-                if (result == null) {
-                    result = new CrossProfileDomainInfo(createForwardingResolveInfoUnchecked(
-                            new WatchedIntentFilter(), sourceUserId, parentUserId), approvalLevel);
-                } else {
-                    result.highestApprovalLevel =
-                            Math.max(approvalLevel, result.highestApprovalLevel);
-                }
-            }
-            if (result != null && result.highestApprovalLevel
-                    <= DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) {
-                return null;
-            }
-            return result;
-        }
-
-        public final Intent getHomeIntent() {
-            Intent intent = new Intent(Intent.ACTION_MAIN);
-            intent.addCategory(Intent.CATEGORY_HOME);
-            intent.addCategory(Intent.CATEGORY_DEFAULT);
-            return intent;
-        }
-
-        public final List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(
-                Intent intent, String resolvedType, int userId) {
-            CrossProfileIntentResolver resolver = mSettings.getCrossProfileIntentResolver(userId);
-            if (resolver != null) {
-                return resolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, userId);
-            }
-            return null;
-        }
-
-        /**
-         * Filters out ephemeral activities.
-         * <p>When resolving for an ephemeral app, only activities that 1) are defined in the
-         * ephemeral app or 2) marked with {@code visibleToEphemeral} are returned.
-         *
-         * @param resolveInfos The pre-filtered list of resolved activities
-         * @param ephemeralPkgName The ephemeral package name. If {@code null}, no filtering
-         *          is performed.
-         * @param intent
-         * @return A filtered list of resolved activities.
-         */
-        public final List<ResolveInfo> applyPostResolutionFilter(
-                @NonNull List<ResolveInfo> resolveInfos,
-                String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
-                boolean resolveForStart, int userId, Intent intent) {
-            final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled(userId);
-            for (int i = resolveInfos.size() - 1; i >= 0; i--) {
-                final ResolveInfo info = resolveInfos.get(i);
-                // remove locally resolved instant app web results when disabled
-                if (info.isInstantAppAvailable && blockInstant) {
-                    resolveInfos.remove(i);
-                    continue;
-                }
-                // allow activities that are defined in the provided package
-                if (allowDynamicSplits
-                        && info.activityInfo != null
-                        && info.activityInfo.splitName != null
-                        && !ArrayUtils.contains(info.activityInfo.applicationInfo.splitNames,
-                                info.activityInfo.splitName)) {
-                    if (instantAppInstallerActivity() == null) {
-                        if (DEBUG_INSTALL) {
-                            Slog.v(TAG, "No installer - not adding it to the ResolveInfo list");
-                        }
-                        resolveInfos.remove(i);
-                        continue;
-                    }
-                    if (blockInstant && isInstantApp(info.activityInfo.packageName, userId)) {
-                        resolveInfos.remove(i);
-                        continue;
-                    }
-                    // requested activity is defined in a split that hasn't been installed yet.
-                    // add the installer to the resolve list
-                    if (DEBUG_INSTALL) {
-                        Slog.v(TAG, "Adding installer to the ResolveInfo list");
-                    }
-                    final ResolveInfo installerInfo = new ResolveInfo(
-                            mInstantAppInstallerInfo);
-                    final ComponentName installFailureActivity = findInstallFailureActivity(
-                            info.activityInfo.packageName,  filterCallingUid, userId);
-                    installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
-                            installFailureActivity,
-                            info.activityInfo.packageName,
-                            info.activityInfo.applicationInfo.longVersionCode,
-                            info.activityInfo.splitName);
-                    // add a non-generic filter
-                    installerInfo.filter = new IntentFilter();
-
-                    // This resolve info may appear in the chooser UI, so let us make it
-                    // look as the one it replaces as far as the user is concerned which
-                    // requires loading the correct label and icon for the resolve info.
-                    installerInfo.resolvePackageName = info.getComponentInfo().packageName;
-                    installerInfo.labelRes = info.resolveLabelResId();
-                    installerInfo.icon = info.resolveIconResId();
-                    installerInfo.isInstantAppAvailable = true;
-                    resolveInfos.set(i, installerInfo);
-                    continue;
-                }
-                if (ephemeralPkgName == null) {
-                    // caller is a full app
-                    SettingBase callingSetting =
-                            mSettings.getSettingLPr(UserHandle.getAppId(filterCallingUid));
-                    PackageSetting resolvedSetting =
-                            getPackageSettingInternal(info.activityInfo.packageName, 0);
-                    if (resolveForStart
-                            || !mAppsFilter.shouldFilterApplication(
-                                    filterCallingUid, callingSetting, resolvedSetting, userId)) {
-                        continue;
-                    }
-                } else if (ephemeralPkgName.equals(info.activityInfo.packageName)) {
-                    // caller is same app; don't need to apply any other filtering
-                    continue;
-                } else if (resolveForStart
-                        && (intent.isWebIntent()
-                                || (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0)
-                        && intent.getPackage() == null
-                        && intent.getComponent() == null) {
-                    // ephemeral apps can launch other ephemeral apps indirectly
-                    continue;
-                } else if (((info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP)
-                                != 0)
-                        && !info.activityInfo.applicationInfo.isInstantApp()) {
-                    // allow activities that have been explicitly exposed to ephemeral apps
-                    continue;
-                }
-                resolveInfos.remove(i);
-            }
-            return resolveInfos;
-        }
-
-        private List<ResolveInfo> applyPostServiceResolutionFilter(List<ResolveInfo> resolveInfos,
-                String instantAppPkgName, @UserIdInt int userId, int filterCallingUid) {
-            for (int i = resolveInfos.size() - 1; i >= 0; i--) {
-                final ResolveInfo info = resolveInfos.get(i);
-                if (instantAppPkgName == null) {
-                    SettingBase callingSetting =
-                            mSettings.getSettingLPr(UserHandle.getAppId(filterCallingUid));
-                    PackageSetting resolvedSetting =
-                            getPackageSettingInternal(info.serviceInfo.packageName, 0);
-                    if (!mAppsFilter.shouldFilterApplication(
-                            filterCallingUid, callingSetting, resolvedSetting, userId)) {
-                        continue;
-                    }
-                }
-                final boolean isEphemeralApp = info.serviceInfo.applicationInfo.isInstantApp();
-                // allow services that are defined in the provided package
-                if (isEphemeralApp && instantAppPkgName.equals(info.serviceInfo.packageName)) {
-                    if (info.serviceInfo.splitName != null
-                            && !ArrayUtils.contains(info.serviceInfo.applicationInfo.splitNames,
-                                    info.serviceInfo.splitName)) {
-                        if (instantAppInstallerActivity() == null) {
-                            if (DEBUG_INSTANT) {
-                                Slog.v(TAG, "No installer - not adding it to the ResolveInfo"
-                                        + "list");
-                            }
-                            resolveInfos.remove(i);
-                            continue;
-                        }
-                        // requested service is defined in a split that hasn't been installed yet.
-                        // add the installer to the resolve list
-                        if (DEBUG_INSTANT) {
-                            Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
-                        }
-                        final ResolveInfo installerInfo = new ResolveInfo(
-                                mInstantAppInstallerInfo);
-                        installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
-                                null /* installFailureActivity */,
-                                info.serviceInfo.packageName,
-                                info.serviceInfo.applicationInfo.longVersionCode,
-                                info.serviceInfo.splitName);
-                        // add a non-generic filter
-                        installerInfo.filter = new IntentFilter();
-                        // load resources from the correct package
-                        installerInfo.resolvePackageName = info.getComponentInfo().packageName;
-                        resolveInfos.set(i, installerInfo);
-                    }
-                    continue;
-                }
-                // allow services that have been explicitly exposed to ephemeral apps
-                if (!isEphemeralApp
-                        && ((info.serviceInfo.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP)
-                                != 0)) {
-                    continue;
-                }
-                resolveInfos.remove(i);
-            }
-            return resolveInfos;
-        }
-
-        private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(Intent intent,
-                int matchFlags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo,
-                int userId) {
-            final boolean debug = (intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0;
-
-            if (DEBUG_PREFERRED || DEBUG_DOMAIN_VERIFICATION) {
-                Slog.v(TAG, "Filtering results with preferred activities. Candidates count: " +
-                        candidates.size());
-            }
-
-            final ArrayList<ResolveInfo> result =
-                    filterCandidatesWithDomainPreferredActivitiesLPrBody(
-                        intent, matchFlags, candidates, xpDomainInfo, userId, debug);
-
-            if (DEBUG_PREFERRED || DEBUG_DOMAIN_VERIFICATION) {
-                Slog.v(TAG, "Filtered results with preferred activities. New candidates count: "
-                        + result.size());
-                for (ResolveInfo info : result) {
-                    Slog.v(TAG, "  + " + info.activityInfo);
-                }
-            }
-            return result;
-        }
-
-        /**
-         * Filter out activities with systemUserOnly flag set, when current user is not System.
-         *
-         * @return filtered list
-         */
-        private List<ResolveInfo> filterIfNotSystemUser(List<ResolveInfo> resolveInfos,
-                int userId) {
-            if (userId == UserHandle.USER_SYSTEM) {
-                return resolveInfos;
-            }
-            for (int i = resolveInfos.size() - 1; i >= 0; i--) {
-                ResolveInfo info = resolveInfos.get(i);
-                if ((info.activityInfo.flags & ActivityInfo.FLAG_SYSTEM_USER_ONLY) != 0) {
-                    resolveInfos.remove(i);
-                }
-            }
-            return resolveInfos;
-        }
-
-        private List<ResolveInfo> maybeAddInstantAppInstaller(List<ResolveInfo> result,
-                Intent intent,
-                String resolvedType, int flags, int userId, boolean resolveForStart,
-                boolean isRequesterInstantApp) {
-            // first, check to see if we've got an instant app already installed
-            final boolean alreadyResolvedLocally = (flags & PackageManager.MATCH_INSTANT) != 0;
-            ResolveInfo localInstantApp = null;
-            boolean blockResolution = false;
-            if (!alreadyResolvedLocally) {
-                final List<ResolveInfo> instantApps = mComponentResolver.queryActivities(
-                        intent,
-                        resolvedType,
-                        flags
-                            | PackageManager.GET_RESOLVED_FILTER
-                            | PackageManager.MATCH_INSTANT
-                            | PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY,
-                        userId);
-                for (int i = instantApps.size() - 1; i >= 0; --i) {
-                    final ResolveInfo info = instantApps.get(i);
-                    final String packageName = info.activityInfo.packageName;
-                    final PackageSetting ps = mSettings.getPackageLPr(packageName);
-                    if (ps.getInstantApp(userId)) {
-                        if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent, flags,
-                                userId)) {
-                            if (DEBUG_INSTANT) {
-                                Slog.v(TAG, "Instant app approved for intent; pkg: "
-                                        + packageName);
-                            }
-                            localInstantApp = info;
-                        } else {
-                            if (DEBUG_INSTANT) {
-                                Slog.v(TAG, "Instant app not approved for intent; pkg: "
-                                        + packageName);
-                            }
-                            blockResolution = true;
-                        }
-                        break;
-                    }
-                }
-            }
-            // no app installed, let's see if one's available
-            AuxiliaryResolveInfo auxiliaryResponse = null;
-            if (!blockResolution) {
-                if (localInstantApp == null) {
-                    // we don't have an instant app locally, resolve externally
-                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
-                    String token = UUID.randomUUID().toString();
-                    InstantAppDigest digest = InstantAppResolver.parseDigest(intent);
-                    final InstantAppRequest requestObject =
-                            new InstantAppRequest(null /*responseObj*/,
-                            intent /*origIntent*/, resolvedType, null /*callingPackage*/,
-                            null /*callingFeatureId*/, isRequesterInstantApp, userId,
-                            null /*verificationBundle*/, resolveForStart,
-                            digest.getDigestPrefixSecure(), token);
-                    auxiliaryResponse = InstantAppResolver.doInstantAppResolutionPhaseOne(
-                            mInstantAppResolverConnection, requestObject);
-                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-                } else {
-                    // we have an instant application locally, but, we can't admit that since
-                    // callers shouldn't be able to determine prior browsing. create a placeholder
-                    // auxiliary response so the downstream code behaves as if there's an
-                    // instant application available externally. when it comes time to start
-                    // the instant application, we'll do the right thing.
-                    final ApplicationInfo ai = localInstantApp.activityInfo.applicationInfo;
-                    auxiliaryResponse = new AuxiliaryResolveInfo(null /* failureActivity */,
-                                            ai.packageName, ai.longVersionCode,
-                            null /* splitName */);
-                }
-            }
-            if (intent.isWebIntent() && auxiliaryResponse == null) {
-                return result;
-            }
-            final PackageSetting ps =
-                    mSettings.getPackageLPr(instantAppInstallerActivity().packageName);
-            if (ps == null
-                    || !ps.readUserState(userId).isEnabled(instantAppInstallerActivity(), 0)) {
-                return result;
-            }
-            final ResolveInfo ephemeralInstaller = new ResolveInfo(mInstantAppInstallerInfo);
-            ephemeralInstaller.activityInfo =
-                    PackageInfoWithoutStateUtils.generateDelegateActivityInfo(
-                            instantAppInstallerActivity(), 0 /*flags*/, ps.readUserState(userId),
-                            userId);
-            ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
-                    | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
-            // add a non-generic filter
-            ephemeralInstaller.filter = new IntentFilter();
-            if (intent.getAction() != null) {
-                ephemeralInstaller.filter.addAction(intent.getAction());
-            }
-            if (intent.getData() != null && intent.getData().getPath() != null) {
-                ephemeralInstaller.filter.addDataPath(
-                        intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
-            }
-            ephemeralInstaller.isInstantAppAvailable = true;
-            // make sure this resolver is the default
-            ephemeralInstaller.isDefault = true;
-            ephemeralInstaller.auxiliaryInfo = auxiliaryResponse;
-            if (DEBUG_INSTANT) {
-                Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
-            }
-
-            result.add(ephemeralInstaller);
-            return result;
-        }
-
-        public final PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
-            if (!mUserManager.exists(userId)) return null;
-            if (ps == null) {
-                return null;
-            }
-            final int callingUid = Binder.getCallingUid();
-            // Filter out ephemeral app metadata:
-            //   * The system/shell/root can see metadata for any app
-            //   * An installed app can see metadata for 1) other installed apps
-            //     and 2) ephemeral apps that have explicitly interacted with it
-            //   * Ephemeral apps can only see their own data and exposed installed apps
-            //   * Holding a signature permission allows seeing instant apps
-            if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
-                return null;
-            }
-
-            if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0
-                    && ps.isSystem()) {
-                flags |= MATCH_ANY_USER;
-            }
-
-            final PackageUserState state = ps.readUserState(userId);
-            AndroidPackage p = ps.pkg;
-            if (p != null) {
-                // Compute GIDs only if requested
-                final int[] gids = (flags & PackageManager.GET_GIDS) == 0 ? EMPTY_INT_ARRAY
-                        : mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId));
-                // Compute granted permissions only if package has requested permissions
-                final Set<String> permissions = ((flags & PackageManager.GET_PERMISSIONS) == 0
-                        || ArrayUtils.isEmpty(p.getRequestedPermissions())) ? Collections.emptySet()
-                        : mPermissionManager.getGrantedPermissions(ps.name, userId);
-
-                PackageInfo packageInfo = PackageInfoUtils.generate(p, gids, flags,
-                        ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId, ps);
-
-                if (packageInfo == null) {
-                    return null;
-                }
-
-                packageInfo.packageName = packageInfo.applicationInfo.packageName =
-                        resolveExternalPackageNameLPr(p);
-
-                return packageInfo;
-            } else if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0 && state.isAvailable(flags)) {
-                PackageInfo pi = new PackageInfo();
-                pi.packageName = ps.name;
-                pi.setLongVersionCode(ps.versionCode);
-                pi.sharedUserId = (ps.sharedUser != null) ? ps.sharedUser.name : null;
-                pi.firstInstallTime = ps.firstInstallTime;
-                pi.lastUpdateTime = ps.lastUpdateTime;
-
-                ApplicationInfo ai = new ApplicationInfo();
-                ai.packageName = ps.name;
-                ai.uid = UserHandle.getUid(userId, ps.appId);
-                ai.primaryCpuAbi = ps.primaryCpuAbiString;
-                ai.secondaryCpuAbi = ps.secondaryCpuAbiString;
-                ai.setVersionCode(ps.versionCode);
-                ai.flags = ps.pkgFlags;
-                ai.privateFlags = ps.pkgPrivateFlags;
-                pi.applicationInfo = PackageInfoWithoutStateUtils.generateDelegateApplicationInfo(
-                        ai, flags, state, userId);
-
-                if (DEBUG_PACKAGE_INFO) Log.v(TAG, "ps.pkg is n/a for ["
-                        + ps.name + "]. Provides a minimum info.");
-                return pi;
-            } else {
-                return null;
-            }
-        }
-
-        public final PackageInfo getPackageInfo(String packageName, int flags, int userId) {
-            return getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST,
-                    flags, Binder.getCallingUid(), userId);
-        }
-
-        /**
-         * Important: The provided filterCallingUid is used exclusively to filter out packages
-         * that can be seen based on user state. It's typically the original caller uid prior
-         * to clearing. Because it can only be provided by trusted code, its value can be
-         * trusted and will be used as-is; unlike userId which will be validated by this method.
-         */
-        public final PackageInfo getPackageInfoInternal(String packageName, long versionCode,
-                int flags, int filterCallingUid, int userId) {
-            if (!mUserManager.exists(userId)) return null;
-            flags = updateFlagsForPackage(flags, userId);
-            enforceCrossUserPermission(Binder.getCallingUid(), userId,
-                    false /* requireFullPermission */, false /* checkShell */, "get package info");
-
-            return getPackageInfoInternalBody(packageName, versionCode, flags, filterCallingUid,
-                    userId);
-        }
-
-        protected PackageInfo getPackageInfoInternalBody(String packageName, long versionCode,
-                int flags, int filterCallingUid, int userId) {
-            // reader
-            // Normalize package name to handle renamed packages and static libs
-            packageName = resolveInternalPackageNameLPr(packageName, versionCode);
-
-            final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0;
-            if (matchFactoryOnly) {
-                // Instant app filtering for APEX modules is ignored
-                if ((flags & MATCH_APEX) != 0) {
-                    return mApexManager.getPackageInfo(packageName,
-                            ApexManager.MATCH_FACTORY_PACKAGE);
-                }
-                final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
-                if (ps != null) {
-                    if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
-                        return null;
-                    }
-                    if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
-                        return null;
-                    }
-                    return generatePackageInfo(ps, flags, userId);
-                }
-            }
-
-            AndroidPackage p = mPackages.get(packageName);
-            if (matchFactoryOnly && p != null && !p.isSystem()) {
-                return null;
-            }
-            if (DEBUG_PACKAGE_INFO)
-                Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
-            if (p != null) {
-                final PackageSetting ps = getPackageSetting(p.getPackageName());
-                if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
-                    return null;
-                }
-                if (ps != null && shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
-                    return null;
-                }
-
-                return generatePackageInfo(ps, flags, userId);
-            }
-            if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) {
-                final PackageSetting ps = mSettings.getPackageLPr(packageName);
-                if (ps == null) return null;
-                if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
-                    return null;
-                }
-                if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
-                    return null;
-                }
-                return generatePackageInfo(ps, flags, userId);
-            }
-            if ((flags & MATCH_APEX) != 0) {
-                return mApexManager.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE);
-            }
-            return null;
-        }
-
-        @Nullable
-        public final PackageSetting getPackageSetting(String packageName) {
-            return getPackageSettingInternal(packageName, Binder.getCallingUid());
-        }
-
-        public PackageSetting getPackageSettingInternal(String packageName, int callingUid) {
-            packageName = resolveInternalPackageNameInternalLocked(
-                    packageName, PackageManager.VERSION_CODE_HIGHEST, callingUid);
-            return mSettings.getPackageLPr(packageName);
-        }
-
-        @Nullable
-        @Override
-        public PackageState getPackageState(@NonNull String packageName) {
-            int callingUid = Binder.getCallingUid();
-            packageName = resolveInternalPackageNameInternalLocked(
-                    packageName, PackageManager.VERSION_CODE_HIGHEST, callingUid);
-            PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
-            return pkgSetting == null ? null : PackageStateImpl.copy(pkgSetting);
-        }
-
-        public final ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
-            final int callingUid = Binder.getCallingUid();
-            if (getInstantAppPackageName(callingUid) != null) {
-                return ParceledListSlice.emptyList();
-            }
-            if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList();
-            flags = updateFlagsForPackage(flags, userId);
-
-            enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
-                    false /* checkShell */, "get installed packages");
-
-            return getInstalledPackagesBody(flags, userId, callingUid);
-        }
-
-        protected ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,
-                                                                          int callingUid) {
-            // writer
-            final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
-            final boolean listApex = (flags & MATCH_APEX) != 0;
-            final boolean listFactory = (flags & MATCH_FACTORY_ONLY) != 0;
-
-            ArrayList<PackageInfo> list;
-            if (listUninstalled) {
-                list = new ArrayList<>(mSettings.getPackagesLocked().size());
-                for (PackageSetting ps : mSettings.getPackagesLocked().values()) {
-                    if (listFactory) {
-                        if (!ps.isSystem()) {
-                            continue;
-                        }
-                        PackageSetting psDisabled = mSettings.getDisabledSystemPkgLPr(ps);
-                        if (psDisabled != null) {
-                            ps = psDisabled;
-                        }
-                    }
-                    if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
-                        continue;
-                    }
-                    if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
-                        continue;
-                    }
-                    final PackageInfo pi = generatePackageInfo(ps, flags, userId);
-                    if (pi != null) {
-                        list.add(pi);
-                    }
-                }
-            } else {
-                list = new ArrayList<>(mPackages.size());
-                for (AndroidPackage p : mPackages.values()) {
-                    PackageSetting ps = getPackageSetting(p.getPackageName());
-                    if (listFactory) {
-                        if (!p.isSystem()) {
-                            continue;
-                        }
-                        PackageSetting psDisabled = mSettings.getDisabledSystemPkgLPr(ps);
-                        if (psDisabled != null) {
-                            ps = psDisabled;
-                        }
-                    }
-                    if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
-                        continue;
-                    }
-                    if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
-                        continue;
-                    }
-                    final PackageInfo pi = generatePackageInfo(ps, flags, userId);
-                    if (pi != null) {
-                        list.add(pi);
-                    }
-                }
-            }
-            if (listApex) {
-                if (listFactory) {
-                    list.addAll(mApexManager.getFactoryPackages());
-                } else {
-                    list.addAll(mApexManager.getActivePackages());
-                }
-                if (listUninstalled) {
-                    list.addAll(mApexManager.getInactivePackages());
-                }
-            }
-            return new ParceledListSlice<>(list);
-        }
-
-        /**
-         * If the filter's target user can handle the intent and is enabled: a [ResolveInfo] that
-         * will forward the intent to the filter's target user, along with the highest approval of
-         * any handler in the target user. Otherwise, returns null.
-         */
-        @Nullable
-        private CrossProfileDomainInfo createForwardingResolveInfo(
-                @NonNull CrossProfileIntentFilter filter, @NonNull Intent intent,
-                @Nullable String resolvedType, int flags, int sourceUserId) {
-            int targetUserId = filter.getTargetUserId();
-            if (!isUserEnabled(targetUserId)) {
-                return null;
-            }
-
-            List<ResolveInfo> resultTargetUser = mComponentResolver.queryActivities(intent,
-                    resolvedType, flags, targetUserId);
-            if (CollectionUtils.isEmpty(resultTargetUser)) {
-                return null;
-            }
-
-            ResolveInfo forwardingInfo = null;
-            for (int i = resultTargetUser.size() - 1; i >= 0; i--) {
-                ResolveInfo targetUserResolveInfo = resultTargetUser.get(i);
-                if ((targetUserResolveInfo.activityInfo.applicationInfo.flags
-                        & ApplicationInfo.FLAG_SUSPENDED) == 0) {
-                    forwardingInfo = createForwardingResolveInfoUnchecked(filter, sourceUserId,
-                            targetUserId);
-                    break;
-                }
-            }
-
-            if (forwardingInfo == null) {
-                // If all the matches in the target profile are suspended, return null.
-                return null;
-            }
-
-            int highestApprovalLevel = DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
-
-            int size = resultTargetUser.size();
-            for (int i = 0; i < size; i++) {
-                ResolveInfo riTargetUser = resultTargetUser.get(i);
-                if (riTargetUser.handleAllWebDataURI) {
-                    continue;
-                }
-                String packageName = riTargetUser.activityInfo.packageName;
-                PackageSetting ps = mSettings.getPackageLPr(packageName);
-                if (ps == null) {
-                    continue;
-                }
-                highestApprovalLevel = Math.max(highestApprovalLevel, mDomainVerificationManager
-                                .approvalLevelForDomain(ps, intent, flags, targetUserId));
-            }
-
-            return new CrossProfileDomainInfo(forwardingInfo, highestApprovalLevel);
-        }
-
-        public final ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
-                int sourceUserId, int targetUserId) {
-            ResolveInfo forwardingResolveInfo = new ResolveInfo();
-            final long ident = Binder.clearCallingIdentity();
-            boolean targetIsProfile;
-            try {
-                targetIsProfile = mUserManager.getUserInfo(targetUserId).isManagedProfile();
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-            String className;
-            if (targetIsProfile) {
-                className = FORWARD_INTENT_TO_MANAGED_PROFILE;
-            } else {
-                className = FORWARD_INTENT_TO_PARENT;
-            }
-            ComponentName forwardingActivityComponentName = new ComponentName(
-                    androidApplication().packageName, className);
-            ActivityInfo forwardingActivityInfo =
-                    getActivityInfo(forwardingActivityComponentName, 0,
-                    sourceUserId);
-            if (!targetIsProfile) {
-                forwardingActivityInfo.showUserIcon = targetUserId;
-                forwardingResolveInfo.noResourceId = true;
-            }
-            forwardingResolveInfo.activityInfo = forwardingActivityInfo;
-            forwardingResolveInfo.priority = 0;
-            forwardingResolveInfo.preferredOrder = 0;
-            forwardingResolveInfo.match = 0;
-            forwardingResolveInfo.isDefault = true;
-            forwardingResolveInfo.filter = new IntentFilter(filter.getIntentFilter());
-            forwardingResolveInfo.targetUserId = targetUserId;
-            return forwardingResolveInfo;
-        }
-
-        // Return matching ResolveInfo in target user if any.
-        @Nullable
-        private CrossProfileDomainInfo queryCrossProfileIntents(
-                List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
-                int flags, int sourceUserId, boolean matchInCurrentProfile) {
-            if (matchingFilters == null) {
-                return null;
-            }
-            // Two {@link CrossProfileIntentFilter}s can have the same targetUserId and
-            // match the same intent. For performance reasons, it is better not to
-            // run queryIntent twice for the same userId
-            SparseBooleanArray alreadyTriedUserIds = new SparseBooleanArray();
-
-            CrossProfileDomainInfo resultInfo = null;
-
-            int size = matchingFilters.size();
-            for (int i = 0; i < size; i++) {
-                CrossProfileIntentFilter filter = matchingFilters.get(i);
-                int targetUserId = filter.getTargetUserId();
-                boolean skipCurrentProfile =
-                        (filter.getFlags() & PackageManager.SKIP_CURRENT_PROFILE) != 0;
-                boolean skipCurrentProfileIfNoMatchFound =
-                        (filter.getFlags() & PackageManager.ONLY_IF_NO_MATCH_FOUND) != 0;
-                if (!skipCurrentProfile && !alreadyTriedUserIds.get(targetUserId)
-                        && (!skipCurrentProfileIfNoMatchFound || !matchInCurrentProfile)) {
-                    // Checking if there are activities in the target user that can handle the
-                    // intent.
-                    CrossProfileDomainInfo info = createForwardingResolveInfo(filter, intent,
-                            resolvedType, flags, sourceUserId);
-                    if (info != null) {
-                        resultInfo = info;
-                        break;
-                    }
-                    alreadyTriedUserIds.put(targetUserId, true);
-                }
-            }
-
-            if (resultInfo == null) {
-                return null;
-            }
-
-            ResolveInfo forwardingResolveInfo = resultInfo.resolveInfo;
-            if (!isUserEnabled(forwardingResolveInfo.targetUserId)) {
-                return null;
-            }
-
-            List<ResolveInfo> filteredResult =
-                    filterIfNotSystemUser(Collections.singletonList(forwardingResolveInfo),
-                            sourceUserId);
-            if (filteredResult.isEmpty()) {
-                return null;
-            }
-
-            return resultInfo;
-        }
-
-        private ResolveInfo querySkipCurrentProfileIntents(
-                List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
-                int flags, int sourceUserId) {
-            if (matchingFilters != null) {
-                int size = matchingFilters.size();
-                for (int i = 0; i < size; i ++) {
-                    CrossProfileIntentFilter filter = matchingFilters.get(i);
-                    if ((filter.getFlags() & PackageManager.SKIP_CURRENT_PROFILE) != 0) {
-                        // Checking if there are activities in the target user that can handle the
-                        // intent.
-                        CrossProfileDomainInfo info = createForwardingResolveInfo(filter, intent,
-                                resolvedType, flags, sourceUserId);
-                        if (info != null) {
-                            return info.resolveInfo;
-                        }
-                    }
-                }
-            }
-            return null;
-        }
-
-        public final ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
-            if (!mUserManager.exists(userId)) return null;
-            final int callingUid = Binder.getCallingUid();
-            flags = updateFlagsForComponent(flags, userId);
-            enforceCrossUserOrProfilePermission(callingUid, userId,
-                    false /* requireFullPermission */,
-                    false /* checkShell */, "get service info");
-            return getServiceInfoBody(component, flags, userId, callingUid);
-        }
-
-        protected ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
-                                                 int callingUid) {
-            ParsedService s = mComponentResolver.getService(component);
-            if (DEBUG_PACKAGE_INFO) Log.v(
-                    TAG, "getServiceInfo " + component + ": " + s);
-            if (s == null) {
-                return null;
-            }
-
-            AndroidPackage pkg = mPackages.get(s.getPackageName());
-            if (mSettings.isEnabledAndMatchLPr(pkg, s, flags, userId)) {
-                PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
-                if (ps == null) return null;
-                if (shouldFilterApplicationLocked(
-                        ps, callingUid, component, TYPE_SERVICE, userId)) {
-                    return null;
-                }
-                return PackageInfoUtils.generateServiceInfo(pkg,
-                        s, flags, ps.readUserState(userId), userId, ps);
-            }
-            return null;
-        }
-
-        @Nullable
-        public final SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version) {
-            return getSharedLibraryInfo(name, version, mSharedLibraries, null);
-        }
-
-        /**
-         * Returns the package name of the calling Uid if it's an instant app. If it isn't
-         * instant, returns {@code null}.
-         */
-        public String getInstantAppPackageName(int callingUid) {
-            // If the caller is an isolated app use the owner's uid for the lookup.
-            if (Process.isIsolated(callingUid)) {
-                callingUid = getIsolatedOwner(callingUid);
-            }
-            final int appId = UserHandle.getAppId(callingUid);
-            final Object obj = mSettings.getSettingLPr(appId);
-            if (obj instanceof PackageSetting) {
-                final PackageSetting ps = (PackageSetting) obj;
-                final boolean isInstantApp = ps.getInstantApp(UserHandle.getUserId(callingUid));
-                return isInstantApp ? ps.pkg.getPackageName() : null;
-            }
-            return null;
-        }
-
-        /**
-         * Finds the owner for the provided isolated UID. Throws IllegalStateException if no such
-         * isolated UID is found.
-         */
-        private int getIsolatedOwner(int isolatedUid) {
-            final int ownerUid = mIsolatedOwners.get(isolatedUid, -1);
-            if (ownerUid == -1) {
-                throw new IllegalStateException(
-                        "No owner UID found for isolated UID " + isolatedUid);
-            }
-            return ownerUid;
-        }
-
-        public final String resolveExternalPackageNameLPr(AndroidPackage pkg) {
-            if (pkg.getStaticSharedLibName() != null) {
-                return pkg.getManifestPackageName();
-            }
-            return pkg.getPackageName();
-        }
-
-        private String resolveInternalPackageNameInternalLocked(
-                String packageName, long versionCode, int callingUid) {
-            // Handle renamed packages
-            String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
-            packageName = normalizedPackageName != null ? normalizedPackageName : packageName;
-
-            // Is this a static library?
-            WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
-                    mStaticLibsByDeclaringPackage.get(packageName);
-            if (versionedLib == null || versionedLib.size() <= 0) {
-                return packageName;
-            }
-
-            // Figure out which lib versions the caller can see
-            LongSparseLongArray versionsCallerCanSee = null;
-            final int callingAppId = UserHandle.getAppId(callingUid);
-            if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.SHELL_UID
-                    && callingAppId != Process.ROOT_UID) {
-                versionsCallerCanSee = new LongSparseLongArray();
-                String libName = versionedLib.valueAt(0).getName();
-                String[] uidPackages = getPackagesForUidInternal(callingUid, callingUid);
-                if (uidPackages != null) {
-                    for (String uidPackage : uidPackages) {
-                        PackageSetting ps = mSettings.getPackageLPr(uidPackage);
-                        final int libIdx = ArrayUtils.indexOf(ps.usesStaticLibraries, libName);
-                        if (libIdx >= 0) {
-                            final long libVersion = ps.usesStaticLibrariesVersions[libIdx];
-                            versionsCallerCanSee.append(libVersion, libVersion);
-                        }
-                    }
-                }
-            }
-
-            // Caller can see nothing - done
-            if (versionsCallerCanSee != null && versionsCallerCanSee.size() <= 0) {
-                return packageName;
-            }
-
-            // Find the version the caller can see and the app version code
-            SharedLibraryInfo highestVersion = null;
-            final int versionCount = versionedLib.size();
-            for (int i = 0; i < versionCount; i++) {
-                SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
-                if (versionsCallerCanSee != null && versionsCallerCanSee.indexOfKey(
-                        libraryInfo.getLongVersion()) < 0) {
-                    continue;
-                }
-                final long libVersionCode = libraryInfo.getDeclaringPackage().getLongVersionCode();
-                if (versionCode != PackageManager.VERSION_CODE_HIGHEST) {
-                    if (libVersionCode == versionCode) {
-                        return libraryInfo.getPackageName();
-                    }
-                } else if (highestVersion == null) {
-                    highestVersion = libraryInfo;
-                } else if (libVersionCode  > highestVersion
-                        .getDeclaringPackage().getLongVersionCode()) {
-                    highestVersion = libraryInfo;
-                }
-            }
-
-            if (highestVersion != null) {
-                return highestVersion.getPackageName();
-            }
-
-            return packageName;
-        }
-
-        public final String resolveInternalPackageNameLPr(String packageName, long versionCode) {
-            final int callingUid = Binder.getCallingUid();
-            return resolveInternalPackageNameInternalLocked(packageName, versionCode,
-                    callingUid);
-        }
-
-        /**
-         * <em>IMPORTANT:</em> Not all packages returned by this method may be known
-         * to the system. There are two conditions in which this may occur:
-         * <ol>
-         *   <li>The package is on adoptable storage and the device has been removed</li>
-         *   <li>The package is being removed and the internal structures are partially updated</li>
-         * </ol>
-         * The second is an artifact of the current data structures and should be fixed. See
-         * b/111075456 for one such instance.
-         * This binder API is cached.  If the algorithm in this method changes,
-         * or if the underlying objecs (as returned by getSettingLPr()) change
-         * then the logic that invalidates the cache must be revisited.  See
-         * calls to invalidateGetPackagesForUidCache() to locate the points at
-         * which the cache is invalidated.
-         */
-        public final String[] getPackagesForUid(int uid) {
-            return getPackagesForUidInternal(uid, Binder.getCallingUid());
-        }
-
-        private String[] getPackagesForUidInternal(int uid, int callingUid) {
-            final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
-            final int userId = UserHandle.getUserId(uid);
-            final int appId = UserHandle.getAppId(uid);
-            return getPackagesForUidInternalBody(callingUid, userId, appId, isCallerInstantApp);
-        }
-
-        protected String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId,
-                                                         boolean isCallerInstantApp) {
-            // reader
-            final Object obj = mSettings.getSettingLPr(appId);
-            if (obj instanceof SharedUserSetting) {
-                if (isCallerInstantApp) {
-                    return null;
-                }
-                final SharedUserSetting sus = (SharedUserSetting) obj;
-                final int N = sus.packages.size();
-                String[] res = new String[N];
-                int i = 0;
-                for (int index = 0; index < N; index++) {
-                    final PackageSetting ps = sus.packages.valueAt(index);
-                    if (ps.getInstalled(userId)
-                            && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
-                        res[i++] = ps.name;
-                    }
-                }
-                return ArrayUtils.trimToSize(res, i);
-            } else if (obj instanceof PackageSetting) {
-                final PackageSetting ps = (PackageSetting) obj;
-                if (ps.getInstalled(userId)
-                        && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
-                    return new String[]{ps.name};
-                }
-            }
-            return null;
-        }
-
-        public final UserInfo getProfileParent(int userId) {
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                return mUserManager.getProfileParent(userId);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-
-        /**
-         * Returns whether or not instant apps have been disabled remotely.
-         */
-        private boolean areWebInstantAppsDisabled(int userId) {
-            return mWebInstantAppsDisabled.get(userId);
-        }
-
-        /**
-         * Returns whether or not a full application can see an instant application.
-         * <p>
-         * Currently, there are four cases in which this can occur:
-         * <ol>
-         * <li>The calling application is a "special" process. Special processes
-         *     are those with a UID < {@link Process#FIRST_APPLICATION_UID}.</li>
-         * <li>The calling application has the permission
-         *     {@link android.Manifest.permission#ACCESS_INSTANT_APPS}.</li>
-         * <li>The calling application is the default launcher on the
-         *     system partition.</li>
-         * <li>The calling application is the default app prediction service.</li>
-         * </ol>
-         */
-        public final boolean canViewInstantApps(int callingUid, int userId) {
-            if (callingUid < Process.FIRST_APPLICATION_UID) {
-                return true;
-            }
-            if (mContext.checkCallingOrSelfPermission(
-                    android.Manifest.permission.ACCESS_INSTANT_APPS) == PERMISSION_GRANTED) {
-                return true;
-            }
-            if (mContext.checkCallingOrSelfPermission(
-                    android.Manifest.permission.VIEW_INSTANT_APPS) == PERMISSION_GRANTED) {
-                final ComponentName homeComponent = getDefaultHomeActivity(userId);
-                if (homeComponent != null
-                        && isCallerSameApp(homeComponent.getPackageName(), callingUid)) {
-                    return true;
-                }
-                // TODO(b/122900055) Change/Remove this and replace with new permission role.
-                return mAppPredictionServicePackage != null
-                        && isCallerSameApp(mAppPredictionServicePackage, callingUid);
-            }
-            return false;
-        }
-
-        public final boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid,
-                int userId, int flags) {
-            // Callers can access only the libs they depend on, otherwise they need to explicitly
-            // ask for the shared libraries given the caller is allowed to access all static libs.
-            if ((flags & PackageManager.MATCH_STATIC_SHARED_LIBRARIES) != 0) {
-                // System/shell/root get to see all static libs
-                final int appId = UserHandle.getAppId(uid);
-                if (appId == Process.SYSTEM_UID || appId == Process.SHELL_UID
-                        || appId == Process.ROOT_UID) {
-                    return false;
-                }
-                // Installer gets to see all static libs.
-                if (PackageManager.PERMISSION_GRANTED
-                        == checkUidPermission(Manifest.permission.INSTALL_PACKAGES, uid)) {
-                    return false;
-                }
-            }
-
-            // No package means no static lib as it is always on internal storage
-            if (ps == null || ps.pkg == null || !ps.pkg.isStaticSharedLibrary()) {
-                return false;
-            }
-
-            final SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(
-                    ps.pkg.getStaticSharedLibName(), ps.pkg.getStaticSharedLibVersion());
-            if (libraryInfo == null) {
-                return false;
-            }
-
-            final int resolvedUid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
-            final String[] uidPackageNames = getPackagesForUid(resolvedUid);
-            if (uidPackageNames == null) {
-                return true;
-            }
-
-            for (String uidPackageName : uidPackageNames) {
-                if (ps.name.equals(uidPackageName)) {
-                    return false;
-                }
-                PackageSetting uidPs = mSettings.getPackageLPr(uidPackageName);
-                if (uidPs != null) {
-                    final int index = ArrayUtils.indexOf(uidPs.usesStaticLibraries,
-                            libraryInfo.getName());
-                    if (index < 0) {
-                        continue;
-                    }
-                    if (uidPs.pkg.getUsesStaticLibrariesVersions()[index]
-                            == libraryInfo.getLongVersion()) {
-                        return false;
-                    }
-                }
-            }
-            return true;
-        }
-
-        private boolean hasCrossUserPermission(
-                int callingUid, int callingUserId, int userId, boolean requireFullPermission,
-                boolean requirePermissionWhenSameUser) {
-            if (!requirePermissionWhenSameUser && userId == callingUserId) {
-                return true;
-            }
-            if (callingUid == Process.SYSTEM_UID || callingUid == Process.ROOT_UID) {
-                return true;
-            }
-            if (requireFullPermission) {
-                return hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
-            }
-            return hasPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
-                    || hasPermission(Manifest.permission.INTERACT_ACROSS_USERS);
-        }
-
-        /**
-         * @param resolveInfos list of resolve infos in descending priority order
-         * @return if the list contains a resolve info with non-negative priority
-         */
-        private boolean hasNonNegativePriority(List<ResolveInfo> resolveInfos) {
-            return resolveInfos.size() > 0 && resolveInfos.get(0).priority >= 0;
-        }
-
-        private boolean hasPermission(String permission) {
-            return mContext.checkCallingOrSelfPermission(permission)
-                    == PackageManager.PERMISSION_GRANTED;
-        }
-
-        public final boolean isCallerSameApp(String packageName, int uid) {
-            AndroidPackage pkg = mPackages.get(packageName);
-            return pkg != null
-                    && UserHandle.getAppId(uid) == pkg.getUid();
-        }
-
-        public final boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) {
-            if (isComponentVisibleToInstantApp(component, TYPE_ACTIVITY)) {
-                return true;
-            }
-            if (isComponentVisibleToInstantApp(component, TYPE_SERVICE)) {
-                return true;
-            }
-            return isComponentVisibleToInstantApp(component, TYPE_PROVIDER);
-        }
-
-        public final boolean isComponentVisibleToInstantApp(
-                @Nullable ComponentName component, @ComponentType int type) {
-            if (type == TYPE_ACTIVITY) {
-                final ParsedActivity activity = mComponentResolver.getActivity(component);
-                if (activity == null) {
-                    return false;
-                }
-                final boolean visibleToInstantApp =
-                        (activity.getFlags() & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
-                final boolean explicitlyVisibleToInstantApp =
-                        (activity.getFlags() & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP)
-                        == 0;
-                return visibleToInstantApp && explicitlyVisibleToInstantApp;
-            } else if (type == TYPE_RECEIVER) {
-                final ParsedActivity activity = mComponentResolver.getReceiver(component);
-                if (activity == null) {
-                    return false;
-                }
-                final boolean visibleToInstantApp =
-                        (activity.getFlags() & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
-                final boolean explicitlyVisibleToInstantApp =
-                        (activity.getFlags() & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP)
-                        == 0;
-                return visibleToInstantApp && !explicitlyVisibleToInstantApp;
-            } else if (type == TYPE_SERVICE) {
-                final ParsedService service = mComponentResolver.getService(component);
-                return service != null
-                        && (service.getFlags() & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
-            } else if (type == TYPE_PROVIDER) {
-                final ParsedProvider provider = mComponentResolver.getProvider(component);
-                return provider != null
-                        && (provider.getFlags() & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
-            } else if (type == TYPE_UNKNOWN) {
-                return isComponentVisibleToInstantApp(component);
-            }
-            return false;
-        }
-
-        /**
-         * From Android R,
-         *  camera intents have to match system apps. The only exception to this is if
-         * the DPC has set the camera persistent preferred activity. This case was introduced
-         * because it is important that the DPC has the ability to set both system and non-system
-         * camera persistent preferred activities.
-         *
-         * @return {@code true} if the intent is a camera intent and the persistent preferred
-         * activity was not set by the DPC.
-         */
-        public final boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent,
-                int userId, String resolvedType, int flags) {
-            return intent.isImplicitImageCaptureIntent() && !isPersistentPreferredActivitySetByDpm(
-                    intent, userId, resolvedType, flags);
-        }
-
-        public final boolean isInstantApp(String packageName, int userId) {
-            final int callingUid = Binder.getCallingUid();
-            enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
-                    false /* checkShell */, "isInstantApp");
-
-            return isInstantAppInternal(packageName, userId, callingUid);
-        }
-
-        public final boolean isInstantAppInternal(String packageName, @UserIdInt int userId,
-                int callingUid) {
-            if (HIDE_EPHEMERAL_APIS) {
-                return false;
-            }
-            return isInstantAppInternalBody(packageName, userId, callingUid);
-        }
-
-        protected boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
-                int callingUid) {
-            if (Process.isIsolated(callingUid)) {
-                callingUid = getIsolatedOwner(callingUid);
-            }
-            final PackageSetting ps = mSettings.getPackageLPr(packageName);
-            final boolean returnAllowed =
-                    ps != null
-                    && (isCallerSameApp(packageName, callingUid)
-                            || canViewInstantApps(callingUid, userId)
-                            || mInstantAppRegistry.isInstantAccessGranted(
-                                    userId, UserHandle.getAppId(callingUid), ps.appId));
-            if (returnAllowed) {
-                return ps.getInstantApp(userId);
-            }
-            return false;
-        }
-
-        private boolean isInstantAppResolutionAllowed(
-                Intent intent, List<ResolveInfo> resolvedActivities, int userId,
-                boolean skipPackageCheck, int flags) {
-            if (mInstantAppResolverConnection == null) {
-                return false;
-            }
-            if (instantAppInstallerActivity() == null) {
-                return false;
-            }
-            if (intent.getComponent() != null) {
-                return false;
-            }
-            if ((intent.getFlags() & Intent.FLAG_IGNORE_EPHEMERAL) != 0) {
-                return false;
-            }
-            if (!skipPackageCheck && intent.getPackage() != null) {
-                return false;
-            }
-            if (!intent.isWebIntent()) {
-                // for non web intents, we should not resolve externally if an app already exists to
-                // handle it or if the caller didn't explicitly request it.
-                if ((resolvedActivities != null && resolvedActivities.size() != 0)
-                        || (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) == 0) {
-                    return false;
-                }
-            } else {
-                if (intent.getData() == null || TextUtils.isEmpty(intent.getData().getHost())) {
-                    return false;
-                } else if (areWebInstantAppsDisabled(userId)) {
-                    return false;
-                }
-            }
-            // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
-            // Or if there's already an ephemeral app installed that handles the action
-            return isInstantAppResolutionAllowedBody(intent, resolvedActivities, userId,
-                                                       skipPackageCheck, flags);
-        }
-
-        // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
-        // Or if there's already an ephemeral app installed that handles the action
-        protected boolean isInstantAppResolutionAllowedBody(
-                Intent intent, List<ResolveInfo> resolvedActivities, int userId,
-                boolean skipPackageCheck, int flags) {
-            final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
-            for (int n = 0; n < count; n++) {
-                final ResolveInfo info = resolvedActivities.get(n);
-                final String packageName = info.activityInfo.packageName;
-                final PackageSetting ps = mSettings.getPackageLPr(packageName);
-                if (ps != null) {
-                    // only check domain verification status if the app is not a browser
-                    if (!info.handleAllWebDataURI) {
-                        if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent, flags,
-                                userId)) {
-                            if (DEBUG_INSTANT) {
-                                Slog.v(TAG, "DENY instant app;" + " pkg: " + packageName
-                                        + ", approved");
-                            }
-                            return false;
-                        }
-                    }
-                    if (ps.getInstantApp(userId)) {
-                        if (DEBUG_INSTANT) {
-                            Slog.v(TAG, "DENY instant app installed;"
-                                    + " pkg: " + packageName);
-                        }
-                        return false;
-                    }
-                }
-            }
-            // We've exhausted all ways to deny ephemeral application; let the system look for them.
-            return true;
-        }
-
-        private boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId,
-                String resolvedType, int flags) {
-            PersistentPreferredIntentResolver ppir =
-                    mSettings.getPersistentPreferredActivities(userId);
-            //TODO(b/158003772): Remove double query
-            List<PersistentPreferredActivity> pprefs = ppir != null
-                    ? ppir.queryIntent(intent, resolvedType,
-                    (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
-                    userId)
-                    : new ArrayList<>();
-            for (PersistentPreferredActivity ppa : pprefs) {
-                if (ppa.mIsSetByDpm) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        private boolean isRecentsAccessingChildProfiles(int callingUid, int targetUserId) {
-            if (!mInjector.getLocalService(ActivityTaskManagerInternal.class)
-                    .isCallerRecents(callingUid)) {
-                return false;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                final int callingUserId = UserHandle.getUserId(callingUid);
-                if (ActivityManager.getCurrentUser() != callingUserId) {
-                    return false;
-                }
-                return mUserManager.isSameProfileGroup(callingUserId, targetUserId);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        public final boolean isSameProfileGroup(@UserIdInt int callerUserId,
-                @UserIdInt int userId) {
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                return UserManagerService.getInstance().isSameProfileGroup(callerUserId, userId);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-
-        private boolean isUserEnabled(int userId) {
-            final long callingId = Binder.clearCallingIdentity();
-            try {
-                UserInfo userInfo = mUserManager.getUserInfo(userId);
-                return userInfo != null && userInfo.isEnabled();
-            } finally {
-                Binder.restoreCallingIdentity(callingId);
-            }
-        }
-
-        /**
-         * Returns whether or not access to the application should be filtered.
-         * <p>
-         * Access may be limited based upon whether the calling or target applications
-         * are instant applications.
-         *
-         * @see #canViewInstantApps(int, int)
-         */
-        public final boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps,
-                int callingUid,
-                @Nullable ComponentName component, @ComponentType int componentType, int userId) {
-            // if we're in an isolated process, get the real calling UID
-            if (Process.isIsolated(callingUid)) {
-                callingUid = getIsolatedOwner(callingUid);
-            }
-            final String instantAppPkgName = getInstantAppPackageName(callingUid);
-            final boolean callerIsInstantApp = instantAppPkgName != null;
-            if (ps == null) {
-                // pretend the application exists, but, needs to be filtered
-                return callerIsInstantApp;
-            }
-            // if the target and caller are the same application, don't filter
-            if (isCallerSameApp(ps.name, callingUid)) {
-                return false;
-            }
-            if (callerIsInstantApp) {
-                // both caller and target are both instant, but, different applications, filter
-                if (ps.getInstantApp(userId)) {
-                    return true;
-                }
-                // request for a specific component; if it hasn't been explicitly exposed through
-                // property or instrumentation target, filter
-                if (component != null) {
-                    final ParsedInstrumentation instrumentation =
-                            mInstrumentation.get(component);
-                    if (instrumentation != null
-                            && isCallerSameApp(instrumentation.getTargetPackage(), callingUid)) {
-                        return false;
-                    }
-                    return !isComponentVisibleToInstantApp(component, componentType);
-                }
-                // request for application; if no components have been explicitly exposed, filter
-                return !ps.pkg.isVisibleToInstantApps();
-            }
-            if (ps.getInstantApp(userId)) {
-                // caller can see all components of all instant applications, don't filter
-                if (canViewInstantApps(callingUid, userId)) {
-                    return false;
-                }
-                // request for a specific instant application component, filter
-                if (component != null) {
-                    return true;
-                }
-                // request for an instant application; if the caller hasn't been granted access,
-                //filter
-                return !mInstantAppRegistry.isInstantAccessGranted(
-                        userId, UserHandle.getAppId(callingUid), ps.appId);
-            }
-            int appId = UserHandle.getAppId(callingUid);
-            final SettingBase callingPs = mSettings.getSettingLPr(appId);
-            return mAppsFilter.shouldFilterApplication(callingUid, callingPs, ps, userId);
-        }
-
-        /**
-         * @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int)
-         */
-        public final boolean shouldFilterApplicationLocked(
-                @Nullable PackageSetting ps, int callingUid, int userId) {
-            return shouldFilterApplicationLocked(ps, callingUid, null, TYPE_UNKNOWN, userId);
-        }
-
-        /**
-         * @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int)
-         */
-        public final boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus,
-                int callingUid, int userId) {
-            boolean filterApp = true;
-            for (int index = sus.packages.size() - 1; index >= 0 && filterApp; index--) {
-                filterApp &= shouldFilterApplicationLocked(sus.packages.valueAt(index),
-                        callingUid, /* component */ null, TYPE_UNKNOWN, userId);
-            }
-            return filterApp;
-        }
-
-        /**
-         * Verification statuses are ordered from the worse to the best, except for
-         * INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER, which is the worse.
-         */
-        private int bestDomainVerificationStatus(int status1, int status2) {
-            if (status1 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
-                return status2;
-            }
-            if (status2 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
-                return status1;
-            }
-            return (int) MathUtils.max(status1, status2);
-        }
-
-        // NOTE: Can't remove without a major refactor. Keep around for now.
-        public final int checkUidPermission(String permName, int uid) {
-            return mPermissionManager.checkUidPermission(uid, permName);
-        }
-
-        public int getPackageUidInternal(String packageName, int flags, int userId,
-                int callingUid) {
-            // reader
-            final AndroidPackage p = mPackages.get(packageName);
-            if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) {
-                final PackageSetting ps = getPackageSettingInternal(p.getPackageName(), callingUid);
-                if (ps != null && ps.getInstalled(userId)
-                        && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
-                    return UserHandle.getUid(userId, p.getUid());
-                }
-            }
-            if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
-                final PackageSetting ps = mSettings.getPackageLPr(packageName);
-                if (ps != null && ps.isMatch(flags)
-                        && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
-                    return UserHandle.getUid(userId, ps.appId);
-                }
-            }
-
-            return -1;
-        }
-
-        /**
-         * Update given flags based on encryption status of current user.
-         */
-        private int updateFlags(int flags, int userId) {
-            if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                    | PackageManager.MATCH_DIRECT_BOOT_AWARE)) != 0) {
-                // Caller expressed an explicit opinion about what encryption
-                // aware/unaware components they want to see, so fall through and
-                // give them what they want
-            } else {
-                final UserManagerInternal umInternal = mInjector.getUserManagerInternal();
-                // Caller expressed no opinion, so match based on user state
-                if (umInternal.isUserUnlockingOrUnlocked(userId)) {
-                    flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
-                } else {
-                    flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE;
-                }
-            }
-            return flags;
-        }
-
-        /**
-         * Update given flags when being used to request {@link ApplicationInfo}.
-         */
-        public final int updateFlagsForApplication(int flags, int userId) {
-            return updateFlagsForPackage(flags, userId);
-        }
-
-        /**
-         * Update given flags when being used to request {@link ComponentInfo}.
-         */
-        public final int updateFlagsForComponent(int flags, int userId) {
-            return updateFlags(flags, userId);
-        }
-
-        /**
-         * Update given flags when being used to request {@link PackageInfo}.
-         */
-        public final int updateFlagsForPackage(int flags, int userId) {
-            final boolean isCallerSystemUser = UserHandle.getCallingUserId()
-                                               == UserHandle.USER_SYSTEM;
-            if ((flags & PackageManager.MATCH_ANY_USER) != 0) {
-                // require the permission to be held; the calling uid and given user id referring
-                // to the same user is not sufficient
-                enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false,
-                        !isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId),
-                        "MATCH_ANY_USER flag requires INTERACT_ACROSS_USERS permission");
-            } else if ((flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0
-                    && isCallerSystemUser
-                    && mUserManager.hasManagedProfile(UserHandle.USER_SYSTEM)) {
-                // If the caller wants all packages and has a restricted profile associated with it,
-                // then match all users. This is to make sure that launchers that need to access
-                //work
-                // profile apps don't start breaking. TODO: Remove this hack when launchers stop
-                //using
-                // MATCH_UNINSTALLED_PACKAGES to query apps in other profiles. b/31000380
-                flags |= PackageManager.MATCH_ANY_USER;
-            }
-            return updateFlags(flags, userId);
-        }
-
-        /**
-         * Update given flags when being used to request {@link ResolveInfo}.
-         * <p>Instant apps are resolved specially, depending upon context. Minimally,
-         * {@code}flags{@code} must have the {@link PackageManager#MATCH_INSTANT}
-         * flag set. However, this flag is only honoured in three circumstances:
-         * <ul>
-         * <li>when called from a system process</li>
-         * <li>when the caller holds the permission {@code
-         * android.permission.ACCESS_INSTANT_APPS}</li>
-         * <li>when resolution occurs to start an activity with a {@code android.intent.action.VIEW}
-         * action and a {@code android.intent.category.BROWSABLE} category</li>
-         * </ul>
-         */
-        public final int updateFlagsForResolve(int flags, int userId, int callingUid,
-                boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
-            return updateFlagsForResolve(flags, userId, callingUid,
-                    wantInstantApps, false /*onlyExposedExplicitly*/,
-                    isImplicitImageCaptureIntentAndNotSetByDpc);
-        }
-
-        public final int updateFlagsForResolve(int flags, int userId, int callingUid,
-                boolean wantInstantApps, boolean onlyExposedExplicitly,
-                boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
-            // Safe mode means we shouldn't match any third-party components
-            if (safeMode() || isImplicitImageCaptureIntentAndNotSetByDpc) {
-                flags |= PackageManager.MATCH_SYSTEM_ONLY;
-            }
-            if (getInstantAppPackageName(callingUid) != null) {
-                // But, ephemeral apps see both ephemeral and exposed, non-ephemeral components
-                if (onlyExposedExplicitly) {
-                    flags |= PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY;
-                }
-                flags |= PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY;
-                flags |= PackageManager.MATCH_INSTANT;
-            } else {
-                final boolean wantMatchInstant = (flags & PackageManager.MATCH_INSTANT) != 0;
-                final boolean allowMatchInstant = wantInstantApps
-                        || (wantMatchInstant && canViewInstantApps(callingUid, userId));
-                flags &= ~(PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY
-                        | PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY);
-                if (!allowMatchInstant) {
-                    flags &= ~PackageManager.MATCH_INSTANT;
-                }
-            }
-            return updateFlagsForComponent(flags, userId);
-        }
-
-        /**
-         * Checks if the request is from the system or an app that has the appropriate cross-user
-         * permissions defined as follows:
-         * <ul>
-         * <li>INTERACT_ACROSS_USERS_FULL if {@code requireFullPermission} is true.</li>
-         * <li>INTERACT_ACROSS_USERS if the given {@code userId} is in a different profile group
-         * to the caller.</li>
-         * <li>Otherwise,
-         *  INTERACT_ACROSS_PROFILES if the given {@code userId} is in the same profile
-         * group as the caller.</li>
-         * </ul>
-         *
-         * @param checkShell whether to prevent shell from access if there's a debugging restriction
-         * @param message the message to log on security exception
-         */
-        public final void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
-                boolean requireFullPermission, boolean checkShell, String message) {
-            if (userId < 0) {
-                throw new IllegalArgumentException("Invalid userId " + userId);
-            }
-            if (checkShell) {
-                PackageManagerServiceUtils.enforceShellRestriction(
-                        mInjector.getUserManagerInternal(),
-                        UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
-            }
-            final int callingUserId = UserHandle.getUserId(callingUid);
-            if (hasCrossUserPermission(callingUid, callingUserId, userId, requireFullPermission,
-                    /*requirePermissionWhenSameUser= */ false)) {
-                return;
-            }
-            final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, userId);
-            if (isSameProfileGroup && PermissionChecker.checkPermissionForPreflight(
-                    mContext,
-                    android.Manifest.permission.INTERACT_ACROSS_PROFILES,
-                    PermissionChecker.PID_UNKNOWN,
-                    callingUid,
-                    getPackage(callingUid).getPackageName())
-                    == PermissionChecker.PERMISSION_GRANTED) {
-                return;
-            }
-            String errorMessage = buildInvalidCrossUserOrProfilePermissionMessage(
-                    callingUid, userId, message, requireFullPermission, isSameProfileGroup);
-            Slog.w(TAG, errorMessage);
-            throw new SecurityException(errorMessage);
-        }
-
-        /**
-         * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
-         * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller.
-         *
-         * @param checkShell whether to prevent shell from access if there's a debugging restriction
-         * @param message the message to log on security exception
-         */
-        public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
-                boolean requireFullPermission, boolean checkShell, String message) {
-            enforceCrossUserPermission(callingUid, userId, requireFullPermission, checkShell, false,
-                    message);
-        }
-
-        /**
-         * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
-         * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller.
-         *
-         * @param checkShell whether to prevent shell from access if there's a debugging restriction
-         * @param requirePermissionWhenSameUser When {@code true}, still require the cross user
-         *                                      permission to be held even if the callingUid and
-         * userId
-         *                                      reference the same user.
-         * @param message the message to log on security exception
-         */
-        public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
-                boolean requireFullPermission, boolean checkShell,
-                boolean requirePermissionWhenSameUser, String message) {
-            if (userId < 0) {
-                throw new IllegalArgumentException("Invalid userId " + userId);
-            }
-            if (checkShell) {
-                PackageManagerServiceUtils.enforceShellRestriction(
-                        mInjector.getUserManagerInternal(),
-                        UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
-            }
-            final int callingUserId = UserHandle.getUserId(callingUid);
-            if (hasCrossUserPermission(
-                    callingUid, callingUserId, userId, requireFullPermission,
-                    requirePermissionWhenSameUser)) {
-                return;
-            }
-            String errorMessage = buildInvalidCrossUserPermissionMessage(
-                    callingUid, userId, message, requireFullPermission);
-            Slog.w(TAG, errorMessage);
-            throw new SecurityException(errorMessage);
-        }
-
-        public SigningDetails getSigningDetails(@NonNull String packageName) {
-            AndroidPackage p = mPackages.get(packageName);
-            if (p == null) {
-                return null;
-            }
-            return p.getSigningDetails();
-        }
-
-        public SigningDetails getSigningDetails(int uid) {
-            final int appId = UserHandle.getAppId(uid);
-            final Object obj = mSettings.getSettingLPr(appId);
-            if (obj != null) {
-                if (obj instanceof SharedUserSetting) {
-                    return ((SharedUserSetting) obj).signatures.mSigningDetails;
-                } else if (obj instanceof PackageSetting) {
-                    final PackageSetting ps = (PackageSetting) obj;
-                    return ps.signatures.mSigningDetails;
-                }
-            }
-            return SigningDetails.UNKNOWN;
-        }
-
-        public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
-            PackageSetting ps = getPackageSetting(pkg.getPackageName());
-            return shouldFilterApplicationLocked(ps, callingUid,
-                    userId);
-        }
-
-        public boolean filterAppAccess(String packageName, int callingUid, int userId) {
-            PackageSetting ps = getPackageSetting(packageName);
-            return shouldFilterApplicationLocked(ps, callingUid,
-                    userId);
-        }
-
-        public boolean filterAppAccess(int uid, int callingUid) {
-            final int userId = UserHandle.getUserId(uid);
-            final int appId = UserHandle.getAppId(uid);
-            final Object setting = mSettings.getSettingLPr(appId);
-
-            if (setting instanceof SharedUserSetting) {
-                return shouldFilterApplicationLocked(
-                        (SharedUserSetting) setting, callingUid, userId);
-            } else if (setting == null
-                    || setting instanceof PackageSetting) {
-                return shouldFilterApplicationLocked(
-                        (PackageSetting) setting, callingUid, userId);
-            }
-            return false;
-        }
-
-        public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
-            final String packageName = dumpState.getTargetPackageName();
-            final PackageSetting setting = mSettings.getPackageLPr(packageName);
-            final boolean checkin = dumpState.isCheckIn();
-
-            // Return if the package doesn't exist.
-            if (packageName != null && setting == null) {
-                return;
-            }
-
-            switch (type) {
-                case DumpState.DUMP_VERSION:
-                {
-                    if (dumpState.onTitlePrinted()) {
-                        pw.println();
-                    }
-                    pw.println("Database versions:");
-                    mSettings.dumpVersionLPr(new IndentingPrintWriter(pw, "  "));
-                    break;
-                }
-
-                case DumpState.DUMP_LIBS:
-                {
-                    boolean printedHeader = false;
-                    final int numSharedLibraries = mSharedLibraries.size();
-                    for (int index = 0; index < numSharedLibraries; index++) {
-                        final String libName = mSharedLibraries.keyAt(index);
-                        final WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
-                                mSharedLibraries.get(libName);
-                        if (versionedLib == null) {
-                            continue;
-                        }
-                        final int versionCount = versionedLib.size();
-                        for (int i = 0; i < versionCount; i++) {
-                            SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
-                            if (!checkin) {
-                                if (!printedHeader) {
-                                    if (dumpState.onTitlePrinted()) {
-                                        pw.println();
-                                    }
-                                    pw.println("Libraries:");
-                                    printedHeader = true;
-                                }
-                                pw.print("  ");
-                            } else {
-                                pw.print("lib,");
-                            }
-                            pw.print(libraryInfo.getName());
-                            if (libraryInfo.isStatic()) {
-                                pw.print(" version=" + libraryInfo.getLongVersion());
-                            }
-                            if (!checkin) {
-                                pw.print(" -> ");
-                            }
-                            if (libraryInfo.getPath() != null) {
-                                if (libraryInfo.isNative()) {
-                                    pw.print(" (so) ");
-                                } else {
-                                    pw.print(" (jar) ");
-                                }
-                                pw.print(libraryInfo.getPath());
-                            } else {
-                                pw.print(" (apk) ");
-                                pw.print(libraryInfo.getPackageName());
-                            }
-                            pw.println();
-                        }
-                    }
-                    break;
-                }
-
-                case DumpState.DUMP_PREFERRED:
-                    mSettings.dumpPreferred(pw, dumpState, packageName);
-                    break;
-
-                case DumpState.DUMP_PREFERRED_XML:
-                {
-                    pw.flush();
-                    FileOutputStream fout = new FileOutputStream(fd);
-                    BufferedOutputStream str = new BufferedOutputStream(fout);
-                    TypedXmlSerializer serializer = Xml.newFastSerializer();
-                    try {
-                        serializer.setOutput(str, StandardCharsets.UTF_8.name());
-                        serializer.startDocument(null, true);
-                        serializer.setFeature(
-                                "http://xmlpull.org/v1/doc/features.html#indent-output", true);
-                        mSettings.writePreferredActivitiesLPr(serializer, 0,
-                                dumpState.isFullPreferred());
-                        serializer.endDocument();
-                        serializer.flush();
-                    } catch (IllegalArgumentException e) {
-                        pw.println("Failed writing: " + e);
-                    } catch (IllegalStateException e) {
-                        pw.println("Failed writing: " + e);
-                    } catch (IOException e) {
-                        pw.println("Failed writing: " + e);
-                    }
-                    break;
-                }
-
-                case DumpState.DUMP_QUERIES:
-                {
-                    final Integer filteringAppId = setting == null ? null : setting.appId;
-                    mAppsFilter.dumpQueries(
-                            pw, filteringAppId, dumpState, mUserManager.getUserIds(),
-                            this::getPackagesForUidInternalBody);
-                    break;
-                }
-
-                case DumpState.DUMP_DOMAIN_PREFERRED:
-                {
-                    final android.util.IndentingPrintWriter writer =
-                            new android.util.IndentingPrintWriter(pw);
-                    if (dumpState.onTitlePrinted()) {
-                        pw.println();
-                    }
-                    writer.println("Domain verification status:");
-                    writer.increaseIndent();
-                    try {
-                        mDomainVerificationManager.printState(writer, packageName,
-                                UserHandle.USER_ALL, mSettings::getPackageLPr);
-                    } catch (PackageManager.NameNotFoundException e) {
-                        pw.println("Failure printing domain verification information");
-                        Slog.e(TAG, "Failure printing domain verification information", e);
-                    }
-                    writer.decreaseIndent();
-                    break;
-                }
-
-                case DumpState.DUMP_DEXOPT:
-                {
-                    final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
-                    if (dumpState.onTitlePrinted()) {
-                        pw.println();
-                    }
-                    ipw.println("Dexopt state:");
-                    ipw.increaseIndent();
-                    Collection<PackageSetting> pkgSettings;
-                    if (setting != null) {
-                        pkgSettings = Collections.singletonList(setting);
-                    } else {
-                        pkgSettings = mSettings.getPackagesLocked().values();
-                    }
-
-                    for (PackageSetting pkgSetting : pkgSettings) {
-                        final AndroidPackage pkg = pkgSetting.getPkg();
-                        if (pkg == null) {
-                            continue;
-                        }
-                        final String pkgName = pkg.getPackageName();
-                        ipw.println("[" + pkgName + "]");
-                        ipw.increaseIndent();
-
-                        mPackageDexOptimizer.dumpDexoptState(ipw, pkg, pkgSetting,
-                                mDexManager.getPackageUseInfoOrDefault(pkgName));
-                        ipw.decreaseIndent();
-                    }
-                    break;
-                }
-
-                case DumpState.DUMP_COMPILER_STATS:
-                {
-                    final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
-                    if (dumpState.onTitlePrinted()) {
-                        pw.println();
-                    }
-                    ipw.println("Compiler stats:");
-                    ipw.increaseIndent();
-                    Collection<PackageSetting> pkgSettings;
-                    if (setting != null) {
-                        pkgSettings = Collections.singletonList(setting);
-                    } else {
-                        pkgSettings = mSettings.getPackagesLocked().values();
-                    }
-
-                    for (PackageSetting pkgSetting : pkgSettings) {
-                        final AndroidPackage pkg = pkgSetting.getPkg();
-                        if (pkg == null) {
-                            continue;
-                        }
-                        final String pkgName = pkg.getPackageName();
-                        ipw.println("[" + pkgName + "]");
-                        ipw.increaseIndent();
-
-                        final CompilerStats.PackageStats stats =
-                                mCompilerStats.getPackageStats(pkgName);
-                        if (stats == null) {
-                            ipw.println("(No recorded stats)");
-                        } else {
-                            stats.dump(ipw);
-                        }
-                        ipw.decreaseIndent();
-                    }
-                    break;
-                }
-            } // switch
-        }
-
-        // The body of findPreferredActivity.
-        protected FindPreferredActivityBodyResult findPreferredActivityBody(
-                Intent intent, String resolvedType, int flags,
-                List<ResolveInfo> query, boolean always,
-                boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered,
-                int callingUid, boolean isDeviceProvisioned) {
-            FindPreferredActivityBodyResult result = new FindPreferredActivityBodyResult();
-
-            flags = updateFlagsForResolve(
-                    flags, userId, callingUid, false /*includeInstantApps*/,
-                    isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
-                            resolvedType, flags));
-            intent = updateIntentForResolve(intent);
-
-            // Try to find a matching persistent preferred activity.
-            result.mPreferredResolveInfo = findPersistentPreferredActivityLP(intent,
-                    resolvedType, flags, query, debug, userId);
-
-            // If a persistent preferred activity matched, use it.
-            if (result.mPreferredResolveInfo != null) {
-                return result;
-            }
-
-            PreferredIntentResolver pir = mSettings.getPreferredActivities(userId);
-            // Get the list of preferred activities that handle the intent
-            if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities...");
-            List<PreferredActivity> prefs = pir != null
-                    ? pir.queryIntent(intent, resolvedType,
-                            (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
-                            userId)
-                    : null;
-            if (prefs != null && prefs.size() > 0) {
-
-                // First figure out how good the original match set is.
-                // We will only allow preferred activities that came
-                // from the same match quality.
-                int match = 0;
-
-                if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match...");
-
-                final int N = query.size();
-                for (int j = 0; j < N; j++) {
-                    final ResolveInfo ri = query.get(j);
-                    if (DEBUG_PREFERRED || debug) {
-                        Slog.v(TAG, "Match for " + ri.activityInfo
-                                + ": 0x" + Integer.toHexString(match));
-                    }
-                    if (ri.match > match) {
-                        match = ri.match;
-                    }
-                }
-
-                if (DEBUG_PREFERRED || debug) {
-                    Slog.v(TAG, "Best match: 0x" + Integer.toHexString(match));
-                }
-                match &= IntentFilter.MATCH_CATEGORY_MASK;
-                final int M = prefs.size();
-                for (int i = 0; i < M; i++) {
-                    final PreferredActivity pa = prefs.get(i);
-                    if (DEBUG_PREFERRED || debug) {
-                        Slog.v(TAG, "Checking PreferredActivity ds="
-                                + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "<none>")
-                                + "\n  component=" + pa.mPref.mComponent);
-                        pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
-                    }
-                    if (pa.mPref.mMatch != match) {
-                        if (DEBUG_PREFERRED || debug) {
-                            Slog.v(TAG, "Skipping bad match "
-                                    + Integer.toHexString(pa.mPref.mMatch));
-                        }
-                        continue;
-                    }
-                    // If it's not an "always" type preferred activity and that's what we're
-                    // looking for, skip it.
-                    if (always && !pa.mPref.mAlways) {
-                        if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry");
-                        continue;
-                    }
-                    final ActivityInfo ai = getActivityInfo(
-                            pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS
-                                    | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
-                            userId);
-                    if (DEBUG_PREFERRED || debug) {
-                        Slog.v(TAG, "Found preferred activity:");
-                        if (ai != null) {
-                            ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
-                        } else {
-                            Slog.v(TAG, "  null");
-                        }
-                    }
-                    final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent)
-                            && !isDeviceProvisioned;
-                    final boolean allowSetMutation = !excludeSetupWizardHomeActivity
-                            && !queryMayBeFiltered;
-                    if (ai == null) {
-                        // Do not remove launcher's preferred activity during SetupWizard
-                        // due to it may not install yet
-                        if (!allowSetMutation) {
-                            continue;
-                        }
-
-                        // This previously registered preferred activity
-                        // component is no longer known.  Most likely an update
-                        // to the app was installed and in the new version this
-                        // component no longer exists.  Clean it up by removing
-                        // it from the preferred activities list, and skip it.
-                        Slog.w(TAG, "Removing dangling preferred activity: "
-                                + pa.mPref.mComponent);
-                        pir.removeFilter(pa);
-                        result.mChanged = true;
-                        continue;
-                    }
-                    for (int j = 0; j < N; j++) {
-                        final ResolveInfo ri = query.get(j);
-                        if (!ri.activityInfo.applicationInfo.packageName
-                                .equals(ai.applicationInfo.packageName)) {
-                            continue;
-                        }
-                        if (!ri.activityInfo.name.equals(ai.name)) {
-                            continue;
-                        }
-
-                        if (removeMatches && allowSetMutation) {
-                            pir.removeFilter(pa);
-                            result.mChanged = true;
-                            if (DEBUG_PREFERRED) {
-                                Slog.v(TAG, "Removing match " + pa.mPref.mComponent);
-                            }
-                            break;
-                        }
-
-                        // Okay we found a previously set preferred or last chosen app.
-                        // If the result set is different from when this
-                        // was created, and is not a subset of the preferred set, we need to
-                        // clear it and re-ask the user their preference, if we're looking for
-                        // an "always" type entry.
-
-                        if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) {
-                            if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) {
-                                if (allowSetMutation) {
-                                    // some components of the set are no longer present in
-                                    // the query, but the preferred activity can still be reused
-                                    if (DEBUG_PREFERRED) {
-                                        Slog.i(TAG, "Result set changed, but PreferredActivity"
-                                                + " is still valid as only non-preferred"
-                                                + " components were removed for " + intent
-                                                + " type " + resolvedType);
-                                    }
-                                    // remove obsolete components and re-add the up-to-date
-                                    // filter
-                                    PreferredActivity freshPa = new PreferredActivity(pa,
-                                            pa.mPref.mMatch,
-                                            pa.mPref.discardObsoleteComponents(query),
-                                            pa.mPref.mComponent,
-                                            pa.mPref.mAlways);
-                                    pir.removeFilter(pa);
-                                    pir.addFilter(freshPa);
-                                    result.mChanged = true;
-                                } else {
-                                    if (DEBUG_PREFERRED) {
-                                        Slog.i(TAG, "Do not remove preferred activity");
-                                    }
-                                }
-                            } else {
-                                if (allowSetMutation) {
-                                    Slog.i(TAG,
-                                            "Result set changed, dropping preferred activity "
-                                                    + "for " + intent + " type "
-                                                    + resolvedType);
-                                    if (DEBUG_PREFERRED) {
-                                        Slog.v(TAG,
-                                                "Removing preferred activity since set changed "
-                                                        + pa.mPref.mComponent);
-                                    }
-                                    pir.removeFilter(pa);
-                                    // Re-add the filter as a "last chosen" entry (!always)
-                                    PreferredActivity lastChosen = new PreferredActivity(
-                                            pa, pa.mPref.mMatch, null, pa.mPref.mComponent,
-                                            false);
-                                    pir.addFilter(lastChosen);
-                                    result.mChanged = true;
-                                }
-                                result.mPreferredResolveInfo = null;
-                                return result;
-                            }
-                        }
-
-                        // Yay! Either the set matched or we're looking for the last chosen
-                        if (DEBUG_PREFERRED || debug) {
-                            Slog.v(TAG, "Returning preferred activity: "
-                                    + ri.activityInfo.packageName + "/" + ri.activityInfo.name);
-                        }
-                        result.mPreferredResolveInfo = ri;
-                        return result;
-                    }
-                }
-            }
-            return result;
-        }
-
-        public final FindPreferredActivityBodyResult findPreferredActivityInternal(
-                Intent intent, String resolvedType, int flags,
-                List<ResolveInfo> query, boolean always,
-                boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
-
-            final int callingUid = Binder.getCallingUid();
-            // Do NOT hold the packages lock; this calls up into the settings provider which
-            // could cause a deadlock.
-            final boolean isDeviceProvisioned =
-                    android.provider.Settings.Global.getInt(mContext.getContentResolver(),
-                            android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1;
-            // Find the preferred activity - the lock is held inside the method.
-            return findPreferredActivityBody(
-                    intent, resolvedType, flags, query, always, removeMatches, debug,
-                    userId, queryMayBeFiltered, callingUid, isDeviceProvisioned);
-        }
-
-        public final ResolveInfo findPersistentPreferredActivityLP(Intent intent,
-                String resolvedType,
-                int flags, List<ResolveInfo> query, boolean debug, int userId) {
-            final int N = query.size();
-            PersistentPreferredIntentResolver ppir =
-                    mSettings.getPersistentPreferredActivities(userId);
-            // Get the list of persistent preferred activities that handle the intent
-            if (DEBUG_PREFERRED || debug) {
-                Slog.v(TAG, "Looking for persistent preferred activities...");
-            }
-            List<PersistentPreferredActivity> pprefs = ppir != null
-                    ? ppir.queryIntent(intent, resolvedType,
-                            (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
-                            userId)
-                    : null;
-            if (pprefs != null && pprefs.size() > 0) {
-                final int M = pprefs.size();
-                for (int i = 0; i < M; i++) {
-                    final PersistentPreferredActivity ppa = pprefs.get(i);
-                    if (DEBUG_PREFERRED || debug) {
-                        Slog.v(TAG, "Checking PersistentPreferredActivity ds="
-                                + (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "<none>")
-                                + "\n  component=" + ppa.mComponent);
-                        ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
-                    }
-                    final ActivityInfo ai = getActivityInfo(ppa.mComponent,
-                            flags | MATCH_DISABLED_COMPONENTS, userId);
-                    if (DEBUG_PREFERRED || debug) {
-                        Slog.v(TAG, "Found persistent preferred activity:");
-                        if (ai != null) {
-                            ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
-                        } else {
-                            Slog.v(TAG, "  null");
-                        }
-                    }
-                    if (ai == null) {
-                        // This previously registered persistent preferred activity
-                        // component is no longer known. Ignore it and do NOT remove it.
-                        continue;
-                    }
-                    for (int j = 0; j < N; j++) {
-                        final ResolveInfo ri = query.get(j);
-                        if (!ri.activityInfo.applicationInfo.packageName
-                                .equals(ai.applicationInfo.packageName)) {
-                            continue;
-                        }
-                        if (!ri.activityInfo.name.equals(ai.name)) {
-                            continue;
-                        }
-                        //  Found a persistent preference that can handle the intent.
-                        if (DEBUG_PREFERRED || debug) {
-                            Slog.v(TAG, "Returning persistent preferred activity: "
-                                    + ri.activityInfo.packageName + "/" + ri.activityInfo.name);
-                        }
-                        return ri;
-                    }
-                }
-            }
-            return null;
-        }
-    }
-
-    /**
-     * This subclass is the external interface to the live computer.  Some internal helper
-     * methods are overridden to fetch live data instead of snapshot data.  For each
-     * Computer interface that is overridden in this class, the override takes the PM lock
-     * and then delegates to the live computer engine.  This is required because there are
-     * no locks taken in the engine itself.
-     */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
-    protected static class ComputerLocked extends ComputerEngine {
-        private final Object mLock;
-
-        ComputerLocked(Snapshot args) {
-            super(args);
-            mLock = mService.mLock;
-        }
-
-        protected final ComponentName resolveComponentName() {
-            return mService.mResolveComponentName;
-        }
-        protected final ActivityInfo instantAppInstallerActivity() {
-            return mService.mInstantAppInstallerActivity;
-        }
-        protected final ApplicationInfo androidApplication() {
-            return mService.mAndroidApplication;
-        }
-
-        public final @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
-                String resolvedType, int flags, int userId, int callingUid,
-                String instantAppPkgName) {
-            synchronized (mLock) {
-                return super.queryIntentServicesInternalBody(intent, resolvedType, flags, userId,
-                        callingUid, instantAppPkgName);
-            }
-        }
-        public final @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
-                Intent intent, String resolvedType, int flags, int filterCallingUid, int userId,
-                boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
-                String instantAppPkgName) {
-            synchronized (mLock) {
-                return super.queryIntentActivitiesInternalBody(intent, resolvedType, flags,
-                        filterCallingUid, userId, resolveForStart, allowDynamicSplits, pkgName,
-                        instantAppPkgName);
-            }
-        }
-        public final ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
-                int filterCallingUid, int userId) {
-            synchronized (mLock) {
-                return super.getActivityInfoInternalBody(component, flags, filterCallingUid,
-                        userId);
-            }
-        }
-        public final AndroidPackage getPackage(String packageName) {
-            synchronized (mLock) {
-                return super.getPackage(packageName);
-            }
-        }
-        public final AndroidPackage getPackage(int uid) {
-            synchronized (mLock) {
-                return super.getPackage(uid);
-            }
-        }
-        public final ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
-                int filterCallingUid, int userId) {
-            synchronized (mLock) {
-                return super.getApplicationInfoInternalBody(packageName, flags, filterCallingUid,
-                        userId);
-            }
-        }
-        public final ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(
-                Intent intent, int matchFlags, List<ResolveInfo> candidates,
-                CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) {
-            synchronized (mLock) {
-                return super.filterCandidatesWithDomainPreferredActivitiesLPrBody(intent,
-                        matchFlags, candidates, xpDomainInfo, userId, debug);
-            }
-        }
-        public final PackageInfo getPackageInfoInternalBody(String packageName, long versionCode,
-                int flags, int filterCallingUid, int userId) {
-            synchronized (mLock) {
-                return super.getPackageInfoInternalBody(packageName, versionCode, flags,
-                        filterCallingUid, userId);
-            }
-        }
-        public final PackageSetting getPackageSettingInternal(String packageName, int callingUid) {
-            synchronized (mLock) {
-                return super.getPackageSettingInternal(packageName, callingUid);
-            }
-        }
-
-        @Nullable
-        public final PackageState getPackageState(@NonNull String packageName) {
-            synchronized (mLock) {
-                return super.getPackageState(packageName);
-            }
-        }
-
-        public final ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,
-                int callingUid) {
-            synchronized (mLock) {
-                return super.getInstalledPackagesBody(flags, userId, callingUid);
-            }
-        }
-        public final ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
-                int callingUid) {
-            synchronized (mLock) {
-                return super.getServiceInfoBody(component, flags, userId, callingUid);
-            }
-        }
-        public final String getInstantAppPackageName(int callingUid) {
-            synchronized (mLock) {
-                return super.getInstantAppPackageName(callingUid);
-            }
-        }
-        public final String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId,
-                boolean isCallerInstantApp) {
-            synchronized (mLock) {
-                return super.getPackagesForUidInternalBody(callingUid, userId, appId,
-                        isCallerInstantApp);
-            }
-        }
-        public final boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
-                int callingUid) {
-            synchronized (mLock) {
-                return super.isInstantAppInternalBody(packageName, userId, callingUid);
-            }
-        }
-        public final boolean isInstantAppResolutionAllowedBody(Intent intent,
-                List<ResolveInfo> resolvedActivities, int userId, boolean skipPackageCheck,
-                int flags) {
-            synchronized (mLock) {
-                return super.isInstantAppResolutionAllowedBody(intent, resolvedActivities, userId,
-                        skipPackageCheck, flags);
-            }
-        }
-        public final int getPackageUidInternal(String packageName, int flags, int userId,
-                int callingUid) {
-            synchronized (mLock) {
-                return super.getPackageUidInternal(packageName, flags, userId, callingUid);
-            }
-        }
-        public final SigningDetails getSigningDetails(@NonNull String packageName) {
-            synchronized (mLock) {
-                return super.getSigningDetails(packageName);
-            }
-        }
-        public final SigningDetails getSigningDetails(int uid) {
-            synchronized (mLock) {
-                return super.getSigningDetails(uid);
-            }
-        }
-        public final boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
-            synchronized (mLock) {
-                return super.filterAppAccess(pkg, callingUid, userId);
-            }
-        }
-        public final boolean filterAppAccess(String packageName, int callingUid, int userId) {
-            synchronized (mLock) {
-                return super.filterAppAccess(packageName, callingUid, userId);
-            }
-        }
-        public final boolean filterAppAccess(int uid, int callingUid) {
-            synchronized (mLock) {
-                return super.filterAppAccess(uid, callingUid);
-            }
-        }
-        public final void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
-            synchronized (mLock) {
-                super.dump(type, fd, pw, dumpState);
-            }
-        }
-        public final FindPreferredActivityBodyResult findPreferredActivityBody(Intent intent,
-                String resolvedType, int flags, List<ResolveInfo> query, boolean always,
-                boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered,
-                int callingUid, boolean isDeviceProvisioned) {
-            synchronized (mLock) {
-                return super.findPreferredActivityBody(intent, resolvedType, flags, query, always,
-                        removeMatches, debug, userId, queryMayBeFiltered, callingUid,
-                        isDeviceProvisioned);
-            }
-        }
-    }
-
-    /**
-     * This subclass delegates to methods in a Computer after reference-counting the computer.
-     */
-    private static class ComputerTracker implements Computer {
-
-        // The number of times a thread reused a computer in its stack instead of fetching
-        // a snapshot computer.
-        private final AtomicInteger mReusedSnapshot = new AtomicInteger(0);
-
-        // The number of times a thread reused a computer in its stack instead of fetching
-        // a live computer.
-        private final AtomicInteger mReusedLive = new AtomicInteger(0);
-
-        private final PackageManagerService mService;
-        ComputerTracker(PackageManagerService s) {
-            mService = s;
-        }
-
-        private ThreadComputer live() {
-            ThreadComputer current = sThreadComputer.get();
-            if (current.mRefCount > 0) {
-                current.acquire();
-                mReusedLive.incrementAndGet();
-            } else {
-                current.acquire(mService.liveComputer());
-            }
-            return current;
-        }
-
-        private ThreadComputer snapshot() {
-            ThreadComputer current = sThreadComputer.get();
-            if (current.mRefCount > 0) {
-                current.acquire();
-                mReusedSnapshot.incrementAndGet();
-            } else {
-                current.acquire(mService.snapshotComputer());
-            }
-            return current;
-        }
-
-        public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
-                String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags,
-                int filterCallingUid, int userId, boolean resolveForStart,
-                boolean allowDynamicSplits) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.queryIntentActivitiesInternal(intent, resolvedType, flags,
-                        privateResolveFlags, filterCallingUid, userId, resolveForStart,
-                        allowDynamicSplits);
-            } finally {
-                current.release();
-            }
-        }
-        public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
-                String resolvedType, int flags, int userId) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.queryIntentActivitiesInternal(intent, resolvedType, flags,
-                        userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
-                String resolvedType, int flags, int userId, int callingUid,
-                boolean includeInstantApps) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.queryIntentServicesInternal(intent, resolvedType, flags,
-                        userId, callingUid, includeInstantApps);
-            } finally {
-                current.release();
-            }
-        }
-        public final @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
-                Intent intent,
-                String resolvedType, int flags, int filterCallingUid, int userId,
-                boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
-                String instantAppPkgName) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.queryIntentActivitiesInternalBody(intent, resolvedType,
-                        flags, filterCallingUid, userId, resolveForStart, allowDynamicSplits,
-                        pkgName, instantAppPkgName);
-            } finally {
-                current.release();
-            }
-        }
-        public final ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.getActivityInfo(component, flags, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
-                int filterCallingUid, int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.getActivityInfoInternal(component, flags, filterCallingUid,
-                        userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final AndroidPackage getPackage(String packageName) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.getPackage(packageName);
-            } finally {
-                current.release();
-            }
-        }
-        public final AndroidPackage getPackage(int uid) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.getPackage(uid);
-            } finally {
-                current.release();
-            }
-        }
-        public final ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName,
-                int flags, int filterCallingUid, int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.generateApplicationInfoFromSettingsLPw(packageName, flags,
-                        filterCallingUid, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.getApplicationInfo(packageName, flags, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
-                int filterCallingUid, int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.getApplicationInfoInternal(packageName, flags,
-                        filterCallingUid, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final ComponentName getDefaultHomeActivity(int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.getDefaultHomeActivity(userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
-                int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.getHomeActivitiesAsUser(allHomeCandidates, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
-                String resolvedType, int flags, int sourceUserId, int parentUserId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.getCrossProfileDomainPreferredLpr(intent, resolvedType,
-                        flags, sourceUserId, parentUserId);
-            } finally {
-                current.release();
-            }
-        }
-        public final Intent getHomeIntent() {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.getHomeIntent();
-            } finally {
-                current.release();
-            }
-        }
-        public final List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(
-                Intent intent, String resolvedType, int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.getMatchingCrossProfileIntentFilters(intent, resolvedType,
-                        userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final List<ResolveInfo> applyPostResolutionFilter(
-                @NonNull List<ResolveInfo> resolveInfos,
-                String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
-                boolean resolveForStart, int userId, Intent intent) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.applyPostResolutionFilter(resolveInfos, ephemeralPkgName,
-                        allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent);
-            } finally {
-                current.release();
-            }
-        }
-        public final PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.generatePackageInfo(ps, flags, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final PackageInfo getPackageInfo(String packageName, int flags, int userId) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.getPackageInfo(packageName, flags, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final PackageInfo getPackageInfoInternal(String packageName, long versionCode,
-                int flags, int filterCallingUid, int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.getPackageInfoInternal(packageName, versionCode, flags,
-                        filterCallingUid, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final PackageSetting getPackageSetting(String packageName) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.getPackageSetting(packageName);
-            } finally {
-                current.release();
-            }
-        }
-        public final PackageSetting getPackageSettingInternal(String packageName, int callingUid) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.getPackageSettingInternal(packageName, callingUid);
-            } finally {
-                current.release();
-            }
-        }
-
-        @Nullable
-        public final PackageState getPackageState(@NonNull String packageName) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.getPackageState(packageName);
-            } finally {
-                current.release();
-            }
-        }
-
-        public final ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.getInstalledPackages(flags, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
-                int sourceUserId, int targetUserId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.createForwardingResolveInfoUnchecked(filter, sourceUserId,
-                        targetUserId);
-            } finally {
-                current.release();
-            }
-        }
-        public final ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.getServiceInfo(component, flags, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.getSharedLibraryInfoLPr(name, version);
-            } finally {
-                current.release();
-            }
-        }
-        public final SigningDetails getSigningDetails(@NonNull String packageName) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.getSigningDetails(packageName);
-            } finally {
-                current.release();
-            }
-        }
-        public final SigningDetails getSigningDetails(int uid) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.getSigningDetails(uid);
-            } finally {
-                current.release();
-            }
-        }
-        public final String getInstantAppPackageName(int callingUid) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.getInstantAppPackageName(callingUid);
-            } finally {
-                current.release();
-            }
-        }
-        public final String resolveExternalPackageNameLPr(AndroidPackage pkg) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.resolveExternalPackageNameLPr(pkg);
-            } finally {
-                current.release();
-            }
-        }
-        public final String resolveInternalPackageNameLPr(String packageName, long versionCode) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.resolveInternalPackageNameLPr(packageName, versionCode);
-            } finally {
-                current.release();
-            }
-        }
-        public final String[] getPackagesForUid(int uid) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.getPackagesForUid(uid);
-            } finally {
-                current.release();
-            }
-        }
-        public final UserInfo getProfileParent(int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.getProfileParent(userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final boolean canViewInstantApps(int callingUid, int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.canViewInstantApps(callingUid, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.filterAppAccess(pkg, callingUid, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final boolean filterAppAccess(String packageName, int callingUid, int userId) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.filterAppAccess(packageName, callingUid, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final boolean filterAppAccess(int uid, int callingUid) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.filterAppAccess(uid, callingUid);
-            } finally {
-                current.release();
-            }
-        }
-        public final boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid,
-                int userId, int flags) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.filterSharedLibPackageLPr(ps, uid, userId, flags);
-            } finally {
-                current.release();
-            }
-        }
-        public final boolean isCallerSameApp(String packageName, int uid) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.isCallerSameApp(packageName, uid);
-            } finally {
-                current.release();
-            }
-        }
-        public final boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.isComponentVisibleToInstantApp(component);
-            } finally {
-                current.release();
-            }
-        }
-        public final boolean isComponentVisibleToInstantApp(@Nullable ComponentName component,
-                @ComponentType int type) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.isComponentVisibleToInstantApp(component, type);
-            } finally {
-                current.release();
-            }
-        }
-        public final boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent,
-                int userId, String resolvedType, int flags) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent,
-                        userId, resolvedType, flags);
-            } finally {
-                current.release();
-            }
-        }
-        public final boolean isInstantApp(String packageName, int userId) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.isInstantApp(packageName, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final boolean isInstantAppInternal(String packageName, @UserIdInt int userId,
-                int callingUid) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.isInstantAppInternal(packageName, userId, callingUid);
-            } finally {
-                current.release();
-            }
-        }
-        public final boolean isSameProfileGroup(@UserIdInt int callerUserId,
-                @UserIdInt int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.isSameProfileGroup(callerUserId, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus,
-                int callingUid, int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.shouldFilterApplicationLocked(sus, callingUid, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps,
-                int callingUid,
-                @Nullable ComponentName component, @ComponentType int componentType, int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.shouldFilterApplicationLocked(ps, callingUid, component,
-                        componentType, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps,
-                int callingUid, int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.shouldFilterApplicationLocked(ps, callingUid, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final int checkUidPermission(String permName, int uid) {
-            ThreadComputer current = snapshot();
-            try {
-                return current.mComputer.checkUidPermission(permName, uid);
-            } finally {
-                current.release();
-            }
-        }
-        public final int getPackageUidInternal(String packageName, int flags, int userId,
-                int callingUid) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.getPackageUidInternal(packageName, flags, userId,
-                        callingUid);
-            } finally {
-                current.release();
-            }
-        }
-        public final int updateFlagsForApplication(int flags, int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.updateFlagsForApplication(flags, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final int updateFlagsForComponent(int flags, int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.updateFlagsForComponent(flags, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final int updateFlagsForPackage(int flags, int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.updateFlagsForPackage(flags, userId);
-            } finally {
-                current.release();
-            }
-        }
-        public final int updateFlagsForResolve(int flags, int userId, int callingUid,
-                boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.updateFlagsForResolve(flags, userId, callingUid,
-                        wantInstantApps, isImplicitImageCaptureIntentAndNotSetByDpc);
-            } finally {
-                current.release();
-            }
-        }
-        public final int updateFlagsForResolve(int flags, int userId, int callingUid,
-                boolean wantInstantApps, boolean onlyExposedExplicitly,
-                boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.updateFlagsForResolve(flags, userId, callingUid,
-                        wantInstantApps, onlyExposedExplicitly,
-                        isImplicitImageCaptureIntentAndNotSetByDpc);
-            } finally {
-                current.release();
-            }
-        }
-        public final void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
-            ThreadComputer current = live();
-            try {
-                current.mComputer.dump(type, fd, pw, dumpState);
-            } finally {
-                current.release();
-            }
-        }
-        public final void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
-                boolean requireFullPermission, boolean checkShell, String message) {
-            ThreadComputer current = live();
-            try {
-                current.mComputer.enforceCrossUserOrProfilePermission(callingUid, userId,
-                        requireFullPermission, checkShell, message);
-            } finally {
-                current.release();
-            }
-        }
-        public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
-                boolean requireFullPermission, boolean checkShell, String message) {
-            ThreadComputer current = live();
-            try {
-                current.mComputer.enforceCrossUserPermission(callingUid, userId,
-                        requireFullPermission, checkShell, message);
-            } finally {
-                current.release();
-            }
-        }
-        public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
-                boolean requireFullPermission, boolean checkShell,
-                boolean requirePermissionWhenSameUser, String message) {
-            ThreadComputer current = live();
-            try {
-                current.mComputer.enforceCrossUserPermission(callingUid, userId,
-                        requireFullPermission, checkShell, requirePermissionWhenSameUser, message);
-            } finally {
-                current.release();
-            }
-        }
-        public final FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent,
-                String resolvedType, int flags, List<ResolveInfo> query, boolean always,
-                boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.findPreferredActivityInternal(intent, resolvedType, flags,
-                        query, always, removeMatches, debug, userId, queryMayBeFiltered);
-            } finally {
-                current.release();
-            }
-        }
-        public final ResolveInfo findPersistentPreferredActivityLP(Intent intent,
-                String resolvedType, int flags, List<ResolveInfo> query, boolean debug,
-                int userId) {
-            ThreadComputer current = live();
-            try {
-                return current.mComputer.findPersistentPreferredActivityLP(intent, resolvedType,
-                        flags, query, debug, userId);
-            } finally {
-                current.release();
-            }
-        }
-    }
-
-
     // Compute read-only functions, based on live data.  This attribute may be modified multiple
     // times during the PackageManagerService constructor but it should not be modified thereafter.
     private ComputerLocked mLiveComputer;
@@ -5896,40 +1641,12 @@
     // should only be set true while holding mLock.  However, the attribute id guaranteed
     // to be set false only while mLock and mSnapshotLock are both held.
     private static final AtomicBoolean sSnapshotInvalid = new AtomicBoolean(true);
-    // The package manager that is using snapshots.
-    private static PackageManagerService sSnapshotConsumer = null;
     // If true, the snapshot is corked.  Do not create a new snapshot but use the live
     // computer.  This throttles snapshot creation during periods of churn in Package
     // Manager.
     static final AtomicInteger sSnapshotCorked = new AtomicInteger(0);
 
-    /**
-     * This class records the Computer being used by a thread and the Computer's reference
-     * count.  There is a thread-local copy of this class.
-     */
-    private static class ThreadComputer {
-        Computer mComputer = null;
-        int mRefCount = 0;
-        void acquire(Computer c) {
-            if (mRefCount != 0 && mComputer != c) {
-                throw new RuntimeException("computer mismatch, count = " + mRefCount);
-            }
-            mComputer = c;
-            mRefCount++;
-        }
-        void acquire() {
-            if (mRefCount == 0 || mComputer == null) {
-                throw new RuntimeException("computer acquire on empty ref count");
-            }
-            mRefCount++;
-        }
-        void release() {
-            if (--mRefCount == 0) {
-                mComputer = null;
-            }
-        }
-    }
-    private static final ThreadLocal<ThreadComputer> sThreadComputer =
+    static final ThreadLocal<ThreadComputer> sThreadComputer =
             ThreadLocal.withInitial(ThreadComputer::new);
 
     /**
@@ -5950,9 +1667,6 @@
     // and an image with the flag set false does not use snapshots.
     private static final boolean SNAPSHOT_ENABLED = true;
 
-    // The default auto-cork delay for snapshots.  This is 1s.
-    private static final long SNAPSHOT_AUTOCORK_DELAY_MS = TimeUnit.SECONDS.toMillis(1);
-
     // The per-instance snapshot disable/enable flag.  This is generally set to false in
     // test instances and set to SNAPSHOT_ENABLED in operational instances.
     private final boolean mSnapshotEnabled;
@@ -5960,7 +1674,7 @@
     /**
      * Return the live computer.
      */
-    private Computer liveComputer() {
+    Computer liveComputer() {
         return mLiveComputer;
     }
 
@@ -5968,7 +1682,7 @@
      * Return the cached computer.  The method will rebuild the cached computer if necessary.
      * The live computer will be returned if snapshots are disabled.
      */
-    private Computer snapshotComputer() {
+    Computer snapshotComputer() {
         if (!mSnapshotEnabled) {
             return mLiveComputer;
         }
@@ -6024,30 +1738,6 @@
     }
 
     /**
-     * Create a new snapshot.  Used for testing only.  This does collect statistics or
-     * update the snapshot used by other actors.  It does not alter the invalidation
-     * flag.  This method takes the mLock internally.
-     */
-    private Computer createNewSnapshot() {
-        synchronized (mLock) {
-            final Snapshot args = new Snapshot(Snapshot.SNAPPED);
-            return new ComputerEngine(args);
-        }
-    }
-
-    /**
-     * Cork snapshots.  This times out after the programmed delay.
-     */
-    private void corkSnapshots(int multiplier) {
-        int corking = sSnapshotCorked.getAndIncrement();
-        if (TRACE_SNAPSHOTS && corking == 0) {
-            Log.i(TAG, "snapshot: corking goes positive");
-        }
-        Message message = mHandler.obtainMessage(SNAPSHOT_UNCORK);
-        mHandler.sendMessageDelayed(message, SNAPSHOT_AUTOCORK_DELAY_MS * multiplier);
-    }
-
-    /**
      * Create a live computer
      */
     private ComputerLocked createLiveComputer() {
@@ -6075,9 +1765,6 @@
         onChange(null);
     }
 
-
-
-
     @Override
     public void notifyPackagesReplacedReceived(String[] packages) {
         final int callingUid = Binder.getCallingUid();
@@ -6117,11 +1804,6 @@
         }
     }
 
-    void scheduleDeferredNoKillPostDelete(InstallArgs args) {
-        Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_POST_DELETE, args);
-        mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_POST_DELETE_DELAY_MS);
-    }
-
     void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info,
             IPackageInstallObserver2 observer) {
         String packageName = info.mPkg.getPackageName();
@@ -6201,35 +1883,7 @@
         }
     }
 
-    /**
-     * Gets the type of the external storage a package is installed on.
-     * @param packageVolume The storage volume of the package.
-     * @param packageIsExternal true if the package is currently installed on
-     * external/removable/unprotected storage.
-     * @return {@link StorageEnums#UNKNOWN} if the package is not stored externally or the
-     * corresponding {@link StorageEnums} storage type value if it is.
-     * corresponding {@link StorageEnums} storage type value if it is.
-     */
-    static int getPackageExternalStorageType(VolumeInfo packageVolume,
-            boolean packageIsExternal) {
-        if (packageVolume != null) {
-            DiskInfo disk = packageVolume.getDisk();
-            if (disk != null) {
-                if (disk.isSd()) {
-                    return StorageEnums.SD_CARD;
-                }
-                if (disk.isUsb()) {
-                    return StorageEnums.USB;
-                }
-                if (packageIsExternal) {
-                    return StorageEnums.OTHER;
-                }
-            }
-        }
-        return StorageEnums.UNKNOWN;
-    }
-
-    Bundle extrasForInstallResult(PackageInstalledInfo res) {
+    private static Bundle extrasForInstallResult(PackageInstalledInfo res) {
         Bundle extras = null;
         switch (res.mReturnCode) {
             case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: {
@@ -6359,7 +2013,6 @@
                 LocalServices::getService,
                 context::getSystemService);
 
-
         if (Build.VERSION.SDK_INT <= 0) {
             Slog.w(TAG, "**** ro.build.version.sdk not set!");
         }
@@ -6565,6 +2218,7 @@
         mIsEngBuild = testParams.isEngBuild;
         mIsUserDebugBuild = testParams.isUserDebugBuild;
         mIncrementalVersion = testParams.incrementalVersion;
+        mDomainVerificationConnection = new DomainVerificationConnection(this);
 
         invalidatePackageInfoCache();
     }
@@ -6670,7 +2324,7 @@
         mPackageDexOptimizer = injector.getPackageDexOptimizer();
         mDexManager = injector.getDexManager();
         mArtManagerService = injector.getArtManagerService();
-        mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
+        mMoveCallbacks = new MovePackageHelper.MoveCallbacks(FgThread.get().getLooper());
         mViewCompiler = injector.getViewCompiler();
 
         mContext.getSystemService(DisplayManager.class)
@@ -6705,6 +2359,7 @@
         mAppInstallDir = new File(Environment.getDataDirectory(), "app");
         mAppLib32InstallDir = getAppLib32InstallDir();
 
+        mDomainVerificationConnection = new DomainVerificationConnection(this);
         mDomainVerificationManager = injector.getDomainVerificationManagerInternal();
         mDomainVerificationManager.setConnection(mDomainVerificationConnection);
 
@@ -6715,7 +2370,6 @@
             // corked initially to ensure a cached computer is not built until the end of the
             // constructor.
             mSnapshotStatistics = new SnapshotStatistics();
-            sSnapshotConsumer = this;
             sSnapshotCorked.set(1);
             sSnapshotInvalid.set(true);
             mLiveComputer = createLiveComputer();
@@ -6798,7 +2452,6 @@
                 Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
             }
 
-
             final VersionInfo ver = mSettings.getInternalVersion();
             mIsUpgrade =
                     !buildFingerprint.equals(ver.fingerprint);
@@ -7705,7 +3358,7 @@
      * @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int)
      */
     @GuardedBy("mLock")
-    private boolean shouldFilterApplicationLocked(
+    boolean shouldFilterApplicationLocked(
             @Nullable PackageSetting ps, int callingUid, int userId) {
         return mComputer.shouldFilterApplicationLocked(
             ps, callingUid, userId);
@@ -8004,9 +3657,6 @@
             if (freeBytesRequired > 0) {
                 smInternal.freeCache(volumeUuid, freeBytesRequired);
             }
-
-            // 12. Clear temp install session files
-            mInstallerService.freeStageDirs(volumeUuid);
         } else {
             try {
                 mInstaller.freeCache(volumeUuid, bytes, 0, 0);
@@ -8109,19 +3759,6 @@
     }
 
     /**
-     * Update given intent when being used to request {@link ResolveInfo}.
-     */
-    private static Intent updateIntentForResolve(Intent intent) {
-        if (intent.getSelector() != null) {
-            intent = intent.getSelector();
-        }
-        if (DEBUG_PREFERRED) {
-            intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
-        }
-        return intent;
-    }
-
-    /**
      * Update given flags when being used to request {@link ResolveInfo}.
      * <p>Instant apps are resolved specially, depending upon context. Minimally,
      * {@code}flags{@code} must have the {@link PackageManager#MATCH_INSTANT}
@@ -9250,7 +4887,7 @@
             return null;
         }
         final int callingUid = Binder.getCallingUid();
-        intent = updateIntentForResolve(intent);
+        intent = PackageManagerServiceUtils.updateIntentForResolve(intent);
         final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
         final int flags = updateFlagsForResolve(
                 0, userId, callingUid, false /*includeInstantApps*/,
@@ -9318,9 +4955,9 @@
             Bundle verificationBundle, int userId) {
         final Message msg = mHandler.obtainMessage(INSTANT_APP_RESOLUTION_PHASE_TWO,
                 new InstantAppRequest(responseObj, origIntent, resolvedType,
-                        callingPackage, callingFeatureId, isRequesterInstantApp, userId, verificationBundle,
-                        false /*resolveForStart*/, responseObj.hostDigestPrefixSecure,
-                        responseObj.token));
+                        callingPackage, callingFeatureId, isRequesterInstantApp, userId,
+                        verificationBundle, false /*resolveForStart*/,
+                        responseObj.hostDigestPrefixSecure, responseObj.token));
         mHandler.sendMessage(msg);
     }
 
@@ -9365,8 +5002,8 @@
                     if (ri.activityInfo.applicationInfo.isInstantApp()) {
                         final String packageName = ri.activityInfo.packageName;
                         final PackageSetting ps = mSettings.getPackageLPr(packageName);
-                        if (ps != null && hasAnyDomainApproval(mDomainVerificationManager, ps,
-                                intent, flags, userId)) {
+                        if (ps != null && PackageManagerServiceUtils.hasAnyDomainApproval(
+                                mDomainVerificationManager, ps, intent, flags, userId)) {
                             return ri;
                         }
                     }
@@ -9416,20 +5053,6 @@
     }
 
     /**
-     * Do NOT use for intent resolution filtering. That should be done with
-     * {@link DomainVerificationManagerInternal#filterToApprovedApp(Intent, List, int, Function)}.
-     *
-     * @return if the package is approved at any non-zero level for the domain in the intent
-     */
-    private static boolean hasAnyDomainApproval(
-            @NonNull DomainVerificationManagerInternal manager, @NonNull PackageSetting pkgSetting,
-            @NonNull Intent intent, @PackageManager.ResolveInfoFlags int resolveInfoFlags,
-            @UserIdInt int userId) {
-        return manager.approvalLevelForDomain(pkgSetting, intent, resolveInfoFlags, userId)
-                > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
-    }
-
-    /**
      * Return true if the given list is not empty and all of its contents have
      * an activityInfo with the given package name.
      */
@@ -9472,16 +5095,9 @@
                 flags, query, debug, userId);
     }
 
-    private static boolean isHomeIntent(Intent intent) {
-        return ACTION_MAIN.equals(intent.getAction())
-                && intent.hasCategory(CATEGORY_HOME)
-                && intent.hasCategory(CATEGORY_DEFAULT);
-    }
-
-
     // findPreferredActivityBody returns two items: a "things changed" flag and a
     // ResolveInfo, which is the preferred activity itself.
-    private static class FindPreferredActivityBodyResult {
+    static class FindPreferredActivityBodyResult {
         boolean mChanged;
         ResolveInfo mPreferredResolveInfo;
     }
@@ -9496,9 +5112,9 @@
             removeMatches, debug, userId, queryMayBeFiltered);
     }
 
-    ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
-            List<ResolveInfo> query, boolean always,
-            boolean removeMatches, boolean debug, int userId) {
+    private ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType,
+            int flags, List<ResolveInfo> query, boolean always, boolean removeMatches,
+            boolean debug, int userId) {
         return findPreferredActivityNotLocked(
                 intent, resolvedType, flags, query, always, removeMatches, debug, userId,
                 UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID);
@@ -9506,8 +5122,8 @@
 
     // TODO: handle preferred activities missing while user has amnesia
     /** <b>must not hold {@link #mLock}</b> */
-    ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
-            List<ResolveInfo> query, boolean always,
+    private ResolveInfo findPreferredActivityNotLocked(
+            Intent intent, String resolvedType, int flags, List<ResolveInfo> query, boolean always,
             boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
         if (Thread.holdsLock(mLock)) {
             Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
@@ -9606,23 +5222,6 @@
                 resolvedType, flags, userId);
     }
 
-    // Collect the results of queryIntentActivitiesInternalBody into a single class
-    private static class QueryIntentActivitiesResult {
-        public boolean sortResult = false;
-        public boolean addInstant = false;
-        public List<ResolveInfo> result = null;
-        public List<ResolveInfo> answer = null;
-
-        QueryIntentActivitiesResult(List<ResolveInfo> l) {
-            answer = l;
-        }
-        QueryIntentActivitiesResult(boolean s, boolean a, List<ResolveInfo> l) {
-            sortResult = s;
-            addInstant = a;
-            result = l;
-        }
-    }
-
     private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
             String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags,
             int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits) {
@@ -9631,25 +5230,6 @@
                 filterCallingUid, userId, resolveForStart, allowDynamicSplits);
     }
 
-    private static class CrossProfileDomainInfo {
-        /* ResolveInfo for IntentForwarderActivity to send the intent to the other profile */
-        ResolveInfo resolveInfo;
-        int highestApprovalLevel;
-
-        CrossProfileDomainInfo(ResolveInfo resolveInfo, int highestApprovalLevel) {
-            this.resolveInfo = resolveInfo;
-            this.highestApprovalLevel = highestApprovalLevel;
-        }
-
-        @Override
-        public String toString() {
-            return "CrossProfileDomainInfo{"
-                    + "resolveInfo=" + resolveInfo
-                    + ", highestApprovalLevel=" + highestApprovalLevel
-                    + '}';
-        }
-    }
-
     private CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
             String resolvedType, int flags, int sourceUserId, int parentUserId) {
         return mComputer.getCrossProfileDomainPreferredLpr(intent,
@@ -9925,7 +5505,7 @@
                     ri.activityInfo = ai;
                     list = new ArrayList<>(1);
                     list.add(ri);
-                    applyEnforceIntentFilterMatching(
+                    PackageManagerServiceUtils.applyEnforceIntentFilterMatching(
                             mInjector.getCompatibility(), mComponentResolver,
                             list, true, intent, resolvedType, filterCallingUid);
                 }
@@ -9954,7 +5534,7 @@
 
         if (originalIntent != null) {
             // We also have to ensure all components match the original intent
-            applyEnforceIntentFilterMatching(
+            PackageManagerServiceUtils.applyEnforceIntentFilterMatching(
                     mInjector.getCompatibility(), mComponentResolver,
                     list, true, originalIntent, resolvedType, filterCallingUid);
         }
@@ -10002,68 +5582,6 @@
                 includeInstantApps);
     }
 
-    // Static to give access to ComputeEngine
-    private static void applyEnforceIntentFilterMatching(
-            PlatformCompat compat, ComponentResolver resolver,
-            List<ResolveInfo> resolveInfos, boolean isReceiver,
-            Intent intent, String resolvedType, int filterCallingUid) {
-        // Do not enforce filter matching when the caller is system or root.
-        // see ActivityManager#checkComponentPermission(String, int, int, boolean)
-        if (filterCallingUid == Process.ROOT_UID || filterCallingUid == Process.SYSTEM_UID) {
-            return;
-        }
-
-        final Printer logPrinter = DEBUG_INTENT_MATCHING
-                ? new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM)
-                : null;
-
-        for (int i = resolveInfos.size() - 1; i >= 0; --i) {
-            final ComponentInfo info = resolveInfos.get(i).getComponentInfo();
-
-            // Do not enforce filter matching when the caller is the same app
-            if (info.applicationInfo.uid == filterCallingUid) {
-                continue;
-            }
-
-            // Only enforce filter matching if target app's target SDK >= T
-            if (!compat.isChangeEnabledInternal(
-                    ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS, info.applicationInfo)) {
-                continue;
-            }
-
-            final ParsedMainComponent comp;
-            if (info instanceof ActivityInfo) {
-                if (isReceiver) {
-                    comp = resolver.getReceiver(info.getComponentName());
-                } else {
-                    comp = resolver.getActivity(info.getComponentName());
-                }
-            } else if (info instanceof ServiceInfo) {
-                comp = resolver.getService(info.getComponentName());
-            } else {
-                // This shall never happen
-                throw new IllegalArgumentException("Unsupported component type");
-            }
-
-            if (comp.getIntents().isEmpty()) {
-                continue;
-            }
-
-            final boolean match = comp.getIntents().stream().anyMatch(
-                    f -> IntentResolver.intentMatchesFilter(f, intent, resolvedType));
-            if (!match) {
-                Slog.w(TAG, "Intent does not match component's intent filter: " + intent);
-                Slog.w(TAG, "Access blocked: " + comp.getComponentName());
-                if (DEBUG_INTENT_MATCHING) {
-                    Slog.v(TAG, "Component intent filters:");
-                    comp.getIntents().forEach(f -> f.dump(logPrinter, "  "));
-                    Slog.v(TAG, "-----------------------------");
-                }
-                resolveInfos.remove(i);
-            }
-        }
-    }
-
     @Override
     public @NonNull ParceledListSlice<ResolveInfo> queryIntentContentProviders(Intent intent,
             String resolvedType, int flags, int userId) {
@@ -10751,53 +6269,6 @@
                 requireFullPermission, checkShell, message);
     }
 
-    private static String buildInvalidCrossUserPermissionMessage(int callingUid,
-            @UserIdInt int userId, String message, boolean requireFullPermission) {
-        StringBuilder builder = new StringBuilder();
-        if (message != null) {
-            builder.append(message);
-            builder.append(": ");
-        }
-        builder.append("UID ");
-        builder.append(callingUid);
-        builder.append(" requires ");
-        builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
-        if (!requireFullPermission) {
-            builder.append(" or ");
-            builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS);
-        }
-        builder.append(" to access user ");
-        builder.append(userId);
-        builder.append(".");
-        return builder.toString();
-    }
-
-    private static String buildInvalidCrossUserOrProfilePermissionMessage(int callingUid,
-            @UserIdInt int userId, String message, boolean requireFullPermission,
-            boolean isSameProfileGroup) {
-        StringBuilder builder = new StringBuilder();
-        if (message != null) {
-            builder.append(message);
-            builder.append(": ");
-        }
-        builder.append("UID ");
-        builder.append(callingUid);
-        builder.append(" requires ");
-        builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
-        if (!requireFullPermission) {
-            builder.append(" or ");
-            builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS);
-            if (isSameProfileGroup) {
-                builder.append(" or ");
-                builder.append(android.Manifest.permission.INTERACT_ACROSS_PROFILES);
-            }
-        }
-        builder.append(" to access user ");
-        builder.append(userId);
-        builder.append(".");
-        return builder.toString();
-    }
-
     @Override
     public void performFstrimIfNeeded() {
         enforceSystemOrRoot("Only the system can request fstrim");
@@ -11389,7 +6860,7 @@
     }
 
     @Nullable
-    private static SharedLibraryInfo getSharedLibraryInfo(String name, long version,
+    public static SharedLibraryInfo getSharedLibraryInfo(String name, long version,
             Map<String, WatchedLongSparseArray<SharedLibraryInfo>> existingLibraries,
             @Nullable Map<String, WatchedLongSparseArray<SharedLibraryInfo>> newLibraries) {
         if (newLibraries != null) {
@@ -11817,8 +7288,8 @@
             final String libName = requestedLibraries.get(i);
             final long libVersion = requiredVersions != null ? requiredVersions[i]
                     : SharedLibraryInfo.VERSION_UNDEFINED;
-            final SharedLibraryInfo libraryInfo = getSharedLibraryInfo(libName, libVersion,
-                    existingLibraries, newLibraries);
+            final SharedLibraryInfo libraryInfo =
+                    getSharedLibraryInfo(libName, libVersion, existingLibraries, newLibraries);
             if (libraryInfo == null) {
                 if (required) {
                     throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
@@ -12681,7 +8152,8 @@
 
     private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting,
             int userId, int dataLoaderType) {
-        final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
+        final boolean isSystem = PackageManagerServiceUtils.isSystemApp(pkgSetting)
+                || PackageManagerServiceUtils.isUpdatedSystemApp(pkgSetting);
         final boolean isInstantApp = pkgSetting.getInstantApp(userId);
         final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
         final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
@@ -13109,6 +8581,7 @@
                                 pkgSetting.pkg.getRequestedPermissions());
                     }
                     mPermissionManager.onPackageInstalled(pkgSetting.pkg,
+                            Process.INVALID_UID /* previousAppId */,
                             permissionParamsBuilder.build(), userId);
                 }
 
@@ -13708,10 +9181,6 @@
         if (millisecondsToDelay < 0) {
             millisecondsToDelay = 0;
         }
-        if ((verificationCodeAtTimeout != PackageManager.VERIFICATION_ALLOW)
-                && (verificationCodeAtTimeout != PackageManager.VERIFICATION_REJECT)) {
-            verificationCodeAtTimeout = PackageManager.VERIFICATION_REJECT;
-        }
 
         if ((state != null) && !state.timeoutExtended()) {
             state.extendTimeout();
@@ -13723,23 +9192,6 @@
         }
     }
 
-    void broadcastPackageVerified(int verificationId, Uri packageUri,
-            int verificationCode, @Nullable String rootHashString, int dataLoaderType,
-            UserHandle user) {
-        final Intent intent = new Intent(Intent.ACTION_PACKAGE_VERIFIED);
-        intent.setDataAndType(packageUri, PACKAGE_MIME_TYPE);
-        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        intent.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
-        intent.putExtra(PackageManager.EXTRA_VERIFICATION_RESULT, verificationCode);
-        if (rootHashString != null) {
-            intent.putExtra(PackageManager.EXTRA_VERIFICATION_ROOT_HASH, rootHashString);
-        }
-        intent.putExtra(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
-
-        mContext.sendBroadcastAsUser(intent, user,
-                android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
-    }
-
     private void setEnableRollbackCode(int token, int enableRollbackCode) {
         final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_STATUS);
         msg.arg1 = token;
@@ -13760,20 +9212,6 @@
         mHandler.sendMessage(msg);
     }
 
-    /**
-     * Get the verification agent timeout.  Used for both the APK verifier and the
-     * intent filter verifier.
-     *
-     * @return verification timeout in milliseconds
-     */
-    long getVerificationTimeout() {
-        long timeout = Global.getLong(mContext.getContentResolver(),
-                Global.PACKAGE_VERIFIER_TIMEOUT, DEFAULT_VERIFICATION_TIMEOUT);
-        // The setting can be used to increase the timeout but not decrease it, since that is
-        // equivalent to disabling the verifier.
-        return Math.max(timeout, DEFAULT_VERIFICATION_TIMEOUT);
-    }
-
     @Deprecated
     @Override
     public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) {
@@ -14174,31 +9612,6 @@
         return new FileInstallArgs(codePath, instructionSets, this);
     }
 
-    /**
-     * Given {@code targetDir}, returns {@code targetDir/~~[randomStrA]/[packageName]-[randomStrB].}
-     * Makes sure that {@code targetDir/~~[randomStrA]} directory doesn't exist.
-     * Notice that this method doesn't actually create any directory.
-     *
-     * @param targetDir Directory that is two-levels up from the result directory.
-     * @param packageName Name of the package whose code files are to be installed under the result
-     *                    directory.
-     * @return File object for the directory that should hold the code files of {@code packageName}.
-     */
-    static File getNextCodePath(File targetDir, String packageName) {
-        SecureRandom random = new SecureRandom();
-        byte[] bytes = new byte[16];
-        File firstLevelDir;
-        do {
-            random.nextBytes(bytes);
-            String dirName = RANDOM_DIR_PREFIX
-                    + Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP);
-            firstLevelDir = new File(targetDir, dirName);
-        } while (firstLevelDir.exists());
-        random.nextBytes(bytes);
-        String suffix = Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP);
-        return new File(firstLevelDir, packageName + "-" + suffix);
-    }
-
     @GuardedBy("mLock")
     Map<String, ReconciledPackage> reconcilePackagesLocked(
             final ReconcileRequest request, KeySetManagerService ksms, Injector injector)
@@ -14312,7 +9725,6 @@
                     // over the latest parsed certs.
                     signingDetails = parsedPackage.getSigningDetails();
 
-
                     // if this is is a sharedUser, check to see if the new package is signed by a
                     // newer
                     // signing certificate than the existing one, and if so, copy over the new
@@ -14578,14 +9990,6 @@
         }
     }
 
-    private static boolean isSystemApp(PackageSetting ps) {
-        return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0;
-    }
-
-    private static boolean isUpdatedSystemApp(PackageSetting ps) {
-        return (ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
-    }
-
     VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) {
         if (pkg.isExternalStorage()) {
             if (TextUtils.isEmpty(pkg.getVolumeUuid())) {
@@ -14988,7 +10392,7 @@
 
             info.mOrigUsers = uninstalledPs.queryInstalledUsers(allUsers, true);
 
-            if (isUpdatedSystemApp(uninstalledPs)
+            if (PackageManagerServiceUtils.isUpdatedSystemApp(uninstalledPs)
                     && ((deleteFlags & PackageManager.DELETE_SYSTEM_APP) == 0)) {
                 // We're downgrading a system app, which will apply to all users, so
                 // freeze them all during the downgrade
@@ -15090,7 +10494,6 @@
         return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
     }
 
-
     /*
      * This method deletes the package from internal data structures. If the DELETE_KEEP_DATA
      * flag is not set, the data directory is removed as well.
@@ -15308,7 +10711,7 @@
         if (ps == null) {
             return null;
         }
-        if (isSystemApp(ps)) {
+        if (PackageManagerServiceUtils.isSystemApp(ps)) {
             final boolean deleteSystem = (flags & PackageManager.DELETE_SYSTEM_APP) != 0;
             final boolean deleteAllUsers =
                     user == null || user.getIdentifier() == UserHandle.USER_ALL;
@@ -15341,7 +10744,6 @@
             return false;
         }
 
-
         try {
             executeDeletePackageLIF(action, packageName, deleteCodeAndResources,
                     allUserHandles, writeSettings);
@@ -15360,7 +10762,7 @@
         final PackageRemovedInfo outInfo = action.mRemovedInfo;
         final UserHandle user = action.mUser;
         final int flags = action.mFlags;
-        final boolean systemApp = isSystemApp(ps);
+        final boolean systemApp = PackageManagerServiceUtils.isSystemApp(ps);
 
         // We need to get the permission state before package state is (potentially) destroyed.
         final SparseBooleanArray hadSuspendAppsPermission = new SparseBooleanArray();
@@ -15746,41 +11148,6 @@
                 "Shame on you for calling the hidden API getPackageSizeInfo(). Shame!");
     }
 
-    @GuardedBy("mInstallLock")
-    private boolean getPackageSizeInfoLI(String packageName, int userId, PackageStats stats) {
-        final PackageSetting ps;
-        synchronized (mLock) {
-            ps = mSettings.getPackageLPr(packageName);
-            if (ps == null) {
-                Slog.w(TAG, "Failed to find settings for " + packageName);
-                return false;
-            }
-        }
-
-        final String[] packageNames = { packageName };
-        final long[] ceDataInodes = { ps.getCeDataInode(userId) };
-        final String[] codePaths = { ps.getPathString() };
-
-        try {
-            mInstaller.getAppSize(ps.volumeUuid, packageNames, userId, 0,
-                    ps.appId, ceDataInodes, codePaths, stats);
-
-            // For now, ignore code size of packages on system partition
-            if (isSystemApp(ps) && !isUpdatedSystemApp(ps)) {
-                stats.codeSize = 0;
-            }
-
-            // External clients expect these to be tracked separately
-            stats.dataSize -= stats.cacheSize;
-
-        } catch (InstallerException e) {
-            Slog.w(TAG, String.valueOf(e));
-            return false;
-        }
-
-        return true;
-    }
-
     @GuardedBy("mLock")
     private int getUidTargetSdkVersionLockedLPr(int uid) {
         final int appId = UserHandle.getAppId(uid);
@@ -17770,19 +13137,6 @@
         return mHasSystemUidErrors;
     }
 
-    static String arrayToString(int[] array) {
-        StringBuilder stringBuilder = new StringBuilder(128);
-        stringBuilder.append('[');
-        if (array != null) {
-            for (int i=0; i<array.length; i++) {
-                if (i > 0) stringBuilder.append(", ");
-                stringBuilder.append(array[i]);
-            }
-        }
-        stringBuilder.append(']');
-        return stringBuilder.toString();
-    }
-
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out,
             FileDescriptor err, String[] args, ShellCallback callback,
@@ -18580,7 +13934,6 @@
         }
     }
 
-
     private void executeBatchLI(@NonNull Installer.Batch batch) {
         try {
             batch.execute(mInstaller);
@@ -18979,7 +14332,9 @@
         final int moveId = mNextMoveId.getAndIncrement();
         mHandler.post(() -> {
             try {
-                movePackageInternal(packageName, volumeUuid, moveId, callingUid, user);
+                MovePackageHelper movePackageHelper = new MovePackageHelper(this);
+                movePackageHelper.movePackageInternal(
+                        packageName, volumeUuid, moveId, callingUid, user);
             } catch (PackageManagerException e) {
                 Slog.w(TAG, "Failed to move " + packageName, e);
                 mMoveCallbacks.notifyStatusChanged(moveId, e.error);
@@ -18988,263 +14343,6 @@
         return moveId;
     }
 
-    private void movePackageInternal(final String packageName, final String volumeUuid,
-            final int moveId, final int callingUid, UserHandle user)
-                    throws PackageManagerException {
-        final StorageManager storage = mInjector.getSystemService(StorageManager.class);
-        final PackageManager pm = mContext.getPackageManager();
-
-        final String currentVolumeUuid;
-        final File codeFile;
-        final InstallSource installSource;
-        final String packageAbiOverride;
-        final int appId;
-        final String seinfo;
-        final String label;
-        final int targetSdkVersion;
-        final PackageFreezer freezer;
-        final int[] installedUserIds;
-        final boolean isCurrentLocationExternal;
-        final String fromCodePath;
-
-        // reader
-        synchronized (mLock) {
-            final AndroidPackage pkg = mPackages.get(packageName);
-            final PackageSetting ps = mSettings.getPackageLPr(packageName);
-            if (pkg == null
-                    || ps == null
-                    || shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) {
-                throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
-            }
-            if (pkg.isSystem()) {
-                throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
-                        "Cannot move system application");
-            }
-
-            final boolean isInternalStorage = VolumeInfo.ID_PRIVATE_INTERNAL.equals(volumeUuid);
-            final boolean allow3rdPartyOnInternal = mContext.getResources().getBoolean(
-                    com.android.internal.R.bool.config_allow3rdPartyAppOnInternal);
-            if (isInternalStorage && !allow3rdPartyOnInternal) {
-                throw new PackageManagerException(MOVE_FAILED_3RD_PARTY_NOT_ALLOWED_ON_INTERNAL,
-                        "3rd party apps are not allowed on internal storage");
-            }
-
-            currentVolumeUuid = ps.volumeUuid;
-
-            final File probe = new File(pkg.getPath());
-            final File probeOat = new File(probe, "oat");
-            if (!probe.isDirectory() || !probeOat.isDirectory()) {
-                throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
-                        "Move only supported for modern cluster style installs");
-            }
-
-            if (Objects.equals(currentVolumeUuid, volumeUuid)) {
-                throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
-                        "Package already moved to " + volumeUuid);
-            }
-            if (!pkg.isExternalStorage() && isPackageDeviceAdminOnAnyUser(packageName)) {
-                throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN,
-                        "Device admin cannot be moved");
-            }
-
-            if (mFrozenPackages.contains(packageName)) {
-                throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
-                        "Failed to move already frozen package");
-            }
-
-            isCurrentLocationExternal = pkg.isExternalStorage();
-            codeFile = new File(pkg.getPath());
-            installSource = ps.installSource;
-            packageAbiOverride = ps.cpuAbiOverrideString;
-            appId = UserHandle.getAppId(pkg.getUid());
-            seinfo = AndroidPackageUtils.getSeInfo(pkg, ps);
-            label = String.valueOf(pm.getApplicationLabel(
-                    AndroidPackageUtils.generateAppInfoWithoutState(pkg)));
-            targetSdkVersion = pkg.getTargetSdkVersion();
-            freezer = freezePackage(packageName, "movePackageInternal");
-            installedUserIds = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
-            if (codeFile.getParentFile().getName().startsWith(RANDOM_DIR_PREFIX)) {
-                fromCodePath = codeFile.getParentFile().getAbsolutePath();
-            } else {
-                fromCodePath = codeFile.getAbsolutePath();
-            }
-        }
-
-        final Bundle extras = new Bundle();
-        extras.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
-        extras.putString(Intent.EXTRA_TITLE, label);
-        mMoveCallbacks.notifyCreated(moveId, extras);
-
-        int installFlags;
-        final boolean moveCompleteApp;
-        final File measurePath;
-
-        installFlags = INSTALL_INTERNAL;
-        if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
-            moveCompleteApp = true;
-            measurePath = Environment.getDataAppDirectory(volumeUuid);
-        } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
-            moveCompleteApp = false;
-            measurePath = storage.getPrimaryPhysicalVolume().getPath();
-        } else {
-            final VolumeInfo volume = storage.findVolumeByUuid(volumeUuid);
-            if (volume == null || volume.getType() != VolumeInfo.TYPE_PRIVATE
-                    || !volume.isMountedWritable()) {
-                freezer.close();
-                throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
-                        "Move location not mounted private volume");
-            }
-
-            moveCompleteApp = true;
-            measurePath = Environment.getDataAppDirectory(volumeUuid);
-        }
-
-        // If we're moving app data around, we need all the users unlocked
-        if (moveCompleteApp) {
-            for (int userId : installedUserIds) {
-                if (StorageManager.isFileEncryptedNativeOrEmulated()
-                        && !StorageManager.isUserKeyUnlocked(userId)) {
-                    throw new PackageManagerException(MOVE_FAILED_LOCKED_USER,
-                            "User " + userId + " must be unlocked");
-                }
-            }
-        }
-
-        final PackageStats stats = new PackageStats(null, -1);
-        synchronized (mInstaller) {
-            for (int userId : installedUserIds) {
-                if (!getPackageSizeInfoLI(packageName, userId, stats)) {
-                    freezer.close();
-                    throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
-                            "Failed to measure package size");
-                }
-            }
-        }
-
-        if (DEBUG_INSTALL) Slog.d(TAG, "Measured code size " + stats.codeSize + ", data size "
-                + stats.dataSize);
-
-        final long startFreeBytes = measurePath.getUsableSpace();
-        final long sizeBytes;
-        if (moveCompleteApp) {
-            sizeBytes = stats.codeSize + stats.dataSize;
-        } else {
-            sizeBytes = stats.codeSize;
-        }
-
-        if (sizeBytes > storage.getStorageBytesUntilLow(measurePath)) {
-            freezer.close();
-            throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
-                    "Not enough free space to move");
-        }
-
-        mMoveCallbacks.notifyStatusChanged(moveId, 10);
-
-        final CountDownLatch installedLatch = new CountDownLatch(1);
-        final IPackageInstallObserver2 installObserver = new IPackageInstallObserver2.Stub() {
-            @Override
-            public void onUserActionRequired(Intent intent) throws RemoteException {
-                throw new IllegalStateException();
-            }
-
-            @Override
-            public void onPackageInstalled(String basePackageName, int returnCode, String msg,
-                    Bundle extras) throws RemoteException {
-                if (DEBUG_INSTALL) Slog.d(TAG, "Install result for move: "
-                        + PackageManager.installStatusToString(returnCode, msg));
-
-                installedLatch.countDown();
-                freezer.close();
-
-                final int status = PackageManager.installStatusToPublicStatus(returnCode);
-                switch (status) {
-                    case PackageInstaller.STATUS_SUCCESS:
-                        mMoveCallbacks.notifyStatusChanged(moveId,
-                                PackageManager.MOVE_SUCCEEDED);
-                        logAppMovedStorage(packageName, isCurrentLocationExternal);
-                        break;
-                    case PackageInstaller.STATUS_FAILURE_STORAGE:
-                        mMoveCallbacks.notifyStatusChanged(moveId,
-                                PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE);
-                        break;
-                    default:
-                        mMoveCallbacks.notifyStatusChanged(moveId,
-                                PackageManager.MOVE_FAILED_INTERNAL_ERROR);
-                        break;
-                }
-            }
-        };
-
-        final MoveInfo move;
-        if (moveCompleteApp) {
-            // Kick off a thread to report progress estimates
-            new Thread(() -> {
-                while (true) {
-                    try {
-                        if (installedLatch.await(1, TimeUnit.SECONDS)) {
-                            break;
-                        }
-                    } catch (InterruptedException ignored) {
-                    }
-
-                    final long deltaFreeBytes = startFreeBytes - measurePath.getUsableSpace();
-                    final int progress = 10 + (int) MathUtils.constrain(
-                            ((deltaFreeBytes * 80) / sizeBytes), 0, 80);
-                    mMoveCallbacks.notifyStatusChanged(moveId, progress);
-                }
-            }).start();
-
-            move = new MoveInfo(moveId, currentVolumeUuid, volumeUuid, packageName,
-                    appId, seinfo, targetSdkVersion, fromCodePath);
-        } else {
-            move = null;
-        }
-
-        installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
-
-        final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
-        final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
-        final ParseResult<PackageLite> ret = ApkLiteParseUtils.parsePackageLite(input,
-                new File(origin.mResolvedPath), /* flags */ 0);
-        final PackageLite lite = ret.isSuccess() ? ret.getResult() : null;
-        final InstallParams params = new InstallParams(origin, move, installObserver, installFlags,
-                installSource, volumeUuid, user, packageAbiOverride, lite, this);
-        params.movePackage();
-    }
-
-    /**
-     * Logs that an app has been moved from internal to external storage and vice versa.
-     * @param packageName The package that was moved.
-     */
-    private void logAppMovedStorage(String packageName, boolean isPreviousLocationExternal) {
-        final AndroidPackage pkg;
-        synchronized (mLock) {
-            pkg = mPackages.get(packageName);
-        }
-        if (pkg == null) {
-            return;
-        }
-
-        final StorageManager storage = mInjector.getSystemService(StorageManager.class);;
-        VolumeInfo volume = storage.findVolumeByUuid(
-                StorageManager.convert(pkg.getVolumeUuid()).toString());
-        int packageExternalStorageType = getPackageExternalStorageType(volume, pkg.isExternalStorage());
-
-        if (!isPreviousLocationExternal && pkg.isExternalStorage()) {
-            // Move from internal to external storage.
-            FrameworkStatsLog.write(FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED,
-                    packageExternalStorageType,
-                    FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_EXTERNAL,
-                    packageName);
-        } else if (isPreviousLocationExternal && !pkg.isExternalStorage()) {
-            // Move from external to internal storage.
-            FrameworkStatsLog.write(FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED,
-                    packageExternalStorageType,
-                    FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_INTERNAL,
-                    packageName);
-        }
-    }
-
     @Override
     public int movePrimaryStorage(String volumeUuid) throws RemoteException {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
@@ -19593,84 +14691,6 @@
         }
     }
 
-    private static class MoveCallbacks extends Handler {
-        private static final int MSG_CREATED = 1;
-        private static final int MSG_STATUS_CHANGED = 2;
-
-        private final RemoteCallbackList<IPackageMoveObserver>
-                mCallbacks = new RemoteCallbackList<>();
-
-        private final SparseIntArray mLastStatus = new SparseIntArray();
-
-        public MoveCallbacks(Looper looper) {
-            super(looper);
-        }
-
-        public void register(IPackageMoveObserver callback) {
-            mCallbacks.register(callback);
-        }
-
-        public void unregister(IPackageMoveObserver callback) {
-            mCallbacks.unregister(callback);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            final SomeArgs args = (SomeArgs) msg.obj;
-            final int n = mCallbacks.beginBroadcast();
-            for (int i = 0; i < n; i++) {
-                final IPackageMoveObserver callback = mCallbacks.getBroadcastItem(i);
-                try {
-                    invokeCallback(callback, msg.what, args);
-                } catch (RemoteException ignored) {
-                }
-            }
-            mCallbacks.finishBroadcast();
-            args.recycle();
-        }
-
-        private void invokeCallback(IPackageMoveObserver callback, int what, SomeArgs args)
-                throws RemoteException {
-            switch (what) {
-                case MSG_CREATED: {
-                    callback.onCreated(args.argi1, (Bundle) args.arg2);
-                    break;
-                }
-                case MSG_STATUS_CHANGED: {
-                    callback.onStatusChanged(args.argi1, args.argi2, (long) args.arg3);
-                    break;
-                }
-            }
-        }
-
-        private void notifyCreated(int moveId, Bundle extras) {
-            Slog.v(TAG, "Move " + moveId + " created " + extras.toString());
-
-            final SomeArgs args = SomeArgs.obtain();
-            args.argi1 = moveId;
-            args.arg2 = extras;
-            obtainMessage(MSG_CREATED, args).sendToTarget();
-        }
-
-        private void notifyStatusChanged(int moveId, int status) {
-            notifyStatusChanged(moveId, status, -1);
-        }
-
-        private void notifyStatusChanged(int moveId, int status, long estMillis) {
-            Slog.v(TAG, "Move " + moveId + " status " + status);
-
-            final SomeArgs args = SomeArgs.obtain();
-            args.argi1 = moveId;
-            args.argi2 = status;
-            args.arg3 = estMillis;
-            obtainMessage(MSG_STATUS_CHANGED, args).sendToTarget();
-
-            synchronized (mLastStatus) {
-                mLastStatus.put(moveId, status);
-            }
-        }
-    }
-
     private final class PackageChangeObserverDeathRecipient implements IBinder.DeathRecipient {
         private final IPackageChangeObserver mObserver;
 
@@ -20013,6 +15033,23 @@
             return PackageManagerService.this.getPackage(uid);
         }
 
+        @Override
+        public List<AndroidPackage> getPackagesForAppId(int appId) {
+            final Object obj;
+            synchronized (mLock) {
+                obj = mSettings.getSettingLPr(appId);
+            }
+            if (obj instanceof SharedUserSetting) {
+                final SharedUserSetting sus = (SharedUserSetting) obj;
+                return sus.getPackages();
+            } else if (obj instanceof PackageSetting) {
+                final PackageSetting ps = (PackageSetting) obj;
+                return List.of(ps.getPkg());
+            } else {
+                return Collections.emptyList();
+            }
+        }
+
         @Nullable
         @Override
         public PackageSetting getPackageSetting(String packageName) {
@@ -21874,7 +16911,7 @@
     }
 
     @Override
-    public boolean mayPackageQuery(String sourcePackageName, String targetPackageName, int userId) {
+    public boolean canPackageQuery(String sourcePackageName, String targetPackageName, int userId) {
         if (!mUserManager.exists(userId)) return false;
         final int callingUid = Binder.getCallingUid();
         enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
@@ -21917,4 +16954,16 @@
             this.installed = installed;
         }
     }
+
+    public boolean getSafeMode() {
+        return mSafeMode;
+    }
+
+    public ComponentName getResolveComponentName() {
+        return mResolveComponentName;
+    }
+
+    public DefaultAppProvider getDefaultAppProvider() {
+        return mDefaultAppProvider;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 5fdb57d..709fc93 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -24,21 +24,33 @@
 import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION;
 import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
 import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
+import static com.android.server.pm.PackageManagerService.DEBUG_INTENT_MATCHING;
+import static com.android.server.pm.PackageManagerService.DEBUG_PREFERRED;
+import static com.android.server.pm.PackageManagerService.RANDOM_DIR_PREFIX;
 import static com.android.server.pm.PackageManagerService.STUB_SUFFIX;
 import static com.android.server.pm.PackageManagerService.TAG;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.AppGlobals;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
 import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.SharedLibraryInfo;
 import android.content.pm.Signature;
 import android.content.pm.SigningDetails;
 import android.content.pm.parsing.ApkLiteParseUtils;
 import android.content.pm.parsing.PackageLite;
+import android.content.pm.parsing.component.ParsedMainComponent;
 import android.content.pm.parsing.result.ParseResult;
 import android.content.pm.parsing.result.ParseTypeImpl;
 import android.os.Build;
@@ -52,11 +64,17 @@
 import android.os.incremental.IncrementalManager;
 import android.os.incremental.V4Signature;
 import android.os.incremental.V4Signature.HashingInfo;
+import android.os.storage.DiskInfo;
+import android.os.storage.VolumeInfo;
 import android.service.pm.PackageServiceDumpProto;
+import android.stats.storage.StorageEnums;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.util.ArraySet;
+import android.util.Base64;
 import android.util.Log;
+import android.util.LogPrinter;
+import android.util.Printer;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
@@ -66,9 +84,13 @@
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.HexDump;
 import com.android.server.EventLogTags;
+import com.android.server.IntentResolver;
+import com.android.server.compat.PlatformCompat;
 import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.dex.PackageDexUsage;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
+import com.android.server.utils.WatchedLongSparseArray;
 
 import dalvik.system.VMRuntime;
 
@@ -86,6 +108,7 @@
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.nio.file.Path;
+import java.security.SecureRandom;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateException;
 import java.text.SimpleDateFormat;
@@ -96,6 +119,8 @@
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.zip.GZIPInputStream;
 
@@ -111,6 +136,20 @@
     public final static Predicate<PackageSetting> REMOVE_IF_NULL_PKG =
             pkgSetting -> pkgSetting.pkg == null;
 
+    /**
+     * Components of apps targeting Android T and above will stop receiving intents from
+     * external callers that do not match its declared intent filters.
+     *
+     * When an app registers an exported component in its manifest and adds an <intent-filter>,
+     * the component can be started by any intent - even those that do not match the intent filter.
+     * This has proven to be something that many developers find counterintuitive.
+     * Without checking the intent when the component is started, in some circumstances this can
+     * allow 3P apps to trigger internal-only functionality.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S)
+    private static final long ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS = 161252188;
+
     private static ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) {
         List<ResolveInfo> ris = null;
         try {
@@ -1071,4 +1110,168 @@
         }
         return null;
     }
+
+    public static boolean isSystemApp(PackageSetting ps) {
+        return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0;
+    }
+
+    public static boolean isUpdatedSystemApp(PackageSetting ps) {
+        return (ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
+    }
+
+    // Static to give access to ComputeEngine
+    public static void applyEnforceIntentFilterMatching(
+            PlatformCompat compat, ComponentResolver resolver,
+            List<ResolveInfo> resolveInfos, boolean isReceiver,
+            Intent intent, String resolvedType, int filterCallingUid) {
+        // Do not enforce filter matching when the caller is system or root.
+        // see ActivityManager#checkComponentPermission(String, int, int, boolean)
+        if (filterCallingUid == Process.ROOT_UID || filterCallingUid == Process.SYSTEM_UID) {
+            return;
+        }
+
+        final Printer logPrinter = DEBUG_INTENT_MATCHING
+                ? new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM)
+                : null;
+
+        for (int i = resolveInfos.size() - 1; i >= 0; --i) {
+            final ComponentInfo info = resolveInfos.get(i).getComponentInfo();
+
+            // Do not enforce filter matching when the caller is the same app
+            if (info.applicationInfo.uid == filterCallingUid) {
+                continue;
+            }
+
+            // Only enforce filter matching if target app's target SDK >= T
+            if (!compat.isChangeEnabledInternal(
+                    ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS, info.applicationInfo)) {
+                continue;
+            }
+
+            final ParsedMainComponent comp;
+            if (info instanceof ActivityInfo) {
+                if (isReceiver) {
+                    comp = resolver.getReceiver(info.getComponentName());
+                } else {
+                    comp = resolver.getActivity(info.getComponentName());
+                }
+            } else if (info instanceof ServiceInfo) {
+                comp = resolver.getService(info.getComponentName());
+            } else {
+                // This shall never happen
+                throw new IllegalArgumentException("Unsupported component type");
+            }
+
+            if (comp.getIntents().isEmpty()) {
+                continue;
+            }
+
+            final boolean match = comp.getIntents().stream().anyMatch(
+                    f -> IntentResolver.intentMatchesFilter(f, intent, resolvedType));
+            if (!match) {
+                Slog.w(TAG, "Intent does not match component's intent filter: " + intent);
+                Slog.w(TAG, "Access blocked: " + comp.getComponentName());
+                if (DEBUG_INTENT_MATCHING) {
+                    Slog.v(TAG, "Component intent filters:");
+                    comp.getIntents().forEach(f -> f.dump(logPrinter, "  "));
+                    Slog.v(TAG, "-----------------------------");
+                }
+                resolveInfos.remove(i);
+            }
+        }
+    }
+
+
+    /**
+     * Do NOT use for intent resolution filtering. That should be done with
+     * {@link DomainVerificationManagerInternal#filterToApprovedApp(Intent, List, int, Function)}.
+     *
+     * @return if the package is approved at any non-zero level for the domain in the intent
+     */
+    public static boolean hasAnyDomainApproval(
+            @NonNull DomainVerificationManagerInternal manager, @NonNull PackageSetting pkgSetting,
+            @NonNull Intent intent, @PackageManager.ResolveInfoFlags int resolveInfoFlags,
+            @UserIdInt int userId) {
+        return manager.approvalLevelForDomain(pkgSetting, intent, resolveInfoFlags, userId)
+                > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
+    }
+
+    /**
+     * Update given intent when being used to request {@link ResolveInfo}.
+     */
+    public static Intent updateIntentForResolve(Intent intent) {
+        if (intent.getSelector() != null) {
+            intent = intent.getSelector();
+        }
+        if (DEBUG_PREFERRED) {
+            intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
+        }
+        return intent;
+    }
+
+    public static String arrayToString(int[] array) {
+        StringBuilder stringBuilder = new StringBuilder(128);
+        stringBuilder.append('[');
+        if (array != null) {
+            for (int i = 0; i < array.length; i++) {
+                if (i > 0) stringBuilder.append(", ");
+                stringBuilder.append(array[i]);
+            }
+        }
+        stringBuilder.append(']');
+        return stringBuilder.toString();
+    }
+
+    /**
+     * Given {@code targetDir}, returns {@code targetDir/~~[randomStrA]/[packageName]-[randomStrB].}
+     * Makes sure that {@code targetDir/~~[randomStrA]} directory doesn't exist.
+     * Notice that this method doesn't actually create any directory.
+     *
+     * @param targetDir Directory that is two-levels up from the result directory.
+     * @param packageName Name of the package whose code files are to be installed under the result
+     *                    directory.
+     * @return File object for the directory that should hold the code files of {@code packageName}.
+     */
+    public static File getNextCodePath(File targetDir, String packageName) {
+        SecureRandom random = new SecureRandom();
+        byte[] bytes = new byte[16];
+        File firstLevelDir;
+        do {
+            random.nextBytes(bytes);
+            String dirName = RANDOM_DIR_PREFIX
+                    + Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP);
+            firstLevelDir = new File(targetDir, dirName);
+        } while (firstLevelDir.exists());
+        random.nextBytes(bytes);
+        String suffix = Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP);
+        return new File(firstLevelDir, packageName + "-" + suffix);
+    }
+
+    /**
+     * Gets the type of the external storage a package is installed on.
+     * @param packageVolume The storage volume of the package.
+     * @param packageIsExternal true if the package is currently installed on
+     * external/removable/unprotected storage.
+     * @return {@link StorageEnums#UNKNOWN} if the package is not stored externally or the
+     * corresponding {@link StorageEnums} storage type value if it is.
+     * corresponding {@link StorageEnums} storage type value if it is.
+     */
+    public static int getPackageExternalStorageType(VolumeInfo packageVolume,
+            boolean packageIsExternal) {
+        if (packageVolume != null) {
+            DiskInfo disk = packageVolume.getDisk();
+            if (disk != null) {
+                if (disk.isSd()) {
+                    return StorageEnums.SD_CARD;
+                }
+                if (disk.isUsb()) {
+                    return StorageEnums.USB;
+                }
+                if (packageIsExternal) {
+                    return StorageEnums.OTHER;
+                }
+            }
+        }
+        return StorageEnums.UNKNOWN;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/QueryIntentActivitiesResult.java b/services/core/java/com/android/server/pm/QueryIntentActivitiesResult.java
new file mode 100644
index 0000000..dde7536
--- /dev/null
+++ b/services/core/java/com/android/server/pm/QueryIntentActivitiesResult.java
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+import android.content.pm.ResolveInfo;
+
+import java.util.List;
+
+// Collect the results of queryIntentActivitiesInternalBody into a single class
+public final class QueryIntentActivitiesResult {
+    public boolean sortResult = false;
+    public boolean addInstant = false;
+    public List<ResolveInfo> result = null;
+    public List<ResolveInfo> answer = null;
+
+    QueryIntentActivitiesResult(List<ResolveInfo> l) {
+        answer = l;
+    }
+
+    QueryIntentActivitiesResult(boolean s, boolean a, List<ResolveInfo> l) {
+        sortResult = s;
+        addInstant = a;
+        result = l;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ScanPackageHelper.java b/services/core/java/com/android/server/pm/ScanPackageHelper.java
index 5fab84e..a76e419 100644
--- a/services/core/java/com/android/server/pm/ScanPackageHelper.java
+++ b/services/core/java/com/android/server/pm/ScanPackageHelper.java
@@ -73,6 +73,7 @@
 import android.content.pm.parsing.result.ParseResult;
 import android.content.pm.parsing.result.ParseTypeImpl;
 import android.os.Build;
+import android.os.Process;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -130,10 +131,12 @@
      */
     public boolean optimisticallyRegisterAppId(@NonNull ScanResult result)
             throws PackageManagerException {
-        if (!result.mExistingSettingCopied || result.mNeedsNewAppId) {
-            // THROWS: when we can't allocate a user id. add call to check if there's
-            // enough space to ensure we won't throw; otherwise, don't modify state
-            return mPm.mSettings.registerAppIdLPw(result.mPkgSetting, result.mNeedsNewAppId);
+        if (!result.mExistingSettingCopied || result.needsNewAppId()) {
+            synchronized (mPm.mLock) {
+                // THROWS: when we can't allocate a user id. add call to check if there's
+                // enough space to ensure we won't throw; otherwise, don't modify state
+                return mPm.mSettings.registerAppIdLPw(result.mPkgSetting, result.needsNewAppId());
+            }
         }
         return false;
     }
@@ -337,11 +340,11 @@
             }
         }
 
-        boolean leavingSharedUser = false;
+        int previousAppId = Process.INVALID_UID;
 
         if (pkgSetting != null && pkgSetting.sharedUser != sharedUserSetting) {
             if (pkgSetting.sharedUser != null && sharedUserSetting == null) {
-                leavingSharedUser = true;
+                previousAppId = pkgSetting.appId;
                 // Log that something is leaving shareduid and keep going
                 Slog.i(TAG,
                         "Package " + parsedPackage.getPackageName() + " shared user changed from "
@@ -630,7 +633,7 @@
 
         return new ScanResult(request, true, pkgSetting, changedAbiCodePath,
                 !createNewPackage /* existingSettingCopied */,
-                leavingSharedUser /* needsNewAppId */, staticSharedLibraryInfo,
+                previousAppId, staticSharedLibraryInfo,
                 dynamicSharedLibraryInfos);
     }
 
diff --git a/services/core/java/com/android/server/pm/ScanResult.java b/services/core/java/com/android/server/pm/ScanResult.java
index 34f86ba..eb44a82 100644
--- a/services/core/java/com/android/server/pm/ScanResult.java
+++ b/services/core/java/com/android/server/pm/ScanResult.java
@@ -18,6 +18,7 @@
 
 import android.annotation.Nullable;
 import android.content.pm.SharedLibraryInfo;
+import android.os.Process;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -36,10 +37,11 @@
      */
     public final boolean mExistingSettingCopied;
     /**
-     * Whether or not the original PackageSetting needs to be updated with
-     * a new uid. Useful when leaving a sharedUserID.
+     * The previous app ID if the app decided to leave a shared user ID.
+     * The value is set *only* if the app is leaving a shared user ID.
+     * Default value is Process.INVALID_UID.
      */
-    public final boolean mNeedsNewAppId;
+    public final int mPreviousAppId;
     /**
      * The final package settings. This may be the same object passed in
      * the {@link ScanRequest}, but, with modified values.
@@ -57,7 +59,7 @@
             ScanRequest request, boolean success,
             @Nullable PackageSetting pkgSetting,
             @Nullable List<String> changedAbiCodePath, boolean existingSettingCopied,
-            boolean needsNewAppId,
+            int previousAppId,
             SharedLibraryInfo staticSharedLibraryInfo,
             List<SharedLibraryInfo> dynamicSharedLibraryInfos) {
         mRequest = request;
@@ -65,8 +67,16 @@
         mPkgSetting = pkgSetting;
         mChangedAbiCodePath = changedAbiCodePath;
         mExistingSettingCopied = existingSettingCopied;
-        mNeedsNewAppId = needsNewAppId;
+        mPreviousAppId = previousAppId;
         mStaticSharedLibraryInfo = staticSharedLibraryInfo;
         mDynamicSharedLibraryInfos = dynamicSharedLibraryInfos;
     }
+
+    /**
+     * Whether the original PackageSetting needs to be updated with
+     * a new app ID. Useful when leaving a sharedUserId.
+     */
+    public boolean needsNewAppId() {
+        return mPreviousAppId != Process.INVALID_UID;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 2c649d2..f111967 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -5075,7 +5075,7 @@
         if (!ArrayUtils.isEmpty(gids)) {
             pw.print(prefix);
             pw.print("gids="); pw.println(
-                    PackageManagerService.arrayToString(gids));
+                    PackageManagerServiceUtils.arrayToString(gids));
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/ThreadComputer.java b/services/core/java/com/android/server/pm/ThreadComputer.java
new file mode 100644
index 0000000..2a42c6b
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ThreadComputer.java
@@ -0,0 +1,47 @@
+/*
+ * 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 class records the Computer being used by a thread and the Computer's reference
+ * count.  There is a thread-local copy of this class.
+ */
+public final class ThreadComputer {
+    Computer mComputer = null;
+    int mRefCount = 0;
+
+    void acquire(Computer c) {
+        if (mRefCount != 0 && mComputer != c) {
+            throw new RuntimeException("computer mismatch, count = " + mRefCount);
+        }
+        mComputer = c;
+        mRefCount++;
+    }
+
+    void acquire() {
+        if (mRefCount == 0 || mComputer == null) {
+            throw new RuntimeException("computer acquire on empty ref count");
+        }
+        mRefCount++;
+    }
+
+    void release() {
+        if (--mRefCount == 0) {
+            mComputer = null;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index d02d301..844833b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -5152,8 +5152,14 @@
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
 
-        long now = System.currentTimeMillis();
+        final long now = System.currentTimeMillis();
         final long nowRealtime = SystemClock.elapsedRealtime();
+        final StringBuilder sb = new StringBuilder();
+
+        if (args != null && args.length > 0 && args[0].equals("--user")) {
+            dumpUser(pw, UserHandle.parseUserArg(args[1]), sb, now, nowRealtime);
+            return;
+        }
 
         final ActivityManagerInternal amInternal = LocalServices
                 .getService(ActivityManagerInternal.class);
@@ -5165,7 +5171,6 @@
         }
 
         pw.println();
-        StringBuilder sb = new StringBuilder();
         synchronized (mPackagesLock) {
             synchronized (mUsersLock) {
                 pw.println("Users:");
@@ -5174,89 +5179,7 @@
                     if (userData == null) {
                         continue;
                     }
-                    UserInfo userInfo = userData.info;
-                    final int userId = userInfo.id;
-                    pw.print("  "); pw.print(userInfo);
-                    pw.print(" serialNo="); pw.print(userInfo.serialNumber);
-                    pw.print(" isPrimary="); pw.print(userInfo.isPrimary());
-                    if (userInfo.profileGroupId != userInfo.id
-                            &&  userInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) {
-                        pw.print(" parentId="); pw.print(userInfo.profileGroupId);
-                    }
-
-                    if (mRemovingUserIds.get(userId)) {
-                        pw.print(" <removing> ");
-                    }
-                    if (userInfo.partial) {
-                        pw.print(" <partial>");
-                    }
-                    if (userInfo.preCreated) {
-                        pw.print(" <pre-created>");
-                    }
-                    if (userInfo.convertedFromPreCreated) {
-                        pw.print(" <converted>");
-                    }
-                    pw.println();
-                    pw.print("    Type: "); pw.println(userInfo.userType);
-                    pw.print("    Flags: "); pw.print(userInfo.flags); pw.print(" (");
-                    pw.print(UserInfo.flagsToString(userInfo.flags)); pw.println(")");
-                    pw.print("    State: ");
-                    final int state;
-                    synchronized (mUserStates) {
-                        state = mUserStates.get(userId, -1);
-                    }
-                    pw.println(UserState.stateToString(state));
-                    pw.print("    Created: ");
-                    dumpTimeAgo(pw, sb, now, userInfo.creationTime);
-
-                    pw.print("    Last logged in: ");
-                    dumpTimeAgo(pw, sb, now, userInfo.lastLoggedInTime);
-
-                    pw.print("    Last logged in fingerprint: ");
-                    pw.println(userInfo.lastLoggedInFingerprint);
-
-                    pw.print("    Start time: ");
-                    dumpTimeAgo(pw, sb, nowRealtime, userData.startRealtime);
-
-                    pw.print("    Unlock time: ");
-                    dumpTimeAgo(pw, sb, nowRealtime, userData.unlockRealtime);
-
-                    pw.print("    Has profile owner: ");
-                    pw.println(mIsUserManaged.get(userId));
-                    pw.println("    Restrictions:");
-                    synchronized (mRestrictionsLock) {
-                        UserRestrictionsUtils.dumpRestrictions(
-                                pw, "      ", mBaseUserRestrictions.getRestrictions(userInfo.id));
-                        pw.println("    Device policy global restrictions:");
-                        UserRestrictionsUtils.dumpRestrictions(
-                                pw, "      ",
-                                mDevicePolicyGlobalUserRestrictions.getRestrictions(userInfo.id));
-                        pw.println("    Device policy local restrictions:");
-                        getDevicePolicyLocalRestrictionsForTargetUserLR(
-                                userInfo.id).dumpRestrictions(pw, "      ");
-                        pw.println("    Effective restrictions:");
-                        UserRestrictionsUtils.dumpRestrictions(
-                                pw, "      ",
-                                mCachedEffectiveUserRestrictions.getRestrictions(userInfo.id));
-                    }
-
-                    if (userData.account != null) {
-                        pw.print("    Account name: " + userData.account);
-                        pw.println();
-                    }
-
-                    if (userData.seedAccountName != null) {
-                        pw.print("    Seed account name: " + userData.seedAccountName);
-                        pw.println();
-                        if (userData.seedAccountType != null) {
-                            pw.print("         account type: " + userData.seedAccountType);
-                            pw.println();
-                        }
-                        if (userData.seedAccountOptions != null) {
-                            pw.print("         account options exist");
-                            pw.println();
-                        }
-                    }
+                    dumpUserLocked(pw, userData, sb, now, nowRealtime);
                 }
             }
 
@@ -5345,6 +5268,116 @@
         }
     }
 
+    private void dumpUser(PrintWriter pw, @UserIdInt int userId, StringBuilder sb, long now,
+            long nowRealtime) {
+        if (userId == UserHandle.USER_CURRENT) {
+            final ActivityManagerInternal amInternal = LocalServices
+                    .getService(ActivityManagerInternal.class);
+            if (amInternal == null) {
+                pw.println("Cannot determine current user");
+                return;
+            }
+            userId = amInternal.getCurrentUserId();
+        }
+
+        synchronized (mUsersLock) {
+            final UserData userData = mUsers.get(userId);
+            if (userData == null) {
+                pw.println("User " + userId + " not found");
+                return;
+            }
+            dumpUserLocked(pw, userData, sb, now, nowRealtime);
+        }
+    }
+
+    @GuardedBy("mUsersLock")
+    private void dumpUserLocked(PrintWriter pw, UserData userData, StringBuilder tempStringBuilder,
+            long now, long nowRealtime) {
+        final UserInfo userInfo = userData.info;
+        final int userId = userInfo.id;
+        pw.print("  "); pw.print(userInfo);
+        pw.print(" serialNo="); pw.print(userInfo.serialNumber);
+        pw.print(" isPrimary="); pw.print(userInfo.isPrimary());
+        if (userInfo.profileGroupId != userInfo.id
+                &&  userInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) {
+            pw.print(" parentId="); pw.print(userInfo.profileGroupId);
+        }
+
+        if (mRemovingUserIds.get(userId)) {
+            pw.print(" <removing> ");
+        }
+        if (userInfo.partial) {
+            pw.print(" <partial>");
+        }
+        if (userInfo.preCreated) {
+            pw.print(" <pre-created>");
+        }
+        if (userInfo.convertedFromPreCreated) {
+            pw.print(" <converted>");
+        }
+        pw.println();
+        pw.print("    Type: "); pw.println(userInfo.userType);
+        pw.print("    Flags: "); pw.print(userInfo.flags); pw.print(" (");
+        pw.print(UserInfo.flagsToString(userInfo.flags)); pw.println(")");
+        pw.print("    State: ");
+        final int state;
+        synchronized (mUserStates) {
+            state = mUserStates.get(userId, -1);
+        }
+        pw.println(UserState.stateToString(state));
+        pw.print("    Created: ");
+        dumpTimeAgo(pw, tempStringBuilder, now, userInfo.creationTime);
+
+        pw.print("    Last logged in: ");
+        dumpTimeAgo(pw, tempStringBuilder, now, userInfo.lastLoggedInTime);
+
+        pw.print("    Last logged in fingerprint: ");
+        pw.println(userInfo.lastLoggedInFingerprint);
+
+        pw.print("    Start time: ");
+        dumpTimeAgo(pw, tempStringBuilder, nowRealtime, userData.startRealtime);
+
+        pw.print("    Unlock time: ");
+        dumpTimeAgo(pw, tempStringBuilder, nowRealtime, userData.unlockRealtime);
+
+        pw.print("    Has profile owner: ");
+        pw.println(mIsUserManaged.get(userId));
+        pw.println("    Restrictions:");
+        synchronized (mRestrictionsLock) {
+            UserRestrictionsUtils.dumpRestrictions(
+                    pw, "      ", mBaseUserRestrictions.getRestrictions(userInfo.id));
+            pw.println("    Device policy global restrictions:");
+            UserRestrictionsUtils.dumpRestrictions(
+                    pw, "      ",
+                    mDevicePolicyGlobalUserRestrictions.getRestrictions(userInfo.id));
+            pw.println("    Device policy local restrictions:");
+            getDevicePolicyLocalRestrictionsForTargetUserLR(
+                    userInfo.id).dumpRestrictions(pw, "      ");
+            pw.println("    Effective restrictions:");
+            UserRestrictionsUtils.dumpRestrictions(
+                    pw, "      ",
+                    mCachedEffectiveUserRestrictions.getRestrictions(userInfo.id));
+        }
+
+        if (userData.account != null) {
+            pw.print("    Account name: " + userData.account);
+            pw.println();
+        }
+
+        if (userData.seedAccountName != null) {
+            pw.print("    Seed account name: " + userData.seedAccountName);
+            pw.println();
+            if (userData.seedAccountType != null) {
+                pw.print("         account type: " + userData.seedAccountType);
+                pw.println();
+            }
+            if (userData.seedAccountOptions != null) {
+                pw.print("         account options exist");
+                pw.println();
+            }
+        }
+    }
+
     private static void dumpTimeAgo(PrintWriter pw, StringBuilder sb, long nowTime, long time) {
         if (time == 0) {
             pw.println("<unknown>");
diff --git a/services/core/java/com/android/server/pm/VerificationHelper.java b/services/core/java/com/android/server/pm/VerificationHelper.java
new file mode 100644
index 0000000..b04d6de
--- /dev/null
+++ b/services/core/java/com/android/server/pm/VerificationHelper.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+import static com.android.server.pm.PackageManagerService.PACKAGE_MIME_TYPE;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+public final class VerificationHelper {
+    /**
+     * The default maximum time to wait for the verification agent to return in
+     * milliseconds.
+     */
+    private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000;
+
+    Context mContext;
+
+    public VerificationHelper(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Get the verification agent timeout.  Used for both the APK verifier and the
+     * intent filter verifier.
+     *
+     * @return verification timeout in milliseconds
+     */
+    public long getVerificationTimeout() {
+        long timeout = Settings.Global.getLong(mContext.getContentResolver(),
+                Settings.Global.PACKAGE_VERIFIER_TIMEOUT, DEFAULT_VERIFICATION_TIMEOUT);
+        // The setting can be used to increase the timeout but not decrease it, since that is
+        // equivalent to disabling the verifier.
+        return Math.max(timeout, DEFAULT_VERIFICATION_TIMEOUT);
+    }
+
+    public void broadcastPackageVerified(int verificationId, Uri packageUri,
+            int verificationCode, @Nullable String rootHashString, int dataLoaderType,
+            UserHandle user) {
+        final Intent intent = new Intent(Intent.ACTION_PACKAGE_VERIFIED);
+        intent.setDataAndType(packageUri, PACKAGE_MIME_TYPE);
+        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        intent.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
+        intent.putExtra(PackageManager.EXTRA_VERIFICATION_RESULT, verificationCode);
+        if (rootHashString != null) {
+            intent.putExtra(PackageManager.EXTRA_VERIFICATION_ROOT_HASH, rootHashString);
+        }
+        intent.putExtra(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
+
+        mContext.sendBroadcastAsUser(intent, user,
+                android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/VerificationParams.java b/services/core/java/com/android/server/pm/VerificationParams.java
index dae4038..3d2ffe1 100644
--- a/services/core/java/com/android/server/pm/VerificationParams.java
+++ b/services/core/java/com/android/server/pm/VerificationParams.java
@@ -404,7 +404,7 @@
 
             DeviceIdleInternal idleController =
                     mPm.mInjector.getLocalService(DeviceIdleInternal.class);
-            final long idleDuration = mPm.getVerificationTimeout();
+            final long idleDuration = mVerificationHelper.getVerificationTimeout();
             final BroadcastOptions options = BroadcastOptions.makeBasic();
             options.setTemporaryAppAllowlist(idleDuration,
                     TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
@@ -460,7 +460,8 @@
                                 final Message msg = mPm.mHandler
                                         .obtainMessage(CHECK_PENDING_VERIFICATION);
                                 msg.arg1 = verificationId;
-                                mPm.mHandler.sendMessageDelayed(msg, mPm.getVerificationTimeout());
+                                mPm.mHandler.sendMessageDelayed(msg,
+                                        mVerificationHelper.getVerificationTimeout());
                             }
                         }, null, 0, null, null);
 
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index e40cb40..e503f21 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -2620,8 +2620,7 @@
         // being upgraded to target a newer SDK, in which case dangerous permissions
         // are transformed from install time to runtime ones.
 
-        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
-                pkg.getPackageName());
+        final PackageSetting ps = mPackageManagerInt.getPackageSetting(pkg.getPackageName());
         if (ps == null) {
             return;
         }
@@ -3954,21 +3953,24 @@
         }
     }
 
-    @UserIdInt
-    private int revokeSharedUserPermissionsForDeletedPackageInternal(
-            @Nullable AndroidPackage pkg, @NonNull List<AndroidPackage> sharedUserPkgs,
+    private void revokeSharedUserPermissionsForLeavingPackageInternal(
+            @Nullable AndroidPackage pkg, int appId, @NonNull List<AndroidPackage> sharedUserPkgs,
             @UserIdInt int userId) {
         if (pkg == null) {
             Slog.i(TAG, "Trying to update info for null package. Just ignoring");
-            return UserHandle.USER_NULL;
+            return;
         }
 
         // No shared user packages
         if (sharedUserPkgs.isEmpty()) {
-            return UserHandle.USER_NULL;
+            return;
         }
 
-        int affectedUserId = UserHandle.USER_NULL;
+        PackageSetting disabledPs = mPackageManagerInt.getDisabledSystemPackage(
+                pkg.getPackageName());
+        boolean isShadowingSystemPkg = disabledPs != null && disabledPs.appId == pkg.getUid();
+
+        boolean shouldKillUid = false;
         // Update permissions
         for (String eachPerm : pkg.getRequestedPermissions()) {
             // Check if another package in the shared user needs the permission.
@@ -3985,26 +3987,15 @@
                 continue;
             }
 
-            PackageSetting disabledPs = mPackageManagerInt.getDisabledSystemPackage(
-                    pkg.getPackageName());
-
-            // If the package is shadowing is a disabled system package,
+            // If the package is shadowing a disabled system package,
             // do not drop permissions that the shadowed package requests.
-            if (disabledPs != null) {
-                boolean reqByDisabledSysPkg = false;
-                for (String permission : disabledPs.pkg.getRequestedPermissions()) {
-                    if (permission.equals(eachPerm)) {
-                        reqByDisabledSysPkg = true;
-                        break;
-                    }
-                }
-                if (reqByDisabledSysPkg) {
-                    continue;
-                }
+            if (isShadowingSystemPkg
+                    && disabledPs.getPkg().getRequestedPermissions().contains(eachPerm)) {
+                continue;
             }
 
             synchronized (mLock) {
-                UidPermissionState uidState = getUidStateLocked(pkg, userId);
+                UidPermissionState uidState = getUidStateLocked(appId, userId);
                 if (uidState == null) {
                     Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()
                             + " and user " + userId);
@@ -4019,12 +4010,18 @@
                 // TODO(zhanghai): Why are we only killing the UID when GIDs changed, instead of any
                 //  permission change?
                 if (uidState.removePermissionState(bp.getName()) && bp.hasGids()) {
-                    affectedUserId = userId;
+                    shouldKillUid = true;
                 }
             }
         }
 
-        return affectedUserId;
+        // If gids changed, kill all affected packages.
+        if (shouldKillUid) {
+            mHandler.post(() -> {
+                // This has to happen with no lock held.
+                killUid(appId, UserHandle.USER_ALL, KILL_APP_REASON_GIDS_CHANGED);
+            });
+        }
     }
 
     @GuardedBy("mLock")
@@ -4892,9 +4889,48 @@
         return true;
     }
 
-    private void onPackageInstalledInternal(@NonNull AndroidPackage pkg,
+    private void onPackageInstalledInternal(@NonNull AndroidPackage pkg, int previousAppId,
             @NonNull PermissionManagerServiceInternal.PackageInstalledParams params,
             @UserIdInt int[] userIds) {
+        // If previousAppId is not Process.INVALID_UID, the package is performing a migration out
+        // of a shared user group. Operations we need to do before calling updatePermissions():
+        // - Retrieve the original uid permission state and create a copy of it as the new app's
+        //   uid state. The new permission state will be properly updated in updatePermissions().
+        // - Remove the app from the original shared user group. Other apps in the shared
+        //   user group will perceive as if the original app is uninstalled.
+        if (previousAppId != Process.INVALID_UID) {
+            final PackageSetting ps = mPackageManagerInt.getPackageSetting(pkg.getPackageName());
+            final List<AndroidPackage> origSharedUserPackages =
+                    mPackageManagerInt.getPackagesForAppId(previousAppId);
+
+            synchronized (mLock) {
+                // All users are affected
+                for (final int userId : getAllUserIds()) {
+                    // Retrieve the original uid state
+                    final UserPermissionState userState = mState.getUserState(userId);
+                    if (userState == null) {
+                        continue;
+                    }
+                    final UidPermissionState prevUidState = userState.getUidState(previousAppId);
+                    if (prevUidState == null) {
+                        continue;
+                    }
+
+                    // Insert new uid state by cloning the original one
+                    userState.createUidStateWithExisting(ps.getAppId(), prevUidState);
+
+                    // Remove original app ID from original shared user group
+                    // Should match the implementation of onPackageUninstalledInternal(...)
+                    if (origSharedUserPackages.isEmpty()) {
+                        removeUidStateAndResetPackageInstallPermissionsFixed(
+                                previousAppId, pkg.getPackageName(), userId);
+                    } else {
+                        revokeSharedUserPermissionsForLeavingPackageInternal(pkg, previousAppId,
+                                origSharedUserPackages, userId);
+                    }
+                }
+            }
+        }
         updatePermissions(pkg.getPackageName(), pkg);
         for (final int userId : userIds) {
             addAllowlistedRestrictedPermissionsInternal(pkg,
@@ -4931,6 +4967,9 @@
     private void onPackageUninstalledInternal(@NonNull String packageName, int appId,
             @Nullable AndroidPackage pkg, @NonNull List<AndroidPackage> sharedUserPkgs,
             @UserIdInt int[] userIds) {
+        // TODO: Handle the case when a system app upgrade is uninstalled and need to rejoin
+        //  a shared UID permission state.
+
         // TODO: Move these checks to check PackageState to be more reliable.
         // System packages should always have an available APK.
         if (pkg != null && pkg.isSystem()
@@ -4956,16 +4995,8 @@
                 // or packages running under the shared user of the removed
                 // package if revoking the permissions requested only by the removed
                 // package is successful and this causes a change in gids.
-                final int userIdToKill = revokeSharedUserPermissionsForDeletedPackageInternal(pkg,
+                revokeSharedUserPermissionsForLeavingPackageInternal(pkg, appId,
                         sharedUserPkgs, userId);
-                final boolean shouldKill = userIdToKill != UserHandle.USER_NULL;
-                // If gids changed, kill all affected packages.
-                if (shouldKill) {
-                    mHandler.post(() -> {
-                        // This has to happen with no lock held.
-                        killUid(appId, UserHandle.USER_ALL, KILL_APP_REASON_GIDS_CHANGED);
-                    });
-                }
             }
         }
     }
@@ -5236,7 +5267,7 @@
         }
 
         @Override
-        public void onPackageInstalled(@NonNull AndroidPackage pkg,
+        public void onPackageInstalled(@NonNull AndroidPackage pkg, int previousAppId,
                 @NonNull PackageInstalledParams params, @UserIdInt int userId) {
             Objects.requireNonNull(pkg, "pkg");
             Objects.requireNonNull(params, "params");
@@ -5244,7 +5275,7 @@
                     || userId == UserHandle.USER_ALL, "userId");
             final int[] userIds = userId == UserHandle.USER_ALL ? getAllUserIds()
                     : new int[] { userId };
-            onPackageInstalledInternal(pkg, params, userIds);
+            onPackageInstalledInternal(pkg, previousAppId, params, userIds);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index f4fb810..d2c4ec4 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -252,11 +252,14 @@
      * Callback when a package has been installed for a user.
      *
      * @param pkg the installed package
+     * @param previousAppId the previous app ID if the package is leaving a shared UID,
+     *                      or Process.INVALID_UID
      * @param params the parameters passed in for package installation
      * @param userId the user ID this package is installed for
      */
     //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-    void onPackageInstalled(@NonNull AndroidPackage pkg, @NonNull PackageInstalledParams params,
+    void onPackageInstalled(@NonNull AndroidPackage pkg, int previousAppId,
+            @NonNull PackageInstalledParams params,
             @UserIdInt int userId);
 
     /**
diff --git a/services/core/java/com/android/server/pm/permission/UserPermissionState.java b/services/core/java/com/android/server/pm/permission/UserPermissionState.java
index 2c741cf..f39086b3 100644
--- a/services/core/java/com/android/server/pm/permission/UserPermissionState.java
+++ b/services/core/java/com/android/server/pm/permission/UserPermissionState.java
@@ -69,6 +69,15 @@
         return uidState;
     }
 
+    @NonNull
+    UidPermissionState createUidStateWithExisting(
+            @AppIdInt int appId, @NonNull UidPermissionState other) {
+        checkAppId(appId);
+        UidPermissionState uidState = new UidPermissionState(other);
+        mUidStates.put(appId, uidState);
+        return uidState;
+    }
+
     public void removeUidState(@AppIdInt int appId) {
         checkAppId(appId);
         mUidStates.delete(appId);
diff --git a/services/core/java/com/android/server/policy/GlobalKeyManager.java b/services/core/java/com/android/server/policy/GlobalKeyManager.java
index 2d48452..b9bd9f1 100644
--- a/services/core/java/com/android/server/policy/GlobalKeyManager.java
+++ b/services/core/java/com/android/server/policy/GlobalKeyManager.java
@@ -56,11 +56,10 @@
 
     private static final int GLOBAL_KEY_FILE_VERSION = 1;
 
-    private SparseArray<GlobalKeyAction> mKeyMapping;
+    private final SparseArray<GlobalKeyAction> mKeyMapping = new SparseArray<>();
     private boolean mBeganFromNonInteractive = false;
 
     public GlobalKeyManager(Context context) {
-        mKeyMapping = new SparseArray<>();
         loadGlobalKeys(context);
     }
 
@@ -69,7 +68,7 @@
      *
      * @param context context used to broadcast the event
      * @param keyCode keyCode which triggered this function
-     * @param event keyEvent which trigged this function
+     * @param event keyEvent which triggered this function
      * @return {@code true} if this was handled
      */
     boolean handleGlobalKey(Context context, int keyCode, KeyEvent event) {
@@ -113,18 +112,17 @@
     }
 
     class GlobalKeyAction {
-        private ComponentName mComponentName;
-        private boolean mDispatchWhenNonInteractive;
+        private final ComponentName mComponentName;
+        private final boolean mDispatchWhenNonInteractive;
         GlobalKeyAction(String componentName, String dispatchWhenNonInteractive) {
             mComponentName = ComponentName.unflattenFromString(componentName);
-            mDispatchWhenNonInteractive = Boolean.valueOf(dispatchWhenNonInteractive);
+            mDispatchWhenNonInteractive = Boolean.parseBoolean(dispatchWhenNonInteractive);
         }
     }
 
     private void loadGlobalKeys(Context context) {
-        XmlResourceParser parser = null;
-        try {
-            parser = context.getResources().getXml(com.android.internal.R.xml.global_keys);
+        try (XmlResourceParser parser = context.getResources().getXml(
+                com.android.internal.R.xml.global_keys)) {
             XmlUtils.beginDocument(parser, TAG_GLOBAL_KEYS);
             int version = parser.getAttributeIntValue(null, ATTR_VERSION, 0);
             if (GLOBAL_KEY_FILE_VERSION == version) {
@@ -153,10 +151,6 @@
             Log.w(TAG, "XML parser exception reading global keys file", e);
         } catch (IOException e) {
             Log.w(TAG, "I/O exception reading global keys file", e);
-        } finally {
-            if (parser != null) {
-                parser.close();
-            }
         }
     }
 
diff --git a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
index 6fee69b..1d4943f 100644
--- a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
+++ b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
@@ -54,6 +54,7 @@
     private int mDownKeyCode = KeyEvent.KEYCODE_UNKNOWN;
     private volatile boolean mHandledByLongPress = false;
     private final Handler mHandler;
+    private long mLastDownTime = 0;
     private static final long MULTI_PRESS_TIMEOUT = ViewConfiguration.getMultiPressTimeout();
 
     /** Supported gesture flags */
@@ -83,7 +84,6 @@
      *  </pre>
      */
     abstract static class SingleKeyRule {
-
         private final int mKeyCode;
         private final int mSupportedGestures;
         private final long mDefaultLongPressTimeout;
@@ -205,7 +205,10 @@
                 mHandledByLongPress = true;
                 mHandler.removeMessages(MSG_KEY_LONG_PRESS);
                 mHandler.removeMessages(MSG_KEY_VERY_LONG_PRESS);
-                mActiveRule.onLongPress(event.getEventTime());
+                final Message msg = mHandler.obtainMessage(MSG_KEY_LONG_PRESS, mActiveRule.mKeyCode,
+                        0, mActiveRule);
+                msg.setAsynchronous(true);
+                mHandler.sendMessage(msg);
             }
             return;
         }
@@ -219,6 +222,7 @@
             reset();
         }
         mDownKeyCode = keyCode;
+        mLastDownTime = event.getDownTime();
 
         // Picks a new rule, return if no rule picked.
         if (mActiveRule == null) {
@@ -238,18 +242,17 @@
             return;
         }
 
-        final long eventTime = event.getEventTime();
         if (mKeyPressCounter == 0) {
             if (mActiveRule.supportLongPress()) {
                 final Message msg = mHandler.obtainMessage(MSG_KEY_LONG_PRESS, keyCode, 0,
-                        eventTime);
+                        mActiveRule);
                 msg.setAsynchronous(true);
                 mHandler.sendMessageDelayed(msg, mActiveRule.getLongPressTimeoutMs());
             }
 
             if (mActiveRule.supportVeryLongPress()) {
                 final Message msg = mHandler.obtainMessage(MSG_KEY_VERY_LONG_PRESS, keyCode, 0,
-                        eventTime);
+                        mActiveRule);
                 msg.setAsynchronous(true);
                 mHandler.sendMessageDelayed(msg, mActiveRule.getVeryLongPressTimeoutMs());
             }
@@ -262,9 +265,12 @@
             if (mKeyPressCounter == mActiveRule.getMaxMultiPressCount() - 1) {
                 if (DEBUG) {
                     Log.i(TAG, "Trigger multi press " + mActiveRule.toString() + " for it"
-                            + " reach the max count " + mKeyPressCounter);
+                            + " reached the max count " + (mKeyPressCounter + 1));
                 }
-                mActiveRule.onMultiPress(eventTime, mKeyPressCounter + 1);
+                final Message msg = mHandler.obtainMessage(MSG_KEY_DELAYED_PRESS, keyCode,
+                        mKeyPressCounter + 1, mActiveRule);
+                msg.setAsynchronous(true);
+                mHandler.sendMessage(msg);
                 mKeyPressCounter = 0;
             }
         }
@@ -284,7 +290,6 @@
             return true;
         }
 
-        final long downTime = event.getDownTime();
         if (event.getKeyCode() == mActiveRule.mKeyCode) {
             // Directly trigger short press when max count is 1.
             if (mActiveRule.getMaxMultiPressCount() == 1) {
@@ -292,16 +297,17 @@
                     Log.i(TAG, "press key " + KeyEvent.keyCodeToString(event.getKeyCode()));
                 }
                 Message msg = mHandler.obtainMessage(MSG_KEY_DELAYED_PRESS, mActiveRule.mKeyCode,
-                        1, downTime);
+                        1, mActiveRule);
                 msg.setAsynchronous(true);
                 mHandler.sendMessage(msg);
+                reset();
                 return true;
             }
 
             // This could be a multi-press.  Wait a little bit longer to confirm.
             mKeyPressCounter++;
             Message msg = mHandler.obtainMessage(MSG_KEY_DELAYED_PRESS, mActiveRule.mKeyCode,
-                    mKeyPressCounter, downTime);
+                    mKeyPressCounter, mActiveRule);
             msg.setAsynchronous(true);
             mHandler.sendMessageDelayed(msg, MULTI_PRESS_TIMEOUT);
             return true;
@@ -358,18 +364,24 @@
 
         @Override
         public void handleMessage(Message msg) {
-            if (mActiveRule == null) {
+            final SingleKeyRule rule = (SingleKeyRule) msg.obj;
+            if (rule == null) {
+                Log.wtf(TAG, "No active rule.");
                 return;
             }
+            // We count the press count when interceptKeyUp. Reset the counter here to prevent if
+            // the multi-press or press happened but the count is less than max multi-press count.
+            mKeyPressCounter = 0;
+
             final int keyCode = msg.arg1;
-            final long eventTime = (long) msg.obj;
+            final int pressCount = msg.arg2;
             switch(msg.what) {
                 case MSG_KEY_LONG_PRESS:
                     if (DEBUG) {
                         Log.i(TAG, "Detect long press " + KeyEvent.keyCodeToString(keyCode));
                     }
                     mHandledByLongPress = true;
-                    mActiveRule.onLongPress(eventTime);
+                    rule.onLongPress(mLastDownTime);
                     break;
                 case MSG_KEY_VERY_LONG_PRESS:
                     if (DEBUG) {
@@ -377,19 +389,18 @@
                                 + KeyEvent.keyCodeToString(keyCode));
                     }
                     mHandledByLongPress = true;
-                    mActiveRule.onVeryLongPress(eventTime);
+                    rule.onVeryLongPress(mLastDownTime);
                     break;
                 case MSG_KEY_DELAYED_PRESS:
                     if (DEBUG) {
                         Log.i(TAG, "Detect press " + KeyEvent.keyCodeToString(keyCode)
-                                + ", count " + mKeyPressCounter);
+                                + ", count " + pressCount);
                     }
-                    if (mKeyPressCounter == 1) {
-                        mActiveRule.onPress(eventTime);
+                    if (pressCount == 1) {
+                        rule.onPress(mLastDownTime);
                     } else {
-                        mActiveRule.onMultiPress(eventTime, mKeyPressCounter);
+                        rule.onMultiPress(mLastDownTime, pressCount);
                     }
-                    reset();
                     break;
             }
         }
diff --git a/services/core/java/com/android/server/statusbar/TEST_MAPPING b/services/core/java/com/android/server/statusbar/TEST_MAPPING
new file mode 100644
index 0000000..67ea557
--- /dev/null
+++ b/services/core/java/com/android/server/statusbar/TEST_MAPPING
@@ -0,0 +1,29 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsTileServiceTestCases",
+      "options": [
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "CtsAppTestCases",
+      "options": [
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "include-filter": "android.app.cts.RequestTileServiceAddTest"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
index 4f3101d..b2b5844 100644
--- a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
+++ b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
@@ -38,6 +38,7 @@
 import android.os.IBinder;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
+import android.os.StatFs;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.text.format.DateUtils;
@@ -280,7 +281,8 @@
         try {
             fileStream = mPreviousValuesFile.startWrite();
             TypedXmlSerializer out = Xml.resolveSerializer(fileStream);
-            saveToXml(out, processedRequests, 0);
+            final StatFs stats = new StatFs(Environment.getDataDirectory().getAbsolutePath());
+            saveToXml(out, processedRequests, stats.getAvailableBytes());
             mPreviousValuesFile.finishWrite(fileStream);
         } catch (Exception e) {
             Slog.e(TAG, "An error occurred while writing the cache quota file.", e);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index c45b661..195da18 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1411,7 +1411,9 @@
         this.task = newTask;
 
         if (shouldStartChangeTransition(newParent, oldParent)) {
-            initializeChangeTransition(getBounds());
+            // The new parent and old parent may be in different position. Need to offset the
+            // animation surface to keep it in its original position.
+            initializeChangeTransition(getBounds(), newParent.getBounds());
         }
 
         super.onParentChanged(newParent, oldParent);
@@ -3790,8 +3792,6 @@
 
         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Removing app token: %s", this);
 
-        commitVisibility(false /* visible */, true /* performLayout */);
-
         getDisplayContent().mOpeningApps.remove(this);
         getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this);
         mWmService.mTaskSnapshotController.onAppRemoved(this);
@@ -3799,8 +3799,6 @@
         mTaskSupervisor.mStoppingActivities.remove(this);
         waitingToShow = false;
 
-        // TODO(b/169035022): move to a more-appropriate place.
-        mAtmService.getTransitionController().collect(this);
         // Defer removal of this activity when either a child is animating, or app transition is on
         // going. App transition animation might be applied on the parent task not on the activity,
         // but the actual frame buffer is associated with the activity, so we have to keep the
@@ -3816,6 +3814,16 @@
             delayed = true;
         }
 
+        // Don't commit visibility if it is waiting to animate. It will be set post animation.
+        if (!delayed) {
+            commitVisibility(false /* visible */, true /* performLayout */);
+        } else {
+            setVisibleRequested(false /* visible */);
+        }
+
+        // TODO(b/169035022): move to a more-appropriate place.
+        mAtmService.getTransitionController().collect(this);
+
         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
                 "Removing app %s delayed=%b animation=%s animating=%b", this, delayed,
                 getAnimation(),
@@ -4972,7 +4980,7 @@
     private void postApplyAnimation(boolean visible) {
         final boolean usingShellTransitions =
                 mAtmService.getTransitionController().getTransitionPlayer() != null;
-        final boolean delayed = isAnimating(PARENTS | CHILDREN,
+        final boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN,
                 ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION
                         | ANIMATION_TYPE_RECENTS);
         if (!delayed && !usingShellTransitions) {
@@ -5943,6 +5951,9 @@
     }
 
     void startFreezingScreen(int overrideOriginalDisplayRotation) {
+        if (mAtmService.getTransitionController().isShellTransitionsEnabled()) {
+            return;
+        }
         ProtoLog.i(WM_DEBUG_ORIENTATION,
                 "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s",
                 appToken, isVisible(), mFreezingScreen, mVisibleRequested,
@@ -6909,7 +6920,7 @@
 
     @Override
     void prepareSurfaces() {
-        final boolean show = isVisible() || isAnimating(PARENTS,
+        final boolean show = isVisible() || isAnimating(TRANSITION | PARENTS,
                 ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS);
 
         if (mSurfaceControl != null) {
@@ -8443,9 +8454,7 @@
         if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) {
             // Aha, the activity isn't handling the change, so DIE DIE DIE.
             configChangeFlags |= changes;
-            if (!mAtmService.getTransitionController().isShellTransitionsEnabled()) {
-                startFreezingScreenLocked(globalChanges);
-            }
+            startFreezingScreenLocked(globalChanges);
             forceNewConfig = false;
             // Do not preserve window if it is freezing screen because the original window won't be
             // able to update drawn state that causes freeze timeout.
@@ -9269,7 +9278,7 @@
                 record.getMode(), record.mAdapter.mCapturedLeash, !fillsParent(),
                 new Rect(), insets,
                 getPrefixOrderIndex(), record.mAdapter.mPosition, record.mAdapter.mLocalBounds,
-                record.mAdapter.mRootTaskBounds, task.getWindowConfiguration(),
+                record.mAdapter.mEndBounds, task.getWindowConfiguration(),
                 false /*isNotInRecents*/,
                 record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null,
                 record.mStartBounds, task.getTaskInfo(), checkEnterPictureInPictureAppOpsState());
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 71ac730..a50746d 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.Manifest.permission.ACTIVITY_EMBEDDING;
 import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
 import static android.app.Activity.RESULT_CANCELED;
 import static android.app.ActivityManager.START_ABORTED;
@@ -89,6 +88,9 @@
 import android.app.PendingIntent;
 import android.app.ProfilerInfo;
 import android.app.WaitResult;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
 import android.content.ComponentName;
 import android.content.IIntentSender;
 import android.content.Intent;
@@ -102,6 +104,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Process;
@@ -147,6 +150,13 @@
     private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
     private static final int INVALID_LAUNCH_MODE = -1;
 
+    /**
+     * Feature flag to protect PendingIntent being abused to start background activity.
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+    static final long ENABLE_PENDING_INTENT_BAL_OPTION = 192341120L;
+
     private final ActivityTaskManagerService mService;
     private final RootWindowContainer mRootWindowContainer;
     private final ActivityTaskSupervisor mSupervisor;
@@ -988,6 +998,10 @@
         abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,
                 callingPackage);
 
+        // Merge the two options bundles, while realCallerOptions takes precedence.
+        ActivityOptions checkedOptions = options != null
+                ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
+
         boolean restrictedBgActivity = false;
         if (!abort) {
             try {
@@ -996,15 +1010,12 @@
                 restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
                         callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
                         request.originatingPendingIntent, request.allowBackgroundActivityStart,
-                        intent);
+                        intent, checkedOptions);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
             }
         }
 
-        // Merge the two options bundles, while realCallerOptions takes precedence.
-        ActivityOptions checkedOptions = options != null
-                ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
         if (request.allowPendingRemoteAnimationRegistryLookup) {
             checkedOptions = mService.getActivityStartController()
                     .getPendingRemoteAnimationRegistry()
@@ -1246,7 +1257,7 @@
     boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
             final String callingPackage, int realCallingUid, int realCallingPid,
             WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent,
-            boolean allowBackgroundActivityStart, Intent intent) {
+            boolean allowBackgroundActivityStart, Intent intent, ActivityOptions checkedOptions) {
         // don't abort for the most important UIDs
         final int callingAppId = UserHandle.getAppId(callingUid);
         if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID
@@ -1315,7 +1326,29 @@
                 ? isCallingUidPersistentSystemProcess
                 : (realCallingAppId == Process.SYSTEM_UID)
                         || realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
-        if (realCallingUid != callingUid) {
+
+        // If caller a legacy app, we won't check if caller has BAL permission.
+        final boolean isPiBalOptionEnabled = CompatChanges.isChangeEnabled(
+                ENABLE_PENDING_INTENT_BAL_OPTION, callingUid);
+
+        // Legacy behavior allows to use caller foreground state to bypass BAL restriction.
+        final boolean balAllowedByPiSender =
+                PendingIntentRecord.isPendingIntentBalAllowedByCaller(checkedOptions);
+
+        if (balAllowedByPiSender && realCallingUid != callingUid) {
+            if (isPiBalOptionEnabled) {
+                if (ActivityManager.checkComponentPermission(
+                        android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
+                        realCallingUid, -1, true)
+                        == PackageManager.PERMISSION_GRANTED) {
+                    if (DEBUG_ACTIVITY_STARTS) {
+                        Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid
+                                + ") has BAL permission.");
+                    }
+                    return false;
+                }
+            }
+
             // don't abort if the realCallingUid has a visible window
             // TODO(b/171459802): We should check appSwitchAllowed also
             if (realCallingUidHasAnyVisibleWindow) {
@@ -1390,9 +1423,9 @@
         // If we don't have callerApp at this point, no caller was provided to startActivity().
         // That's the case for PendingIntent-based starts, since the creator's process might not be
         // up and alive. If that's the case, we retrieve the WindowProcessController for the send()
-        // caller, so that we can make the decision based on its state.
+        // caller if caller allows, so that we can make the decision based on its state.
         int callerAppUid = callingUid;
-        if (callerApp == null) {
+        if (callerApp == null && balAllowedByPiSender) {
             callerApp = mService.getProcessController(realCallingPid, realCallingUid);
             callerAppUid = realCallingUid;
         }
@@ -1953,38 +1986,43 @@
             }
         }
 
-        if (mInTaskFragment != null && mInTaskFragment.getTask() != null) {
-            final int hostUid = mInTaskFragment.getTask().effectiveUid;
-            final int embeddingUid = targetTask != null ? targetTask.effectiveUid : r.getUid();
-            if (!canTaskBeEmbedded(hostUid, embeddingUid)) {
-                Slog.e(TAG, "Cannot embed activity to a task owned by " + hostUid + " targetTask= "
-                        + targetTask);
-                return START_PERMISSION_DENIED;
-            }
+        if (mInTaskFragment != null && !canEmbedActivity(mInTaskFragment, r, newTask, targetTask)) {
+            Slog.e(TAG, "Permission denied: Cannot embed " + r + " to " + mInTaskFragment.getTask()
+                    + " targetTask= " + targetTask);
+            return START_PERMISSION_DENIED;
         }
 
         return START_SUCCESS;
     }
 
     /**
-     * Return {@code true} if the {@param task} can embed another task.
-     * @param hostUid the uid of the host task
-     * @param embeddedUid the uid of the task the are going to be embedded
+     * Return {@code true} if an activity can be embedded to the TaskFragment.
+     * @param taskFragment the TaskFragment for embedding.
+     * @param starting the starting activity.
+     * @param newTask whether the starting activity is going to be launched on a new task.
+     * @param targetTask the target task for launching activity, which could be different from
+     *                   the one who hosting the embedding.
      */
-    private boolean canTaskBeEmbedded(int hostUid, int embeddedUid) {
+    private boolean canEmbedActivity(@NonNull TaskFragment taskFragment, ActivityRecord starting,
+            boolean newTask, Task targetTask) {
+        final Task hostTask = taskFragment.getTask();
+        if (hostTask == null) {
+            return false;
+        }
+
         // Allowing the embedding if the task is owned by system.
+        final int hostUid = hostTask.effectiveUid;
         if (hostUid == Process.SYSTEM_UID) {
             return true;
         }
 
-        // Allowing embedding if the host task is owned by an app that has the ACTIVITY_EMBEDDING
-        // permission
-        if (mService.checkPermission(ACTIVITY_EMBEDDING, -1, hostUid) == PERMISSION_GRANTED) {
-            return true;
+        // Not allowed embedding an activity of another app.
+        if (hostUid != starting.getUid()) {
+            return false;
         }
 
-        // Allowing embedding if it is from the same app that owned the task
-        return hostUid == embeddedUid;
+        // Not allowed embedding task.
+        return !newTask && (targetTask == null || targetTask == hostTask);
     }
 
     /**
@@ -2801,10 +2839,15 @@
                 newParent = mInTaskFragment;
             }
         } else {
-            // Use the child TaskFragment (if any) as the new parent if the activity can be embedded
             final ActivityRecord top = task.topRunningActivity(false /* focusableOnly */,
                     false /* includingEmbeddedTask */);
-            newParent = top != null ? top.getTaskFragment() : task;
+            final TaskFragment taskFragment = top != null ? top.getTaskFragment() : null;
+            if (taskFragment != null && taskFragment.isEmbedded()
+                    && canEmbedActivity(taskFragment, mStartActivity, false /* newTask */, task)) {
+                // Use the embedded TaskFragment of the top activity as the new parent if the
+                // activity can be embedded.
+                newParent = top.getTaskFragment();
+            }
         }
 
         if (mStartActivity.getTaskFragment() == null
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 84b10d0..6f61221 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1731,10 +1731,8 @@
         final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(bOptions);
         final long origId = Binder.clearCallingIdentity();
         try {
-            synchronized (mGlobalLock) {
-                return mTaskSupervisor.startActivityFromRecents(callingPid, callingUid, taskId,
-                        safeOptions);
-            }
+            return mTaskSupervisor.startActivityFromRecents(callingPid, callingUid, taskId,
+                    safeOptions);
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
@@ -2077,7 +2075,7 @@
         final ActivityStarter starter = getActivityStartController().obtainStarter(
                 null /* intent */, "moveTaskToFront");
         if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, -1,
-                -1, callerApp, null, false, null)) {
+                -1, callerApp, null, false, null, null)) {
             if (!isBackgroundActivityStartsEnabled()) {
                 return;
             }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index e6aa4fc..145bdfd 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -1940,6 +1940,7 @@
     void removeHistoryRecords(WindowProcessController app) {
         removeHistoryRecords(mStoppingActivities, app, "mStoppingActivities");
         removeHistoryRecords(mFinishingActivities, app, "mFinishingActivities");
+        removeHistoryRecords(mNoHistoryActivities, app, "mNoHistoryActivities");
     }
 
     private void removeHistoryRecords(ArrayList<ActivityRecord> list, WindowProcessController app,
@@ -1977,6 +1978,7 @@
                 mWaitingActivityLaunched.get(i).dump(pw, prefix + "  ");
             }
         }
+        pw.println(prefix + "mNoHistoryActivities=" + mNoHistoryActivities);
         pw.println();
     }
 
@@ -2472,102 +2474,126 @@
         }
     }
 
+    /**
+     * Start the given task from the recent tasks. Do not hold WM global lock when calling this
+     * method to avoid potential deadlock or permission deny by UriGrantsManager when resolving
+     * activity (see {@link ActivityStarter.Request#resolveActivity} and
+     * {@link com.android.server.am.ContentProviderHelper#checkContentProviderUriPermission}).
+     *
+     * @return The result code of starter.
+     */
     int startActivityFromRecents(int callingPid, int callingUid, int taskId,
             SafeActivityOptions options) {
-        Task task = null;
+        final Task task;
+        final int taskCallingUid;
         final String callingPackage;
         final String callingFeatureId;
         final Intent intent;
         final int userId;
-        int activityType = ACTIVITY_TYPE_UNDEFINED;
-        int windowingMode = WINDOWING_MODE_UNDEFINED;
         final ActivityOptions activityOptions = options != null
                 ? options.getOptions(this)
                 : null;
         boolean moveHomeTaskForward = true;
-        if (activityOptions != null) {
-            activityType = activityOptions.getLaunchActivityType();
-            windowingMode = activityOptions.getLaunchWindowingMode();
-            if (activityOptions.freezeRecentTasksReordering()
-                    && mRecentTasks.isCallerRecents(callingUid)) {
-                mRecentTasks.setFreezeTaskListReordering();
+        synchronized (mService.mGlobalLock) {
+            int activityType = ACTIVITY_TYPE_UNDEFINED;
+            if (activityOptions != null) {
+                activityType = activityOptions.getLaunchActivityType();
+                final int windowingMode = activityOptions.getLaunchWindowingMode();
+                if (activityOptions.freezeRecentTasksReordering()
+                        && mRecentTasks.isCallerRecents(callingUid)) {
+                    mRecentTasks.setFreezeTaskListReordering();
+                }
+                if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+                        || activityOptions.getLaunchRootTask() != null) {
+                    // Don't move home activity forward if we are launching into primary split or
+                    // there is a launch root set.
+                    moveHomeTaskForward = false;
+                }
             }
-            if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
-                    || activityOptions.getLaunchRootTask() != null) {
-                // Don't move home activity forward if we are launching into primary split or there
-                // is a launch root set.
-                moveHomeTaskForward = false;
-            }
-        }
-        if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
-            throw new IllegalArgumentException("startActivityFromRecents: Task "
-                    + taskId + " can't be launch in the home/recents root task.");
-        }
-
-        mService.deferWindowLayout();
-        try {
-            task = mRootWindowContainer.anyTaskForId(taskId,
-                    MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP);
-            if (task == null) {
-                mWindowManager.executeAppTransition();
-                throw new IllegalArgumentException(
-                        "startActivityFromRecents: Task " + taskId + " not found.");
+            if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
+                throw new IllegalArgumentException("startActivityFromRecents: Task "
+                        + taskId + " can't be launch in the home/recents root task.");
             }
 
-            if (moveHomeTaskForward) {
-                // We always want to return to the home activity instead of the recents activity
-                // from whatever is started from the recents activity, so move the home root task
-                // forward.
-                // TODO (b/115289124): Multi-display supports for recents.
-                mRootWindowContainer.getDefaultTaskDisplayArea().moveHomeRootTaskToFront(
-                        "startActivityFromRecents");
-            }
-
-            // If the user must confirm credentials (e.g. when first launching a work app and the
-            // Work Challenge is present) let startActivityInPackage handle the intercepting.
-            if (!mService.mAmInternal.shouldConfirmCredentials(task.mUserId)
-                    && task.getRootActivity() != null) {
-                final ActivityRecord targetActivity = task.getTopNonFinishingActivity();
-
-                mRootWindowContainer.startPowerModeLaunchIfNeeded(
-                        true /* forceSend */, targetActivity);
-                final LaunchingState launchingState =
-                        mActivityMetricsLogger.notifyActivityLaunching(task.intent);
-                try {
-                    mService.moveTaskToFrontLocked(null /* appThread */, null /* callingPackage */,
-                            task.mTaskId, 0, options);
-                    // Apply options to prevent pendingOptions be taken when scheduling activity
-                    // lifecycle transaction to make sure the override pending app transition will
-                    // be applied immediately.
-                    targetActivity.applyOptionsAnimation();
-                } finally {
-                    mActivityMetricsLogger.notifyActivityLaunched(launchingState,
-                            START_TASK_TO_FRONT, false /* newActivityCreated */, targetActivity,
-                            activityOptions);
+            boolean shouldStartActivity = false;
+            mService.deferWindowLayout();
+            try {
+                task = mRootWindowContainer.anyTaskForId(taskId,
+                        MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP);
+                if (task == null) {
+                    mWindowManager.executeAppTransition();
+                    throw new IllegalArgumentException(
+                            "startActivityFromRecents: Task " + taskId + " not found.");
                 }
 
-                mService.getActivityStartController().postStartActivityProcessingForLastStarter(
-                        task.getTopNonFinishingActivity(), ActivityManager.START_TASK_TO_FRONT,
-                        task.getRootTask());
+                if (moveHomeTaskForward) {
+                    // We always want to return to the home activity instead of the recents
+                    // activity from whatever is started from the recents activity, so move
+                    // the home root task forward.
+                    // TODO (b/115289124): Multi-display supports for recents.
+                    mRootWindowContainer.getDefaultTaskDisplayArea().moveHomeRootTaskToFront(
+                            "startActivityFromRecents");
+                }
 
-                // As it doesn't go to ActivityStarter.executeRequest() path, we need to resume
-                // app switching here also.
-                mService.resumeAppSwitches();
+                // If the user must confirm credentials (e.g. when first launching a work
+                // app and the Work Challenge is present) let startActivityInPackage handle
+                // the intercepting.
+                if (!mService.mAmInternal.shouldConfirmCredentials(task.mUserId)
+                        && task.getRootActivity() != null) {
+                    final ActivityRecord targetActivity = task.getTopNonFinishingActivity();
 
-                return ActivityManager.START_TASK_TO_FRONT;
+                    mRootWindowContainer.startPowerModeLaunchIfNeeded(
+                            true /* forceSend */, targetActivity);
+                    final LaunchingState launchingState =
+                            mActivityMetricsLogger.notifyActivityLaunching(task.intent);
+                    try {
+                        mService.moveTaskToFrontLocked(null /* appThread */,
+                                null /* callingPackage */, task.mTaskId, 0, options);
+                        // Apply options to prevent pendingOptions be taken when scheduling
+                        // activity lifecycle transaction to make sure the override pending app
+                        // transition will be applied immediately.
+                        targetActivity.applyOptionsAnimation();
+                    } finally {
+                        mActivityMetricsLogger.notifyActivityLaunched(launchingState,
+                                START_TASK_TO_FRONT, false /* newActivityCreated */,
+                                targetActivity, activityOptions);
+                    }
+
+                    mService.getActivityStartController().postStartActivityProcessingForLastStarter(
+                            task.getTopNonFinishingActivity(), ActivityManager.START_TASK_TO_FRONT,
+                            task.getRootTask());
+
+                    // As it doesn't go to ActivityStarter.executeRequest() path, we need to resume
+                    // app switching here also.
+                    mService.resumeAppSwitches();
+                    return ActivityManager.START_TASK_TO_FRONT;
+                }
+                // The task is empty or needs to show the confirmation for credential.
+                shouldStartActivity = true;
+            } finally {
+                if (!shouldStartActivity) {
+                    mService.continueWindowLayout();
+                }
             }
+            taskCallingUid = task.mCallingUid;
             callingPackage = task.mCallingPackage;
             callingFeatureId = task.mCallingFeatureId;
             intent = task.intent;
             intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
             userId = task.mUserId;
-            return mService.getActivityStartController().startActivityInPackage(task.mCallingUid,
+        }
+        // ActivityStarter will acquire the lock where the places need, so execute the request
+        // outside of the lock.
+        try {
+            return mService.getActivityStartController().startActivityInPackage(taskCallingUid,
                     callingPid, callingUid, callingPackage, callingFeatureId, intent, null, null,
                     null, 0, 0, options, userId, task, "startActivityFromRecents",
                     false /* validateIncomingUser */, null /* originatingPendingIntent */,
                     false /* allowBackgroundActivityStart */);
         } finally {
-            mService.continueWindowLayout();
+            synchronized (mService.mGlobalLock) {
+                mService.continueWindowLayout();
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/AnimationAdapter.java b/services/core/java/com/android/server/wm/AnimationAdapter.java
index 486328a..529c4f6 100644
--- a/services/core/java/com/android/server/wm/AnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/AnimationAdapter.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import android.annotation.ColorInt;
 import android.util.proto.ProtoOutputStream;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
@@ -107,14 +106,4 @@
     default boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
         return false;
     }
-
-    /**
-     * Gets the background color to show behind an animation.
-     *
-     * @return The background color to show behind an animation (0 for no background color).
-     */
-    @ColorInt
-    default int getBackgroundColor() {
-        return 0;
-    }
 }
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 7f0adca..22a2c41 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -35,10 +35,10 @@
  */
 class AppTaskImpl extends IAppTask.Stub {
     private static final String TAG = "AppTaskImpl";
-    private ActivityTaskManagerService mService;
+    private final ActivityTaskManagerService mService;
 
-    private int mTaskId;
-    private int mCallingUid;
+    private final int mTaskId;
+    private final int mCallingUid;
 
     public AppTaskImpl(ActivityTaskManagerService service, int taskId, int callingUid) {
         mService = service;
@@ -108,14 +108,14 @@
                 final ActivityStarter starter = mService.getActivityStartController().obtainStarter(
                         null /* intent */, "moveToFront");
                 if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid,
-                        callingPackage, -1, -1, callerApp, null, false, null)) {
+                        callingPackage, -1, -1, callerApp, null, false, null, null)) {
                     if (!mService.isBackgroundActivityStartsEnabled()) {
                         return;
                     }
                 }
-                mService.mTaskSupervisor.startActivityFromRecents(callingPid,
-                        callingUid, mTaskId, null);
             }
+            mService.mTaskSupervisor.startActivityFromRecents(callingPid, callingUid, mTaskId,
+                    null /* options */);
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index cf25de9..a97ca6c 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -165,8 +165,8 @@
     void handleAppTransitionReady() {
         mTempTransitionReasons.clear();
         if (!transitionGoodToGo(mDisplayContent.mOpeningApps, mTempTransitionReasons)
-                || !transitionGoodToGo(mDisplayContent.mChangingContainers,
-                        mTempTransitionReasons)) {
+                || !transitionGoodToGo(mDisplayContent.mChangingContainers, mTempTransitionReasons)
+                || !transitionGoodToGoForTaskFragments()) {
             return;
         }
         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
@@ -599,6 +599,13 @@
         }
     }
 
+    @Nullable
+    static Task findRootTaskFromContainer(WindowContainer wc) {
+        return wc.asTaskFragment() != null ? wc.asTaskFragment().getRootTask()
+                : wc.asActivityRecord().getRootTask();
+    }
+
+    @Nullable
     static ActivityRecord getAppFromContainer(WindowContainer wc) {
         return wc.asTaskFragment() != null ? wc.asTaskFragment().getTopNonFinishingActivity()
                 : wc.asActivityRecord();
@@ -972,72 +979,109 @@
         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
                 "Checking %d opening apps (frozen=%b timeout=%b)...", apps.size(),
                 mService.mDisplayFrozen, mDisplayContent.mAppTransition.isTimeout());
-
+        if (mDisplayContent.mAppTransition.isTimeout()) {
+            return true;
+        }
         final ScreenRotationAnimation screenRotationAnimation = mService.mRoot.getDisplayContent(
                 Display.DEFAULT_DISPLAY).getRotationAnimation();
 
-        if (!mDisplayContent.mAppTransition.isTimeout()) {
-            // Imagine the case where we are changing orientation due to an app transition, but a
-            // previous orientation change is still in progress. We won't process the orientation
-            // change for our transition because we need to wait for the rotation animation to
-            // finish.
-            // If we start the app transition at this point, we will interrupt it halfway with a
-            // new rotation animation after the old one finally finishes. It's better to defer the
-            // app transition.
-            if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()
-                    && mDisplayContent.getDisplayRotation().needsUpdate()) {
-                ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
-                        "Delaying app transition for screen rotation animation to finish");
-                return false;
-            }
-            for (int i = 0; i < apps.size(); i++) {
-                WindowContainer wc = apps.valueAt(i);
-                final ActivityRecord activity = getAppFromContainer(wc);
-                if (activity == null) {
-                    continue;
-                }
-                ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
-                        "Check opening app=%s: allDrawn=%b startingDisplayed=%b "
-                                + "startingMoved=%b isRelaunching()=%b startingWindow=%s",
-                        activity, activity.allDrawn, activity.startingDisplayed,
-                        activity.startingMoved, activity.isRelaunching(),
-                        activity.mStartingWindow);
-
-
-                final boolean allDrawn = activity.allDrawn && !activity.isRelaunching();
-                if (!allDrawn && !activity.startingDisplayed && !activity.startingMoved) {
-                    return false;
-                }
-                if (allDrawn) {
-                    outReasons.put(activity, APP_TRANSITION_WINDOWS_DRAWN);
-                } else {
-                    outReasons.put(activity,
-                            activity.mStartingData instanceof SplashScreenStartingData
-                                    ? APP_TRANSITION_SPLASH_SCREEN
-                                    : APP_TRANSITION_SNAPSHOT);
-                }
-            }
-
-            // We also need to wait for the specs to be fetched, if needed.
-            if (mDisplayContent.mAppTransition.isFetchingAppTransitionsSpecs()) {
-                ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "isFetchingAppTransitionSpecs=true");
-                return false;
-            }
-
-            if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) {
-                ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "unknownApps is not empty: %s",
-                            mDisplayContent.mUnknownAppVisibilityController.getDebugMessage());
-                return false;
-            }
-
-            // If the wallpaper is visible, we need to check it's ready too.
-            boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() ||
-                    mWallpaperControllerLocked.wallpaperTransitionReady();
-            if (wallpaperReady) {
-                return true;
-            }
+        // Imagine the case where we are changing orientation due to an app transition, but a
+        // previous orientation change is still in progress. We won't process the orientation
+        // change for our transition because we need to wait for the rotation animation to
+        // finish.
+        // If we start the app transition at this point, we will interrupt it halfway with a
+        // new rotation animation after the old one finally finishes. It's better to defer the
+        // app transition.
+        if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()
+                && mDisplayContent.getDisplayRotation().needsUpdate()) {
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                    "Delaying app transition for screen rotation animation to finish");
             return false;
         }
+        for (int i = 0; i < apps.size(); i++) {
+            WindowContainer wc = apps.valueAt(i);
+            final ActivityRecord activity = getAppFromContainer(wc);
+            if (activity == null) {
+                continue;
+            }
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                    "Check opening app=%s: allDrawn=%b startingDisplayed=%b "
+                            + "startingMoved=%b isRelaunching()=%b startingWindow=%s",
+                    activity, activity.allDrawn, activity.startingDisplayed,
+                    activity.startingMoved, activity.isRelaunching(),
+                    activity.mStartingWindow);
+
+            final boolean allDrawn = activity.allDrawn && !activity.isRelaunching();
+            if (!allDrawn && !activity.startingDisplayed && !activity.startingMoved) {
+                return false;
+            }
+            if (allDrawn) {
+                outReasons.put(activity, APP_TRANSITION_WINDOWS_DRAWN);
+            } else {
+                outReasons.put(activity,
+                        activity.mStartingData instanceof SplashScreenStartingData
+                                ? APP_TRANSITION_SPLASH_SCREEN
+                                : APP_TRANSITION_SNAPSHOT);
+            }
+        }
+
+        // We also need to wait for the specs to be fetched, if needed.
+        if (mDisplayContent.mAppTransition.isFetchingAppTransitionsSpecs()) {
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "isFetchingAppTransitionSpecs=true");
+            return false;
+        }
+
+        if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) {
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "unknownApps is not empty: %s",
+                    mDisplayContent.mUnknownAppVisibilityController.getDebugMessage());
+            return false;
+        }
+
+        // If the wallpaper is visible, we need to check it's ready too.
+        return !mWallpaperControllerLocked.isWallpaperVisible()
+                || mWallpaperControllerLocked.wallpaperTransitionReady();
+    }
+
+    private boolean transitionGoodToGoForTaskFragments() {
+        if (mDisplayContent.mAppTransition.isTimeout()) {
+            return true;
+        }
+
+        // Check all Tasks in this transition. This is needed because new TaskFragment created for
+        // launching activity may not be in the tracking lists, but we still want to wait for the
+        // activity launch to start the transition.
+        final ArraySet<Task> rootTasks = new ArraySet<>();
+        for (int i = mDisplayContent.mOpeningApps.size() - 1; i >= 0; i--) {
+            rootTasks.add(mDisplayContent.mOpeningApps.valueAt(i).getRootTask());
+        }
+        for (int i = mDisplayContent.mClosingApps.size() - 1; i >= 0; i--) {
+            rootTasks.add(mDisplayContent.mClosingApps.valueAt(i).getRootTask());
+        }
+        for (int i = mDisplayContent.mChangingContainers.size() - 1; i >= 0; i--) {
+            rootTasks.add(
+                    findRootTaskFromContainer(mDisplayContent.mChangingContainers.valueAt(i)));
+        }
+
+        // Organized TaskFragment can be empty for two situations:
+        // 1. New created and is waiting for Activity launch. In this case, we want to wait for
+        //    the Activity launch to trigger the transition.
+        // 2. Last Activity is just removed. In this case, we want to wait for organizer to
+        //    remove the TaskFragment because it may also want to change other TaskFragments in
+        //    the same transition.
+        for (int i = rootTasks.size() - 1; i >= 0; i--) {
+            final Task rootTask = rootTasks.valueAt(i);
+            final boolean notReady = rootTask.forAllLeafTaskFragments(taskFragment -> {
+                if (!taskFragment.isReadyToTransit()) {
+                    ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Organized TaskFragment is not ready= %s",
+                            taskFragment);
+                    return true;
+                }
+                return false;
+            });
+            if (notReady) {
+                return false;
+            }
+        }
         return true;
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index ea3b725..9d51b6f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -75,6 +75,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
@@ -1384,11 +1385,16 @@
         final Configuration currentDisplayConfig = getConfiguration();
         mTmpConfiguration.setTo(currentDisplayConfig);
         computeScreenConfiguration(mTmpConfiguration);
-        configChanged |= currentDisplayConfig.diff(mTmpConfiguration) != 0;
+        final int changes = currentDisplayConfig.diff(mTmpConfiguration);
+        configChanged |= changes != 0;
 
         if (configChanged) {
             mWaitingForConfig = true;
-            mWmService.startFreezingDisplay(0 /* exitAnim */, 0 /* enterAnim */, this);
+            if (mAtmService.getTransitionController().isShellTransitionsEnabled()) {
+                requestChangeTransitionIfNeeded(changes);
+            } else {
+                mWmService.startFreezingDisplay(0 /* exitAnim */, 0 /* enterAnim */, this);
+            }
             sendNewConfiguration();
         }
 
@@ -3160,6 +3166,24 @@
         return mScreenRotationAnimation;
     }
 
+    /**
+     * Requests to start a transition for the display configuration change. The given changes must
+     * be non-zero. This method is no-op if the display has been collected.
+     */
+    void requestChangeTransitionIfNeeded(@ActivityInfo.Config int changes) {
+        final TransitionController controller = mAtmService.getTransitionController();
+        if (controller.isCollecting()) {
+            if (!controller.isCollecting(this)) {
+                controller.collect(this);
+            }
+            return;
+        }
+        final Transition t = controller.requestTransitionIfNeeded(TRANSIT_CHANGE, this);
+        if (t != null) {
+            t.setKnownConfigChanges(this, changes);
+        }
+    }
+
     /** If the display is in transition, there should be a screenshot covering it. */
     @Override
     boolean inTransition() {
@@ -5691,6 +5715,9 @@
             }
             mWmService.mDisplayNotificationController.dispatchDisplayChanged(
                     this, getConfiguration());
+            if (isReady() && mAtmService.getTransitionController().isShellTransitionsEnabled()) {
+                requestChangeTransitionIfNeeded(changes);
+            }
         }
         return changes;
     }
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index c9db14d..971bebd 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -22,7 +22,6 @@
 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;
@@ -492,12 +491,6 @@
             recentsAnimationController.cancelAnimationForDisplayChange();
         }
 
-        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);
@@ -511,11 +504,10 @@
         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 {
+            final boolean wasInTransition = mDisplayContent.inTransition();
+            mDisplayContent.requestChangeTransitionIfNeeded(
+                    ActivityInfo.CONFIG_WINDOW_CONFIGURATION);
+            if (wasInTransition) {
                 // Use remote-rotation infra since the transition has already been requested
                 // TODO(shell-transitions): Remove this once lifecycle management can cover all
                 //                          rotation cases.
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index d073f94..17a11dc 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -22,6 +22,7 @@
 
 import android.annotation.NonNull;
 import android.content.ClipData;
+import android.content.Context;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -32,6 +33,7 @@
 import android.view.IWindow;
 import android.view.SurfaceControl;
 import android.view.View;
+import android.view.accessibility.AccessibilityManager;
 
 import com.android.server.wm.WindowManagerInternal.IDragDropCallback;
 
@@ -43,7 +45,8 @@
  */
 class DragDropController {
     private static final float DRAG_SHADOW_ALPHA_TRANSPARENT = .7071f;
-    private static final long DRAG_TIMEOUT_MS = 5000;
+    static final long DRAG_TIMEOUT_MS = 5000;
+    private static final int A11Y_DRAG_TIMEOUT_DEFAULT_MS = 60000;
 
     // Messages for Handler.
     static final int MSG_DRAG_END_TIMEOUT = 0;
@@ -151,36 +154,48 @@
                     mDragState.mOriginalAlpha = alpha;
                     mDragState.mToken = dragToken;
                     mDragState.mDisplayContent = displayContent;
-
-                    final Display display = displayContent.getDisplay();
-                    if (!mCallback.get().registerInputChannel(
-                            mDragState, display, mService.mInputManager,
-                            callingWin.mInputChannel)) {
-                        Slog.e(TAG_WM, "Unable to transfer touch focus");
-                        return null;
-                    }
-
-                    final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
                     mDragState.mData = data;
-                    mDragState.broadcastDragStartedLocked(touchX, touchY);
-                    mDragState.overridePointerIconLocked(touchSource);
-                    // remember the thumb offsets for later
-                    mDragState.mThumbOffsetX = thumbCenterX;
-                    mDragState.mThumbOffsetY = thumbCenterY;
 
-                    // Make the surface visible at the proper location
-                    if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> OPEN TRANSACTION performDrag");
+                    if ((flags & View.DRAG_FLAG_ACCESSIBILITY_ACTION) == 0) {
+                        final Display display = displayContent.getDisplay();
+                        if (!mCallback.get().registerInputChannel(
+                                mDragState, display, mService.mInputManager,
+                                callingWin.mInputChannel)) {
+                            Slog.e(TAG_WM, "Unable to transfer touch focus");
+                            return null;
+                        }
 
-                    final SurfaceControl.Transaction transaction = mDragState.mTransaction;
-                    transaction.setAlpha(surfaceControl, mDragState.mOriginalAlpha);
-                    transaction.setPosition(
-                            surfaceControl, touchX - thumbCenterX, touchY - thumbCenterY);
-                    transaction.show(surfaceControl);
-                    displayContent.reparentToOverlay(transaction, surfaceControl);
-                    callingWin.scheduleAnimation();
+                        final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
+                        mDragState.broadcastDragStartedLocked(touchX, touchY);
+                        mDragState.overridePointerIconLocked(touchSource);
+                        // remember the thumb offsets for later
+                        mDragState.mThumbOffsetX = thumbCenterX;
+                        mDragState.mThumbOffsetY = thumbCenterY;
 
-                    if (SHOW_LIGHT_TRANSACTIONS) {
-                        Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
+                        // Make the surface visible at the proper location
+                        if (SHOW_LIGHT_TRANSACTIONS) {
+                            Slog.i(TAG_WM, ">>> OPEN TRANSACTION performDrag");
+                        }
+
+                        final SurfaceControl.Transaction transaction = mDragState.mTransaction;
+                        transaction.setAlpha(surfaceControl, mDragState.mOriginalAlpha);
+                        transaction.setPosition(
+                                surfaceControl, touchX - thumbCenterX, touchY - thumbCenterY);
+                        transaction.show(surfaceControl);
+                        displayContent.reparentToOverlay(transaction, surfaceControl);
+                        callingWin.scheduleAnimation();
+                        if (SHOW_LIGHT_TRANSACTIONS) {
+                            Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
+                        }
+                    } else {
+                        // Skip surface logic for a drag triggered by an AccessibilityAction
+                        mDragState.broadcastDragStartedLocked(touchX, touchY);
+
+                        // Timeout for the user to drop the content
+                        sendTimeoutMessage(MSG_DRAG_END_TIMEOUT, callingWin.mClient.asBinder(),
+                                getAccessibilityManager().getRecommendedTimeoutMillis(
+                                        A11Y_DRAG_TIMEOUT_DEFAULT_MS,
+                                        AccessibilityManager.FLAG_CONTENT_CONTROLS));
                     }
                 } finally {
                     if (surface != null) {
@@ -311,10 +326,10 @@
     /**
      * Sends a timeout message to the Handler managed by DragDropController.
      */
-    void sendTimeoutMessage(int what, Object arg) {
+    void sendTimeoutMessage(int what, Object arg, long timeoutMs) {
         mHandler.removeMessages(what, arg);
         final Message msg = mHandler.obtainMessage(what, arg);
-        mHandler.sendMessageDelayed(msg, DRAG_TIMEOUT_MS);
+        mHandler.sendMessageDelayed(msg, timeoutMs);
     }
 
     /**
@@ -334,6 +349,30 @@
         }
     }
 
+    boolean dropForAccessibility(IWindow window, float x, float y) {
+        synchronized (mService.mGlobalLock) {
+            final boolean isA11yEnabled = getAccessibilityManager().isEnabled();
+            if (!dragDropActiveLocked()) {
+                return false;
+            }
+            if (mDragState.isAccessibilityDragDrop() && isA11yEnabled) {
+                final WindowState winState = mService.windowForClientLocked(
+                        null, window, false);
+                if (!mDragState.isWindowNotified(winState)) {
+                    return false;
+                }
+                IBinder token = winState.mInputChannelToken;
+                return mDragState.reportDropWindowLock(token, x, y);
+            }
+            return false;
+        }
+    }
+
+    AccessibilityManager getAccessibilityManager() {
+        return (AccessibilityManager) mService.mContext.getSystemService(
+                Context.ACCESSIBILITY_SERVICE);
+    }
+
     private class DragHandler extends Handler {
         /**
          * Lock for window manager.
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index aa257f8..4fc123d 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -253,7 +253,7 @@
                 mTransaction.reparent(mSurfaceControl, null).apply();
             } else {
                 mDragDropController.sendTimeoutMessage(MSG_REMOVE_DRAG_SURFACE_TIMEOUT,
-                        mSurfaceControl);
+                        mSurfaceControl, DragDropController.DRAG_TIMEOUT_MS);
             }
             mSurfaceControl = null;
         }
@@ -276,9 +276,9 @@
      * Notify the drop target and tells it about the data. If the drop event is not sent to the
      * target, invokes {@code endDragLocked} immediately.
      */
-    void reportDropWindowLock(IBinder token, float x, float y) {
+    boolean reportDropWindowLock(IBinder token, float x, float y) {
         if (mAnimator != null) {
-            return;
+            return false;
         }
 
         final WindowState touchedWin = mService.mInputToWindowMap.get(token);
@@ -288,7 +288,7 @@
             mDragResult = false;
             endDragLocked();
             if (DEBUG_DRAG) Slog.d(TAG_WM, "Drop outside a valid window " + touchedWin);
-            return;
+            return false;
         }
 
         if (DEBUG_DRAG) Slog.d(TAG_WM, "sending DROP to " + touchedWin);
@@ -322,16 +322,19 @@
             touchedWin.mClient.dispatchDragEvent(event);
 
             // 5 second timeout for this window to respond to the drop
-            mDragDropController.sendTimeoutMessage(MSG_DRAG_END_TIMEOUT, clientToken);
+            mDragDropController.sendTimeoutMessage(MSG_DRAG_END_TIMEOUT, clientToken,
+                    DragDropController.DRAG_TIMEOUT_MS);
         } catch (RemoteException e) {
             Slog.w(TAG_WM, "can't send drop notification to win " + touchedWin);
             endDragLocked();
+            return false;
         } finally {
             if (myPid != touchedWin.mSession.mPid) {
                 event.recycle();
             }
         }
         mToken = clientToken;
+        return true;
     }
 
     class InputInterceptor {
@@ -553,7 +556,7 @@
         }
     }
 
-    private boolean isWindowNotified(WindowState newWin) {
+    boolean isWindowNotified(WindowState newWin) {
         for (WindowState ws : mNotifiedWindows) {
             if (ws == newWin) {
                 return true;
@@ -567,8 +570,10 @@
             return;
         }
         if (!mDragResult) {
-            mAnimator = createReturnAnimationLocked();
-            return;  // Will call closeLocked() when the animation is done.
+            if (!isAccessibilityDragDrop()) {
+                mAnimator = createReturnAnimationLocked();
+                return;  // Will call closeLocked() when the animation is done.
+            }
         }
         closeLocked();
     }
@@ -577,7 +582,7 @@
         if (mAnimator != null) {
             return;
         }
-        if (!mDragInProgress || skipAnimation) {
+        if (!mDragInProgress || skipAnimation || isAccessibilityDragDrop()) {
             // mDragInProgress is false if an app invokes Session#cancelDragAndDrop before
             // Session#performDrag. Reset the drag state without playing the cancel animation
             // because H.DRAG_START_TIMEOUT may be sent to WindowManagerService, which will cause
@@ -722,4 +727,8 @@
             mDragDropController.sendHandlerMessage(MSG_ANIMATION_END, null);
         }
     }
+
+    boolean isAccessibilityDragDrop() {
+        return (mFlags & View.DRAG_FLAG_ACCESSIBILITY_ACTION) != 0;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index fed4f62..6560d15 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -103,12 +103,12 @@
         ArrayList<TaskFragment> adjacentTaskFragments = null;
         for (int i = mTaskFragment.mChildren.size() - 1; i >= 0; --i) {
             final WindowContainer child = mTaskFragment.mChildren.get(i);
-            if (child.asTaskFragment() != null) {
-                final TaskFragment childTaskFragment = child.asTaskFragment();
+            final TaskFragment childTaskFragment = child.asTaskFragment();
+            if (childTaskFragment != null && childTaskFragment.topRunningActivity() != null) {
                 childTaskFragment.updateActivityVisibilities(starting, configChanges,
                         preserveWindows, notifyClients);
-                mBehindFullyOccludedContainer |= childTaskFragment.getBounds().equals(
-                        mTaskFragment.getBounds());
+                mBehindFullyOccludedContainer |=
+                        childTaskFragment.getBounds().equals(mTaskFragment.getBounds());
                 if (mAboveTop && mTop.getTaskFragment() == childTaskFragment) {
                     mAboveTop = false;
                 }
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index 76a098d..72fbfcc 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -174,7 +174,7 @@
      * Whether corners of letterboxed activities are rounded.
      */
     boolean isLetterboxActivityCornersRounded() {
-        return getLetterboxActivityCornersRadius() > 0;
+        return getLetterboxActivityCornersRadius() != 0;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 0d99bac..cf2afc9 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -38,6 +38,9 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.Slog;
+import android.view.InsetsSource;
+import android.view.InsetsState;
+import android.view.RoundedCorner;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.WindowManager;
@@ -295,31 +298,66 @@
     }
 
     private void updateRoundedCorners(WindowState mainWindow) {
-        int cornersRadius =
-                // Don't round corners if letterboxed only for display cutout.
-                shouldShowLetterboxUi(mainWindow)
-                                && !mainWindow.isLetterboxedForDisplayCutout()
-                        ? Math.max(0, mLetterboxConfiguration.getLetterboxActivityCornersRadius())
-                        : 0;
-        setCornersRadius(mainWindow, cornersRadius);
-    }
-
-    private void setCornersRadius(WindowState mainWindow, int cornersRadius) {
         final SurfaceControl windowSurface = mainWindow.getClientViewRootSurface();
         if (windowSurface != null && windowSurface.isValid()) {
             Transaction transaction = mActivityRecord.getSyncTransaction();
-            transaction.setCornerRadius(windowSurface, cornersRadius);
+
+            if (!isLetterboxedNotForDisplayCutout(mainWindow)
+                    || !mLetterboxConfiguration.isLetterboxActivityCornersRounded()) {
+                transaction
+                        .setWindowCrop(windowSurface, null)
+                        .setCornerRadius(windowSurface, 0);
+                return;
+            }
+
+            final InsetsState insetsState = mainWindow.getInsetsState();
+            final InsetsSource taskbarInsetsSource =
+                    insetsState.getSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
+
+            Rect cropBounds = new Rect(mActivityRecord.getBounds());
+            // Activity bounds are in screen coordinates while (0,0) for activity's surface control
+            // is at the top left corner of an app window so offsetting bounds accordingly.
+            cropBounds.offsetTo(0, 0);
+            // Rounded cornerners should be displayed above the taskbar.
+            cropBounds.bottom = Math.min(cropBounds.bottom, taskbarInsetsSource.getFrame().top);
+            transaction
+                    .setWindowCrop(windowSurface, cropBounds)
+                    .setCornerRadius(windowSurface, getRoundedCorners(insetsState));
         }
     }
 
+    // Returns rounded corners radius based on override in
+    // R.integer.config_letterboxActivityCornersRadius or min device bottom corner radii.
+    // Device corners can be different on the right and left sides but we use the same radius
+    // for all corners for consistency and pick a minimal bottom one for consistency with a
+    // taskbar rounded corners.
+    private int getRoundedCorners(InsetsState insetsState) {
+        if (mLetterboxConfiguration.getLetterboxActivityCornersRadius() >= 0) {
+            return mLetterboxConfiguration.getLetterboxActivityCornersRadius();
+        }
+        return Math.min(
+                getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_LEFT),
+                getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_RIGHT));
+    }
+
+    private int getInsetsStateCornerRadius(
+                InsetsState insetsState, @RoundedCorner.Position int position) {
+        RoundedCorner corner = insetsState.getRoundedCorners().getRoundedCorner(position);
+        return corner == null ? 0 : corner.getRadius();
+    }
+
+    private boolean isLetterboxedNotForDisplayCutout(WindowState mainWindow) {
+        return shouldShowLetterboxUi(mainWindow)
+                && !mainWindow.isLetterboxedForDisplayCutout();
+    }
+
     private void updateWallpaperForLetterbox(WindowState mainWindow) {
         @LetterboxBackgroundType int letterboxBackgroundType =
                 mLetterboxConfiguration.getLetterboxBackgroundType();
         boolean wallpaperShouldBeShown =
                 letterboxBackgroundType == LETTERBOX_BACKGROUND_WALLPAPER
-                        && shouldShowLetterboxUi(mainWindow)
                         // Don't use wallpaper as a background if letterboxed for display cutout.
-                        && !mainWindow.isLetterboxedForDisplayCutout()
+                        && isLetterboxedNotForDisplayCutout(mainWindow)
                         // Check that dark scrim alpha or blur radius are provided
                         && (getLetterboxWallpaperBlurRadius() > 0
                                 || getLetterboxWallpaperDarkScrimAlpha() > 0)
@@ -375,6 +413,8 @@
         pw.println(prefix + "  letterboxBackgroundType="
                 + letterboxBackgroundTypeToString(
                         mLetterboxConfiguration.getLetterboxBackgroundType()));
+        pw.println(prefix + "  letterboxCornerRadius="
+                + getRoundedCorners(mainWin.getInsetsState()));
         if (mLetterboxConfiguration.getLetterboxBackgroundType()
                 == LETTERBOX_BACKGROUND_WALLPAPER) {
             pw.println(prefix + "  isLetterboxWallpaperBlurSupported="
diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
index 8f161bf..520bd8b 100644
--- a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
@@ -19,7 +19,6 @@
 import static com.android.server.wm.AnimationAdapterProto.LOCAL;
 import static com.android.server.wm.LocalAnimationAdapterProto.ANIMATION_SPEC;
 
-import android.annotation.ColorInt;
 import android.os.SystemClock;
 import android.util.proto.ProtoOutputStream;
 import android.view.SurfaceControl;
@@ -73,12 +72,6 @@
     }
 
     @Override
-    @ColorInt
-    public int getBackgroundColor() {
-        return mSpec.getBackgroundColor();
-    }
-
-    @Override
     public void dump(PrintWriter pw, String prefix) {
         mSpec.dump(pw, prefix);
     }
@@ -156,9 +149,5 @@
         }
 
         void dumpDebugInner(ProtoOutputStream proto);
-
-        default int getBackgroundColor() {
-            return 0;
-        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index b90f937..16a45fe 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -65,7 +65,6 @@
             new ArrayList<>();
     @VisibleForTesting
     final ArrayList<NonAppWindowAnimationAdapter> mPendingNonAppAnimations = new ArrayList<>();
-    private final Rect mTmpRect = new Rect();
     private final Handler mHandler;
     private final Runnable mTimeoutRunnable = () -> cancelAnimation("timeoutRunnable");
 
@@ -85,18 +84,18 @@
      * Creates an animation record for each individual {@link WindowContainer}.
      *
      * @param windowContainer The windows to animate.
-     * @param position The position app bounds, in screen coordinates.
+     * @param position The position app bounds relative to its parent.
      * @param localBounds The bounds of the app relative to its parent.
-     * @param stackBounds The stack bounds of the app relative to position.
-     * @param startBounds The stack bounds before the transition, in screen coordinates
+     * @param endBounds The end bounds after the transition, in screen coordinates.
+     * @param startBounds The start bounds before the transition, in screen coordinates.
      * @return The record representing animation(s) to run on the app.
      */
     RemoteAnimationRecord createRemoteAnimationRecord(WindowContainer windowContainer,
-            Point position, Rect localBounds, Rect stackBounds, Rect startBounds) {
+            Point position, Rect localBounds, Rect endBounds, Rect startBounds) {
         ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAnimationAdapter(): container=%s",
                 windowContainer);
         final RemoteAnimationRecord adapters = new RemoteAnimationRecord(windowContainer, position,
-                localBounds, stackBounds, startBounds);
+                localBounds, endBounds, startBounds);
         mPendingAnimations.add(adapters);
         return adapters;
     }
@@ -405,16 +404,17 @@
                 mStartBounds = new Rect(startBounds);
                 mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds,
                         mStartBounds);
-                mTmpRect.set(startBounds);
-                mTmpRect.offsetTo(0, 0);
                 if (mRemoteAnimationAdapter.getChangeNeedsSnapshot()) {
-                    mThumbnailAdapter =
-                            new RemoteAnimationAdapterWrapper(this, new Point(0, 0), localBounds,
-                                    mTmpRect, new Rect());
+                    final Rect thumbnailLocalBounds = new Rect(startBounds);
+                    thumbnailLocalBounds.offsetTo(0, 0);
+                    // Snapshot is located at (0,0) of the animation leash. It doesn't have size
+                    // change, so the startBounds is its end bounds, and no start bounds for it.
+                    mThumbnailAdapter = new RemoteAnimationAdapterWrapper(this, new Point(0, 0),
+                            thumbnailLocalBounds, startBounds, new Rect());
                 }
             } else {
                 mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds,
-                        new Rect(endPos.x, endPos.y, endBounds.right, endBounds.bottom));
+                        new Rect());
                 mStartBounds = null;
             }
         }
@@ -458,15 +458,15 @@
         private @AnimationType int mAnimationType;
         final Point mPosition = new Point();
         final Rect mLocalBounds;
-        final Rect mRootTaskBounds = new Rect();
+        final Rect mEndBounds = new Rect();
         final Rect mStartBounds = new Rect();
 
         RemoteAnimationAdapterWrapper(RemoteAnimationRecord record, Point position,
-                Rect localBounds, Rect rootTaskBounds, Rect startBounds) {
+                Rect localBounds, Rect endBounds, Rect startBounds) {
             mRecord = record;
             mPosition.set(position.x, position.y);
             mLocalBounds = localBounds;
-            mRootTaskBounds.set(rootTaskBounds);
+            mEndBounds.set(endBounds);
             mStartBounds.set(startBounds);
         }
 
@@ -480,12 +480,17 @@
                 @AnimationType int type, OnAnimationFinishedCallback finishCallback) {
             ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation");
 
-            // Restore position and stack crop until client has a chance to modify it.
             if (mStartBounds.isEmpty()) {
-                t.setPosition(animationLeash, 0, 0);
-                t.setWindowCrop(animationLeash, -1, -1);
+                // Restore position and stack crop until client has a chance to modify it.
+                t.setPosition(animationLeash, mPosition.x, mPosition.y);
+                t.setWindowCrop(animationLeash, mEndBounds.width(), mEndBounds.height());
             } else {
-                t.setPosition(animationLeash, mStartBounds.left, mStartBounds.top);
+                // Offset the change animation leash to the relative start position in parent.
+                // (mPosition) is the relative end position in parent container.
+                // (mStartBounds - mEndBounds) is the position difference between start and end.
+                // (mPosition + mStartBounds - mEndBounds) will be the relative start position.
+                t.setPosition(animationLeash, mPosition.x + mStartBounds.left - mEndBounds.left,
+                        mPosition.y + mStartBounds.top - mEndBounds.top);
                 t.setWindowCrop(animationLeash, mStartBounds.width(), mStartBounds.height());
             }
             mCapturedLeash = animationLeash;
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 0b56777..8c056b2 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -299,6 +299,17 @@
         }
     }
 
+
+    @Override
+    public boolean dropForAccessibility(IWindow window, int x, int y) {
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            return mDragDropController.dropForAccessibility(window, x, y);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
     /**
      * Validates the given drag data.
      */
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 3c6c23b..c7bf8ec 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -59,11 +59,30 @@
     @VisibleForTesting
     final Animatable mAnimatable;
     private final OnAnimationFinishedCallback mInnerAnimationFinishedCallback;
+
+    /**
+     * Static callback to run on all animations started through this SurfaceAnimator
+     * when an animation on a Surface is finished or cancelled without restart.
+     */
     @VisibleForTesting
     @Nullable
     final OnAnimationFinishedCallback mStaticAnimationFinishedCallback;
+
+    /**
+     * Callback unique to each animation (i.e. AnimationAdapter). To be run when an animation on a
+     * Surface is finished or cancelled without restart.
+     */
     @Nullable
-    private OnAnimationFinishedCallback mAnimationFinishedCallback;
+    private OnAnimationFinishedCallback mSurfaceAnimationFinishedCallback;
+
+    /**
+     * The callback is triggered after the SurfaceAnimator sends a cancel call to the underlying
+     * AnimationAdapter.
+     * NOTE: Must be called wherever we call onAnimationCancelled on mAnimation.
+     */
+    @Nullable
+    private Runnable mAnimationCancelledCallback;
+
     private boolean mAnimationStartDelayed;
 
     /**
@@ -100,7 +119,7 @@
                         return;
                     }
                     final OnAnimationFinishedCallback animationFinishCallback =
-                            mAnimationFinishedCallback;
+                            mSurfaceAnimationFinishedCallback;
                     reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */);
                     if (staticAnimationFinishedCallback != null) {
                         staticAnimationFinishedCallback.onAnimationFinished(type, anim);
@@ -130,15 +149,19 @@
      *               This is important as it will start with the leash hidden or visible before
      *               handing it to the component that is responsible to run the animation.
      * @param animationFinishedCallback The callback being triggered when the animation finishes.
+     * @param animationCancelledCallback The callback is triggered after the SurfaceAnimator sends a
+     *                                   cancel call to the underlying AnimationAdapter.
      */
     void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
             @AnimationType int type,
             @Nullable OnAnimationFinishedCallback animationFinishedCallback,
+            @Nullable Runnable animationCancelledCallback,
             @Nullable SurfaceFreezer freezer) {
         cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
         mAnimation = anim;
         mAnimationType = type;
-        mAnimationFinishedCallback = animationFinishedCallback;
+        mSurfaceAnimationFinishedCallback = animationFinishedCallback;
+        mAnimationCancelledCallback = animationCancelledCallback;
         final SurfaceControl surface = mAnimatable.getSurfaceControl();
         if (surface == null) {
             Slog.w(TAG, "Unable to start animation, surface is null or no children.");
@@ -161,14 +184,9 @@
     }
 
     void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
-            @AnimationType int type,
-            @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
-        startAnimation(t, anim, hidden, type, animationFinishedCallback, null /* freezer */);
-    }
-
-    void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
             @AnimationType int type) {
-        startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */);
+        startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */,
+                null /* animationCancelledCallback */, null /* freezer */);
     }
 
     /**
@@ -278,7 +296,8 @@
         mLeash = from.mLeash;
         mAnimation = from.mAnimation;
         mAnimationType = from.mAnimationType;
-        mAnimationFinishedCallback = from.mAnimationFinishedCallback;
+        mSurfaceAnimationFinishedCallback = from.mSurfaceAnimationFinishedCallback;
+        mAnimationCancelledCallback = from.mAnimationCancelledCallback;
 
         // Cancel source animation, but don't let animation runner cancel the animation.
         from.cancelAnimation(t, false /* restarting */, false /* forwardCancel */);
@@ -306,11 +325,16 @@
         final SurfaceControl leash = mLeash;
         final AnimationAdapter animation = mAnimation;
         final @AnimationType int animationType = mAnimationType;
-        final OnAnimationFinishedCallback animationFinishedCallback = mAnimationFinishedCallback;
+        final OnAnimationFinishedCallback animationFinishedCallback =
+                mSurfaceAnimationFinishedCallback;
+        final Runnable animationCancelledCallback = mAnimationCancelledCallback;
         reset(t, false);
         if (animation != null) {
             if (!mAnimationStartDelayed && forwardCancel) {
                 animation.onAnimationCancelled(leash);
+                if (animationCancelledCallback != null) {
+                    animationCancelledCallback.run();
+                }
             }
             if (!restarting) {
                 if (mStaticAnimationFinishedCallback != null) {
@@ -335,7 +359,7 @@
     private void reset(Transaction t, boolean destroyLeash) {
         mService.mAnimationTransferMap.remove(mAnimation);
         mAnimation = null;
-        mAnimationFinishedCallback = null;
+        mSurfaceAnimationFinishedCallback = null;
         mAnimationType = ANIMATION_TYPE_NONE;
         if (mLeash == null) {
             return;
diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java
index fce2f8d..9c4f6f5 100644
--- a/services/core/java/com/android/server/wm/SurfaceFreezer.java
+++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java
@@ -24,6 +24,7 @@
 import android.annotation.Nullable;
 import android.graphics.GraphicBuffer;
 import android.graphics.PixelFormat;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.HardwareBuffer;
 import android.view.Surface;
@@ -70,13 +71,14 @@
      * above the target surface) and then taking a snapshot and placing it over the target surface.
      *
      * @param startBounds The original bounds (on screen) of the surface we are snapshotting.
+     * @param relativePosition The related position of the snapshot surface to its parent.
      */
-    void freeze(SurfaceControl.Transaction t, Rect startBounds) {
+    void freeze(SurfaceControl.Transaction t, Rect startBounds, Point relativePosition) {
         mFreezeBounds.set(startBounds);
 
         mLeash = SurfaceAnimator.createAnimationLeash(mAnimatable, mAnimatable.getSurfaceControl(),
                 t, ANIMATION_TYPE_SCREEN_ROTATION, startBounds.width(), startBounds.height(),
-                startBounds.left, startBounds.top, false /* hidden */,
+                relativePosition.x, relativePosition.y, false /* hidden */,
                 mWmService.mTransactionFactory);
         mAnimatable.onAnimationLeashCreated(t, mLeash);
 
@@ -123,6 +125,18 @@
         }
     }
 
+    void setLayer(SurfaceControl.Transaction t, int layer) {
+        if (mLeash != null) {
+            t.setLayer(mLeash, layer);
+        }
+    }
+
+    void setRelativeLayer(SurfaceControl.Transaction t, SurfaceControl relativeTo, int layer) {
+        if (mLeash != null) {
+            t.setRelativeLayer(mLeash, relativeTo, layer);
+        }
+    }
+
     boolean hasLeash() {
         return mLeash != null;
     }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a3626d2..3f6708d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2347,11 +2347,6 @@
         return getRootTask().mTaskId;
     }
 
-    @Nullable
-    Task getRootTask() {
-        return getRootTaskFragment().asTask();
-    }
-
     /** @return the first organized task. */
     @Nullable
     Task getOrganizedTask() {
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 4a1a922..a257e90 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -42,6 +42,9 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
+import static java.lang.Integer.MIN_VALUE;
+
+import android.annotation.ColorInt;
 import android.annotation.Nullable;
 import android.app.ActivityOptions;
 import android.app.WindowConfiguration;
@@ -80,6 +83,22 @@
     DisplayContent mDisplayContent;
 
     /**
+     * A color layer that serves as a solid color background to certain animations.
+     */
+    private SurfaceControl mColorBackgroundLayer;
+
+    /**
+     * This counter is used to make sure we don't prematurely clear the background color in the
+     * case that background color animations are interleaved.
+     * NOTE: The last set color will remain until the counter is reset to 0, which means that an
+     * animation background color may sometime remain after the animation has finished through an
+     * animation with a different background color if an animation starts after and ends before
+     * another where both set different background colors. However, this is not a concern as
+     * currently all task animation backgrounds are the same color.
+     */
+    private int mColorLayerCounter = 0;
+
+    /**
      * A control placed at the appropriate level for transitions to occur.
      */
     private SurfaceControl mAppAnimationLayer;
@@ -959,6 +978,11 @@
     void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
         if (getParent() != null) {
             super.onParentChanged(newParent, oldParent, () -> {
+                mColorBackgroundLayer = makeChildSurface(null)
+                        .setColorLayer()
+                        .setName("colorBackgroundLayer")
+                        .setCallsite("TaskDisplayArea.onParentChanged")
+                        .build();
                 mAppAnimationLayer = makeChildSurface(null)
                         .setName("animationLayer")
                         .setCallsite("TaskDisplayArea.onParentChanged")
@@ -975,6 +999,7 @@
                         .setName("splitScreenDividerAnchor")
                         .setCallsite("TaskDisplayArea.onParentChanged")
                         .build();
+
                 getSyncTransaction()
                         .show(mAppAnimationLayer)
                         .show(mBoostedAppAnimationLayer)
@@ -984,11 +1009,13 @@
         } else {
             super.onParentChanged(newParent, oldParent);
             mWmService.mTransactionFactory.get()
+                    .remove(mColorBackgroundLayer)
                     .remove(mAppAnimationLayer)
                     .remove(mBoostedAppAnimationLayer)
                     .remove(mHomeAppAnimationLayer)
                     .remove(mSplitScreenDividerAnchor)
                     .apply();
+            mColorBackgroundLayer = null;
             mAppAnimationLayer = null;
             mBoostedAppAnimationLayer = null;
             mHomeAppAnimationLayer = null;
@@ -996,6 +1023,39 @@
         }
     }
 
+    void setBackgroundColor(@ColorInt int color) {
+        if (mColorBackgroundLayer == null) {
+            return;
+        }
+
+        float r = ((color >> 16) & 0xff) / 255.0f;
+        float g = ((color >>  8) & 0xff) / 255.0f;
+        float b = ((color >>  0) & 0xff) / 255.0f;
+        float a = ((color >> 24) & 0xff) / 255.0f;
+
+        mColorLayerCounter++;
+
+        getPendingTransaction().setLayer(mColorBackgroundLayer, MIN_VALUE)
+                .setColor(mColorBackgroundLayer, new float[]{r, g, b})
+                .setAlpha(mColorBackgroundLayer, a)
+                .setWindowCrop(mColorBackgroundLayer, getSurfaceWidth(), getSurfaceHeight())
+                .setPosition(mColorBackgroundLayer, 0, 0)
+                .show(mColorBackgroundLayer);
+
+        scheduleAnimation();
+    }
+
+    void clearBackgroundColor() {
+        mColorLayerCounter--;
+
+        // Only clear the color layer if we have received the same amounts of clear as set
+        // requests.
+        if (mColorLayerCounter == 0) {
+            getPendingTransaction().hide(mColorBackgroundLayer);
+            scheduleAnimation();
+        }
+    }
+
     @Override
     void migrateToNewSurfaceControl(SurfaceControl.Transaction t) {
         super.migrateToNewSurfaceControl(t);
@@ -1004,6 +1064,7 @@
         }
 
         // As TaskDisplayArea is getting a new surface, reparent and reorder the child surfaces.
+        t.reparent(mColorBackgroundLayer, mSurfaceControl);
         t.reparent(mAppAnimationLayer, mSurfaceControl);
         t.reparent(mBoostedAppAnimationLayer, mSurfaceControl);
         t.reparent(mHomeAppAnimationLayer, mSurfaceControl);
@@ -2159,6 +2220,11 @@
     }
 
     @Override
+    TaskDisplayArea getTaskDisplayArea() {
+        return this;
+    }
+
+    @Override
     boolean isTaskDisplayArea() {
         return true;
     }
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index a902ca9..fce279d 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -459,6 +459,11 @@
         return parentTaskFragment == null ? this : parentTaskFragment.getRootTaskFragment();
     }
 
+    @Nullable
+    Task getRootTask() {
+        return getRootTaskFragment().asTask();
+    }
+
     @Override
     TaskFragment asTaskFragment() {
         return this;
@@ -578,9 +583,6 @@
             isPausingDied = true;
         }
         if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
-            if (mLastPausedActivity.isNoHistory()) {
-                mTaskSupervisor.mNoHistoryActivities.remove(mLastPausedActivity);
-            }
             mLastPausedActivity = null;
         }
         return isPausingDied;
@@ -2156,6 +2158,13 @@
         return mTaskFragmentOrganizer != null;
     }
 
+    boolean isReadyToTransit() {
+        // We don't want to start the transition if the organized TaskFragment is empty, unless
+        // it is requested to be removed.
+        return !isOrganizedTaskFragment() || getTopNonFinishingActivity() != null
+                || mIsRemovalRequested;
+    }
+
     /** Clear {@link #mLastPausedActivity} for all {@link TaskFragment} children */
     void clearLastPausedActivity() {
         forAllTaskFragments(taskFragment -> taskFragment.mLastPausedActivity = null);
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 28beaf3..ccda126 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -688,6 +688,7 @@
                     if (state != null) {
                         state.mOrganizer.onTaskVanished(task);
                     }
+                    mLastSentTaskInfos.remove(task);
                     break;
                 case PendingTaskEvent.EVENT_INFO_CHANGED:
                     dispatchTaskInfoChanged(event.mTask, event.mForce);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 2805dce..795286d 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -170,6 +170,9 @@
      */
     @VisibleForTesting
     void addSkipClosingAppSnapshotTasks(ArraySet<Task> tasks) {
+        if (shouldDisableSnapshots()) {
+            return;
+        }
         mSkipClosingAppSnapshotTasks.addAll(tasks);
     }
 
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 1a46d0f..1909875 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -58,6 +58,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.content.pm.ActivityInfo;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Binder;
@@ -269,6 +270,18 @@
         mChanges.get(wc).mExistenceChanged = true;
     }
 
+    /**
+     * Specifies configuration change explicitly for the window container, so it can be chosen as
+     * transition target. This is usually used with transition mode
+     * {@link android.view.WindowManager#TRANSIT_CHANGE}.
+     */
+    void setKnownConfigChanges(WindowContainer<?> wc, @ActivityInfo.Config int changes) {
+        final ChangeInfo changeInfo = mChanges.get(wc);
+        if (changeInfo != null) {
+            changeInfo.mKnownConfigChanges = changes;
+        }
+    }
+
     private void sendRemoteCallback(@Nullable IRemoteCallback callback) {
         if (callback == null) return;
         mController.mAtm.mH.sendMessage(PooledLambda.obtainMessage(cb -> {
@@ -1218,6 +1231,7 @@
         final Rect mAbsoluteBounds = new Rect();
         boolean mShowWallpaper;
         int mRotation = ROTATION_UNDEFINED;
+        @ActivityInfo.Config int mKnownConfigChanges;
 
         ChangeInfo(@NonNull WindowContainer origState) {
             mVisible = origState.isVisibleRequested();
@@ -1240,6 +1254,7 @@
             final boolean currVisible = newState.isVisibleRequested();
             if (currVisible == mVisible && !mVisible) return false;
             return currVisible != mVisible
+                    || mKnownConfigChanges != 0
                     // if mWindowingMode is 0, this container wasn't attached at collect time, so
                     // assume no change in windowing-mode.
                     || (mWindowingMode != 0 && newState.getWindowingMode() != mWindowingMode)
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index c1d0f80..fc54239 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -71,15 +71,7 @@
 
     final Lock mRunningLock = new Lock();
 
-    private final IBinder.DeathRecipient mTransitionPlayerDeath = () -> {
-        // clean-up/finish any playing transitions.
-        for (int i = 0; i < mPlayingTransitions.size(); ++i) {
-            mPlayingTransitions.get(i).cleanUpOnFailure();
-        }
-        mPlayingTransitions.clear();
-        mTransitionPlayer = null;
-        mRunningLock.doNotifyLocked();
-    };
+    private final IBinder.DeathRecipient mTransitionPlayerDeath;
 
     /** The transition currently being constructed (collecting participants). */
     private Transition mCollectingTransition = null;
@@ -90,6 +82,17 @@
     TransitionController(ActivityTaskManagerService atm) {
         mAtm = atm;
         mStatusBar = LocalServices.getService(StatusBarManagerInternal.class);
+        mTransitionPlayerDeath = () -> {
+            synchronized (mAtm.mGlobalLock) {
+                // Clean-up/finish any playing transitions.
+                for (int i = 0; i < mPlayingTransitions.size(); ++i) {
+                    mPlayingTransitions.get(i).cleanUpOnFailure();
+                }
+                mPlayingTransitions.clear();
+                mTransitionPlayer = null;
+                mRunningLock.doNotifyLocked();
+            }
+        };
     }
 
     /** @see #createTransition(int, int) */
diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
index 70822ee..073a508 100644
--- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java
+++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
@@ -21,7 +21,6 @@
 import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION;
 import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_NONE;
 
-import android.annotation.ColorInt;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.SystemClock;
@@ -86,12 +85,6 @@
     }
 
     @Override
-    @ColorInt
-    public int getBackgroundColor() {
-        return mAnimation.getBackgroundColor();
-    }
-
-    @Override
     public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
         final TmpValues tmp = mThreadLocalTmps.get();
         tmp.transformation.clear();
@@ -125,16 +118,30 @@
     @Override
     public long calculateStatusBarTransitionStartTime() {
         TranslateAnimation openTranslateAnimation = findTranslateAnimation(mAnimation);
-        if (openTranslateAnimation != null) {
 
-            // Some interpolators are extremely quickly mostly finished, but not completely. For
-            // our purposes, we need to find the fraction for which ther interpolator is mostly
-            // there, and use that value for the calculation.
-            float t = findAlmostThereFraction(openTranslateAnimation.getInterpolator());
-            return SystemClock.uptimeMillis()
-                    + openTranslateAnimation.getStartOffset()
-                    + (long)(openTranslateAnimation.getDuration() * t)
-                    - STATUS_BAR_TRANSITION_DURATION;
+        if (openTranslateAnimation != null) {
+            if (openTranslateAnimation.isXAxisTransition()
+                    && openTranslateAnimation.isFullWidthTranslate()) {
+                // On X axis transitions that are fullscreen (heuristic for task like transitions)
+                // we want the status bar to animate right in the middle of the translation when
+                // the windows/tasks have each moved half way across.
+                float t = findMiddleOfTranslationFraction(openTranslateAnimation.getInterpolator());
+
+                return SystemClock.uptimeMillis()
+                        + openTranslateAnimation.getStartOffset()
+                        + (long) (openTranslateAnimation.getDuration() * t)
+                        - (long) (STATUS_BAR_TRANSITION_DURATION * 0.5);
+            } else {
+                // Some interpolators are extremely quickly mostly finished, but not completely. For
+                // our purposes, we need to find the fraction for which their interpolator is mostly
+                // there, and use that value for the calculation.
+                float t = findAlmostThereFraction(openTranslateAnimation.getInterpolator());
+
+                return SystemClock.uptimeMillis()
+                        + openTranslateAnimation.getStartOffset()
+                        + (long) (openTranslateAnimation.getDuration() * t)
+                        - STATUS_BAR_TRANSITION_DURATION;
+            }
         } else {
             return SystemClock.uptimeMillis();
         }
@@ -183,20 +190,39 @@
     }
 
     /**
-     * Binary searches for a {@code t} such that there exists a {@code -0.01 < eps < 0.01} for which
-     * {@code interpolator(t + eps) > 0.99}.
+     * Finds the fraction of the animation's duration at which the transition is almost done with a
+     * maximal error of 0.01 when it is animated with {@code interpolator}.
      */
     private static float findAlmostThereFraction(Interpolator interpolator) {
+        return findInterpolationAdjustedTargetFraction(interpolator, 0.99f, 0.01f);
+    }
+
+    /**
+     * Finds the fraction of the animation's duration at which the transition is spacially half way
+     * done with a maximal error of 0.01 when it is animated with {@code interpolator}.
+     */
+    private float findMiddleOfTranslationFraction(Interpolator interpolator) {
+        return findInterpolationAdjustedTargetFraction(interpolator, 0.5f, 0.01f);
+    }
+
+    /**
+     * Binary searches for a {@code val} such that there exists an {@code -0.01 < epsilon < 0.01}
+     * for which {@code interpolator(val + epsilon) > target}.
+     */
+    private static float findInterpolationAdjustedTargetFraction(
+            Interpolator interpolator, float target, float epsilon) {
         float val = 0.5f;
         float adj = 0.25f;
-        while (adj >= 0.01f) {
-            if (interpolator.getInterpolation(val) < 0.99f) {
+
+        while (adj >= epsilon) {
+            if (interpolator.getInterpolation(val) < target) {
                 val += adj;
             } else {
                 val -= adj;
             }
             adj /= 2;
         }
+
         return val;
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 578e971..fe3e560 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -32,6 +32,10 @@
 import static android.view.SurfaceControl.Transaction;
 import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
 import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_BACK;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_FRONT;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
@@ -62,10 +66,13 @@
 import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_AFTER_ANIM;
 
 import android.annotation.CallSuper;
+import android.annotation.ColorInt;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityThread;
 import android.app.WindowConfiguration;
+import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Point;
@@ -91,6 +98,7 @@
 import android.window.IWindowContainerToken;
 import android.window.WindowContainerToken;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.ToBooleanFunction;
@@ -857,6 +865,12 @@
         return parent != null ? parent.getRootDisplayArea() : null;
     }
 
+    @Nullable
+    TaskDisplayArea getTaskDisplayArea() {
+        WindowContainer parent = getParent();
+        return parent != null ? parent.getTaskDisplayArea() : null;
+    }
+
     boolean isAttached() {
         WindowContainer parent = getParent();
         return parent != null && parent.isAttached();
@@ -2321,10 +2335,15 @@
     }
 
     protected void setLayer(Transaction t, int layer) {
-
-        // Route through surface animator to accommodate that our surface control might be
-        // attached to the leash, and leash is attached to parent container.
-        mSurfaceAnimator.setLayer(t, layer);
+        if (mSurfaceFreezer.hasLeash()) {
+            // When the freezer has created animation leash parent for the window, set the layer
+            // there instead.
+            mSurfaceFreezer.setLayer(t, layer);
+        } else {
+            // Route through surface animator to accommodate that our surface control might be
+            // attached to the leash, and leash is attached to parent container.
+            mSurfaceAnimator.setLayer(t, layer);
+        }
     }
 
     int getLastLayer() {
@@ -2332,10 +2351,15 @@
     }
 
     protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
-
-        // Route through surface animator to accommodate that our surface control might be
-        // attached to the leash, and leash is attached to parent container.
-        mSurfaceAnimator.setRelativeLayer(t, relativeTo, layer);
+        if (mSurfaceFreezer.hasLeash()) {
+            // When the freezer has created animation leash parent for the window, set the layer
+            // there instead.
+            mSurfaceFreezer.setRelativeLayer(t, relativeTo, layer);
+        } else {
+            // Route through surface animator to accommodate that our surface control might be
+            // attached to the leash, and leash is attached to parent container.
+            mSurfaceAnimator.setRelativeLayer(t, relativeTo, layer);
+        }
     }
 
     protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) {
@@ -2555,10 +2579,13 @@
      *               some point but the meaning is too weird to work for all containers.
      * @param type The type of animation defined as {@link AnimationType}.
      * @param animationFinishedCallback The callback being triggered when the animation finishes.
+     * @param animationCancelledCallback The callback is triggered after the SurfaceAnimator sends a
+     *                                   cancel call to the underlying AnimationAdapter.
      */
     void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
             @AnimationType int type,
-            @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
+            @Nullable OnAnimationFinishedCallback animationFinishedCallback,
+            @Nullable Runnable animationCancelledCallback) {
         if (DEBUG_ANIM) {
             Slog.v(TAG, "Starting animation on " + this + ": type=" + type + ", anim=" + anim);
         }
@@ -2566,7 +2593,14 @@
         // TODO: This should use isVisible() but because isVisible has a really weird meaning at
         // the moment this doesn't work for all animatable window containers.
         mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback,
-                mSurfaceFreezer);
+                animationCancelledCallback, mSurfaceFreezer);
+    }
+
+    void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
+            @AnimationType int type,
+            @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
+        startAnimation(t, anim, hidden, type, animationFinishedCallback,
+                null /* adapterAnimationCancelledCallback */);
     }
 
     void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@@ -2593,11 +2627,20 @@
      * 3. {@link ActivityRecord} is reparented into an organized {@link TaskFragment}.
      *
      * This shouldn't be called on other {@link WindowContainer} unless there is a valid use case.
+     *
+     * @param startBounds The original bounds (on screen) of the surface we are snapshotting.
+     * @param parentBounds The parent bounds (on screen) to calculate the animation surface
+     *                     position.
      */
-    void initializeChangeTransition(Rect startBounds) {
+    void initializeChangeTransition(Rect startBounds, Rect parentBounds) {
         mDisplayContent.prepareAppTransition(TRANSIT_CHANGE);
         mDisplayContent.mChangingContainers.add(this);
-        mSurfaceFreezer.freeze(getSyncTransaction(), startBounds);
+        mTmpPoint.set(startBounds.left - parentBounds.left, startBounds.top - parentBounds.top);
+        mSurfaceFreezer.freeze(getSyncTransaction(), startBounds, mTmpPoint);
+    }
+
+    void initializeChangeTransition(Rect startBounds) {
+        initializeChangeTransition(startBounds, getParent().getBounds());
     }
 
     ArraySet<WindowContainer> getAnimationSources() {
@@ -2800,8 +2843,26 @@
             if (sources != null) {
                 mSurfaceAnimationSources.addAll(sources);
             }
+
+            TaskDisplayArea taskDisplayArea = getTaskDisplayArea();
+            boolean isSettingBackgroundColor = taskDisplayArea != null
+                    && isTransitionWithBackgroundColor(transit);
+
+            if (isSettingBackgroundColor) {
+                Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
+                @ColorInt int backgroundColor = uiContext.getColor(R.color.overview_background);
+
+                taskDisplayArea.setBackgroundColor(backgroundColor);
+            }
+
+            final Runnable cleanUpCallback = isSettingBackgroundColor
+                    ? taskDisplayArea::clearBackgroundColor : () -> {};
+
             startAnimation(getPendingTransaction(), adapter, !isVisible(),
-                    ANIMATION_TYPE_APP_TRANSITION);
+                    ANIMATION_TYPE_APP_TRANSITION,
+                    (type, anim) -> cleanUpCallback.run(),
+                    cleanUpCallback);
+
             if (adapter.getShowWallpaper()) {
                 getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
             }
@@ -2812,6 +2873,13 @@
         }
     }
 
+    private boolean isTransitionWithBackgroundColor(@TransitionOldType int transit) {
+        return transit == TRANSIT_OLD_TASK_OPEN
+                || transit == TRANSIT_OLD_TASK_CLOSE
+                || transit == TRANSIT_OLD_TASK_TO_FRONT
+                || transit == TRANSIT_OLD_TASK_TO_BACK;
+    }
+
     final SurfaceAnimationRunner getSurfaceAnimationRunner() {
         return mWmService.mSurfaceAnimationRunner;
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b4b2bdc..e6615e1 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -173,8 +173,10 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
-import android.hardware.configstore.V1_0.ISurfaceFlingerConfigs;
 import android.hardware.configstore.V1_0.OptionalBool;
+import android.hardware.configstore.V1_1.DisplayOrientation;
+import android.hardware.configstore.V1_1.ISurfaceFlingerConfigs;
+import android.hardware.configstore.V1_1.OptionalDisplayOrientation;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.input.InputManager;
@@ -227,6 +229,7 @@
 import android.util.proto.ProtoOutputStream;
 import android.view.Choreographer;
 import android.view.Display;
+import android.view.DisplayAddress;
 import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.IAppTransitionAnimationSpecsFuture;
@@ -451,6 +454,8 @@
      */
     static final boolean ENABLE_FIXED_ROTATION_TRANSFORM =
             SystemProperties.getBoolean("persist.wm.fixed_rotation_transform", true);
+    private @Surface.Rotation int mPrimaryDisplayOrientation = Surface.ROTATION_0;
+    private DisplayAddress mPrimaryDisplayPhysicalAddress;
 
     // Enums for animation scale update types.
     @Retention(RetentionPolicy.SOURCE)
@@ -2461,16 +2466,21 @@
             configChanged = displayContent.updateOrientation();
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
 
-            final DisplayInfo rotatedDisplayInfo =
-                    win.mToken.getFixedRotationTransformDisplayInfo();
-            if (rotatedDisplayInfo != null) {
-                outSurfaceControl.setTransformHint(rotatedDisplayInfo.rotation);
-            } else {
-                // We have to update the transform hint of display here, but we need to get if from
-                // SurfaceFlinger, so set it as rotation of display for most cases, then
-                // SurfaceFlinger would still update the transform hint of display in next frame.
-                outSurfaceControl.setTransformHint(displayContent.getDisplayInfo().rotation);
+            final DisplayInfo displayInfo = win.getDisplayInfo();
+            int transformHint = displayInfo.rotation;
+            // If the window is on the primary display, use the panel orientation to adjust the
+            // transform hint
+            final boolean isPrimaryDisplay = displayInfo.address != null &&
+                    displayInfo.address.equals(mPrimaryDisplayPhysicalAddress);
+            if (isPrimaryDisplay) {
+                transformHint = (transformHint + mPrimaryDisplayOrientation) % 4;
             }
+            outSurfaceControl.setTransformHint(transformHint);
+            ProtoLog.v(WM_DEBUG_ORIENTATION,
+                    "Passing transform hint %d for window %s%s",
+                    transformHint, win,
+                    isPrimaryDisplay ? " on primary display with orientation "
+                            + mPrimaryDisplayOrientation : "");
 
             if (toBeDisplayed && win.mIsWallpaper) {
                 displayContent.mWallpaperController.updateWallpaperOffset(win, false /* sync */);
@@ -4876,6 +4886,9 @@
         mTaskSnapshotController.systemReady();
         mHasWideColorGamutSupport = queryWideColorGamutSupport();
         mHasHdrSupport = queryHdrSupport();
+        mPrimaryDisplayOrientation = queryPrimaryDisplayOrientation();
+        mPrimaryDisplayPhysicalAddress =
+            DisplayAddress.fromPhysicalDisplayId(SurfaceControl.getPrimaryPhysicalDisplayId());
         UiThread.getHandler().post(mSettingsObserver::loadSettings);
         IVrManager vrManager = IVrManager.Stub.asInterface(
                 ServiceManager.getService(Context.VR_SERVICE));
@@ -4895,6 +4908,9 @@
         }
     }
 
+
+    // Keep logic in sync with SurfaceFlingerProperties.cpp
+    // Consider exposing properties via ISurfaceComposer instead.
     private static boolean queryWideColorGamutSupport() {
         boolean defaultValue = false;
         Optional<Boolean> hasWideColorProp = SurfaceFlingerProperties.has_wide_color_display();
@@ -4935,6 +4951,39 @@
         return false;
     }
 
+    private static @Surface.Rotation int queryPrimaryDisplayOrientation() {
+        Optional<SurfaceFlingerProperties.primary_display_orientation_values> prop =
+                SurfaceFlingerProperties.primary_display_orientation();
+        if (prop.isPresent()) {
+            switch (prop.get()) {
+                case ORIENTATION_90: return Surface.ROTATION_90;
+                case ORIENTATION_180: return Surface.ROTATION_180;
+                case ORIENTATION_270: return Surface.ROTATION_270;
+                case ORIENTATION_0:
+                default:
+                    return Surface.ROTATION_0;
+            }
+        }
+        try {
+            ISurfaceFlingerConfigs surfaceFlinger = ISurfaceFlingerConfigs.getService();
+            OptionalDisplayOrientation primaryDisplayOrientation =
+                    surfaceFlinger.primaryDisplayOrientation();
+            if (primaryDisplayOrientation != null && primaryDisplayOrientation.specified) {
+                switch (primaryDisplayOrientation.value) {
+                    case DisplayOrientation.ORIENTATION_90: return Surface.ROTATION_90;
+                    case DisplayOrientation.ORIENTATION_180: return Surface.ROTATION_180;
+                    case DisplayOrientation.ORIENTATION_270: return Surface.ROTATION_270;
+                    case DisplayOrientation.ORIENTATION_0:
+                    default:
+                        return Surface.ROTATION_0;
+                }
+            }
+        } catch (Exception e) {
+            // Use default value if we can't talk to config store.
+        }
+        return Surface.ROTATION_0;
+    }
+
     void reportFocusChanged(IBinder oldToken, IBinder newToken) {
         WindowState lastFocus;
         WindowState newFocus;
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 834b6e6..6931381 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -122,7 +122,8 @@
      * A Map which manages the relationship between
      * {@link TaskFragmentCreationParams#getFragmentToken()} and {@link TaskFragment}
      */
-    private final ArrayMap<IBinder, TaskFragment> mLaunchTaskFragments = new ArrayMap<>();
+    @VisibleForTesting
+    final ArrayMap<IBinder, TaskFragment> mLaunchTaskFragments = new ArrayMap<>();
 
     WindowOrganizerController(ActivityTaskManagerService atm) {
         mService = atm;
@@ -317,7 +318,7 @@
      * @param caller Info about the calling process.
      */
     private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
-            @Nullable Transition transition, @Nullable CallerInfo caller) {
+            @Nullable Transition transition, @NonNull CallerInfo caller) {
         int effects = 0;
         ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
         mService.deferWindowLayout();
@@ -326,7 +327,7 @@
             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()) {
+                if (dc != null && transition.mChanges.get(dc).hasChanged(dc)) {
                     // Go through all tasks and collect them before the rotation
                     // TODO(shell-transitions): move collect() to onConfigurationChange once
                     //       wallpaper handling is synchronized.
@@ -539,7 +540,7 @@
 
     private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
             int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
-            @Nullable CallerInfo caller, @Nullable IBinder errorCallbackToken,
+            @NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,
             @Nullable ITaskFragmentOrganizer organizer) {
         final int type = hop.getType();
         switch (type) {
@@ -627,11 +628,28 @@
                 final int taskId = launchOpts.getInt(
                         WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
                 launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
-                final SafeActivityOptions safeOptions = caller != null
-                        ? SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid)
-                        : SafeActivityOptions.fromBundle(launchOpts);
-                mService.mTaskSupervisor.startActivityFromRecents(caller.mPid, caller.mUid,
-                        taskId, safeOptions);
+                final SafeActivityOptions safeOptions =
+                        SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);
+                final Integer[] starterResult = { null };
+                // startActivityFromRecents should not be called in lock.
+                mService.mH.post(() -> {
+                    try {
+                        starterResult[0] = mService.mTaskSupervisor.startActivityFromRecents(
+                                caller.mPid, caller.mUid, taskId, safeOptions);
+                    } catch (Throwable t) {
+                        starterResult[0] = ActivityManager.START_CANCELED;
+                        Slog.w(TAG, t);
+                    }
+                    synchronized (mGlobalLock) {
+                        mGlobalLock.notifyAll();
+                    }
+                });
+                while (starterResult[0] == null) {
+                    try {
+                        mGlobalLock.wait();
+                    } catch (InterruptedException ignored) {
+                    }
+                }
                 break;
             case HIERARCHY_OP_TYPE_PENDING_INTENT:
                 String resolvedType = hop.getActivityIntent() != null
@@ -672,7 +690,7 @@
                     throw new IllegalArgumentException(
                             "Can only delete organized TaskFragment, but not Task.");
                 }
-                deleteTaskFragment(taskFragment, errorCallbackToken);
+                effects |= deleteTaskFragment(taskFragment, errorCallbackToken);
                 break;
             case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
                 fragmentToken = hop.getContainer();
@@ -704,6 +722,7 @@
                     break;
                 }
                 activity.reparent(mLaunchTaskFragments.get(fragmentToken), POSITION_TOP);
+                effects |= TRANSACT_EFFECTS_LIFECYCLE;
                 break;
             case HIERARCHY_OP_TYPE_REPARENT_CHILDREN:
                 final WindowContainer oldParent = WindowContainer.fromBinder(hop.getContainer());
@@ -716,6 +735,7 @@
                     break;
                 }
                 reparentTaskFragment(oldParent, newParent, errorCallbackToken);
+                effects |= TRANSACT_EFFECTS_LIFECYCLE;
                 break;
             case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS:
                 fragmentToken = hop.getContainer();
@@ -731,6 +751,7 @@
                     break;
                 }
                 tf1.setAdjacentTaskFragment(tf2);
+                effects |= TRANSACT_EFFECTS_LIFECYCLE;
 
                 final Bundle bundle = hop.getLaunchOptions();
                 final WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams =
@@ -1175,7 +1196,7 @@
         }
     }
 
-    void deleteTaskFragment(@NonNull TaskFragment taskFragment,
+    private int deleteTaskFragment(@NonNull TaskFragment taskFragment,
             @Nullable IBinder errorCallbackToken) {
         final int index = mLaunchTaskFragments.indexOfValue(taskFragment);
         if (index < 0) {
@@ -1184,10 +1205,11 @@
                             + "taskFragment");
             sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(),
                     errorCallbackToken, exception);
-            return;
+            return 0;
         }
         mLaunchTaskFragments.removeAt(index);
         taskFragment.remove(true /* withTransition */, "deleteTaskFragment");
+        return TRANSACT_EFFECTS_LIFECYCLE;
     }
 
     @Nullable
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c30db19..ed98b9d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -26,7 +26,6 @@
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.graphics.GraphicsProtos.dumpPointProto;
 import static android.hardware.display.DisplayManager.SWITCHING_TYPE_NONE;
-import static android.hardware.input.InputManager.BLOCK_UNTRUSTED_TOUCHES;
 import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.os.PowerManager.DRAW_WAKE_LOCK;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
@@ -196,7 +195,6 @@
 import android.app.ActivityTaskManager;
 import android.app.AppOpsManager;
 import android.app.admin.DevicePolicyCache;
-import android.app.compat.CompatChanges;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Matrix;
@@ -1172,9 +1170,6 @@
     }
 
     int getTouchOcclusionMode() {
-        if (!CompatChanges.isChangeEnabled(BLOCK_UNTRUSTED_TOUCHES, mOwnerUid)) {
-            return TouchOcclusionMode.ALLOW;
-        }
         if (WindowManager.LayoutParams.isSystemAlertWindowType(mAttrs.type)) {
             return TouchOcclusionMode.USE_OPACITY;
         }
@@ -2582,8 +2577,7 @@
                     }
                 }
                 final boolean isAnimating = mAnimatingExit
-                        || isAnimating(TRANSITION | PARENTS, EXIT_ANIMATING_TYPES)
-                        && (mActivityRecord == null || !mActivityRecord.isWaitingForTransitionStart());
+                        || isAnimating(TRANSITION | PARENTS, EXIT_ANIMATING_TYPES);
                 final boolean lastWindowIsStartingWindow = startingWindow && mActivityRecord != null
                         && mActivityRecord.isLastWindow(this);
                 // We delay the removal of a window if it has a showing surface that can be used to run
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index aa5b209..dae1275 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -645,6 +645,21 @@
         TimeUtils.formatDuration(mRuntimeStartElapsedTime, pw); pw.println();
     }
 
+    /**
+     * Service used to dump {@link SystemServer} state that is not associated with any service.
+     *
+     * <p>To dump all services:
+     *
+     * <pre><code>adb shell dumpsys system_server_dumper</code></pre>
+     *
+     * <p>To get a list of all services:
+     *
+     * <pre><code>adb shell dumpsys system_server_dumper --list</code></pre>
+     *
+     * <p>To dump a specific service (use {@code --list} above to get service names):
+     *
+     * <pre><code>adb shell dumpsys system_server_dumper --name NAME</code></pre>
+     */
     private final class SystemServerDumper extends Binder {
 
         @GuardedBy("mDumpables")
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index ff7cd75..680e6db 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -37,6 +37,7 @@
     ],
 
     static_libs: [
+        "frameworks-base-testutils",
         "services.core",
         "services.devicepolicy",
         "services.net",
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 16afef5..942958c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -63,6 +63,7 @@
 import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES;
 import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_ALARMS;
 import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_FOR_CANCELED;
+import static com.android.server.alarm.AlarmManagerService.AlarmHandler.TARE_AFFORDABILITY_CHANGED;
 import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA;
 import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_COMPAT_WINDOW;
 import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_QUOTA;
@@ -109,6 +110,7 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
 import android.app.AlarmManager;
 import android.app.AppOpsManager;
 import android.app.BroadcastOptions;
@@ -119,9 +121,12 @@
 import android.app.PendingIntent;
 import android.app.compat.CompatChanges;
 import android.app.usage.UsageStatsManagerInternal;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManagerInternal;
+import android.database.ContentObserver;
+import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.Bundle;
 import android.os.Handler;
@@ -137,6 +142,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
+import android.text.format.DateFormat;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -157,6 +163,7 @@
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.tare.EconomyManagerInternal;
 import com.android.server.usage.AppStandbyInternal;
 
 import libcore.util.EmptyArray;
@@ -200,6 +207,8 @@
     @Mock
     private Context mMockContext;
     @Mock
+    private ContentResolver mContentResolver;
+    @Mock
     private IActivityManager mIActivityManager;
     @Mock
     private IAppOpsService mIAppOpsService;
@@ -224,6 +233,8 @@
     @Mock
     private PowerManager.WakeLock mWakeLock;
     @Mock
+    private EconomyManagerInternal mEconomyManagerInternal;
+    @Mock
     DeviceConfig.Properties mDeviceConfigProperties;
     HashSet<String> mDeviceConfigKeys = new HashSet<>();
 
@@ -349,6 +360,11 @@
         }
 
         @Override
+        void registerContentObserver(ContentObserver observer, Uri uri) {
+            // Do nothing.
+        }
+
+        @Override
         void registerDeviceConfigListener(DeviceConfig.OnPropertiesChangedListener listener) {
             // Do nothing.
             // The tests become flaky with an error message of
@@ -368,6 +384,7 @@
                 .initMocks(this)
                 .spyStatic(ActivityManager.class)
                 .mockStatic(CompatChanges.class)
+                .spyStatic(DateFormat.class)
                 .spyStatic(DeviceConfig.class)
                 .mockStatic(LocalServices.class)
                 .spyStatic(Looper.class)
@@ -383,6 +400,8 @@
         doReturn(mIActivityManager).when(ActivityManager::getService);
         doReturn(mDeviceIdleInternal).when(
                 () -> LocalServices.getService(DeviceIdleInternal.class));
+        doReturn(mEconomyManagerInternal).when(
+                () -> LocalServices.getService(EconomyManagerInternal.class));
         doReturn(mPermissionManagerInternal).when(
                 () -> LocalServices.getService(PermissionManagerServiceInternal.class));
         doReturn(mActivityManagerInternal).when(
@@ -402,6 +421,8 @@
                 eq(TEST_CALLING_USER), anyLong())).thenReturn(STANDBY_BUCKET_ACTIVE);
         doReturn(Looper.getMainLooper()).when(Looper::myLooper);
 
+        when(mMockContext.getContentResolver()).thenReturn(mContentResolver);
+
         doReturn(mDeviceConfigKeys).when(mDeviceConfigProperties).getKeyset();
         when(mDeviceConfigProperties.getLong(anyString(), anyLong()))
                 .thenAnswer((Answer<Long>) invocationOnMock -> {
@@ -420,6 +441,9 @@
         doReturn(mDeviceConfigProperties).when(
                 () -> DeviceConfig.getProperties(
                         eq(DeviceConfig.NAMESPACE_ALARM_MANAGER), ArgumentMatchers.<String>any()));
+        // Needed to ensure logging doesn't cause tests to fail.
+        doReturn(true)
+                .when(() -> DateFormat.is24HourFormat(eq(mMockContext), anyInt()));
 
         when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
 
@@ -446,6 +470,7 @@
 
         // Other boot phases don't matter
         mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
+        setTareEnabled(false);
         mAppStandbyWindow = mService.mConstants.APP_STANDBY_WINDOW;
         mAllowWhileIdleWindow = mService.mConstants.ALLOW_WHILE_IDLE_WINDOW;
         ArgumentCaptor<AppStandbyInternal.AppIdleStateChangeListener> captor =
@@ -550,15 +575,24 @@
                 FLAG_STANDALONE, null, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE, null, 0);
     }
 
-
     private PendingIntent getNewMockPendingIntent() {
-        return getNewMockPendingIntent(TEST_CALLING_UID, TEST_CALLING_PACKAGE);
+        return getNewMockPendingIntent(false);
+    }
+
+    private PendingIntent getNewMockPendingIntent(boolean isActivity) {
+        return getNewMockPendingIntent(TEST_CALLING_UID, TEST_CALLING_PACKAGE, isActivity);
     }
 
     private PendingIntent getNewMockPendingIntent(int creatorUid, String creatorPackage) {
+        return getNewMockPendingIntent(creatorUid, creatorPackage, false);
+    }
+
+    private PendingIntent getNewMockPendingIntent(int creatorUid, String creatorPackage,
+            boolean isActivity) {
         final PendingIntent mockPi = mock(PendingIntent.class, Answers.RETURNS_DEEP_STUBS);
         when(mockPi.getCreatorUid()).thenReturn(creatorUid);
         when(mockPi.getCreatorPackage()).thenReturn(creatorPackage);
+        when(mockPi.isActivity()).thenReturn(isActivity);
         return mockPi;
     }
 
@@ -586,6 +620,15 @@
         mService.mConstants.onPropertiesChanged(mDeviceConfigProperties);
     }
 
+    private void setTareEnabled(boolean enabled) {
+        doReturn(enabled ? 1 : 0).when(
+                () -> Settings.Global.getInt(mContentResolver, Settings.Global.ENABLE_TARE));
+        doReturn(enabled ? 1 : 0).when(
+                () -> Settings.Global.getInt(mContentResolver,
+                        Settings.Global.ENABLE_TARE, Settings.Global.DEFAULT_ENABLE_TARE));
+        mService.mConstants.onChange(true);
+    }
+
     /**
      * Lowers quotas to make testing feasible. Careful while calling as this will replace any
      * existing settings for the calling test.
@@ -1978,6 +2021,44 @@
     }
 
     @Test
+    public void tareThrottling() {
+        setTareEnabled(true);
+        final ArgumentCaptor<EconomyManagerInternal.AffordabilityChangeListener> listenerCaptor =
+                ArgumentCaptor.forClass(EconomyManagerInternal.AffordabilityChangeListener.class);
+        final ArgumentCaptor<EconomyManagerInternal.ActionBill> billCaptor =
+                ArgumentCaptor.forClass(EconomyManagerInternal.ActionBill.class);
+
+        when(mEconomyManagerInternal
+                .canPayFor(eq(TEST_CALLING_USER), eq(TEST_CALLING_PACKAGE), billCaptor.capture()))
+                .thenReturn(false);
+
+        final PendingIntent alarmPi = getNewMockPendingIntent();
+        setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 15, alarmPi);
+        assertEquals(mNowElapsedTest + INDEFINITE_DELAY, mTestTimer.getElapsed());
+
+        final EconomyManagerInternal.ActionBill bill = billCaptor.getValue();
+        verify(mEconomyManagerInternal).registerAffordabilityChangeListener(
+                eq(TEST_CALLING_USER), eq(TEST_CALLING_PACKAGE),
+                listenerCaptor.capture(), eq(bill));
+        final EconomyManagerInternal.AffordabilityChangeListener listener =
+                listenerCaptor.getValue();
+
+        when(mEconomyManagerInternal
+                .canPayFor(eq(TEST_CALLING_USER), eq(TEST_CALLING_PACKAGE), eq(bill)))
+                .thenReturn(true);
+        listener.onAffordabilityChanged(TEST_CALLING_USER, TEST_CALLING_PACKAGE, bill, true);
+        assertAndHandleMessageSync(TARE_AFFORDABILITY_CHANGED);
+        assertEquals(mNowElapsedTest + 15, mTestTimer.getElapsed());
+
+        when(mEconomyManagerInternal
+                .canPayFor(eq(TEST_CALLING_USER), eq(TEST_CALLING_PACKAGE), eq(bill)))
+                .thenReturn(false);
+        listener.onAffordabilityChanged(TEST_CALLING_USER, TEST_CALLING_PACKAGE, bill, false);
+        assertAndHandleMessageSync(TARE_AFFORDABILITY_CHANGED);
+        assertEquals(mNowElapsedTest + INDEFINITE_DELAY, mTestTimer.getElapsed());
+    }
+
+    @Test
     public void dispatchOrder() throws Exception {
         setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, 0);
 
@@ -2801,21 +2882,57 @@
                 anyString()));
     }
 
-    @Test
-    public void idleOptionsSentOnExpiration() throws Exception {
+    private void optionsSentOnExpiration(boolean isActivity, Bundle idleOptions)
+            throws Exception {
         final long triggerTime = mNowElapsedTest + 5000;
-        final PendingIntent alarmPi = getNewMockPendingIntent();
-        final Bundle idleOptions = new Bundle();
-        idleOptions.putChar("TEST_CHAR_KEY", 'x');
-        idleOptions.putInt("TEST_INT_KEY", 53);
+        final PendingIntent alarmPi = getNewMockPendingIntent(isActivity);
         setTestAlarm(ELAPSED_REALTIME_WAKEUP, triggerTime, 0, alarmPi, 0, 0, TEST_CALLING_UID,
                 idleOptions);
 
         mNowElapsedTest = mTestTimer.getElapsed();
         mTestTimer.expire();
 
+        ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
         verify(alarmPi).send(eq(mMockContext), eq(0), any(Intent.class),
-                any(), any(Handler.class), isNull(), eq(idleOptions));
+                any(), any(Handler.class), isNull(), bundleCaptor.capture());
+        if (idleOptions != null) {
+            assertEquals(idleOptions, bundleCaptor.getValue());
+        } else {
+            if (isActivity) {
+                assertFalse("BAL flag needs to be false in alarm manager",
+                        bundleCaptor.getValue().getBoolean(
+                                ActivityOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED,
+                                true));
+            } else {
+                assertNull(bundleCaptor.getValue());
+            }
+        }
+    }
+
+    @Test
+    public void activityIdleOptionsSentOnExpiration() throws Exception {
+        final Bundle idleOptions = new Bundle();
+        idleOptions.putChar("TEST_CHAR_KEY", 'x');
+        idleOptions.putInt("TEST_INT_KEY", 53);
+        optionsSentOnExpiration(true, idleOptions);
+    }
+
+    @Test
+    public void broadcastIdleOptionsSentOnExpiration() throws Exception {
+        final Bundle idleOptions = new Bundle();
+        idleOptions.putChar("TEST_CHAR_KEY", 'x');
+        idleOptions.putInt("TEST_INT_KEY", 53);
+        optionsSentOnExpiration(false, idleOptions);
+    }
+
+    @Test
+    public void emptyActivityOptionsSentOnExpiration() throws Exception {
+        optionsSentOnExpiration(true, null);
+    }
+
+    @Test
+    public void emptyBroadcastOptionsSentOnExpiration() throws Exception {
+        optionsSentOnExpiration(false, null);
     }
 
     @Test
@@ -3020,6 +3137,23 @@
     }
 
     @Test
+    public void tareEventPushed() throws Exception {
+        setTareEnabled(true);
+
+        for (int i = 0; i < 10; i++) {
+            final int type = (i % 2 == 1) ? ELAPSED_REALTIME : ELAPSED_REALTIME_WAKEUP;
+            setTestAlarm(type, mNowElapsedTest + i, getNewMockPendingIntent());
+        }
+
+        final ArrayList<Alarm> alarms = mService.mAlarmStore.remove((alarm) -> {
+            return alarm.creatorUid == TEST_CALLING_UID;
+        });
+        mService.deliverAlarmsLocked(alarms, mNowElapsedTest);
+        verify(mEconomyManagerInternal, times(10)).noteInstantaneousEvent(
+                eq(TEST_CALLING_USER), eq(TEST_CALLING_PACKAGE), anyInt(), any());
+    }
+
+    @Test
     public void setTimeZoneImpl() {
         final long durationMs = 20000L;
         when(mActivityManagerInternal.getBootTimeTempAllowListDuration()).thenReturn(durationMs);
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java
index f11cba0..a129f39 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java
@@ -28,6 +28,7 @@
 import static com.android.server.alarm.Alarm.NUM_POLICIES;
 import static com.android.server.alarm.Alarm.REQUESTER_POLICY_INDEX;
 import static com.android.server.alarm.AlarmManagerService.isExemptFromAppStandby;
+import static com.android.server.alarm.AlarmManagerService.isExemptFromTare;
 import static com.android.server.alarm.Constants.TEST_CALLING_PACKAGE;
 import static com.android.server.alarm.Constants.TEST_CALLING_UID;
 
@@ -193,4 +194,20 @@
                 createDefaultAlarm(anything, anything, FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED)));
         assertTrue("Alarm clock not exempt", isExemptFromAppStandby(createAlarmClock(anything)));
     }
+
+    @Test
+    public void testIsExemptFromTare() {
+        final long anything = 54321;    // Arbitrary number, doesn't matter for this test.
+
+        assertFalse("Basic alarm exempt", isExemptFromTare(
+                createDefaultAlarm(anything, anything, 0)));
+        assertFalse("FLAG_ALLOW_WHILE_IDLE_COMPAT exempt", isExemptFromTare(
+                createDefaultAlarm(anything, anything, FLAG_ALLOW_WHILE_IDLE_COMPAT)));
+        assertFalse("ALLOW_WHILE_IDLE exempt", isExemptFromTare(
+                createDefaultAlarm(anything, anything, FLAG_ALLOW_WHILE_IDLE)));
+
+        assertTrue("ALLOW_WHILE_IDLE_UNRESTRICTED not exempt", isExemptFromTare(
+                createDefaultAlarm(anything, anything, FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED)));
+        assertTrue("Alarm clock not exempt", isExemptFromTare(createAlarmClock(anything)));
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index 85ef8f7..1c21645 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -34,6 +34,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
+import android.os.test.TestLooper;
 import android.platform.test.annotations.Presubmit;
 import android.provider.DeviceConfig;
 import android.util.ArraySet;
@@ -67,6 +68,7 @@
 
     private MockitoSession mMockingSession;
     private String mPackageName;
+    private TestLooper mTestLooper;
     @Mock
     private PackageManager mMockPackageManager;
 
@@ -132,6 +134,7 @@
 
     @Before
     public void setUp() throws Exception {
+        mTestLooper = new TestLooper();
         mMockingSession = mockitoSession()
                 .initMocks(this)
                 .mockStatic(DeviceConfig.class)
@@ -161,6 +164,11 @@
         }
     }
 
+    private void startUser(GameManagerService gameManagerService, int userId) {
+        gameManagerService.onUserStarting(userId);
+        mTestLooper.dispatchAll();
+    }
+
     private void mockModifyGameModeGranted() {
         mMockContext.setPermission(Manifest.permission.MANAGE_GAME_MODE,
                 PackageManager.PERMISSION_GRANTED);
@@ -301,9 +309,10 @@
      */
     @Test
     public void testGameModeDefaultValue() {
-        GameManagerService gameManagerService = new GameManagerService(mMockContext);
-        gameManagerService.onUserStarting(USER_ID_1);
+        GameManagerService gameManagerService =
+                new GameManagerService(mMockContext, mTestLooper.getLooper());
 
+        startUser(gameManagerService, USER_ID_1);
         mockModifyGameModeGranted();
 
         assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
@@ -315,9 +324,10 @@
      */
     @Test
     public void testDefaultValueForNonexistentUser() {
-        GameManagerService gameManagerService = new GameManagerService(mMockContext);
-        gameManagerService.onUserStarting(USER_ID_1);
+        GameManagerService gameManagerService =
+                new GameManagerService(mMockContext, mTestLooper.getLooper());
 
+        startUser(gameManagerService, USER_ID_1);
         mockModifyGameModeGranted();
 
         gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_2);
@@ -330,8 +340,11 @@
      */
     @Test
     public void testGameMode() {
-        GameManagerService gameManagerService = new GameManagerService(mMockContext);
-        gameManagerService.onUserStarting(USER_ID_1);
+        GameManagerService gameManagerService =
+                new GameManagerService(mMockContext, mTestLooper.getLooper());
+
+
+        startUser(gameManagerService, USER_ID_1);
         gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
         mockModifyGameModeGranted();
         assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
@@ -353,8 +366,10 @@
      */
     @Test
     public void testGetGameModeInvalidPackageName() {
-        GameManagerService gameManagerService = new GameManagerService(mMockContext);
-        gameManagerService.onUserStarting(USER_ID_1);
+        GameManagerService gameManagerService =
+                new GameManagerService(mMockContext, mTestLooper.getLooper());
+
+        startUser(gameManagerService, USER_ID_1);
         try {
             assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
                     gameManagerService.getGameMode(PACKAGE_NAME_INVALID,
@@ -375,8 +390,9 @@
     public void testSetGameModePermissionDenied() {
         mockModifyGameModeGranted();
         mockDeviceConfigAll();
-        GameManagerService gameManagerService = new GameManagerService(mMockContext);
-        gameManagerService.onUserStarting(USER_ID_1);
+        GameManagerService gameManagerService =
+                new GameManagerService(mMockContext, mTestLooper.getLooper());
+        startUser(gameManagerService, USER_ID_1);
 
         // Update the game mode so we can read back something valid.
         gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_1);
@@ -408,9 +424,11 @@
     public void testGameModeMultipleUsers() {
         mockModifyGameModeGranted();
         mockDeviceConfigAll();
-        GameManagerService gameManagerService = new GameManagerService(mMockContext);
-        gameManagerService.onUserStarting(USER_ID_1);
-        gameManagerService.onUserStarting(USER_ID_2);
+        GameManagerService gameManagerService =
+                new GameManagerService(mMockContext, mTestLooper.getLooper());
+
+        startUser(gameManagerService, USER_ID_1);
+        startUser(gameManagerService, USER_ID_2);
         gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
         gameManagerService.updateConfigsForUser(USER_ID_2, mPackageName);
 
@@ -437,8 +455,10 @@
     }
 
     private void checkReportedModes(int ...requiredModes) {
-        GameManagerService gameManagerService = new GameManagerService(mMockContext);
-        gameManagerService.onUserStarting(USER_ID_1);
+        GameManagerService gameManagerService =
+                new GameManagerService(mMockContext, mTestLooper.getLooper());
+
+        startUser(gameManagerService, USER_ID_1);
         gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
         ArraySet<Integer> reportedModes = new ArraySet<>();
         int[] modes = gameManagerService.getAvailableGameModes(mPackageName);
@@ -453,8 +473,10 @@
     }
 
     private void checkDownscaling(int gameMode, String scaling) {
-        GameManagerService gameManagerService = new GameManagerService(mMockContext);
-        gameManagerService.onUserStarting(USER_ID_1);
+        GameManagerService gameManagerService =
+                new GameManagerService(mMockContext, mTestLooper.getLooper());
+
+        startUser(gameManagerService, USER_ID_1);
         gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
         GameManagerService.GamePackageConfiguration config =
                 gameManagerService.getConfig(mPackageName);
@@ -643,8 +665,10 @@
      */
     @Test
     public void testInterventionAllowAngleDefault() throws Exception {
-        GameManagerService gameManagerService = new GameManagerService(mMockContext);
-        gameManagerService.onUserStarting(USER_ID_1);
+        GameManagerService gameManagerService = new GameManagerService(
+                mMockContext, mTestLooper.getLooper());
+
+        startUser(gameManagerService, USER_ID_1);
         mockDeviceConfigPerformance();
         mockModifyGameModeGranted();
         checkAngleEnabled(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, false);
@@ -655,7 +679,8 @@
      */
     @Test
     public void testInterventionAllowAngleFalse() throws Exception {
-        GameManagerService gameManagerService = new GameManagerService(mMockContext);
+        GameManagerService gameManagerService =
+                new GameManagerService(mMockContext, mTestLooper.getLooper());
         gameManagerService.onUserStarting(USER_ID_1);
         mockDeviceConfigPerformanceEnableAngle();
         mockInterventionAllowAngleFalse();
@@ -672,8 +697,9 @@
         mockDeviceConfigPerformanceEnableAngle();
         mockInterventionAllowAngleTrue();
 
-        GameManagerService gameManagerService = new GameManagerService(mMockContext);
-        gameManagerService.onUserStarting(USER_ID_1);
+        GameManagerService gameManagerService =
+                new GameManagerService(mMockContext, mTestLooper.getLooper());
+        startUser(gameManagerService, USER_ID_1);
         mockModifyGameModeGranted();
         gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
         assertEquals(GameManager.GAME_MODE_PERFORMANCE,
@@ -691,8 +717,9 @@
         mockDeviceConfigPerformance();
         mockGameModeOptInPerformance();
         mockModifyGameModeGranted();
-        GameManagerService gameManagerService = new GameManagerService(mMockContext);
-        gameManagerService.onUserStarting(USER_ID_1);
+        GameManagerService gameManagerService =
+                new GameManagerService(mMockContext, mTestLooper.getLooper());
+        startUser(gameManagerService, USER_ID_1);
         gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
         GameManagerService.GamePackageConfiguration config =
                 gameManagerService.getConfig(mPackageName);
@@ -707,8 +734,9 @@
     public void testUnsetInvalidGameMode() throws Exception {
         mockDeviceConfigNone();
         mockModifyGameModeGranted();
-        GameManagerService gameManagerService = new GameManagerService(mMockContext);
-        gameManagerService.onUserStarting(USER_ID_1);
+        GameManagerService gameManagerService =
+                new GameManagerService(mMockContext, mTestLooper.getLooper());
+        startUser(gameManagerService, USER_ID_1);
         gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
         gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
         assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
@@ -723,8 +751,9 @@
     public void testResetInvalidGameMode() throws Exception {
         mockDeviceConfigPerformance();
         mockModifyGameModeGranted();
-        GameManagerService gameManagerService = new GameManagerService(mMockContext);
-        gameManagerService.onUserStarting(USER_ID_1);
+        GameManagerService gameManagerService =
+                new GameManagerService(mMockContext, mTestLooper.getLooper());
+        startUser(gameManagerService, USER_ID_1);
         gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY, USER_ID_1);
         gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
         assertEquals(GameManager.GAME_MODE_STANDARD,
@@ -739,8 +768,9 @@
     public void testSetValidGameMode() throws Exception {
         mockDeviceConfigPerformance();
         mockModifyGameModeGranted();
-        GameManagerService gameManagerService = new GameManagerService(mMockContext);
-        gameManagerService.onUserStarting(USER_ID_1);
+        GameManagerService gameManagerService =
+                new GameManagerService(mMockContext, mTestLooper.getLooper());
+        startUser(gameManagerService, USER_ID_1);
         gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_UNSUPPORTED, USER_ID_1);
         gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
         assertEquals(GameManager.GAME_MODE_STANDARD,
diff --git a/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesParserTest.java b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesParserTest.java
index bf97042..df19be4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesParserTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesParserTest.java
@@ -31,8 +31,6 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.compat.overrides.AppCompatOverridesParser.PackageOverrides;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -183,115 +181,84 @@
     }
 
     @Test
-    public void parsePackageOverrides_emptyConfig_returnsEmpty() {
-        PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
-                "", /* versionCode= */ 0, /* changeIdsToSkip= */ emptySet());
+    public void parsePackageOverrides_emptyConfigNoOwnedChangeIds_returnsEmpty() {
+        Map<Long, PackageOverride> result = AppCompatOverridesParser.parsePackageOverrides(
+                /* configStr= */ "", /* versionCode= */ 0, /* changeIdsToSkip= */ emptySet());
 
-        assertThat(result.overridesToAdd).isEmpty();
-        assertThat(result.overridesToRemove).isEmpty();
+        assertThat(result).isEmpty();
     }
 
     @Test
     public void parsePackageOverrides_configWithSingleOverride_returnsOverride() {
-        PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
-                "123:::true", /* versionCode= */ 5, /* changeIdsToSkip= */ emptySet());
-
-        assertThat(result.overridesToAdd).hasSize(1);
-        assertThat(result.overridesToAdd.get(123L)).isEqualTo(
-                new PackageOverride.Builder().setEnabled(true).build());
-    }
-
-    @Test
-    public void parsePackageOverrides_configWithMultipleOverridesToAdd_returnsOverrides() {
-        PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
-                "910:3:4:false,78:10::false,12:::false,34:1:2:true,34:10::true,56::2:true,"
-                        + "56:3:4:false,34:4:8:true,78:6:7:true,910:5::true,1112::5:true,"
-                        + "56:6::true,1112:6:7:false", /* versionCode= */
-                5, /* changeIdsToSkip= */ emptySet());
-
-        assertThat(result.overridesToAdd).hasSize(6);
-        assertThat(result.overridesToAdd.get(12L)).isEqualTo(
-                new PackageOverride.Builder().setEnabled(false).build());
-        assertThat(result.overridesToAdd.get(34L)).isEqualTo(
-                new PackageOverride.Builder().setMinVersionCode(4).setMaxVersionCode(8).setEnabled(
-                        true).build());
-        assertThat(result.overridesToAdd.get(56L)).isEqualTo(
-                new PackageOverride.Builder().setMinVersionCode(3).setMaxVersionCode(4).setEnabled(
-                        false).build());
-        assertThat(result.overridesToAdd.get(78L)).isEqualTo(
-                new PackageOverride.Builder().setMinVersionCode(6).setMaxVersionCode(7).setEnabled(
-                        true).build());
-        assertThat(result.overridesToAdd.get(910L)).isEqualTo(
-                new PackageOverride.Builder().setMinVersionCode(5).setEnabled(true).build());
-        assertThat(result.overridesToAdd.get(1112L)).isEqualTo(
-                new PackageOverride.Builder().setMaxVersionCode(5).setEnabled(true).build());
-        assertThat(result.overridesToRemove).isEmpty();
-    }
-
-    @Test
-    public void parsePackageOverrides_configWithMultipleOverridesToRemove_returnsOverrides() {
-        PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
-                "12:::,34:1:2:", /* versionCode= */ 5, /* changeIdsToSkip= */ emptySet());
-
-        assertThat(result.overridesToRemove).containsExactly(12L, 34L);
-        assertThat(result.overridesToAdd).isEmpty();
-    }
-
-    @Test
-    public void parsePackageOverrides_configWithBothOverridesToAddAndRemove_returnsOverrides() {
-        // Note that change 56 is both added and removed, therefore it will only be removed.
-        PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
-                "56:::,12:::true,34:::,56:3:7:true", /* versionCode= */ 5, /* changeIdsToSkip= */
+        Map<Long, PackageOverride> result = AppCompatOverridesParser.parsePackageOverrides(
+                /* configStr= */ "123:::true", /* versionCode= */ 5, /* changeIdsToSkip= */
                 emptySet());
 
-        assertThat(result.overridesToAdd).hasSize(1);
-        assertThat(result.overridesToAdd.get(12L)).isEqualTo(
+        assertThat(result).hasSize(1);
+        assertThat(result.get(123L)).isEqualTo(
                 new PackageOverride.Builder().setEnabled(true).build());
-        assertThat(result.overridesToRemove).containsExactly(34L, 56L);
+    }
+
+    @Test
+    public void parsePackageOverrides_configWithMultipleOverrides_returnsOverrides() {
+        Map<Long, PackageOverride> result = AppCompatOverridesParser.parsePackageOverrides(
+                /* configStr= */ "910:3:4:false,78:10::false,12:::false,34:1:2:true,34:10::true,"
+                        + "56::2:true,56:3:4:false,34:4:8:true,78:6:7:true,910:5::true,"
+                        + "1112::5:true,56:6::true,1112:6:7:false", /* versionCode= */
+                5, /* changeIdsToSkip= */ emptySet());
+
+        assertThat(result).hasSize(6);
+        assertThat(result.get(12L)).isEqualTo(
+                new PackageOverride.Builder().setEnabled(false).build());
+        assertThat(result.get(34L)).isEqualTo(
+                new PackageOverride.Builder().setMinVersionCode(4).setMaxVersionCode(8).setEnabled(
+                        true).build());
+        assertThat(result.get(56L)).isEqualTo(
+                new PackageOverride.Builder().setMinVersionCode(3).setMaxVersionCode(4).setEnabled(
+                        false).build());
+        assertThat(result.get(78L)).isEqualTo(
+                new PackageOverride.Builder().setMinVersionCode(6).setMaxVersionCode(7).setEnabled(
+                        true).build());
+        assertThat(result.get(910L)).isEqualTo(
+                new PackageOverride.Builder().setMinVersionCode(5).setEnabled(true).build());
+        assertThat(result.get(1112L)).isEqualTo(
+                new PackageOverride.Builder().setMaxVersionCode(5).setEnabled(true).build());
     }
 
     @Test
     public void parsePackageOverrides_changeIdsToSkipSpecified_returnsWithoutChangeIdsToSkip() {
-        ArraySet<Long> changeIdsToSkip = new ArraySet<>();
-        changeIdsToSkip.add(34L);
-        changeIdsToSkip.add(56L);
-        changeIdsToSkip.add(910L);
-        PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
-                "12:::true,34:::,56:3:7:true,78:::", /* versionCode= */ 5, changeIdsToSkip);
+        ArraySet<Long> changeIdsToSkip = new ArraySet<>(Arrays.asList(34L, 56L));
+        Map<Long, PackageOverride> result = AppCompatOverridesParser.parsePackageOverrides(
+                /* configStr= */ "12:::true,56:3:7:true", /* versionCode= */ 5, changeIdsToSkip);
 
-        assertThat(result.overridesToAdd).hasSize(1);
-        assertThat(result.overridesToAdd.get(12L)).isEqualTo(
+        assertThat(result).hasSize(1);
+        assertThat(result.get(12L)).isEqualTo(
                 new PackageOverride.Builder().setEnabled(true).build());
-        assertThat(result.overridesToRemove).containsExactly(78L);
     }
 
     @Test
     public void parsePackageOverrides_changeIdsToSkipContainsAllIds_returnsEmpty() {
-        ArraySet<Long> changeIdsToSkip = new ArraySet<>();
-        changeIdsToSkip.add(12L);
-        changeIdsToSkip.add(34L);
-        PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
-                "12:::true,34:::", /* versionCode= */ 5, changeIdsToSkip);
+        ArraySet<Long> changeIdsToSkip = new ArraySet<>(Arrays.asList(12L, 34L));
+        Map<Long, PackageOverride> result = AppCompatOverridesParser.parsePackageOverrides(
+                /* configStr= */ "12:::true", /* versionCode= */ 5, changeIdsToSkip);
 
-        assertThat(result.overridesToAdd).isEmpty();
-        assertThat(result.overridesToRemove).isEmpty();
+        assertThat(result).isEmpty();
     }
 
     @Test
     public void parsePackageOverrides_someOverridesAreInvalid_returnsWithoutInvalidOverrides() {
         // We add a valid entry before and after the invalid ones to make sure they are applied.
-        PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
-                "12:::True,56:1:2:FALSE,56:3:true,78:4:8:true:,C1:::true,910:::no,"
-                        + "1112:1:ten:true,1112:one:10:true,,1314:7:3:false,34:one:ten:",
+        Map<Long, PackageOverride> result = AppCompatOverridesParser.parsePackageOverrides(
+                /* configStr= */ "12:::True,56:1:2:FALSE,56:3:true,78:4:8:true:,C1:::true,910:::no,"
+                        + "1112:1:ten:true,1112:one:10:true,,1314:7:3:false,34:::",
                 /* versionCode= */ 5, /* changeIdsToSkip= */ emptySet());
 
-        assertThat(result.overridesToAdd).hasSize(2);
-        assertThat(result.overridesToAdd.get(12L)).isEqualTo(
+        assertThat(result).hasSize(2);
+        assertThat(result.get(12L)).isEqualTo(
                 new PackageOverride.Builder().setEnabled(true).build());
-        assertThat(result.overridesToAdd.get(56L)).isEqualTo(
+        assertThat(result.get(56L)).isEqualTo(
                 new PackageOverride.Builder().setMinVersionCode(1).setMaxVersionCode(2).setEnabled(
                         false).build());
-        assertThat(result.overridesToRemove).containsExactly(34L);
     }
 
     private static ApplicationInfo createAppInfo(String packageName) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java
index 3129272..007191f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java
@@ -95,7 +95,6 @@
     private static final String PACKAGE_2 = "com.android.test2";
     private static final String PACKAGE_3 = "com.android.test3";
     private static final String PACKAGE_4 = "com.android.test4";
-    private static final String PACKAGE_5 = "com.android.test5";
 
     private MockContext mMockContext;
     private BroadcastReceiver mPackageReceiver;
@@ -157,16 +156,14 @@
         mockGetApplicationInfoNotInstalled(PACKAGE_2);
         mockGetApplicationInfo(PACKAGE_3, /* versionCode= */ 10);
         mockGetApplicationInfo(PACKAGE_4, /* versionCode= */ 1);
-        mockGetApplicationInfo(PACKAGE_5, /* versionCode= */ 1);
 
         mService.registerDeviceConfigListeners();
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
-                .setString(PACKAGE_1, "123:::true,456::1:false,456:2::true")
+                .setString(FLAG_OWNED_CHANGE_IDS, "123,456,789")
+                .setString(PACKAGE_1, "123:::true,456::1:false,456:2::true,789:::false")
                 .setString(PACKAGE_2, "123:::true")
-                .setString(PACKAGE_3, "123:1:9:true,123:10:11:false,123:11::true,456:::")
-                .setString(PACKAGE_4, "")
-                .setString(PACKAGE_5, "123:::,789:::")
-                .setString(FLAG_OWNED_CHANGE_IDS, "123,456,789").build());
+                .setString(PACKAGE_3, "123:1:9:true,123:10:11:false,123:11::true")
+                .setString(PACKAGE_4, "").build());
 
         Map<Long, PackageOverride> addedOverrides;
         // Package 1
@@ -175,11 +172,13 @@
         verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
                 any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
         addedOverrides = mOverridesToAddConfigCaptor.getValue().overrides;
-        assertThat(addedOverrides).hasSize(2);
+        assertThat(addedOverrides).hasSize(3);
         assertThat(addedOverrides.get(123L)).isEqualTo(
                 new PackageOverride.Builder().setEnabled(true).build());
         assertThat(addedOverrides.get(456L)).isEqualTo(
                 new PackageOverride.Builder().setMinVersionCode(2).setEnabled(true).build());
+        assertThat(addedOverrides.get(789L)).isEqualTo(
+                new PackageOverride.Builder().setEnabled(false).build());
         // Package 2
         verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
                 any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
@@ -195,24 +194,37 @@
         assertThat(addedOverrides.get(123L)).isEqualTo(
                 new PackageOverride.Builder().setMinVersionCode(10).setMaxVersionCode(
                         11).setEnabled(false).build());
-        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L);
+        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L, 789L);
         // Package 4
         verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
                 any(CompatibilityOverrideConfig.class), eq(PACKAGE_4));
-        verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
-                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_4));
-        // Package 5
-        verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
-                any(CompatibilityOverrideConfig.class), eq(PACKAGE_5));
         verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
-                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_5));
-        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 789L);
+                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_4));
+        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 456L,
+                789L);
+    }
+
+    @Test
+    public void onPropertiesChanged_ownedChangeIdsFlagNotSet_onlyAddsOverrides()
+            throws Exception {
+        mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+
+        mService.registerDeviceConfigListeners();
+        DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+                .setString(PACKAGE_1, "123:::true").build());
+
+        verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
+                eq(PACKAGE_1));
+        verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
+        assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(123L);
     }
 
     @Test
     public void onPropertiesChanged_removeOverridesFlagSetBefore_skipsOverridesToRemove()
             throws Exception {
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+                .setString(FLAG_OWNED_CHANGE_IDS, "123,456,789")
                 .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=123:456," + PACKAGE_2 + "=123")
                 .setString(PACKAGE_1, "123:::true")
                 .setString(PACKAGE_4, "123:::true").build());
@@ -222,7 +234,7 @@
 
         mService.registerDeviceConfigListeners();
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
-                .setString(PACKAGE_1, "123:::true,456:::,789:::false")
+                .setString(PACKAGE_1, "123:::true,789:::false")
                 .setString(PACKAGE_2, "123:::true")
                 .setString(PACKAGE_3, "456:::true").build());
 
@@ -235,14 +247,16 @@
         // Package 2
         verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
                 any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
-        verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
-                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_2));
+        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2));
+        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L, 789L);
         // Package 3
         verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
                 eq(PACKAGE_3));
-        verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
-                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_3));
+        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_3));
         assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(456L);
+        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 789L);
         // Package 4 (not applied because it hasn't changed after the listener was added)
         verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
                 any(CompatibilityOverrideConfig.class), eq(PACKAGE_4));
@@ -253,27 +267,44 @@
     @Test
     public void onPropertiesChanged_removeOverridesFlagChangedNoPackageOverridesFlags_removesOnly()
             throws Exception {
+        DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+                .setString(FLAG_OWNED_CHANGE_IDS, "123,456,789")
+                .setString(PACKAGE_1, "")
+                .setString(PACKAGE_2, "").build());
+        mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+        mockGetApplicationInfo(PACKAGE_2, /* versionCode= */ 0);
+
         mService.registerDeviceConfigListeners();
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
                 .setString(FLAG_REMOVE_OVERRIDES,
-                        PACKAGE_1 + "=123:456," + PACKAGE_2 + "=789").build());
+                        PACKAGE_1 + "=123:456," + PACKAGE_2 + "=*").build());
 
         // Package 1
-        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+        verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+                any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
+        verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds(
                 mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
-        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 456L);
+        List<CompatibilityOverridesToRemoveConfig> configs =
+                mOverridesToRemoveConfigCaptor.getAllValues();
+        assertThat(configs.size()).isAtLeast(2);
+        assertThat(configs.get(configs.size() - 2).changeIds).containsExactly(123L, 456L);
+        assertThat(configs.get(configs.size() - 1).changeIds).containsExactly(789L);
         // Package 2
+        verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+                any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
         verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
                 mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2));
-        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(789L);
+        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 456L,
+                789L);
     }
 
     @Test
     public void onPropertiesChanged_removeOverridesFlagAndSomePackageOverrideFlagsChanged_ok()
             throws Exception {
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+                .setString(FLAG_OWNED_CHANGE_IDS, "123,456,789")
                 .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=123:456")
-                .setString(PACKAGE_1, "123:::true,456:::,789:::false")
+                .setString(PACKAGE_1, "123:::true,789:::false")
                 .setString(PACKAGE_3, "456:::false,789:::true").build());
         mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
         mockGetApplicationInfo(PACKAGE_2, /* versionCode= */ 0);
@@ -282,7 +313,7 @@
         mService.registerDeviceConfigListeners();
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
                 .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_2 + "=123," + PACKAGE_3 + "=789")
-                .setString(PACKAGE_2, "123:::true,456:::").build());
+                .setString(PACKAGE_2, "123:::true").build());
 
         // Package 1
         verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
@@ -301,14 +332,17 @@
                 mOverridesToRemoveConfigCaptor.getAllValues();
         assertThat(configs.size()).isAtLeast(2);
         assertThat(configs.get(configs.size() - 2).changeIds).containsExactly(123L);
-        assertThat(configs.get(configs.size() - 1).changeIds).containsExactly(456L);
+        assertThat(configs.get(configs.size() - 1).changeIds).containsExactly(456L, 789L);
         // Package 3
         verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
                 eq(PACKAGE_3));
-        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+        verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds(
                 mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_3));
         assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(456L);
-        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(789L);
+        configs = mOverridesToRemoveConfigCaptor.getAllValues();
+        assertThat(configs.size()).isAtLeast(2);
+        assertThat(configs.get(configs.size() - 2).changeIds).containsExactly(789L);
+        assertThat(configs.get(configs.size() - 1).changeIds).containsExactly(123L);
     }
 
     @Test
@@ -338,9 +372,10 @@
         // Package 2
         verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
                 eq(PACKAGE_2));
-        verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
-                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_2));
+        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2));
         assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(123L);
+        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L, 789L);
         // Package 3
         verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
                 any(CompatibilityOverrideConfig.class), eq(PACKAGE_3));
@@ -362,10 +397,11 @@
 
         mService.registerDeviceConfigListeners();
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
-                .setString(PACKAGE_1, "123:::true,456:::")
-                .setString(PACKAGE_2, "123:::true,456:::")
-                .setString(PACKAGE_3, "123:::true,456:::")
-                .setString(PACKAGE_4, "123:::true,456:::").build());
+                .setString(FLAG_OWNED_CHANGE_IDS, "123,456")
+                .setString(PACKAGE_1, "123:::true")
+                .setString(PACKAGE_2, "123:::true")
+                .setString(PACKAGE_3, "123:::true")
+                .setString(PACKAGE_4, "123:::true").build());
 
         // Package 1
         verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class),
@@ -478,12 +514,16 @@
     @Test
     public void packageReceiver_packageAddedIntent_appliesOverridesFromAllNamespaces()
             throws Exception {
+        // We're adding the owned_change_ids flag to make sure it's ignored.
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
-                .setString(PACKAGE_1, "101:::true,103:::")
+                .setString(FLAG_OWNED_CHANGE_IDS, "101,102,103")
+                .setString(PACKAGE_1, "101:::true")
                 .setString(PACKAGE_2, "102:::false").build());
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
+                .setString(FLAG_OWNED_CHANGE_IDS, "201,202,203")
                 .setString(PACKAGE_3, "201:::false").build());
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
+                .setString(FLAG_OWNED_CHANGE_IDS, "301,302")
                 .setString(PACKAGE_1, "301:::true,302:::false")
                 .setString(PACKAGE_2, "302:::false").build());
         mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
@@ -493,19 +533,18 @@
 
         verify(mPlatformCompat, times(2)).putOverridesOnReleaseBuilds(
                 mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1));
-        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
-                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
+        verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
         List<CompatibilityOverrideConfig> configs = mOverridesToAddConfigCaptor.getAllValues();
         assertThat(configs.get(0).overrides.keySet()).containsExactly(101L);
         assertThat(configs.get(1).overrides.keySet()).containsExactly(301L, 302L);
-        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(103L);
     }
 
     @Test
     public void packageReceiver_packageChangedIntent_appliesOverrides()
             throws Exception {
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
-                .setString(PACKAGE_1, "101:::true,103:::").build());
+                .setString(PACKAGE_1, "101:::true,103:::false").build());
         mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
 
         mPackageReceiver.onReceive(mMockContext,
@@ -513,10 +552,10 @@
 
         verify(mPlatformCompat).putOverridesOnReleaseBuilds(
                 mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1));
-        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
-                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
-        assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(101L);
-        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(103L);
+        verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
+        assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(101L,
+                103L);
     }
 
     @Test
@@ -524,13 +563,13 @@
             throws Exception {
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
                 .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=103," + PACKAGE_2 + "=101")
-                .setString(PACKAGE_1, "101:::true,103:::")
+                .setString(PACKAGE_1, "101:::true,103:::false")
                 .setString(PACKAGE_2, "102:::false").build());
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
                 .setString(PACKAGE_1, "201:::false").build());
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
                 .setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=301," + PACKAGE_3 + "=302")
-                .setString(PACKAGE_1, "301:::true,302:::false,303:::")
+                .setString(PACKAGE_1, "301:::true,302:::false,303:::true")
                 .setString(PACKAGE_3, "302:::false").build());
         mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
 
@@ -539,13 +578,12 @@
 
         verify(mPlatformCompat, times(3)).putOverridesOnReleaseBuilds(
                 mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1));
-        verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
-                mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
+        verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+                any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
         List<CompatibilityOverrideConfig> configs = mOverridesToAddConfigCaptor.getAllValues();
         assertThat(configs.get(0).overrides.keySet()).containsExactly(101L);
         assertThat(configs.get(1).overrides.keySet()).containsExactly(201L);
-        assertThat(configs.get(2).overrides.keySet()).containsExactly(302L);
-        assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(303L);
+        assertThat(configs.get(2).overrides.keySet()).containsExactly(302L, 303L);
     }
 
     @Test
@@ -573,7 +611,7 @@
             throws Exception {
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
                 .setString(FLAG_OWNED_CHANGE_IDS, "101,102,103")
-                .setString(PACKAGE_1, "101:::true,103:::").build());
+                .setString(PACKAGE_1, "101:::true,103:::false").build());
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
                 .setString(FLAG_OWNED_CHANGE_IDS, "201,202")
                 .setString(PACKAGE_1, "202:::false").build());
@@ -593,14 +631,14 @@
             throws Exception {
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
                 .setString(FLAG_OWNED_CHANGE_IDS, "101,102,103")
-                .setString(PACKAGE_1, "101:::true,103:::")
+                .setString(PACKAGE_1, "101:::true,103:::false")
                 .setString(PACKAGE_2, "102:::false").build());
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
                 .setString(FLAG_OWNED_CHANGE_IDS, "201")
                 .setString(PACKAGE_3, "201:::false").build());
         DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
                 .setString(FLAG_OWNED_CHANGE_IDS, "301,302")
-                .setString(PACKAGE_1, "302:::")
+                .setString(PACKAGE_1, "302:::false")
                 .setString(PACKAGE_2, "301:::true").build());
         mockGetApplicationInfoNotInstalled(PACKAGE_1);
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index f703e2e..d0b2eda 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -906,6 +906,21 @@
     }
 
     @Test
+    public void testProviderRequest_DelayedRequest_Remove() {
+        mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+        ILocationListener listener1 = createMockLocationListener();
+        LocationRequest request1 = new LocationRequest.Builder(60000)
+                .setWorkSource(WORK_SOURCE)
+                .build();
+        mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+        mManager.unregisterLocationRequest(listener1);
+
+        mInjector.getAlarmHelper().incrementAlarmTime(60000);
+        assertThat(mProvider.getRequest().isActive()).isFalse();
+    }
+
+    @Test
     public void testProviderRequest_SpamRequesting() {
         mProvider.setProviderLocation(createLocation(NAME, mRandom));
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
index dd6b744..0bce772 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
@@ -59,6 +59,7 @@
                 .mockStatic(LocalServices.class)
                 .startMocking();
         when(mIrs.getContext()).thenReturn(mContext);
+        when(mIrs.getCompleteEconomicPolicyLocked()).thenReturn(mEconomicPolicy);
         when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mock(AlarmManager.class));
     }
 
@@ -71,7 +72,7 @@
 
     @Test
     public void testRecordTransaction_UnderMax() {
-        Agent agent = new Agent(mIrs, mEconomicPolicy);
+        Agent agent = new Agent(mIrs);
         Ledger ledger = new Ledger();
 
         doReturn(1_000_000L).when(mIrs).getMaxCirculationLocked();
@@ -100,7 +101,7 @@
 
     @Test
     public void testRecordTransaction_MaxCirculation() {
-        Agent agent = new Agent(mIrs, mEconomicPolicy);
+        Agent agent = new Agent(mIrs);
         Ledger ledger = new Ledger();
 
         doReturn(1000L).when(mIrs).getMaxCirculationLocked();
@@ -147,7 +148,7 @@
 
     @Test
     public void testRecordTransaction_MaxSatiatedBalance() {
-        Agent agent = new Agent(mIrs, mEconomicPolicy);
+        Agent agent = new Agent(mIrs);
         Ledger ledger = new Ledger();
 
         doReturn(1_000_000L).when(mIrs).getMaxCirculationLocked();
diff --git a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
index 8344049..8cbed2c 100644
--- a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
@@ -63,29 +63,15 @@
 
     static class MyOomAdjuster extends OomAdjuster {
 
-        private final PlatformCompatCache mPlatformCompatCache;
-
         MyOomAdjuster(ActivityManagerService service, ProcessList processList,
                 ActiveUids activeUids) {
             super(service, processList, activeUids);
-            mPlatformCompatCache = new MyPlatformCompatCache(new long[]{});
-        }
-
-        static class MyPlatformCompatCache extends PlatformCompatCache {
-
-            MyPlatformCompatCache(long[] compatChanges) {
-                super(compatChanges);
-            }
-
-            @Override
-            boolean isChangeEnabled(long changeId, ApplicationInfo app, boolean defaultValue) {
-                return true;
-            }
         }
 
         @Override
-        protected OomAdjuster.PlatformCompatCache getPlatformCompatCache() {
-            return mPlatformCompatCache;
+        protected boolean isChangeEnabled(int changeId, ApplicationInfo app,
+                boolean defaultValue) {
+            return true;
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
index 5c7a580..1c49e6e 100644
--- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
@@ -146,12 +146,15 @@
     }
 
     @Test
-    public void testSetHibernatingForUser_packageIsHibernating() {
+    public void testSetHibernatingForUser_packageIsHibernating() throws Exception {
         // WHEN we hibernate a package for a user
         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
 
         // THEN the package is marked hibernating for the user
         assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1));
+        verify(mIActivityManager).forceStopPackage(PACKAGE_NAME_1, USER_ID_1);
+        verify(mIPackageManager).deleteApplicationCacheFilesAsUser(
+                eq(PACKAGE_NAME_1), eq(USER_ID_1), any());
     }
 
     @Test
@@ -204,6 +207,7 @@
 
         // THEN the package is marked hibernating for the user
         assertTrue(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
+        verify(mPackageManagerInternal).deleteOatArtifactsOfPackage(PACKAGE_NAME_1);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/UserStorageInfoTest.java b/services/tests/servicestests/src/com/android/server/appsearch/UserStorageInfoTest.java
new file mode 100644
index 0000000..c79671f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appsearch/UserStorageInfoTest.java
@@ -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.server.appsearch;
+
+import static com.android.server.appsearch.UserStorageInfo.STORAGE_INFO_FILE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.android.server.appsearch.icing.proto.DocumentStorageInfoProto;
+import com.android.server.appsearch.icing.proto.NamespaceStorageInfoProto;
+import com.android.server.appsearch.icing.proto.StorageInfoProto;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class UserStorageInfoTest {
+    @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+    private File mFileParentPath;
+    private UserStorageInfo mUserStorageInfo;
+
+    @Before
+    public void setUp() throws Exception {
+        mFileParentPath = mTemporaryFolder.newFolder();
+        mUserStorageInfo = new UserStorageInfo(mFileParentPath);
+    }
+
+    @Test
+    public void testReadStorageInfoFromFile() throws IOException {
+        NamespaceStorageInfoProto namespaceStorageInfo1 =
+                NamespaceStorageInfoProto.newBuilder()
+                        .setNamespace("pkg1$db/namespace")
+                        .setNumAliveDocuments(2)
+                        .setNumExpiredDocuments(1)
+                        .build();
+        NamespaceStorageInfoProto namespaceStorageInfo2 =
+                NamespaceStorageInfoProto.newBuilder()
+                        .setNamespace("pkg2$db/namespace")
+                        .setNumAliveDocuments(3)
+                        .setNumExpiredDocuments(3)
+                        .build();
+        DocumentStorageInfoProto documentStorageInfo =
+                DocumentStorageInfoProto.newBuilder()
+                        .setNumAliveDocuments(5)
+                        .setNumExpiredDocuments(4)
+                        .addNamespaceStorageInfo(namespaceStorageInfo1)
+                        .addNamespaceStorageInfo(namespaceStorageInfo2)
+                        .build();
+        StorageInfoProto storageInfo =
+                StorageInfoProto.newBuilder()
+                        .setDocumentStorageInfo(documentStorageInfo)
+                        .setTotalStorageSize(9)
+                        .build();
+        File storageInfoFile = new File(mFileParentPath, STORAGE_INFO_FILE);
+        try (FileOutputStream out = new FileOutputStream(storageInfoFile)) {
+            storageInfo.writeTo(out);
+        }
+
+        mUserStorageInfo.readStorageInfoFromFile();
+
+        assertThat(mUserStorageInfo.getTotalSizeBytes()).isEqualTo(
+                storageInfo.getTotalStorageSize());
+        // We calculate the package storage size based on number of documents a package has.
+        // Here, total storage size is 9. pkg1 has 3 docs and pkg2 has 6 docs. So storage size of
+        // pkg1 is 3. pkg2's storage size is 6.
+        assertThat(mUserStorageInfo.getSizeBytesForPackage("pkg1")).isEqualTo(3);
+        assertThat(mUserStorageInfo.getSizeBytesForPackage("pkg2")).isEqualTo(6);
+        assertThat(mUserStorageInfo.getSizeBytesForPackage("invalid_pkg")).isEqualTo(0);
+    }
+
+    @Test
+    public void testCalculatePackageStorageInfoMap() {
+        NamespaceStorageInfoProto namespaceStorageInfo1 =
+                NamespaceStorageInfoProto.newBuilder()
+                        .setNamespace("pkg1$db/namespace")
+                        .setNumAliveDocuments(2)
+                        .setNumExpiredDocuments(1)
+                        .build();
+        NamespaceStorageInfoProto namespaceStorageInfo2 =
+                NamespaceStorageInfoProto.newBuilder()
+                        .setNamespace("pkg2$db/namespace")
+                        .setNumAliveDocuments(3)
+                        .setNumExpiredDocuments(3)
+                        .build();
+        DocumentStorageInfoProto documentStorageInfo =
+                DocumentStorageInfoProto.newBuilder()
+                        .setNumAliveDocuments(5)
+                        .setNumExpiredDocuments(4)
+                        .addNamespaceStorageInfo(namespaceStorageInfo1)
+                        .addNamespaceStorageInfo(namespaceStorageInfo2)
+                        .build();
+        StorageInfoProto storageInfo =
+                StorageInfoProto.newBuilder()
+                        .setDocumentStorageInfo(documentStorageInfo)
+                        .setTotalStorageSize(9)
+                        .build();
+
+        // We calculate the package storage size based on number of documents a package has.
+        // Here, total storage size is 9. pkg1 has 3 docs and pkg2 has 6 docs. So storage size of
+        // pkg1 is 3. pkg2's storage size is 6.
+        assertThat(mUserStorageInfo.calculatePackageStorageInfoMap(storageInfo))
+                .containsExactly("pkg1", 3L, "pkg2", 6L);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
index 3fcd38b6..03eba9b 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -34,10 +34,10 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.platform.test.annotations.FlakyTest;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.wm.ActivityTaskManagerInternal;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
index 2f72809..f5af6df 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
@@ -190,7 +190,7 @@
         mMessageValidator =
                 new HdmiCecMessageValidator(mHdmiControlService) {
                     @Override
-                    int isValid(HdmiCecMessage message) {
+                    int isValid(HdmiCecMessage message, boolean isMessageReceived) {
                         return HdmiCecMessageValidator.OK;
                     }
                 };
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
index ebd8d77..548a439 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
@@ -649,6 +649,6 @@
     }
 
     private IntegerSubject assertMessageValidity(String message) {
-        return assertThat(mHdmiCecMessageValidator.isValid(HdmiUtils.buildMessage(message)));
+        return assertThat(mHdmiCecMessageValidator.isValid(HdmiUtils.buildMessage(message), false));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index c525f9be..a44bd8e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -671,7 +671,7 @@
     @Test
     public void handleCecCommand_errorParameter_returnsAbortInvalidOperand() {
         // Validity ERROR_PARAMETER. Taken from HdmiCecMessageValidatorTest#isValid_menuStatus
-        HdmiCecMessage message = HdmiUtils.buildMessage("40:8D:03");
+        HdmiCecMessage message = HdmiUtils.buildMessage("80:8D:03");
 
         assertThat(mHdmiControlServiceSpy.handleCecCommand(message))
                 .isEqualTo(Constants.ABORT_INVALID_OPERAND);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index dbed445..734fdba 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -71,7 +71,7 @@
     }
 
     @Test
-    public void testPackageRemoval() throws Exception {
+    public void testPackageRemoval() {
         class PackageSenderImpl implements PackageSender {
             public void sendPackageBroadcast(final String action, final String pkg,
                     final Bundle extras, final int flags, final String targetPkg,
@@ -147,7 +147,7 @@
     }
 
     @Test
-    public void testPartitions() throws Exception {
+    public void testPartitions() {
         String[] partitions = { "system", "vendor", "odm", "oem", "product", "system_ext" };
         String[] appdir = { "app", "priv-app" };
         for (int i = 0; i < partitions.length; i++) {
@@ -440,15 +440,15 @@
     // known constants.
     private Boolean getOverride(Method m) {
         final String name = "Computer." + displayName(m);
-        final PackageManagerService.Computer.LiveImplementation annotation =
-                m.getAnnotation(PackageManagerService.Computer.LiveImplementation.class);
+        final Computer.LiveImplementation annotation =
+                m.getAnnotation(Computer.LiveImplementation.class);
         if (annotation == null) {
             return null;
         }
         final int override = annotation.override();
-        if (override == PackageManagerService.Computer.LiveImplementation.MANDATORY) {
+        if (override == Computer.LiveImplementation.MANDATORY) {
             return true;
-        } else if (override == PackageManagerService.Computer.LiveImplementation.NOT_ALLOWED) {
+        } else if (override == Computer.LiveImplementation.NOT_ALLOWED) {
             return false;
         } else {
             flag(name, "invalid Live value: " + override);
@@ -461,7 +461,7 @@
         // Verify that Copmuter methods are properly annotated and that ComputerLocked is
         // properly populated per annotations.
         // Call PackageManagerService.validateComputer();
-        Class base = PackageManagerService.Computer.class;
+        Class base = Computer.class;
 
         HashMap<Method, Boolean> methodType = new HashMap<>();
 
@@ -476,7 +476,7 @@
             methodType.put(m, override);
         }
 
-        Class coreClass = PackageManagerService.ComputerEngine.class;
+        Class coreClass = ComputerEngine.class;
         final Method[] coreMethods = coreClass.getDeclaredMethods();
 
         // Examine every method in the core.  If it inherits from a base method it must be
@@ -520,7 +520,7 @@
             }
         }
 
-        Class liveClass = PackageManagerService.ComputerLocked.class;
+        Class liveClass = ComputerLocked.class;
         final Method[] liveMethods = liveClass.getDeclaredMethods();
 
         // Examine every method in the live list.  Every method must be final and must
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigNamedActorTest.kt b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigNamedActorTest.kt
index b7199d4..150822b 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigNamedActorTest.kt
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigNamedActorTest.kt
@@ -17,6 +17,7 @@
 package com.android.server.systemconfig
 
 import android.content.Context
+import android.util.Xml
 import androidx.test.InstrumentationRegistry
 import com.android.server.SystemConfig
 import com.google.common.truth.Truth.assertThat
@@ -227,6 +228,7 @@
             .writeText(this.trimIndent())
 
     private fun assertPermissions() = SystemConfig(false).apply {
-        readPermissions(tempFolder.root, 0)
+        val parser = Xml.newPullParser()
+        readPermissions(parser, tempFolder.root, 0)
     }. let { assertThat(it.namedActors) }
 }
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index 5eb21a5..cc53160 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -25,6 +25,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.Xml;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -36,6 +37,7 @@
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
 
 import java.io.BufferedWriter;
 import java.io.File;
@@ -76,6 +78,11 @@
         }
     }
 
+    private void readPermissions(File libraryDir, int permissionFlag) {
+        final XmlPullParser parser = Xml.newPullParser();
+        mSysConfig.readPermissions(parser, libraryDir, permissionFlag);
+    }
+
     /**
      * Tests that readPermissions works correctly for the tag: install-in-user-type
      */
@@ -134,8 +141,8 @@
         // Also, make a third file, but with the name folder1/permFile2.xml, to prove no conflicts.
         createTempFile(folder1, "permFile2.xml", contents3);
 
-        mSysConfig.readPermissions(folder1, /* No permission needed anyway */ 0);
-        mSysConfig.readPermissions(folder2, /* No permission needed anyway */ 0);
+        readPermissions(folder1, /* No permission needed anyway */ 0);
+        readPermissions(folder2, /* No permission needed anyway */ 0);
 
         Map<String, Set<String>> actualWhite = mSysConfig.getAndClearPackageToUserTypeWhitelist();
         Map<String, Set<String>> actualBlack = mSysConfig.getAndClearPackageToUserTypeBlacklist();
@@ -165,7 +172,7 @@
         final File folder = createTempSubfolder("folder");
         createTempFile(folder, "component-override.xml", contents);
 
-        mSysConfig.readPermissions(folder, /* No permission needed anyway */ 0);
+        readPermissions(folder, /* No permission needed anyway */ 0);
 
         final ArrayMap<String, Boolean> packageOneExpected = new ArrayMap<>();
         packageOneExpected.put("com.android.package1.Full", true);
@@ -197,7 +204,7 @@
         final File folder = createTempSubfolder("folder");
         createTempFile(folder, "staged-installer-whitelist.xml", contents);
 
-        mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0);
+        readPermissions(folder, /* Grant all permission flags */ ~0);
 
         assertThat(mSysConfig.getWhitelistedStagedInstallers())
                 .containsExactly("com.android.package1");
@@ -215,7 +222,7 @@
         final File folder = createTempSubfolder("folder");
         createTempFile(folder, "staged-installer-whitelist.xml", contents);
 
-        mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0);
+        readPermissions(folder, /* Grant all permission flags */ ~0);
 
         assertThat(mSysConfig.getWhitelistedStagedInstallers())
                 .containsExactly("com.android.package1");
@@ -238,7 +245,7 @@
 
         IllegalStateException e = expectThrows(
                 IllegalStateException.class,
-                () -> mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0));
+                () -> readPermissions(folder, /* Grant all permission flags */ ~0));
 
         assertThat(e).hasMessageThat().contains("Multiple modules installers");
     }
@@ -257,7 +264,7 @@
         final File folder = createTempSubfolder("folder");
         createTempFile(folder, "staged-installer-whitelist.xml", contents);
 
-        mSysConfig.readPermissions(folder, /* Grant all but ALLOW_APP_CONFIGS flag */ ~0x08);
+        readPermissions(folder, /* Grant all but ALLOW_APP_CONFIGS flag */ ~0x08);
 
         assertThat(mSysConfig.getWhitelistedStagedInstallers()).isEmpty();
     }
@@ -277,7 +284,7 @@
         final File folder = createTempSubfolder("folder");
         createTempFile(folder, "vendor-apex-allowlist.xml", contents);
 
-        mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0);
+        readPermissions(folder, /* Grant all permission flags */ ~0);
 
         assertThat(mSysConfig.getAllowedVendorApexes())
                 .containsExactly("com.android.apex1", "com.installer");
@@ -297,7 +304,7 @@
         final File folder = createTempSubfolder("folder");
         createTempFile(folder, "vendor-apex-allowlist.xml", contents);
 
-        mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0);
+        readPermissions(folder, /* Grant all permission flags */ ~0);
 
         assertThat(mSysConfig.getAllowedVendorApexes()).isEmpty();
     }
@@ -317,7 +324,7 @@
         final File folder = createTempSubfolder("folder");
         createTempFile(folder, "vendor-apex-allowlist.xml", contents);
 
-        mSysConfig.readPermissions(folder, /* Grant all but ALLOW_VENDOR_APEX flag */ ~0x400);
+        readPermissions(folder, /* Grant all but ALLOW_VENDOR_APEX flag */ ~0x400);
 
         assertThat(mSysConfig.getAllowedVendorApexes()).isEmpty();
     }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index f9663f2..987236c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -65,6 +65,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
@@ -1320,16 +1321,15 @@
                 APPROVAL_BY_COMPONENT);
         ComponentName cn = ComponentName.unflattenFromString("a/a");
 
-        service.registerSystemService(cn, 0);
-        when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
-            Object[] args = invocation.getArguments();
-            ServiceConnection sc = (ServiceConnection) args[1];
-            sc.onNullBinding(cn);
-            return true;
-        });
+        ArgumentCaptor<ServiceConnection> captor = ArgumentCaptor.forClass(ServiceConnection.class);
+        when(context.bindServiceAsUser(any(), captor.capture(), anyInt(), any()))
+                .thenAnswer(invocation -> {
+                    captor.getValue().onNullBinding(cn);
+                    return true;
+                });
 
         service.registerSystemService(cn, 0);
-        assertFalse(service.isBound(cn, 0));
+        verify(context).unbindService(captor.getValue());
     }
 
     @Test
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 f660af0..1ae219d 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -4011,6 +4011,80 @@
     }
 
     @Test
+    public void testApplyAdjustmentsLogged() throws Exception {
+        NotificationManagerService.WorkerHandler handler = mock(
+                NotificationManagerService.WorkerHandler.class);
+        mService.setHandler(handler);
+        when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
+
+        // Set up notifications that will be adjusted
+        final NotificationRecord r1 = generateNotificationRecord(
+                mTestNotificationChannel, 1, null, true);
+        r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
+        mService.addNotification(r1);
+        final NotificationRecord r2 = generateNotificationRecord(
+                mTestNotificationChannel, 2, null, true);
+        r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
+        mService.addNotification(r2);
+
+        // Third notification that's NOT adjusted, just to make sure that doesn't get spuriously
+        // logged.
+        final NotificationRecord r3 = generateNotificationRecord(
+                mTestNotificationChannel, 3, null, true);
+        r3.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
+        mService.addNotification(r3);
+
+        List<Adjustment> adjustments = new ArrayList<>();
+
+        // Test an adjustment that's associated with a ranking change and one that's not
+        Bundle signals1 = new Bundle();
+        signals1.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_HIGH);
+        Adjustment adjustment1 = new Adjustment(
+                r1.getSbn().getPackageName(), r1.getKey(), signals1, "",
+                r1.getUser().getIdentifier());
+        adjustments.add(adjustment1);
+
+        // This one wouldn't trigger a ranking change, but should still trigger a log.
+        Bundle signals2 = new Bundle();
+        signals2.putFloat(Adjustment.KEY_RANKING_SCORE, -0.5f);
+        Adjustment adjustment2 = new Adjustment(
+                r2.getSbn().getPackageName(), r2.getKey(), signals2, "",
+                r2.getUser().getIdentifier());
+        adjustments.add(adjustment2);
+
+        mBinderService.applyAdjustmentsFromAssistant(null, adjustments);
+        verify(mRankingHandler, times(1)).requestSort();
+
+        // Actually apply the adjustments & recalculate importance when run
+        doAnswer(invocationOnMock -> {
+            ((NotificationRecord) invocationOnMock.getArguments()[0])
+                    .applyAdjustments();
+            ((NotificationRecord) invocationOnMock.getArguments()[0])
+                    .calculateImportance();
+            return null;
+        }).when(mRankingHelper).extractSignals(any(NotificationRecord.class));
+
+        // Now make sure that when the sort happens, we actually log the changes.
+        mService.handleRankingSort();
+
+        // Even though the ranking score change is not meant to trigger a ranking update,
+        // during this process the package visibility & canShowBadge values are changing
+        // in all notifications, so all 3 seem to trigger a ranking change. Here we check instead
+        // that scheduleSendRankingUpdate is sent and that the relevant fields have been changed
+        // accordingly to confirm the adjustments happened to the 2 relevant notifications.
+        verify(handler, times(3)).scheduleSendRankingUpdate();
+        assertEquals(IMPORTANCE_HIGH, r1.getImportance());
+        assertTrue(r2.rankingScoreMatches(-0.5f));
+        assertEquals(2, mNotificationRecordLogger.numCalls());
+        assertEquals(NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_ADJUSTED,
+                mNotificationRecordLogger.event(0));
+        assertEquals(NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_ADJUSTED,
+                mNotificationRecordLogger.event(1));
+        assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
+        assertEquals(2, mNotificationRecordLogger.get(1).getInstanceId());
+    }
+
+    @Test
     public void testEnqueuedAdjustmentAppliesAdjustments() throws Exception {
         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
         mService.addEnqueuedNotification(r);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java
index 64fd19e..8a11798 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java
@@ -45,6 +45,15 @@
             groupInstanceId = groupId;
         }
 
+        CallRecord(NotificationRecord r, int position, int buzzBeepBlink, InstanceId groupId) {
+            super(r, null);
+            this.position = position;
+            this.buzzBeepBlink = buzzBeepBlink;
+            wasLogged = true;
+            event = NotificationReportedEvent.NOTIFICATION_ADJUSTED;
+            groupInstanceId = groupId;
+        }
+
         CallRecord(NotificationRecord r, UiEventLogger.UiEventEnum event) {
             super(r, null);
             wasLogged = true;
@@ -75,6 +84,12 @@
     }
 
     @Override
+    public void logNotificationAdjusted(NotificationRecord r, int position, int buzzBeepBlink,
+            InstanceId groupId) {
+        mCalls.add(new CallRecord(r, position, buzzBeepBlink, groupId));
+    }
+
+    @Override
     public void log(UiEventLogger.UiEventEnum event, NotificationRecord r) {
         mCalls.add(new CallRecord(r, event));
     }
diff --git a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
index 6b36fe8..1ff67240 100644
--- a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
@@ -18,6 +18,7 @@
 
 import static android.view.KeyEvent.ACTION_DOWN;
 import static android.view.KeyEvent.ACTION_UP;
+import static android.view.KeyEvent.KEYCODE_BACK;
 import static android.view.KeyEvent.KEYCODE_POWER;
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -31,6 +32,9 @@
 
 import android.app.Instrumentation;
 import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
 import android.os.SystemClock;
 import android.view.KeyEvent;
 import android.view.ViewConfiguration;
@@ -50,7 +54,8 @@
 public class SingleKeyGestureTests {
     private SingleKeyGestureDetector mDetector;
 
-    private int mMaxMultiPressPowerCount = 2;
+    private int mMaxMultiPressCount = 3;
+    private int mExpectedMultiPressCount = 2;
 
     private CountDownLatch mShortPressed = new CountDownLatch(1);
     private CountDownLatch mLongPressed = new CountDownLatch(1);
@@ -69,8 +74,11 @@
 
     @Before
     public void setUp() {
-        mDetector = new SingleKeyGestureDetector();
-        initSingleKeyGestureRules();
+        mInstrumentation.runOnMainSync(() -> {
+            mDetector = new SingleKeyGestureDetector();
+            initSingleKeyGestureRules();
+        });
+
         mWaitTimeout = ViewConfiguration.getMultiPressTimeout() + 50;
         mLongPressTime = ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout() + 50;
         mVeryLongPressTime = mContext.getResources().getInteger(
@@ -82,7 +90,7 @@
                 KEY_LONGPRESS | KEY_VERYLONGPRESS) {
             @Override
             int getMaxMultiPressCount() {
-                return mMaxMultiPressPowerCount;
+                return mMaxMultiPressCount;
             }
             @Override
             public void onPress(long downTime) {
@@ -111,9 +119,35 @@
                     return;
                 }
                 mMultiPressed.countDown();
-                assertEquals(mMaxMultiPressPowerCount, count);
+                assertTrue(mMaxMultiPressCount >= count);
+                assertEquals(mExpectedMultiPressCount, count);
             }
         });
+
+        mDetector.addRule(new SingleKeyGestureDetector.SingleKeyRule(mContext, KEYCODE_BACK, 0) {
+            @Override
+            int getMaxMultiPressCount() {
+                return mMaxMultiPressCount;
+            }
+            @Override
+            public void onPress(long downTime) {
+                if (mDetector.beganFromNonInteractive() && !mAllowNonInteractiveForPress) {
+                    return;
+                }
+                mShortPressed.countDown();
+            }
+
+            @Override
+            void onMultiPress(long downTime, int count) {
+                if (mDetector.beganFromNonInteractive() && !mAllowNonInteractiveForPress) {
+                    return;
+                }
+                mMultiPressed.countDown();
+                assertTrue(mMaxMultiPressCount >= count);
+                assertEquals(mExpectedMultiPressCount, count);
+            }
+        });
+
     }
 
     private void pressKey(long eventTime, int keyCode, long pressTime) {
@@ -163,6 +197,16 @@
     @Test
     public void testMultiPress() throws InterruptedException {
         final long eventTime = SystemClock.uptimeMillis();
+        // Double presses.
+        mExpectedMultiPressCount = 2;
+        pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
+        pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
+        assertTrue(mMultiPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
+
+        // Triple presses.
+        mExpectedMultiPressCount = 3;
+        mMultiPressed = new CountDownLatch(1);
+        pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
         pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
         pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
         assertTrue(mMultiPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
@@ -181,4 +225,56 @@
         pressKey(eventTime, KEYCODE_POWER, mLongPressTime, false /* interactive */);
         assertTrue(mLongPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
     }
+
+    @Test
+    public void testShortPress_Pressure() throws InterruptedException {
+        final HandlerThread handlerThread =
+                new HandlerThread("testInputReader", Process.THREAD_PRIORITY_DISPLAY);
+        handlerThread.start();
+        Handler newHandler = new Handler(handlerThread.getLooper());
+        mMaxMultiPressCount = 1; // Will trigger short press when event up.
+        try {
+            // To make sure we won't get any crash while panic pressing keys.
+            for (int i = 0; i < 100; i++) {
+                mShortPressed = new CountDownLatch(2);
+                newHandler.runWithScissors(() -> {
+                    final long eventTime = SystemClock.uptimeMillis();
+                    pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
+                    pressKey(eventTime, KEYCODE_BACK, 0 /* pressTime */);
+                }, mWaitTimeout);
+                assertTrue(mShortPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
+            }
+        } finally {
+            handlerThread.quitSafely();
+        }
+    }
+
+    @Test
+    public void testMultiPress_Pressure() throws InterruptedException {
+        final HandlerThread handlerThread =
+                new HandlerThread("testInputReader", Process.THREAD_PRIORITY_DISPLAY);
+        handlerThread.start();
+        Handler newHandler = new Handler(handlerThread.getLooper());
+        try {
+            // To make sure we won't get any unexpected multi-press count.
+            for (int i = 0; i < 5; i++) {
+                mMultiPressed = new CountDownLatch(1);
+                mShortPressed = new CountDownLatch(1);
+                newHandler.runWithScissors(() -> {
+                    final long eventTime = SystemClock.uptimeMillis();
+                    pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
+                    pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
+                }, mWaitTimeout);
+                assertTrue(mMultiPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
+
+                newHandler.runWithScissors(() -> {
+                    final long eventTime = SystemClock.uptimeMillis();
+                    pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
+                }, mWaitTimeout);
+                assertTrue(mShortPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
+            }
+        } finally {
+            handlerThread.quitSafely();
+        }
+    }
 }
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 51cc318..c434b13 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2987,6 +2987,7 @@
         mDisplayContent.setImeInputTarget(app);
 
         // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
+        mDisplayContent.mOpeningApps.clear();
         app.mActivityRecord.commitVisibility(false, false);
         app.mActivityRecord.onWindowsGone();
 
@@ -3005,6 +3006,24 @@
         assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
     }
 
+    @Test
+    public void testInClosingAnimation_doNotHideSurface() {
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+        makeWindowVisibleAndDrawn(app);
+
+        // Put the activity in close transition.
+        mDisplayContent.mOpeningApps.clear();
+        mDisplayContent.mClosingApps.add(app.mActivityRecord);
+        mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
+
+        // Update visibility and call to remove window
+        app.mActivityRecord.commitVisibility(false, false);
+        app.mActivityRecord.prepareSurfaces();
+
+        // Because the app is waiting for transition, it should not hide the surface.
+        assertTrue(app.mActivityRecord.isSurfaceShowing());
+    }
+
     private void assertHasStartingWindow(ActivityRecord atoken) {
         assertNotNull(atoken.mStartingSurface);
         assertNotNull(atoken.mStartingData);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 0d0cec7..d6d7f07 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -31,13 +31,17 @@
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
 import android.os.Binder;
@@ -791,4 +795,38 @@
         verify(mDisplayContent.mAppTransition)
                 .overridePendingAppTransitionRemote(adapter, false /* sync */);
     }
+
+    @Test
+    public void testTransitionGoodToGoForTaskFragments() {
+        final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+        final Task task = createTask(mDisplayContent);
+        final TaskFragment changeTaskFragment = new TaskFragmentBuilder(mAtm)
+                .setParentTask(task)
+                .createActivityCount(1)
+                .setOrganizer(organizer)
+                .build();
+        final TaskFragment emptyTaskFragment = new TaskFragmentBuilder(mAtm)
+                .setParentTask(task)
+                .setOrganizer(organizer)
+                .build();
+        changeTaskFragment.getTopMostActivity().allDrawn = true;
+        mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0);
+        mDisplayContent.mChangingContainers.add(changeTaskFragment);
+        spyOn(mDisplayContent.mAppTransition);
+        spyOn(emptyTaskFragment);
+
+        mDisplayContent.mAppTransitionController.handleAppTransitionReady();
+
+        // Transition not ready because there is an empty non-finishing TaskFragment.
+        verify(mDisplayContent.mAppTransition, never()).goodToGo(anyInt(), any());
+
+        doReturn(true).when(emptyTaskFragment).hasChild();
+        emptyTaskFragment.remove(false /* withTransition */, "test");
+
+        mDisplayContent.mAppTransitionController.handleAppTransitionReady();
+
+        // Transition ready because the empty (no running activity) TaskFragment is requested to be
+        // removed.
+        verify(mDisplayContent.mAppTransition).goodToGo(anyInt(), any());
+    }
 }
\ No newline at end of file
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 223dc31..a1e8ca4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -58,6 +58,7 @@
 import android.view.SurfaceSession;
 import android.view.View;
 import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
 
 import androidx.test.filters.SmallTest;
 
@@ -70,6 +71,7 @@
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mockito;
 
 import java.util.ArrayList;
 import java.util.concurrent.CountDownLatch;
@@ -97,14 +99,20 @@
     static class TestDragDropController extends DragDropController {
         private Runnable mCloseCallback;
         boolean mDeferDragStateClosed;
+        boolean mIsAccessibilityDrag;
 
         TestDragDropController(WindowManagerService service, Looper looper) {
             super(service, looper);
         }
 
         void setOnClosedCallbackLocked(Runnable runnable) {
-            assertTrue(dragDropActiveLocked());
-            mCloseCallback = runnable;
+            if (mIsAccessibilityDrag) {
+                // Accessibility does not use animation
+                assertTrue(!dragDropActiveLocked());
+            } else {
+                assertTrue(dragDropActiveLocked());
+                mCloseCallback = runnable;
+            }
         }
 
         @Override
@@ -171,6 +179,10 @@
         }
         latch = new CountDownLatch(1);
         mTarget.setOnClosedCallbackLocked(latch::countDown);
+        if (mTarget.mIsAccessibilityDrag) {
+            mTarget.mIsAccessibilityDrag = false;
+            return;
+        }
         assertTrue(awaitInWmLock(() -> latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)));
     }
 
@@ -180,6 +192,12 @@
     }
 
     @Test
+    public void testA11yDragFlow() {
+        mTarget.mIsAccessibilityDrag = true;
+        doA11yDragAndDrop(0, ClipData.newPlainText("label", "Test"), 0, 0);
+    }
+
+    @Test
     public void testPerformDrag_NullDataWithGrantUri() {
         doDragAndDrop(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ, null, 0, 0);
     }
@@ -436,4 +454,22 @@
             appSession.kill();
         }
     }
+
+    private void doA11yDragAndDrop(int flags, ClipData data, float dropX, float dropY) {
+        spyOn(mTarget);
+        AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
+        when(accessibilityManager.isEnabled()).thenReturn(true);
+        doReturn(accessibilityManager).when(mTarget).getAccessibilityManager();
+        startA11yDrag(flags, data, () -> {
+            boolean dropped = mTarget.dropForAccessibility(mWindow.mClient, dropX, dropY);
+            mToken = mWindow.mClient.asBinder();
+        });
+    }
+
+    private void startA11yDrag(int flags, ClipData data, Runnable r) {
+        mToken = mTarget.performDrag(0, 0, mWindow.mClient,
+                flags | View.DRAG_FLAG_ACCESSIBILITY_ACTION, null, 0, 0, 0, 0, 0, data);
+        assertNotNull(mToken);
+        r.run();
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 89ae5ed..08312ef 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -341,7 +341,8 @@
             verify(mMockTransaction).setWindowCrop(
                     mMockLeash, app.startBounds.width(), app.startBounds.height());
             verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0);
-            verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, -1, -1);
+            verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, app.startBounds.width(),
+                    app.startBounds.height());
 
             finishedCaptor.getValue().onAnimationFinished();
             verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION),
@@ -394,7 +395,63 @@
             verify(mMockTransaction).setWindowCrop(
                     mMockLeash, app.startBounds.width(), app.startBounds.height());
             verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0);
-            verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, -1, -1);
+            verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, app.startBounds.width(),
+                    app.startBounds.height());
+
+            finishedCaptor.getValue().onAnimationFinished();
+            verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION),
+                    eq(record.mAdapter));
+            verify(mThumbnailFinishedCallback).onAnimationFinished(
+                    eq(ANIMATION_TYPE_WINDOW_ANIMATION), eq(record.mThumbnailAdapter));
+        } finally {
+            mDisplayContent.mChangingContainers.clear();
+        }
+    }
+
+    @Test
+    public void testChangeToDifferentPosition() throws Exception {
+        final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
+        mDisplayContent.mChangingContainers.add(win.mActivityRecord);
+        try {
+            final RemoteAnimationRecord record = mController.createRemoteAnimationRecord(
+                    win.mActivityRecord, new Point(100, 100), null, new Rect(150, 150, 400, 400),
+                    new Rect(50, 100, 150, 150));
+            assertNotNull(record.mThumbnailAdapter);
+            ((AnimationAdapter) record.mAdapter)
+                    .startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION,
+                            mFinishedCallback);
+            ((AnimationAdapter) record.mThumbnailAdapter).startAnimation(mMockThumbnailLeash,
+                    mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION, mThumbnailFinishedCallback);
+            mController.goodToGo(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE);
+            mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+            final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
+                    ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+            final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
+                    ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+            final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
+                    ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+            final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
+                    ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
+            verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE),
+                    appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
+                    finishedCaptor.capture());
+            assertEquals(1, appsCaptor.getValue().length);
+            final RemoteAnimationTarget app = appsCaptor.getValue()[0];
+            assertEquals(RemoteAnimationTarget.MODE_CHANGING, app.mode);
+            assertEquals(new Point(100, 100), app.position);
+            assertEquals(new Rect(150, 150, 400, 400), app.sourceContainerBounds);
+            assertEquals(new Rect(50, 100, 150, 150), app.startBounds);
+            assertEquals(mMockLeash, app.leash);
+            assertEquals(mMockThumbnailLeash, app.startLeash);
+            assertEquals(false, app.isTranslucent);
+            verify(mMockTransaction).setPosition(
+                    mMockLeash, app.position.x + app.startBounds.left - app.screenSpaceBounds.left,
+                    app.position.y + app.startBounds.top - app.screenSpaceBounds.top);
+            verify(mMockTransaction).setWindowCrop(
+                    mMockLeash, app.startBounds.width(), app.startBounds.height());
+            verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0);
+            verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, app.startBounds.width(),
+                    app.startBounds.height());
 
             finishedCaptor.getValue().onAnimationFinished();
             verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION),
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 98c1eabe..d475c46e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -76,7 +76,7 @@
 
     @Before
     public void setup() {
-        mController = mWm.mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController;
+        mController = mAtm.mWindowOrganizerController.mTaskFragmentOrganizerController;
         mOrganizer = new TaskFragmentOrganizer(Runnable::run);
         mOrganizerToken = mOrganizer.getOrganizerToken();
         mIOrganizer = ITaskFragmentOrganizer.Stub.asInterface(mOrganizerToken.asBinder());
@@ -284,7 +284,9 @@
     @Test
     public void testApplyTransaction_enforceHierarchyChange_deleteTaskFragment()
             throws RemoteException {
+        mController.registerOrganizer(mIOrganizer);
         mOrganizer.applyTransaction(mTransaction);
+        doReturn(true).when(mTaskFragment).isAttached();
 
         // Throw exception if the transaction is trying to change a window that is not organized by
         // the organizer.
@@ -300,8 +302,18 @@
 
         // Allow transaction to change a TaskFragment created by the organizer.
         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
+        clearInvocations(mAtm.mRootWindowContainer);
 
         mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+
+        // No lifecycle update when the TaskFragment is not recorded.
+        verify(mAtm.mRootWindowContainer, never()).resumeFocusedTasksTopActivities();
+
+        mAtm.mWindowOrganizerController.mLaunchTaskFragments
+                .put(mFragmentToken, mTaskFragment);
+        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+
+        verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
     }
 
     @Test
@@ -327,8 +339,11 @@
         // Allow transaction to change a TaskFragment created by the organizer.
         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
         taskFragment2.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
+        clearInvocations(mAtm.mRootWindowContainer);
 
         mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+
+        verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
     }
 
     @Test
@@ -360,6 +375,8 @@
     public void testApplyTransaction_enforceHierarchyChange_reparentChildren()
             throws RemoteException {
         mOrganizer.applyTransaction(mTransaction);
+        mController.registerOrganizer(mIOrganizer);
+        doReturn(true).when(mTaskFragment).isAttached();
 
         // Throw exception if the transaction is trying to change a window that is not organized by
         // the organizer.
@@ -375,7 +392,30 @@
 
         // Allow transaction to change a TaskFragment created by the organizer.
         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
+        clearInvocations(mAtm.mRootWindowContainer);
 
         mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+
+        verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
+    }
+
+    @Test
+    public void testApplyTransaction_reparentActivityToTaskFragment_triggerLifecycleUpdate()
+            throws RemoteException {
+        final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
+        mOrganizer.applyTransaction(mTransaction);
+        mController.registerOrganizer(mIOrganizer);
+        mTaskFragment = new TaskFragmentBuilder(mAtm)
+                .setCreateParentTask()
+                .setFragmentToken(mFragmentToken)
+                .build();
+        mAtm.mWindowOrganizerController.mLaunchTaskFragments
+                .put(mFragmentToken, mTaskFragment);
+        mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.appToken);
+        clearInvocations(mAtm.mRootWindowContainer);
+
+        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+
+        verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 00f3d8b..68053eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -1071,6 +1071,41 @@
         verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 1 /* layer */);
     }
 
+    @Test
+    public void testAssignAnimationLayer() {
+        final WindowContainer container = new WindowContainer(mWm);
+        container.mSurfaceControl = mock(SurfaceControl.class);
+        final SurfaceAnimator surfaceAnimator = container.mSurfaceAnimator;
+        final SurfaceFreezer surfaceFreezer = container.mSurfaceFreezer;
+        final SurfaceControl relativeParent = mock(SurfaceControl.class);
+        final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+        spyOn(container);
+        spyOn(surfaceAnimator);
+        spyOn(surfaceFreezer);
+
+        container.setLayer(t, 1);
+        container.setRelativeLayer(t, relativeParent, 2);
+
+        // Set through surfaceAnimator if surfaceFreezer doesn't have leash.
+        verify(surfaceAnimator).setLayer(t, 1);
+        verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 2);
+        verify(surfaceFreezer, never()).setLayer(any(), anyInt());
+        verify(surfaceFreezer, never()).setRelativeLayer(any(), any(), anyInt());
+
+        clearInvocations(surfaceAnimator);
+        clearInvocations(surfaceFreezer);
+        doReturn(true).when(surfaceFreezer).hasLeash();
+
+        container.setLayer(t, 1);
+        container.setRelativeLayer(t, relativeParent, 2);
+
+        // Set through surfaceFreezer if surfaceFreezer has leash.
+        verify(surfaceFreezer).setLayer(t, 1);
+        verify(surfaceFreezer).setRelativeLayer(t, relativeParent, 2);
+        verify(surfaceAnimator, never()).setLayer(any(), anyInt());
+        verify(surfaceAnimator, never()).setRelativeLayer(any(), any(), anyInt());
+    }
+
     /* Used so we can gain access to some protected members of the {@link WindowContainer} class */
     private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
         private final int mLayer;
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 1f6065f..6626aa4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -1140,6 +1140,7 @@
         private int mCreateActivityCount = 0;
         @Nullable
         private TaskFragmentOrganizer mOrganizer;
+        private IBinder mFragmentToken;
 
         TaskFragmentBuilder(ActivityTaskManagerService service) {
             mAtm = service;
@@ -1171,10 +1172,15 @@
             return this;
         }
 
+        TaskFragmentBuilder setFragmentToken(@Nullable IBinder fragmentToken) {
+            mFragmentToken = fragmentToken;
+            return this;
+        }
+
         TaskFragment build() {
             SystemServicesTestRule.checkHoldsLock(mAtm.mGlobalLock);
 
-            final TaskFragment taskFragment = new TaskFragment(mAtm, null /* fragmentToken */,
+            final TaskFragment taskFragment = new TaskFragment(mAtm, mFragmentToken,
                     mOrganizer != null);
             if (mParentTask == null && mCreateParentTask) {
                 mParentTask = new TaskBuilder(mAtm.mTaskSupervisor).build();
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 763159a..b3b1491 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -561,6 +561,7 @@
 
             switch (msg.what) {
                 case MSG_CHECK_STORAGE_DELTA: {
+                    mStats.restat(Environment.getDataDirectory().getAbsolutePath());
                     long bytesDelta = Math.abs(mPreviousBytes - mStats.getAvailableBytes());
                     if (bytesDelta > mMinimumThresholdBytes) {
                         mPreviousBytes = mStats.getAvailableBytes();
@@ -583,6 +584,7 @@
 
                     // If errors occurred getting the quotas from disk, let's re-calc them.
                     if (mPreviousBytes < 0) {
+                        mStats.restat(Environment.getDataDirectory().getAbsolutePath());
                         mPreviousBytes = mStats.getAvailableBytes();
                         recalculateQuotas(strategy);
                     }
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 36d8c85..c4a8e81 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -891,7 +891,7 @@
             pw.printPair("shortcutId", event.mShortcutId);
         }
         if (event.mEventType == Event.STANDBY_BUCKET_CHANGED) {
-            pw.printPair("standbyBucket", event.getStandbyBucket());
+            pw.printPair("standbyBucket", event.getAppStandbyBucket());
             pw.printPair("reason", UsageStatsManager.reasonToString(event.getStandbyReason()));
         } else if (event.mEventType == Event.ACTIVITY_RESUMED
                 || event.mEventType == Event.ACTIVITY_PAUSED
diff --git a/services/voiceinteraction/Android.bp b/services/voiceinteraction/Android.bp
index 702ddb1..af0eca9 100644
--- a/services/voiceinteraction/Android.bp
+++ b/services/voiceinteraction/Android.bp
@@ -18,5 +18,9 @@
     name: "services.voiceinteraction",
     defaults: ["platform_service_defaults"],
     srcs: [":services.voiceinteraction-sources"],
-    libs: ["services.core"],
+    libs: [
+        "services.core",
+        "android.hardware.power-V1-java",
+        "android.hardware.power-V1.0-java",
+    ],
 }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index cc021a9..08e9703 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -43,11 +43,13 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.graphics.Bitmap;
+import android.hardware.power.Boost;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.PowerManagerInternal;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -62,6 +64,7 @@
 import com.android.internal.app.AssistUtils;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
+import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.am.AssistDataRequester;
 import com.android.server.am.AssistDataRequester.AssistDataRequesterCallbacks;
@@ -70,13 +73,20 @@
 import com.android.server.wm.ActivityAssistInfo;
 
 import java.io.PrintWriter;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.List;
 
 final class VoiceInteractionSessionConnection implements ServiceConnection,
         AssistDataRequesterCallbacks {
 
-    final static String TAG = "VoiceInteractionServiceManager";
+    static final String TAG = "VoiceInteractionServiceManager";
+    static final int POWER_BOOST_TIMEOUT_MS = Integer.parseInt(
+            System.getProperty("vendor.powerhal.interaction.max", "200"));
+    static final int BOOST_TIMEOUT_MS = 300;
+    // TODO: To avoid ap doesn't call hide, only 10 secs for now, need a better way to manage it
+    //  in the future.
+    static final int MAX_POWER_BOOST_TIMEOUT = 10_000;
 
     final IBinder mToken = new Binder();
     final Object mLock;
@@ -104,6 +114,45 @@
     ArrayList<IVoiceInteractionSessionShowCallback> mPendingShowCallbacks = new ArrayList<>();
     private List<ActivityAssistInfo> mPendingHandleAssistWithoutData = new ArrayList<>();
     AssistDataRequester mAssistDataRequester;
+    private final PowerManagerInternal mPowerManagerInternal;
+    private PowerBoostSetter mSetPowerBoostRunnable;
+    private final Handler mFgHandler;
+
+    class PowerBoostSetter implements Runnable {
+
+        private boolean mCanceled;
+        private final Instant mExpiryTime;
+
+        PowerBoostSetter(Instant expiryTime) {
+            mExpiryTime = expiryTime;
+        }
+
+        @Override
+        public void run() {
+            synchronized (mLock) {
+                if (mCanceled) {
+                    return;
+                }
+                // To avoid voice interaction service does not call hide to cancel setting
+                // power boost. We will cancel set boost when reaching the max timeout.
+                if (Instant.now().isBefore(mExpiryTime)) {
+                    mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, BOOST_TIMEOUT_MS);
+                    if (mSetPowerBoostRunnable != null) {
+                        mFgHandler.postDelayed(mSetPowerBoostRunnable, POWER_BOOST_TIMEOUT_MS);
+                    }
+                } else {
+                    Slog.w(TAG, "Reset power boost INTERACTION because reaching max timeout.");
+                    mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, /* durationMs */ -1);
+                }
+            }
+        }
+
+        void cancel() {
+            synchronized (mLock) {
+                mCanceled =  true;
+            }
+        }
+    }
 
     IVoiceInteractionSessionShowCallback mShowCallback =
             new IVoiceInteractionSessionShowCallback.Stub() {
@@ -152,7 +201,9 @@
         mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
         mIWindowManager = IWindowManager.Stub.asInterface(
                 ServiceManager.getService(Context.WINDOW_SERVICE));
+        mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
         mAppOps = context.getSystemService(AppOpsManager.class);
+        mFgHandler = FgThread.getHandler();
         mAssistDataRequester = new AssistDataRequester(mContext, mIWindowManager,
                 (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE),
                 this, mLock, OP_ASSIST_STRUCTURE, OP_ASSIST_SCREENSHOT);
@@ -255,6 +306,13 @@
                     mPendingHandleAssistWithoutData = topActivities;
                 }
             }
+            // remove if already existing one.
+            if (mSetPowerBoostRunnable != null) {
+                mSetPowerBoostRunnable.cancel();
+            }
+            mSetPowerBoostRunnable = new PowerBoostSetter(
+                    Instant.now().plusMillis(MAX_POWER_BOOST_TIMEOUT));
+            mFgHandler.post(mSetPowerBoostRunnable);
             mCallback.onSessionShown(this);
             return true;
         }
@@ -420,6 +478,12 @@
                     } catch (RemoteException e) {
                     }
                 }
+                if (mSetPowerBoostRunnable != null) {
+                    mSetPowerBoostRunnable.cancel();
+                    mSetPowerBoostRunnable = null;
+                }
+                // A negative value indicates canceling previous boost.
+                mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, /* durationMs */ -1);
                 mCallback.onSessionHidden(this);
             }
             if (mFullyBound) {
diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
index fe7e5976..41e24dd 100644
--- a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
@@ -26,8 +26,10 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 
@@ -101,9 +103,11 @@
             }
 
             mSignalThresholdInfos = new ArrayList<>(signalThresholdInfos);
-            // Sort the collection with RAN ascending order, make the ordering not matter for equals
+            // Sort the collection with RAN and then SignalMeasurementType ascending order, make the
+            // ordering not matter for equals
             mSignalThresholdInfos.sort(
-                    Comparator.comparingInt(SignalThresholdInfo::getRadioAccessNetworkType));
+                    Comparator.comparingInt(SignalThresholdInfo::getRadioAccessNetworkType)
+                            .thenComparing(SignalThresholdInfo::getSignalMeasurementType));
             return this;
         }
 
@@ -144,7 +148,7 @@
          * @return the SignalStrengthUpdateRequest object
          *
          * @throws IllegalArgumentException if the SignalThresholdInfo collection is empty size, the
-         * radio access network type in the collection is not unique
+         * signal measurement type for the same RAN in the collection is not unique
          */
         public @NonNull SignalStrengthUpdateRequest build() {
             return new SignalStrengthUpdateRequest(mSignalThresholdInfos,
@@ -258,14 +262,23 @@
     }
 
     /**
-     * Throw IAE when the RAN in the collection is not unique.
+     * Throw IAE if SignalThresholdInfo collection is null or empty,
+     * or the SignalMeasurementType for the same RAN in the collection is not unique.
      */
     private static void validate(Collection<SignalThresholdInfo> infos) {
-        Set<Integer> uniqueRan = new HashSet<>(infos.size());
+        if (infos == null || infos.isEmpty()) {
+            throw new IllegalArgumentException("SignalThresholdInfo collection is null or empty");
+        }
+
+        // Map from RAN to set of SignalMeasurementTypes
+        Map<Integer, Set<Integer>> ranToTypes = new HashMap<>(infos.size());
         for (SignalThresholdInfo info : infos) {
             final int ran = info.getRadioAccessNetworkType();
-            if (!uniqueRan.add(ran)) {
-                throw new IllegalArgumentException("RAN: " + ran + " is not unique");
+            final int type = info.getSignalMeasurementType();
+            ranToTypes.putIfAbsent(ran, new HashSet<>());
+            if (!ranToTypes.get(ran).add(type)) {
+                throw new IllegalArgumentException(
+                        "SignalMeasurementType " + type + " for RAN " + ran + " is not unique");
             }
         }
     }
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index a0b8970..4339cd2 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -2602,6 +2602,19 @@
      *  sending the message.
      * @param sentIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is successfully sent, or failed
+     * The result code will be <code>Activity.RESULT_OK</code> for success
+     * or one of these errors:<br>
+     * <code>MMS_ERROR_UNSPECIFIED</code><br>
+     * <code>MMS_ERROR_INVALID_APN</code><br>
+     * <code>MMS_ERROR_UNABLE_CONNECT_MMS</code><br>
+     * <code>MMS_ERROR_HTTP_FAILURE</code><br>
+     * <code>MMS_ERROR_IO_ERROR</code><br>
+     * <code>MMS_ERROR_RETRY</code><br>
+     * <code>MMS_ERROR_CONFIGURATION_ERROR</code><br>
+     * <code>MMS_ERROR_NO_DATA_NETWORK</code><br>
+     * <code>MMS_ERROR_INVALID_SUBSCRIPTION_ID</code><br>
+     * <code>MMS_ERROR_INACTIVE_SUBSCRIPTION</code><br>
+     * <code>MMS_ERROR_DATA_DISABLED</code><br>
      * @throws IllegalArgumentException if contentUri is empty
      */
     public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl,
@@ -2630,6 +2643,19 @@
      *  sending the message.
      * @param sentIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is successfully sent, or failed
+     * The result code will be <code>Activity.RESULT_OK</code> for success
+     * or one of these errors:<br>
+     * <code>MMS_ERROR_UNSPECIFIED</code><br>
+     * <code>MMS_ERROR_INVALID_APN</code><br>
+     * <code>MMS_ERROR_UNABLE_CONNECT_MMS</code><br>
+     * <code>MMS_ERROR_HTTP_FAILURE</code><br>
+     * <code>MMS_ERROR_IO_ERROR</code><br>
+     * <code>MMS_ERROR_RETRY</code><br>
+     * <code>MMS_ERROR_CONFIGURATION_ERROR</code><br>
+     * <code>MMS_ERROR_NO_DATA_NETWORK</code><br>
+     * <code>MMS_ERROR_INVALID_SUBSCRIPTION_ID</code><br>
+     * <code>MMS_ERROR_INACTIVE_SUBSCRIPTION</code><br>
+     * <code>MMS_ERROR_DATA_DISABLED</code><br>
      * @param messageId an id that uniquely identifies the message requested to be sent.
      * Used for logging and diagnostics purposes. The id may be 0.
      * @throws IllegalArgumentException if contentUri is empty
@@ -2677,6 +2703,19 @@
      *  downloading the message.
      * @param downloadedIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is downloaded, or the download is failed
+     * The result code will be <code>Activity.RESULT_OK</code> for success
+     * or one of these errors:<br>
+     * <code>MMS_ERROR_UNSPECIFIED</code><br>
+     * <code>MMS_ERROR_INVALID_APN</code><br>
+     * <code>MMS_ERROR_UNABLE_CONNECT_MMS</code><br>
+     * <code>MMS_ERROR_HTTP_FAILURE</code><br>
+     * <code>MMS_ERROR_IO_ERROR</code><br>
+     * <code>MMS_ERROR_RETRY</code><br>
+     * <code>MMS_ERROR_CONFIGURATION_ERROR</code><br>
+     * <code>MMS_ERROR_NO_DATA_NETWORK</code><br>
+     * <code>MMS_ERROR_INVALID_SUBSCRIPTION_ID</code><br>
+     * <code>MMS_ERROR_INACTIVE_SUBSCRIPTION</code><br>
+     * <code>MMS_ERROR_DATA_DISABLED</code><br>
      * @throws IllegalArgumentException if locationUrl or contentUri is empty
      */
     public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri,
@@ -2707,6 +2746,19 @@
      *  downloading the message.
      * @param downloadedIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is downloaded, or the download is failed
+     * The result code will be <code>Activity.RESULT_OK</code> for success
+     * or one of these errors:<br>
+     * <code>MMS_ERROR_UNSPECIFIED</code><br>
+     * <code>MMS_ERROR_INVALID_APN</code><br>
+     * <code>MMS_ERROR_UNABLE_CONNECT_MMS</code><br>
+     * <code>MMS_ERROR_HTTP_FAILURE</code><br>
+     * <code>MMS_ERROR_IO_ERROR</code><br>
+     * <code>MMS_ERROR_RETRY</code><br>
+     * <code>MMS_ERROR_CONFIGURATION_ERROR</code><br>
+     * <code>MMS_ERROR_NO_DATA_NETWORK</code><br>
+     * <code>MMS_ERROR_INVALID_SUBSCRIPTION_ID</code><br>
+     * <code>MMS_ERROR_INACTIVE_SUBSCRIPTION</code><br>
+     * <code>MMS_ERROR_DATA_DISABLED</code><br>
      * @param messageId an id that uniquely identifies the message requested to be downloaded.
      * Used for logging and diagnostics purposes. The id may be 0.
      * @throws IllegalArgumentException if locationUrl or contentUri is empty
@@ -2739,15 +2791,62 @@
     }
 
     // MMS send/download failure result codes
+
+    /**
+     * Unspecific MMS error occurred during send/download.
+     */
     public static final int MMS_ERROR_UNSPECIFIED = 1;
+
+    /**
+     * ApnException occurred during MMS network setup.
+     */
     public static final int MMS_ERROR_INVALID_APN = 2;
+
+    /**
+     * An error occurred during the MMS connection setup.
+     */
     public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3;
+
+    /**
+     * An error occurred during the HTTP client setup.
+     */
     public static final int MMS_ERROR_HTTP_FAILURE = 4;
+
+    /**
+     * An I/O error occurred reading the PDU.
+     */
     public static final int MMS_ERROR_IO_ERROR = 5;
+
+    /**
+     * An error occurred while retrying sending/downloading the MMS.
+     */
     public static final int MMS_ERROR_RETRY = 6;
+
+    /**
+     * The carrier-dependent configuration values could not be loaded.
+     */
     public static final int MMS_ERROR_CONFIGURATION_ERROR = 7;
+
+    /**
+     * There is no data network.
+     */
     public static final int MMS_ERROR_NO_DATA_NETWORK = 8;
 
+    /**
+     * The subscription id for the send/download is invalid.
+     */
+    public static final int MMS_ERROR_INVALID_SUBSCRIPTION_ID = 9;
+
+    /**
+     * The subscription id for the send/download is inactive.
+     */
+    public static final int MMS_ERROR_INACTIVE_SUBSCRIPTION = 10;
+
+    /**
+     * Data is disabled for the MMS APN.
+     */
+    public static final int MMS_ERROR_DATA_DISABLED = 11;
+
     /** Intent extra name for MMS sending result data in byte array type */
     public static final String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
     /** Intent extra name for HTTP status code for MMS HTTP failure in integer type */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index 9b34853..9f26c31 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -17,7 +17,6 @@
 
 package com.android.server.wm.flicker.close
 
-import android.platform.test.annotations.Postsubmit
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -80,11 +79,6 @@
     @Test
     override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
 
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
-
     companion object {
         /**
          * Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index e380794..795766f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.server.wm.flicker.close
 
-import android.platform.test.annotations.Postsubmit
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -79,11 +78,6 @@
     @Test
     override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
 
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
-
     companion object {
         /**
          * Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
index bcb4417..a9568b3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.ime
 
 import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
@@ -96,21 +96,21 @@
     /**
      * Checks that [FlickerComponentName.IME] window becomes visible during the transition
      */
-    @Postsubmit
+    @Presubmit
     @Test
     fun imeWindowBecomesVisible() = testSpec.imeWindowBecomesVisible()
 
     /**
      * Checks that [FlickerComponentName.IME] layer becomes visible during the transition
      */
-    @Postsubmit
+    @Presubmit
     @Test
     fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible()
 
     /**
      * Checks that [FlickerComponentName.IME] layer is invisible at the start of the transition
      */
-    @Postsubmit
+    @Presubmit
     @Test
     fun imeLayerNotExistsStart() {
         testSpec.assertLayersStart {
@@ -121,7 +121,7 @@
     /**
      * Checks that [FlickerComponentName.IME] layer is visible at the end of the transition
      */
-    @Postsubmit
+    @Presubmit
     @Test
     fun imeLayerExistsEnd() {
         testSpec.assertLayersEnd {
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index 558798d..7a564fc 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -55,7 +55,7 @@
     ],
     data: [
         ":com.android.apex.apkrollback.test_v1",
-        ":com.android.apex.cts.shim.v2_prebuilt",
+        ":StagedInstallTestApexV2",
         ":StagedInstallTestApexV2_WrongSha",
         ":TestAppAv1",
         ":test.rebootless_apex_v1",
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 991b280..817effd 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -29,6 +29,17 @@
 static const char* PROG_NAME = "validatekeymaps";
 static bool gQuiet = false;
 
+/**
+ * Return true if 'str' contains 'substr', ignoring case.
+ */
+static bool containsSubstringCaseInsensitive(std::string_view str, std::string_view substr) {
+    auto it = std::search(str.begin(), str.end(), substr.begin(), substr.end(),
+                          [](char left, char right) {
+                              return std::tolower(left) == std::tolower(right);
+                          });
+    return it != str.end();
+}
+
 enum class FileType {
     UNKNOWN,
     KEY_LAYOUT,
@@ -85,6 +96,36 @@
     return FileType::UNKNOWN;
 }
 
+/**
+ * Return true if the filename is allowed, false otherwise.
+ */
+static bool validateKeyLayoutFileName(const std::string& filename) {
+    static const std::string kMicrosoftReason =
+            "Microsoft's controllers are designed to work with Generic.kl. Please check with "
+            "Microsoft prior to adding these layouts. See b/194334400";
+    static const std::vector<std::pair<std::string, std::string>> kBannedDevices{
+            std::make_pair("Vendor_0a5c_Product_8502",
+                           "This vendorId/productId combination conflicts with 'SnakeByte "
+                           "iDroid:con', 'BT23BK keyboard', and other keyboards. Instead, consider "
+                           "matching these specific devices by name. See b/36976285, b/191720859"),
+            std::make_pair("Vendor_045e_Product_0b05", kMicrosoftReason),
+            std::make_pair("Vendor_045e_Product_0b20", kMicrosoftReason),
+            std::make_pair("Vendor_045e_Product_0b21", kMicrosoftReason),
+            std::make_pair("Vendor_045e_Product_0b22", kMicrosoftReason),
+    };
+
+    for (const auto& [filenameSubstr, reason] : kBannedDevices) {
+        if (containsSubstringCaseInsensitive(filename, filenameSubstr)) {
+            error("You are trying to add a key layout %s, which matches %s. ", filename.c_str(),
+                  filenameSubstr.c_str());
+            error("This would cause some devices to function incorrectly. ");
+            error("%s. ", reason.c_str());
+            return false;
+        }
+    }
+    return true;
+}
+
 static bool validateFile(const char* filename) {
     log("Validating file '%s'...\n", filename);
 
@@ -95,6 +136,9 @@
             return false;
 
         case FileType::KEY_LAYOUT: {
+            if (!validateKeyLayoutFileName(filename)) {
+                return false;
+            }
             base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(filename);
             if (!ret.ok()) {
                 error("Error %s parsing key layout file.\n\n", ret.error().message().c_str());