Merge "Add a SetSchema API and builders."
diff --git a/apex/jobscheduler/service/Android.bp b/apex/jobscheduler/service/Android.bp
index c9d9d6c..69a9fd8 100644
--- a/apex/jobscheduler/service/Android.bp
+++ b/apex/jobscheduler/service/Android.bp
@@ -9,6 +9,7 @@
     ],
 
     libs: [
+        "app-compat-annotations",
         "framework",
         "services.core",
     ],
diff --git a/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING
new file mode 100644
index 0000000..8fbfb1d
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING
@@ -0,0 +1,22 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksMockingServicesTests",
+      "file_patterns": [
+        "DeviceIdleController\\.java"
+      ],
+      "options": [
+        {"include-filter": "com.android.server.DeviceIdleControllerTest"},
+        {"exclude-annotation": "androidx.test.filters.FlakyTest"}
+      ]
+    }
+  ],
+  "postsubmit": [
+    {
+      "name": "FrameworksMockingServicesTests",
+      "options": [
+        {"include-filter": "com.android.server"}
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING
new file mode 100644
index 0000000..bc7a7d3
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING
@@ -0,0 +1,19 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksMockingServicesTests",
+      "options": [
+        {"include-filter": "com.android.server.DeviceIdleControllerTest"},
+        {"exclude-annotation": "androidx.test.filters.FlakyTest"}
+      ]
+    }
+  ],
+  "postsubmit": [
+    {
+      "name": "FrameworksMockingServicesTests",
+      "options": [
+        {"include-filter": "com.android.server"}
+      ]
+    }
+  ]
+}
\ No newline at end of file
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 9310762..f6512a6 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -37,12 +37,15 @@
 import android.app.job.JobWorkItem;
 import android.app.usage.UsageStatsManager;
 import android.app.usage.UsageStatsManagerInternal;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -54,6 +57,7 @@
 import android.os.BatteryStats;
 import android.os.BatteryStatsInternal;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -67,6 +71,7 @@
 import android.os.WorkSource;
 import android.provider.Settings;
 import android.text.format.DateUtils;
+import android.util.ArrayMap;
 import android.util.KeyValueListParser;
 import android.util.Log;
 import android.util.Slog;
@@ -85,6 +90,7 @@
 import com.android.server.DeviceIdleInternal;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
+import com.android.server.compat.PlatformCompat;
 import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
 import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
 import com.android.server.job.controllers.BackgroundJobsController;
@@ -102,6 +108,9 @@
 import com.android.server.job.restrictions.ThermalStatusRestriction;
 import com.android.server.usage.AppStandbyInternal;
 import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
+import com.android.server.utils.quota.Categorizer;
+import com.android.server.utils.quota.Category;
+import com.android.server.utils.quota.CountQuotaTracker;
 
 import libcore.util.EmptyArray;
 
@@ -145,6 +154,16 @@
     /** The maximum number of jobs that we allow an unprivileged app to schedule */
     private static final int MAX_JOBS_PER_APP = 100;
 
+    /**
+     * {@link #schedule(JobInfo)}, {@link #scheduleAsPackage(JobInfo, String, int, String)}, and
+     * {@link #enqueue(JobInfo, JobWorkItem)} will throw a {@link IllegalStateException} if the app
+     * calls the APIs too frequently.
+     */
+    @ChangeId
+    // This means the change will be enabled for target SDK larger than 29 (Q), meaning R and up.
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+    protected static final long CRASH_ON_EXCEEDED_LIMIT = 144363383L;
+
     @VisibleForTesting
     public static Clock sSystemClock = Clock.systemUTC();
 
@@ -237,6 +256,10 @@
      */
     private final List<JobRestriction> mJobRestrictions;
 
+    private final CountQuotaTracker mQuotaTracker;
+    private static final String QUOTA_TRACKER_SCHEDULE_TAG = ".schedule()";
+    private final PlatformCompat mPlatformCompat;
+
     /**
      * Queue of pending jobs. The JobServiceContext class will receive jobs from this list
      * when ready to execute them.
@@ -276,6 +299,11 @@
     final SparseIntArray mBackingUpUids = new SparseIntArray();
 
     /**
+     * Cache of debuggable app status.
+     */
+    final ArrayMap<String, Boolean> mDebuggableApps = new ArrayMap<>();
+
+    /**
      * Named indices into standby bucket arrays, for clarity in referring to
      * specific buckets' bookkeeping.
      */
@@ -315,6 +343,10 @@
                         final StateController sc = mControllers.get(controller);
                         sc.onConstantsUpdatedLocked();
                     }
+                    mQuotaTracker.setEnabled(mConstants.ENABLE_API_QUOTAS);
+                    mQuotaTracker.setCountLimit(Category.SINGLE_CATEGORY,
+                            mConstants.API_QUOTA_SCHEDULE_COUNT,
+                            mConstants.API_QUOTA_SCHEDULE_WINDOW_MS);
                 } catch (IllegalArgumentException e) {
                     // Failed to parse the settings string, log this and move on
                     // with defaults.
@@ -466,6 +498,11 @@
         private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac";
         private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac";
         private static final String DEPRECATED_KEY_USE_HEARTBEATS = "use_heartbeats";
+        private static final String KEY_ENABLE_API_QUOTAS = "enable_api_quotas";
+        private static final String KEY_API_QUOTA_SCHEDULE_COUNT = "aq_schedule_count";
+        private static final String KEY_API_QUOTA_SCHEDULE_WINDOW_MS = "aq_schedule_window_ms";
+        private static final String KEY_API_QUOTA_SCHEDULE_THROW_EXCEPTION =
+                "aq_schedule_throw_exception";
 
         private static final int DEFAULT_MIN_IDLE_COUNT = 1;
         private static final int DEFAULT_MIN_CHARGING_COUNT = 1;
@@ -484,6 +521,10 @@
         private static final long DEFAULT_MIN_EXP_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;
         private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
         private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
+        private static final boolean DEFAULT_ENABLE_API_QUOTAS = true;
+        private static final int DEFAULT_API_QUOTA_SCHEDULE_COUNT = 500;
+        private static final long DEFAULT_API_QUOTA_SCHEDULE_WINDOW_MS = MINUTE_IN_MILLIS;
+        private static final boolean DEFAULT_API_QUOTA_SCHEDULE_THROW_EXCEPTION = true;
 
         /**
          * Minimum # of idle jobs that must be ready in order to force the JMS to schedule things
@@ -618,6 +659,24 @@
          */
         public float CONN_PREFETCH_RELAX_FRAC = DEFAULT_CONN_PREFETCH_RELAX_FRAC;
 
+        /**
+         * Whether to enable quota limits on APIs.
+         */
+        public boolean ENABLE_API_QUOTAS = DEFAULT_ENABLE_API_QUOTAS;
+        /**
+         * The maximum number of schedule() calls an app can make in a set amount of time.
+         */
+        public int API_QUOTA_SCHEDULE_COUNT = DEFAULT_API_QUOTA_SCHEDULE_COUNT;
+        /**
+         * The time window that {@link #API_QUOTA_SCHEDULE_COUNT} should be evaluated over.
+         */
+        public long API_QUOTA_SCHEDULE_WINDOW_MS = DEFAULT_API_QUOTA_SCHEDULE_WINDOW_MS;
+        /**
+         * Whether to throw an exception when an app hits its schedule quota limit.
+         */
+        public boolean API_QUOTA_SCHEDULE_THROW_EXCEPTION =
+                DEFAULT_API_QUOTA_SCHEDULE_THROW_EXCEPTION;
+
         private final KeyValueListParser mParser = new KeyValueListParser(',');
 
         void updateConstantsLocked(String value) {
@@ -678,6 +737,16 @@
                     DEFAULT_CONN_CONGESTION_DELAY_FRAC);
             CONN_PREFETCH_RELAX_FRAC = mParser.getFloat(KEY_CONN_PREFETCH_RELAX_FRAC,
                     DEFAULT_CONN_PREFETCH_RELAX_FRAC);
+
+            ENABLE_API_QUOTAS = mParser.getBoolean(KEY_ENABLE_API_QUOTAS,
+                DEFAULT_ENABLE_API_QUOTAS);
+            API_QUOTA_SCHEDULE_COUNT = Math.max(250,
+                    mParser.getInt(KEY_API_QUOTA_SCHEDULE_COUNT, DEFAULT_API_QUOTA_SCHEDULE_COUNT));
+            API_QUOTA_SCHEDULE_WINDOW_MS = mParser.getDurationMillis(
+                KEY_API_QUOTA_SCHEDULE_WINDOW_MS, DEFAULT_API_QUOTA_SCHEDULE_WINDOW_MS);
+            API_QUOTA_SCHEDULE_THROW_EXCEPTION = mParser.getBoolean(
+                    KEY_API_QUOTA_SCHEDULE_THROW_EXCEPTION,
+                    DEFAULT_API_QUOTA_SCHEDULE_THROW_EXCEPTION);
         }
 
         void dump(IndentingPrintWriter pw) {
@@ -716,6 +785,12 @@
             pw.printPair(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println();
             pw.printPair(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println();
 
+            pw.printPair(KEY_ENABLE_API_QUOTAS, ENABLE_API_QUOTAS).println();
+            pw.printPair(KEY_API_QUOTA_SCHEDULE_COUNT, API_QUOTA_SCHEDULE_COUNT).println();
+            pw.printPair(KEY_API_QUOTA_SCHEDULE_WINDOW_MS, API_QUOTA_SCHEDULE_WINDOW_MS).println();
+            pw.printPair(KEY_API_QUOTA_SCHEDULE_THROW_EXCEPTION,
+                    API_QUOTA_SCHEDULE_THROW_EXCEPTION).println();
+
             pw.decreaseIndent();
         }
 
@@ -746,6 +821,12 @@
             proto.write(ConstantsProto.MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME);
             proto.write(ConstantsProto.CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC);
             proto.write(ConstantsProto.CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC);
+
+            proto.write(ConstantsProto.ENABLE_API_QUOTAS, ENABLE_API_QUOTAS);
+            proto.write(ConstantsProto.API_QUOTA_SCHEDULE_COUNT, API_QUOTA_SCHEDULE_COUNT);
+            proto.write(ConstantsProto.API_QUOTA_SCHEDULE_WINDOW_MS, API_QUOTA_SCHEDULE_WINDOW_MS);
+            proto.write(ConstantsProto.API_QUOTA_SCHEDULE_THROW_EXCEPTION,
+                    API_QUOTA_SCHEDULE_THROW_EXCEPTION);
         }
     }
 
@@ -847,6 +928,7 @@
                         for (int c = 0; c < mControllers.size(); ++c) {
                             mControllers.get(c).onAppRemovedLocked(pkgName, pkgUid);
                         }
+                        mDebuggableApps.remove(pkgName);
                     }
                 }
             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
@@ -972,6 +1054,45 @@
 
     public int scheduleAsPackage(JobInfo job, JobWorkItem work, int uId, String packageName,
             int userId, String tag) {
+        final String pkg = packageName == null ? job.getService().getPackageName() : packageName;
+        if (!mQuotaTracker.isWithinQuota(userId, pkg, QUOTA_TRACKER_SCHEDULE_TAG)) {
+            Slog.e(TAG, userId + "-" + pkg + " has called schedule() too many times");
+            // TODO(b/145551233): attempt to restrict app
+            if (mConstants.API_QUOTA_SCHEDULE_THROW_EXCEPTION
+                    && mPlatformCompat.isChangeEnabledByPackageName(
+                            CRASH_ON_EXCEEDED_LIMIT, pkg, userId)) {
+                final boolean isDebuggable;
+                synchronized (mLock) {
+                    if (!mDebuggableApps.containsKey(packageName)) {
+                        try {
+                            final ApplicationInfo appInfo = AppGlobals.getPackageManager()
+                                    .getApplicationInfo(pkg, 0, userId);
+                            if (appInfo != null) {
+                                mDebuggableApps.put(packageName,
+                                        (appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
+                            } else {
+                                return JobScheduler.RESULT_FAILURE;
+                            }
+                        } catch (RemoteException e) {
+                            throw new RuntimeException(e);
+                        }
+                    }
+                    isDebuggable = mDebuggableApps.get(packageName);
+                }
+                if (isDebuggable) {
+                    // Only throw the exception for debuggable apps.
+                    throw new IllegalStateException(
+                            "schedule()/enqueue() called more than "
+                                    + mQuotaTracker.getLimit(Category.SINGLE_CATEGORY)
+                                    + " times in the past "
+                                    + mQuotaTracker.getWindowSizeMs(Category.SINGLE_CATEGORY)
+                                    + "ms");
+                }
+            }
+            return JobScheduler.RESULT_FAILURE;
+        }
+        mQuotaTracker.noteEvent(userId, pkg, QUOTA_TRACKER_SCHEDULE_TAG);
+
         try {
             if (ActivityManager.getService().isAppStartModeDisabled(uId,
                     job.getService().getPackageName())) {
@@ -1296,6 +1417,12 @@
         // Set up the app standby bucketing tracker
         mStandbyTracker = new StandbyTracker();
         mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
+        mPlatformCompat =
+                (PlatformCompat) ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
+        mQuotaTracker = new CountQuotaTracker(context, Categorizer.SINGLE_CATEGORIZER);
+        mQuotaTracker.setCountLimit(Category.SINGLE_CATEGORY,
+                mConstants.API_QUOTA_SCHEDULE_COUNT,
+                mConstants.API_QUOTA_SCHEDULE_WINDOW_MS);
 
         AppStandbyInternal appStandby = LocalServices.getService(AppStandbyInternal.class);
         appStandby.addListener(mStandbyTracker);
@@ -2745,7 +2872,7 @@
                 return new ParceledListSlice<>(snapshots);
             }
         }
-    };
+    }
 
     // Shell command infrastructure: run the given job immediately
     int executeRunCommand(String pkgName, int userId, int jobId, boolean force) {
@@ -2968,6 +3095,10 @@
         return 0;
     }
 
+    void resetScheduleQuota() {
+        mQuotaTracker.clear();
+    }
+
     void triggerDockState(boolean idleState) {
         final Intent dockIntent;
         if (idleState) {
@@ -3030,6 +3161,9 @@
             }
             pw.println();
 
+            mQuotaTracker.dump(pw);
+            pw.println();
+
             pw.println("Started users: " + Arrays.toString(mStartedUsers));
             pw.print("Registered ");
             pw.print(mJobs.size());
@@ -3217,6 +3351,9 @@
             for (int u : mStartedUsers) {
                 proto.write(JobSchedulerServiceDumpProto.STARTED_USERS, u);
             }
+
+            mQuotaTracker.dump(proto, JobSchedulerServiceDumpProto.QUOTA_TRACKER);
+
             if (mJobs.size() > 0) {
                 final List<JobStatus> jobs = mJobs.mJobSet.getAllJobs();
                 sortJobs(jobs);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
index a5c6c01..6becf04 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -66,6 +66,8 @@
                     return getJobState(pw);
                 case "heartbeat":
                     return doHeartbeat(pw);
+                case "reset-schedule-quota":
+                    return resetScheduleQuota(pw);
                 case "trigger-dock-state":
                     return triggerDockState(pw);
                 default:
@@ -344,6 +346,18 @@
         return -1;
     }
 
+    private int resetScheduleQuota(PrintWriter pw) throws Exception {
+        checkPermission("reset schedule quota");
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mInternal.resetScheduleQuota();
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+        return 0;
+    }
+
     private int triggerDockState(PrintWriter pw) throws Exception {
         checkPermission("trigger wireless charging dock state");
 
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
index 82292cf..b9df30a 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
@@ -17,7 +17,7 @@
 package com.android.server.usage;
 
 import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
-import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED;
+import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_USER;
 import static android.app.usage.UsageStatsManager.REASON_MAIN_MASK;
 import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED;
 import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
@@ -441,7 +441,7 @@
                 elapsedRealtime, true);
         if (idle) {
             appUsageHistory.currentBucket = STANDBY_BUCKET_RARE;
-            appUsageHistory.bucketingReason = REASON_MAIN_FORCED;
+            appUsageHistory.bucketingReason = REASON_MAIN_FORCED_BY_USER;
         } else {
             appUsageHistory.currentBucket = STANDBY_BUCKET_ACTIVE;
             // This is to pretend that the app was just used, don't freeze the state anymore.
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 58eb589..eb0b54b 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -17,7 +17,8 @@
 package com.android.server.usage;
 
 import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
-import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED;
+import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM;
+import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_USER;
 import static android.app.usage.UsageStatsManager.REASON_MAIN_MASK;
 import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED;
 import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT;
@@ -565,7 +566,7 @@
 
                 // If the bucket was forced by the user/developer, leave it alone.
                 // A usage event will be the only way to bring it out of this forced state
-                if (oldMainReason == REASON_MAIN_FORCED) {
+                if (oldMainReason == REASON_MAIN_FORCED_BY_USER) {
                     return;
                 }
                 final int oldBucket = app.currentBucket;
@@ -783,7 +784,7 @@
         // Inform listeners if necessary
         if (previouslyIdle != stillIdle) {
             maybeInformListeners(packageName, userId, elapsedRealtime, standbyBucket,
-                    REASON_MAIN_FORCED, false);
+                    REASON_MAIN_FORCED_BY_USER, false);
             if (!stillIdle) {
                 notifyBatteryStats(packageName, userId, idle);
             }
@@ -1030,8 +1031,17 @@
                 callingPid, callingUid, userId, false, true, "setAppStandbyBucket", null);
         final boolean shellCaller = callingUid == Process.ROOT_UID
                 || callingUid == Process.SHELL_UID;
-        final boolean systemCaller = UserHandle.isCore(callingUid);
-        final int reason = systemCaller ? REASON_MAIN_FORCED : REASON_MAIN_PREDICTED;
+        final int reason;
+        // The Settings app runs in the system UID but in a separate process. Assume
+        // things coming from other processes are due to the user.
+        if ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && callingPid != Process.myPid())
+                || shellCaller) {
+            reason = REASON_MAIN_FORCED_BY_USER;
+        } else if (UserHandle.isCore(callingUid)) {
+            reason = REASON_MAIN_FORCED_BY_SYSTEM;
+        } else {
+            reason = REASON_MAIN_PREDICTED;
+        }
         final int packageFlags = PackageManager.MATCH_ANY_USER
                 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                 | PackageManager.MATCH_DIRECT_BOOT_AWARE;
@@ -1087,7 +1097,11 @@
             }
 
             // If the bucket was forced, don't allow prediction to override
-            if ((app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED && predicted) return;
+            if (predicted
+                    && ((app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_USER
+                    || (app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_SYSTEM)) {
+                return;
+            }
 
             // If the bucket is required to stay in a higher state for a specified duration, don't
             // override unless the duration has passed
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
new file mode 100644
index 0000000..cf70878
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
@@ -0,0 +1,19 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksServicesTests",
+      "options": [
+        {"include-filter": "com.android.server.usage"},
+        {"exclude-annotation": "androidx.test.filters.FlakyTest"}
+      ]
+    }
+  ],
+  "postsubmit": [
+    {
+      "name": "FrameworksServicesTests",
+      "options": [
+        {"include-filter": "com.android.server.usage"}
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index b3d4198..bbb87ab 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -1502,21 +1502,6 @@
         }
     }
 
-    private void pullPowerProfile(
-            int tagId, long elapsedNanos, long wallClockNanos,
-            List<StatsLogEventWrapper> pulledData) {
-        PowerProfile powerProfile = new PowerProfile(mContext);
-        Objects.requireNonNull(powerProfile);
-
-        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
-                wallClockNanos);
-        ProtoOutputStream proto = new ProtoOutputStream();
-        powerProfile.dumpDebug(proto);
-        proto.flush();
-        e.writeStorage(proto.getBytes());
-        pulledData.add(e);
-    }
-
     private void pullBuildInformation(int tagId,
             long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
         StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
@@ -2261,11 +2246,6 @@
                 break;
             }
 
-            case StatsLog.POWER_PROFILE: {
-                pullPowerProfile(tagId, elapsedNanos, wallClockNanos, ret);
-                break;
-            }
-
             case StatsLog.BUILD_INFORMATION: {
                 pullBuildInformation(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
diff --git a/api/current.txt b/api/current.txt
index 504f055..ba14b4e6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -30507,6 +30507,7 @@
     method @Nullable public java.security.cert.X509Certificate[] getCaCertificates();
     method public java.security.cert.X509Certificate getClientCertificate();
     method @Nullable public java.security.cert.X509Certificate[] getClientCertificateChain();
+    method @Nullable public java.security.PrivateKey getClientPrivateKey();
     method public String getDomainSuffixMatch();
     method public int getEapMethod();
     method public String getIdentity();
@@ -39205,6 +39206,7 @@
     method @NonNull public static android.app.PendingIntent createWriteRequest(@NonNull android.content.ContentResolver, @NonNull java.util.Collection<android.net.Uri>);
     method @Nullable public static android.net.Uri getDocumentUri(@NonNull android.content.Context, @NonNull android.net.Uri);
     method @NonNull public static java.util.Set<java.lang.String> getExternalVolumeNames(@NonNull android.content.Context);
+    method public static long getGeneration(@NonNull android.content.Context, @NonNull String);
     method public static android.net.Uri getMediaScannerUri();
     method @Nullable public static android.net.Uri getMediaUri(@NonNull android.content.Context, @NonNull android.net.Uri);
     method @NonNull public static java.util.Set<java.lang.String> getRecentExternalVolumeNames(@NonNull android.content.Context);
@@ -39515,6 +39517,7 @@
     field public static final String DISPLAY_NAME = "_display_name";
     field public static final String DOCUMENT_ID = "document_id";
     field public static final String DURATION = "duration";
+    field public static final String GENERATION = "generation";
     field public static final String GENRE = "genre";
     field public static final String HEIGHT = "height";
     field public static final String INSTANCE_ID = "instance_id";
@@ -45151,6 +45154,9 @@
     field public static final String ENABLE_EAP_METHOD_PREFIX_BOOL = "enable_eap_method_prefix_bool";
     field public static final String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX";
     field public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
+    field public static final String IMSI_KEY_AVAILABILITY_INT = "imsi_key_availability_int";
+    field public static final String KEY_5G_ICON_CONFIGURATION_STRING = "5g_icon_configuration_string";
+    field public static final String KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT = "5g_icon_display_grace_period_sec_int";
     field public static final String KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY = "5g_nr_ssrsrp_thresholds_int_array";
     field public static final String KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY = "5g_nr_ssrsrq_thresholds_int_array";
     field public static final String KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY = "5g_nr_sssinr_thresholds_int_array";
@@ -45164,18 +45170,32 @@
     field public static final String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
     field public static final String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool";
     field public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
+    field public static final String KEY_ALLOW_VIDEO_CALLING_FALLBACK_BOOL = "allow_video_calling_fallback_bool";
+    field public static final String KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL = "always_show_data_rat_icon_bool";
     field @Deprecated public static final String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool";
+    field public static final String KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN = "always_show_primary_signal_bar_in_opportunistic_network_boolean";
     field public static final String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
+    field public static final String KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY = "apn_settings_default_apn_types_string_array";
     field public static final String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool";
     field public static final String KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL = "call_barring_supports_deactivate_all_bool";
     field public static final String KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL = "call_barring_supports_password_change_bool";
     field public static final String KEY_CALL_BARRING_VISIBILITY_BOOL = "call_barring_visibility_bool";
     field public static final String KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY = "call_forwarding_blocks_while_roaming_string_array";
+    field public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING = "call_redirection_service_component_name_string";
+    field public static final String KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL = "carrier_allow_deflect_ims_call_bool";
     field public static final String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool";
     field public static final String KEY_CARRIER_APP_REQUIRED_DURING_SIM_SETUP_BOOL = "carrier_app_required_during_setup_bool";
     field public static final String KEY_CARRIER_CALL_SCREENING_APP_STRING = "call_screening_app";
+    field public static final String KEY_CARRIER_CERTIFICATE_STRING_ARRAY = "carrier_certificate_string_array";
+    field public static final String KEY_CARRIER_CONFIG_APPLIED_BOOL = "carrier_config_applied_bool";
     field public static final String KEY_CARRIER_CONFIG_VERSION_STRING = "carrier_config_version_string";
     field public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS = "carrier_data_call_permanent_failure_strings";
+    field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DCFAILURE_STRING_ARRAY = "carrier_default_actions_on_dcfailure_string_array";
+    field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DEFAULT_NETWORK_AVAILABLE = "carrier_default_actions_on_default_network_available_string_array";
+    field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY = "carrier_default_actions_on_redirection_string_array";
+    field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET = "carrier_default_actions_on_reset_string_array";
+    field public static final String KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY = "carrier_default_redirection_url_string_array";
+    field public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL = "carrier_default_wfc_ims_enabled_bool";
     field public static final String KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT = "carrier_default_wfc_ims_mode_int";
     field public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT = "carrier_default_wfc_ims_roaming_mode_int";
     field @Deprecated public static final String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL = "carrier_force_disable_etws_cmas_test_bool";
@@ -45188,11 +45208,13 @@
     field public static final String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool";
     field public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string";
     field public static final String KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL = "carrier_rcs_provisioning_required_bool";
+    field public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string";
     field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
     field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool";
     field public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
     field public static final String KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL = "carrier_ut_provisioning_required_bool";
     field public static final String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
+    field public static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL = "carrier_volte_override_wfc_provisioning_bool";
     field public static final String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
     field public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
     field public static final String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
@@ -45206,6 +45228,7 @@
     field public static final String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
     field public static final String KEY_CDMA_ROAMING_MODE_INT = "cdma_roaming_mode_int";
     field public static final String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
+    field public static final String KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL = "check_pricing_with_carrier_data_roaming_bool";
     field public static final String KEY_CI_ACTION_ON_SYS_UPDATE_BOOL = "ci_action_on_sys_update_bool";
     field public static final String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string";
     field public static final String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string";
@@ -45215,6 +45238,7 @@
     field public static final String KEY_CONFIG_IMS_RCS_PACKAGE_OVERRIDE_STRING = "config_ims_rcs_package_override_string";
     field public static final String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING = "config_plans_package_override_string";
     field public static final String KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL = "config_telephony_use_own_number_for_voicemail_bool";
+    field public static final String KEY_CONFIG_WIFI_DISABLE_IN_ECBM = "config_wifi_disable_in_ecbm";
     field public static final String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
     field public static final String KEY_DATA_LIMIT_NOTIFICATION_BOOL = "data_limit_notification_bool";
     field public static final String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long";
@@ -45226,6 +45250,7 @@
     field public static final String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
     field public static final String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
     field public static final String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
+    field public static final String KEY_DISABLE_CHARGE_INDICATION_BOOL = "disable_charge_indication_bool";
     field public static final String KEY_DISABLE_SUPPLEMENTARY_SERVICES_IN_AIRPLANE_MODE_BOOL = "disable_supplementary_services_in_airplane_mode_bool";
     field public static final String KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY = "disconnect_cause_play_busytone_int_array";
     field public static final String KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL = "display_hd_audio_property_bool";
@@ -45235,9 +45260,13 @@
     field public static final String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
     field public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
     field public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool";
+    field public static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool";
+    field public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL = "editable_wfc_roaming_mode_bool";
+    field public static final String KEY_EMERGENCY_NOTIFICATION_DELAY_INT = "emergency_notification_delay_int";
     field public static final String KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY = "emergency_number_prefix_string_array";
     field public static final String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
     field public static final String KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL = "enhanced_4g_lte_on_by_default_bool";
+    field public static final String KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT = "enhanced_4g_lte_title_variant_int";
     field public static final String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
     field public static final String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
     field public static final String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array";
@@ -45246,13 +45275,17 @@
     field public static final String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";
     field public static final String KEY_HIDE_ENHANCED_4G_LTE_BOOL = "hide_enhanced_4g_lte_bool";
     field public static final String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
+    field public static final String KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL = "hide_lte_plus_data_icon_bool";
     field public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
     field public static final String KEY_HIDE_PRESET_APN_DETAILS_BOOL = "hide_preset_apn_details_bool";
     field public static final String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
+    field public static final String KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS = "ignore_data_enabled_changed_for_video_calls";
+    field public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL = "ignore_rtt_mode_setting_bool";
     field public static final String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool";
     field public static final String KEY_IMS_CONFERENCE_SIZE_LIMIT_INT = "ims_conference_size_limit_int";
     field public static final String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int";
     field public static final String KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL = "is_ims_conference_size_enforced_bool";
+    field public static final String KEY_LTE_ENABLED_BOOL = "lte_enabled_bool";
     field public static final String KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY = "lte_rsrq_thresholds_int_array";
     field public static final String KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY = "lte_rssnr_thresholds_int_array";
     field public static final String KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL = "mdn_is_additional_voicemail_number_bool";
@@ -45288,6 +45321,7 @@
     field public static final String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl";
     field public static final String KEY_MMS_USER_AGENT_STRING = "userAgent";
     field public static final String KEY_MONTHLY_DATA_CYCLE_DAY_INT = "monthly_data_cycle_day_int";
+    field public static final String KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL = "only_auto_select_in_home_network";
     field public static final String KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = "only_single_dc_allowed_int_array";
     field public static final String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
     field public static final String KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG = "opportunistic_network_data_switch_hysteresis_time_long";
@@ -45301,15 +45335,24 @@
     field public static final String KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL = "prevent_clir_activation_and_deactivation_code_bool";
     field public static final String KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY = "radio_restart_failure_causes_int_array";
     field public static final String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string";
+    field public static final String KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY = "read_only_apn_fields_string_array";
+    field public static final String KEY_READ_ONLY_APN_TYPES_STRING_ARRAY = "read_only_apn_types_string_array";
     field public static final String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
     field @Deprecated public static final String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool";
     field public static final String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
+    field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool";
+    field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool";
     field public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
+    field public static final String KEY_SHOW_BLOCKING_PAY_PHONE_OPTION_BOOL = "show_blocking_pay_phone_option_bool";
     field public static final String KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL = "show_call_blocking_disabled_notification_always_bool";
+    field public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING = "show_carrier_data_icon_pattern_string";
     field public static final String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
     field public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
+    field public static final String KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL = "show_ims_registration_status_bool";
     field public static final String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
     field public static final String KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL = "show_signal_strength_in_sim_status_bool";
+    field public static final String KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL = "show_video_call_charges_alert_dialog_bool";
+    field public static final String KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL = "show_wfc_location_privacy_policy_bool";
     field public static final String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
     field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
     field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
@@ -45317,14 +45360,20 @@
     field public static final String KEY_SUPPORT_CLIR_NETWORK_DEFAULT_BOOL = "support_clir_network_default_bool";
     field public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
     field public static final String KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL = "support_emergency_sms_over_ims_bool";
+    field public static final String KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL = "support_enhanced_call_blocking_bool";
+    field public static final String KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL = "support_ims_conference_event_package_bool";
     field public static final String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
     field public static final String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
+    field public static final String KEY_SUPPORT_TDSCDMA_BOOL = "support_tdscdma_bool";
+    field public static final String KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY = "support_tdscdma_roaming_networks_string_array";
     field public static final String KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL = "treat_downgraded_video_calls_as_video_calls_bool";
     field public static final String KEY_TTY_SUPPORTED_BOOL = "tty_supported_bool";
+    field public static final String KEY_UNLOGGABLE_NUMBERS_STRING_ARRAY = "unloggable_numbers_string_array";
     field public static final String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool";
     field public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
     field public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
     field public static final String KEY_USE_RCS_SIP_OPTIONS_BOOL = "use_rcs_sip_options_bool";
+    field public static final String KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL = "use_wfc_home_network_mode_in_roaming_network_bool";
     field public static final String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
     field public static final String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
     field public static final String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
@@ -45337,6 +45386,8 @@
     field public static final String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
     field public static final String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
     field public static final String KEY_VVM_TYPE_STRING = "vvm_type_string";
+    field public static final String KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING = "wfc_emergency_address_carrier_app_string";
+    field public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool";
     field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
   }
 
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index d802177..0a67065 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -1 +1,81 @@
 // Signature format: 2.0
+package android.app.timedetector {
+
+  public final class PhoneTimeSuggestion implements android.os.Parcelable {
+    method public void addDebugInfo(@NonNull String);
+    method public void addDebugInfo(@NonNull java.util.List<java.lang.String>);
+    method public int describeContents();
+    method @NonNull public java.util.List<java.lang.String> getDebugInfo();
+    method public int getPhoneId();
+    method @Nullable public android.os.TimestampedValue<java.lang.Long> getUtcTime();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.timedetector.PhoneTimeSuggestion> CREATOR;
+  }
+
+  public static final class PhoneTimeSuggestion.Builder {
+    ctor public PhoneTimeSuggestion.Builder(int);
+    method @NonNull public android.app.timedetector.PhoneTimeSuggestion.Builder addDebugInfo(@NonNull String);
+    method @NonNull public android.app.timedetector.PhoneTimeSuggestion build();
+    method @NonNull public android.app.timedetector.PhoneTimeSuggestion.Builder setUtcTime(@Nullable android.os.TimestampedValue<java.lang.Long>);
+  }
+
+  public class TimeDetector {
+    method @RequiresPermission("android.permission.SUGGEST_PHONE_TIME_AND_ZONE") public void suggestPhoneTime(@NonNull android.app.timedetector.PhoneTimeSuggestion);
+  }
+
+}
+
+package android.app.timezonedetector {
+
+  public final class PhoneTimeZoneSuggestion implements android.os.Parcelable {
+    method public void addDebugInfo(@NonNull String);
+    method public void addDebugInfo(@NonNull java.util.List<java.lang.String>);
+    method @NonNull public static android.app.timezonedetector.PhoneTimeZoneSuggestion createEmptySuggestion(int, @NonNull String);
+    method public int describeContents();
+    method @NonNull public java.util.List<java.lang.String> getDebugInfo();
+    method public int getMatchType();
+    method public int getPhoneId();
+    method public int getQuality();
+    method @Nullable public String getZoneId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.timezonedetector.PhoneTimeZoneSuggestion> CREATOR;
+    field public static final int MATCH_TYPE_EMULATOR_ZONE_ID = 4; // 0x4
+    field public static final int MATCH_TYPE_NA = 0; // 0x0
+    field public static final int MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET = 3; // 0x3
+    field public static final int MATCH_TYPE_NETWORK_COUNTRY_ONLY = 2; // 0x2
+    field public static final int MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY = 5; // 0x5
+    field public static final int QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS = 3; // 0x3
+    field public static final int QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET = 2; // 0x2
+    field public static final int QUALITY_NA = 0; // 0x0
+    field public static final int QUALITY_SINGLE_ZONE = 1; // 0x1
+  }
+
+  public static final class PhoneTimeZoneSuggestion.Builder {
+    ctor public PhoneTimeZoneSuggestion.Builder(int);
+    method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder addDebugInfo(@NonNull String);
+    method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion build();
+    method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder setMatchType(int);
+    method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder setQuality(int);
+    method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder setZoneId(@Nullable String);
+  }
+
+  public class TimeZoneDetector {
+    method @RequiresPermission("android.permission.SUGGEST_PHONE_TIME_AND_ZONE") public void suggestPhoneTimeZone(@NonNull android.app.timezonedetector.PhoneTimeZoneSuggestion);
+  }
+
+}
+
+package android.os {
+
+  public final class TimestampedValue<T> implements android.os.Parcelable {
+    ctor public TimestampedValue(long, @Nullable T);
+    method public int describeContents();
+    method public long getReferenceTimeMillis();
+    method @Nullable public T getValue();
+    method public static long referenceTimeDifference(@NonNull android.os.TimestampedValue<?>, @NonNull android.os.TimestampedValue<?>);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.os.TimestampedValue<?>> CREATOR;
+  }
+
+}
+
diff --git a/api/system-current.txt b/api/system-current.txt
index 789d86f..71d1a38 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -208,6 +208,7 @@
     field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
     field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
     field public static final String SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON = "android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON";
+    field public static final String SUGGEST_PHONE_TIME_AND_ZONE = "android.permission.SUGGEST_PHONE_TIME_AND_ZONE";
     field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
     field public static final String SYSTEM_CAMERA = "android.permission.SYSTEM_CAMERA";
     field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
@@ -327,6 +328,7 @@
     method public void setDeviceLocales(@NonNull android.os.LocaleList);
     method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public static void setPersistentVrThread(int);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean switchUser(@NonNull android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String);
   }
 
   public static interface ActivityManager.OnUidImportanceListener {
@@ -4816,6 +4818,7 @@
     field public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd
     field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
     field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+    field public static final int TYPE_NONE = -1; // 0xffffffff
   }
 
   public abstract static class ConnectivityManager.OnStartTetheringCallback {
@@ -4951,12 +4954,36 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.net.MatchAllNetworkSpecifier> CREATOR;
   }
 
+  public final class NattKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable {
+    ctor public NattKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[]) throws android.net.InvalidPacketException;
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.NattKeepalivePacketData> CREATOR;
+  }
+
   public class Network implements android.os.Parcelable {
     ctor public Network(@NonNull android.net.Network);
     method @NonNull public android.net.Network getPrivateDnsBypassingCopy();
     field public final int netId;
   }
 
+  public final class NetworkAgentConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public String getSubscriberId();
+    method public boolean isNat64DetectionEnabled();
+    method public boolean isProvisioningNotificationEnabled();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkAgentConfig> CREATOR;
+  }
+
+  public static class NetworkAgentConfig.Builder {
+    ctor public NetworkAgentConfig.Builder();
+    method @NonNull public android.net.NetworkAgentConfig build();
+    method @NonNull public android.net.NetworkAgentConfig.Builder disableNat64Detection();
+    method @NonNull public android.net.NetworkAgentConfig.Builder disableProvisioningNotification();
+    method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
+  }
+
   public final class NetworkCapabilities implements android.os.Parcelable {
     method public boolean deduceRestrictedCapability();
     method @NonNull public int[] getTransportTypes();
@@ -5015,6 +5042,9 @@
     field @Deprecated public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
     field public static final String EXTRA_NEW_SCORER = "newScorer";
     field @Deprecated public static final String EXTRA_PACKAGE_NAME = "packageName";
+    field public static final int SCORE_FILTER_CURRENT_NETWORK = 1; // 0x1
+    field public static final int SCORE_FILTER_NONE = 0; // 0x0
+    field public static final int SCORE_FILTER_SCAN_RESULTS = 2; // 0x2
   }
 
   public static interface NetworkScoreManager.NetworkScoreCallback {
@@ -5892,6 +5922,7 @@
   }
 
   public class ScanResult implements android.os.Parcelable {
+    ctor public ScanResult();
     field public static final int CIPHER_CCMP = 3; // 0x3
     field public static final int CIPHER_GCMP_256 = 4; // 0x4
     field public static final int CIPHER_NONE = 0; // 0x0
@@ -6008,6 +6039,7 @@
     method @Deprecated public static boolean isMetered(@Nullable android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiInfo);
     method @Deprecated public boolean isNoInternetAccessExpected();
     method @Deprecated public void setIpConfiguration(@Nullable android.net.IpConfiguration);
+    method @Deprecated public void setNetworkSelectionStatus(@NonNull android.net.wifi.WifiConfiguration.NetworkSelectionStatus);
     method @Deprecated public void setProxy(@NonNull android.net.IpConfiguration.ProxySettings, @NonNull android.net.ProxyInfo);
     field @Deprecated public static final int AP_BAND_2GHZ = 0; // 0x0
     field @Deprecated public static final int AP_BAND_5GHZ = 1; // 0x1
@@ -6052,6 +6084,7 @@
     method @Deprecated public boolean getHasEverConnected();
     method @Deprecated @Nullable public static String getNetworkDisableReasonString(int);
     method @Deprecated public int getNetworkSelectionDisableReason();
+    method @Deprecated public int getNetworkSelectionStatus();
     method @Deprecated @NonNull public String getNetworkStatusString();
     method @Deprecated public boolean isNetworkEnabled();
     method @Deprecated public boolean isNetworkPermanentlyDisabled();
@@ -6066,6 +6099,16 @@
     field @Deprecated public static final int DISABLED_NO_INTERNET_TEMPORARY = 4; // 0x4
     field @Deprecated public static final int NETWORK_SELECTION_DISABLED_MAX = 10; // 0xa
     field @Deprecated public static final int NETWORK_SELECTION_ENABLE = 0; // 0x0
+    field @Deprecated public static final int NETWORK_SELECTION_ENABLED = 0; // 0x0
+    field @Deprecated public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED = 2; // 0x2
+    field @Deprecated public static final int NETWORK_SELECTION_TEMPORARY_DISABLED = 1; // 0x1
+  }
+
+  @Deprecated public static final class WifiConfiguration.NetworkSelectionStatus.Builder {
+    ctor @Deprecated public WifiConfiguration.NetworkSelectionStatus.Builder();
+    method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus build();
+    method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus.Builder setNetworkSelectionDisableReason(int);
+    method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus.Builder setNetworkSelectionStatus(int);
   }
 
   @Deprecated public static class WifiConfiguration.RecentFailure {
@@ -6110,6 +6153,15 @@
     field public static final int INVALID_RSSI = -127; // 0xffffff81
   }
 
+  public static final class WifiInfo.Builder {
+    ctor public WifiInfo.Builder();
+    method @NonNull public android.net.wifi.WifiInfo build();
+    method @NonNull public android.net.wifi.WifiInfo.Builder setBssid(@NonNull String);
+    method @NonNull public android.net.wifi.WifiInfo.Builder setNetworkId(int);
+    method @NonNull public android.net.wifi.WifiInfo.Builder setRssi(int);
+    method @NonNull public android.net.wifi.WifiInfo.Builder setSsid(@NonNull byte[]);
+  }
+
   public class WifiManager {
     method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoin(int, boolean);
@@ -10641,6 +10693,8 @@
     field public static final String EXTRA_ERROR_CODE = "errorCode";
     field public static final String EXTRA_PCO_ID = "pcoId";
     field public static final String EXTRA_PCO_VALUE = "pcoValue";
+    field public static final String EXTRA_PHONE_IN_ECM_STATE = "android.telephony.extra.PHONE_IN_ECM_STATE";
+    field public static final String EXTRA_PHONE_IN_EMERGENCY_CALL = "android.telephony.extra.PHONE_IN_EMERGENCY_CALL";
     field public static final String EXTRA_REDIRECTION_URL = "redirectionUrl";
     field public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";
     field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index bb01911..1441d48 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -341,7 +341,7 @@
     }
 
     // Pulled events will start at field 10000.
-    // Next: 10069
+    // Next: 10070
     oneof pulled {
         WifiBytesTransfer wifi_bytes_transfer = 10000;
         WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001;
@@ -411,6 +411,7 @@
         NotificationRemoteViews notification_remote_views = 10066;
         DangerousPermissionStateSampled dangerous_permission_state_sampled = 10067;
         GraphicsStats graphics_stats = 10068;
+        RuntimeAppOpsAccess runtime_app_ops_access = 10069;
     }
 
     // DO NOT USE field numbers above 100,000 in AOSP.
@@ -4118,10 +4119,10 @@
         // as UMOUNT_STAT_* from init/reboot.cpp.
         // Logged from f/b/services/.../BootReceiver.java.
         SHUTDOWN_UMOUNT_STAT = 2;
-        // Reprepsents fie system mounting error code for the current boot. Error codes defined
-        // as combination of FsStatFlags from system/core/fs_mgr/fs_mgr.cpp.
+        // Reprepsents fie system mounting error code of /data partition for the current boot.
+        // Error codes defined as combination of FsStatFlags from system/core/fs_mgr/fs_mgr.cpp.
         // Logged from f/b/services/.../BootReceiver.java.
-        FS_MGR_FS_STAT = 3;
+        FS_MGR_FS_STAT_DATA_PARTITION = 3;
     }
 
     // Type of the event.
@@ -7086,7 +7087,7 @@
     // Uid of the package requesting the op
     optional int32 uid = 1 [(is_uid) = true];
 
-    // Nmae of the package performing the op
+    // Name of the package performing the op
     optional string package_name = 2;
 
     // operation id; maps to the OP_* constants in AppOpsManager.java
@@ -7872,3 +7873,35 @@
     // more apps are running / rendering.
     optional bool is_today = 16;
 }
+
+/**
+ * Message related to dangerous (runtime) app ops access
+ */
+message RuntimeAppOpsAccess {
+    // Uid of the package accessing app op
+    optional int32 uid = 1 [(is_uid) = true];
+
+    // Name of the package accessing app op
+    optional string package_name = 2;
+
+    // operation id; maps to the OP_* constants in AppOpsManager.java
+    optional int32 op_id = 3;
+
+    // feature id; provided by developer when accessing related API, limited at 50 chars by API.
+    // Features must be provided through manifest using <feature> tag available in R and above.
+    optional string feature_id = 4;
+
+    // message related to app op access, limited to 600 chars by API
+    optional string message = 5;
+
+    enum SamplingStrategy {
+        DEFAULT = 0;
+        UNIFORM = 1;
+        RARELY_USED = 2;
+    }
+
+    // sampling strategy used to collect this message
+    optional SamplingStrategy sampling_strategy = 6;
+}
+
+
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 06046c1..731afe8 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -224,10 +224,6 @@
           .coolDownNs = 3 * NS_PER_SEC,
           .puller = new StatsCompanionServicePuller(android::util::DISK_IO)}},
 
-        // PowerProfile constants for power model calculations.
-        {{.atomTag = android::util::POWER_PROFILE},
-         {.puller = new StatsCompanionServicePuller(android::util::POWER_PROFILE)}},
-
         // Process cpu stats. Min cool-down is 5 sec, inline with what AcitivityManagerService uses.
         {{.atomTag = android::util::PROCESS_CPU_TIME},
          {.coolDownNs = 5 * NS_PER_SEC /* min cool-down in seconds*/,
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 8fe2f12..f2702a8 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -25,6 +25,7 @@
 import android.annotation.Size;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.UserHandleAware;
 import android.app.Activity;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
@@ -40,6 +41,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Parcelable;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.text.TextUtils;
@@ -528,12 +530,9 @@
      *     authenticator known to the AccountManager service.  Empty (never
      *     null) if no authenticators are known.
      */
+    @UserHandleAware
     public AuthenticatorDescription[] getAuthenticatorTypes() {
-        try {
-            return mService.getAuthenticatorTypes(UserHandle.getCallingUserId());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return getAuthenticatorTypesAsUser(mContext.getUserId());
     }
 
     /**
@@ -584,13 +583,10 @@
      * @return An array of {@link Account}, one for each account. Empty (never null) if no accounts
      *         have been added.
      */
+    @UserHandleAware
     @NonNull
     public Account[] getAccounts() {
-        try {
-            return mService.getAccounts(null, mContext.getOpPackageName());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return getAccountsAsUser(mContext.getUserId());
     }
 
     /**
@@ -708,6 +704,7 @@
      * @return An array of {@link Account}, one per matching account. Empty (never null) if no
      *         accounts of the specified type have been added.
      */
+    @UserHandleAware
     @NonNull
     public Account[] getAccountsByType(String type) {
         return getAccountsByTypeAsUser(type, mContext.getUser());
@@ -1183,23 +1180,11 @@
      *     {@link #removeAccount(Account, Activity, AccountManagerCallback, Handler)}
      *     instead
      */
+    @UserHandleAware
     @Deprecated
     public AccountManagerFuture<Boolean> removeAccount(final Account account,
             AccountManagerCallback<Boolean> callback, Handler handler) {
-        if (account == null) throw new IllegalArgumentException("account is null");
-        return new Future2Task<Boolean>(handler, callback) {
-            @Override
-            public void doWork() throws RemoteException {
-                mService.removeAccount(mResponse, account, false);
-            }
-            @Override
-            public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
-                if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
-                    throw new AuthenticatorException("no result in response");
-                }
-                return bundle.getBoolean(KEY_BOOLEAN_RESULT);
-            }
-        }.start();
+        return removeAccountAsUser(account, callback, handler, mContext.getUser());
     }
 
     /**
@@ -1243,15 +1228,10 @@
      *      adding accounts (of this type) has been disabled by policy
      * </ul>
      */
+    @UserHandleAware
     public AccountManagerFuture<Bundle> removeAccount(final Account account,
             final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
-        if (account == null) throw new IllegalArgumentException("account is null");
-        return new AmsTask(activity, handler, callback) {
-            @Override
-            public void doWork() throws RemoteException {
-                mService.removeAccount(mResponse, account, activity != null);
-            }
-        }.start();
+        return removeAccountAsUser(account, activity, callback, handler, mContext.getUser());
     }
 
     /**
@@ -1841,24 +1821,30 @@
      *      creating a new account, usually because of network trouble
      * </ul>
      */
+    @UserHandleAware
     public AccountManagerFuture<Bundle> addAccount(final String accountType,
             final String authTokenType, final String[] requiredFeatures,
             final Bundle addAccountOptions,
             final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
-        if (accountType == null) throw new IllegalArgumentException("accountType is null");
-        final Bundle optionsIn = new Bundle();
-        if (addAccountOptions != null) {
-            optionsIn.putAll(addAccountOptions);
-        }
-        optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
-
-        return new AmsTask(activity, handler, callback) {
-            @Override
-            public void doWork() throws RemoteException {
-                mService.addAccount(mResponse, accountType, authTokenType,
-                        requiredFeatures, activity != null, optionsIn);
+        if (Process.myUserHandle().equals(mContext.getUser())) {
+            if (accountType == null) throw new IllegalArgumentException("accountType is null");
+            final Bundle optionsIn = new Bundle();
+            if (addAccountOptions != null) {
+                optionsIn.putAll(addAccountOptions);
             }
-        }.start();
+            optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
+
+            return new AmsTask(activity, handler, callback) {
+                @Override
+                public void doWork() throws RemoteException {
+                    mService.addAccount(mResponse, accountType, authTokenType,
+                            requiredFeatures, activity != null, optionsIn);
+                }
+            }.start();
+        } else {
+            return addAccountAsUser(accountType, authTokenType, requiredFeatures, addAccountOptions,
+                    activity, callback, handler, mContext.getUser());
+        }
     }
 
     /**
@@ -2002,6 +1988,7 @@
      *      verifying the password, usually because of network trouble
      * </ul>
      */
+    @UserHandleAware
     public AccountManagerFuture<Bundle> confirmCredentials(final Account account,
             final Bundle options,
             final Activity activity,
@@ -3209,6 +3196,7 @@
      *         </ul>
      * @see #startAddAccountSession and #startUpdateCredentialsSession
      */
+    @UserHandleAware
     public AccountManagerFuture<Bundle> finishSession(
             final Bundle sessionBundle,
             final Activity activity,
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 0127138..ce68e08 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -34,7 +34,6 @@
     String getPassword(in Account account);
     String getUserData(in Account account, String key);
     AuthenticatorDescription[] getAuthenticatorTypes(int userId);
-    Account[] getAccounts(String accountType, String opPackageName);
     Account[] getAccountsForPackage(String packageName, int uid, String opPackageName);
     Account[] getAccountsByTypeForPackage(String type, String packageName, String opPackageName);
     Account[] getAccountsAsUser(String accountType, int userId, String opPackageName);
@@ -45,8 +44,6 @@
     void getAccountsByFeatures(in IAccountManagerResponse response, String accountType,
         in String[] features, String opPackageName);
     boolean addAccountExplicitly(in Account account, String password, in Bundle extras);
-    void removeAccount(in IAccountManagerResponse response, in Account account,
-        boolean expectActivityLaunch);
     void removeAccountAsUser(in IAccountManagerResponse response, in Account account,
         boolean expectActivityLaunch, int userId);
     boolean removeAccountExplicitly(in Account account);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 9aef20b..c3b07c8 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4073,6 +4073,29 @@
     }
 
     /**
+     * Updates mcc mnc configuration and applies changes to the entire system.
+     *
+     * @param mcc mcc configuration to update.
+     * @param mnc mnc configuration to update.
+     * @throws RemoteException; IllegalArgumentException if mcc or mnc is null;
+     * @return Returns {@code true} if the configuration was updated successfully;
+     *         {@code false} otherwise.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION)
+    public boolean updateMccMncConfiguration(@NonNull String mcc, @NonNull String mnc) {
+        if (mcc == null || mnc == null) {
+            throw new IllegalArgumentException("mcc or mnc cannot be null.");
+        }
+        try {
+            return getService().updateMccMncConfiguration(mcc, mnc);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Logs out current current foreground user by switching to the system user and stopping the
      * user being switched from.
      * @hide
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index e8494c4..bd6baec 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -188,6 +188,16 @@
      */
     @UnsupportedAppUsage
     boolean updateConfiguration(in Configuration values);
+    /**
+     * Updates mcc mnc configuration and applies changes to the entire system.
+     *
+     * @param mcc mcc configuration to update.
+     * @param mnc mnc configuration to update.
+     * @throws RemoteException; IllegalArgumentException if mcc or mnc is null.
+     * @return Returns {@code true} if the configuration was updated;
+     *         {@code false} otherwise.
+     */
+    boolean updateMccMncConfiguration(in String mcc, in String mnc);
     boolean stopServiceToken(in ComponentName className, in IBinder token, int startId);
     @UnsupportedAppUsage
     void setProcessLimit(int max);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 69640b8..caaa686 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1992,16 +1992,6 @@
     public static final int CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER = 14;
 
     /**
-     * Result code for {@link #checkProvisioningPreCondition}.
-     *
-     * <p>Returned for {@link #ACTION_PROVISION_MANAGED_PROFILE} when adding a managed profile is
-     * disallowed by {@link UserManager#DISALLOW_ADD_MANAGED_PROFILE}.
-     *
-     * @hide
-     */
-    public static final int CODE_ADD_MANAGED_PROFILE_DISALLOWED = 15;
-
-    /**
      * Result codes for {@link #checkProvisioningPreCondition} indicating all the provisioning pre
      * conditions.
      *
@@ -2013,7 +2003,7 @@
             CODE_USER_SETUP_COMPLETED, CODE_NOT_SYSTEM_USER, CODE_HAS_PAIRED,
             CODE_MANAGED_USERS_NOT_SUPPORTED, CODE_SYSTEM_USER, CODE_CANNOT_ADD_MANAGED_PROFILE,
             CODE_NOT_SYSTEM_USER_SPLIT, CODE_DEVICE_ADMIN_NOT_SUPPORTED,
-            CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER, CODE_ADD_MANAGED_PROFILE_DISALLOWED
+            CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER
     })
     public @interface ProvisioningPreCondition {}
 
diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.java b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
index 479e4b4..bd649f8 100644
--- a/core/java/android/app/timedetector/PhoneTimeSuggestion.java
+++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.TimestampedValue;
@@ -28,17 +29,23 @@
 import java.util.Objects;
 
 /**
- * A time signal from a telephony source. The value can be {@code null} to indicate that the
- * telephony source has entered an "un-opinionated" state and any previously sent suggestions are
- * being withdrawn. When not {@code null}, the value consists of the number of milliseconds elapsed
- * since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime clock when that number
- * was established. The elapsed realtime clock is considered accurate but volatile, so time signals
- * must not be persisted across device resets.
+ * A time suggestion from an identified telephony source. e.g. from NITZ information from a specific
+ * radio.
+ *
+ * <p>The time value can be {@code null} to indicate that the telephony source has entered an
+ * "un-opinionated" state and any previous suggestions from the source are being withdrawn. When not
+ * {@code null}, the value consists of the number of milliseconds elapsed since 1/1/1970 00:00:00
+ * UTC and the time according to the elapsed realtime clock when that number was established. The
+ * elapsed realtime clock is considered accurate but volatile, so time suggestions must not be
+ * persisted across device resets.
  *
  * @hide
  */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
 public final class PhoneTimeSuggestion implements Parcelable {
 
+    /** @hide */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final @NonNull Parcelable.Creator<PhoneTimeSuggestion> CREATOR =
             new Parcelable.Creator<PhoneTimeSuggestion>() {
                 public PhoneTimeSuggestion createFromParcel(Parcel in) {
@@ -85,15 +92,27 @@
         dest.writeList(mDebugInfo);
     }
 
+    /**
+     * Returns an identifier for the source of this suggestion. When a device has several "phones",
+     * i.e. sim slots or equivalent, it is used to identify which one.
+     */
     public int getPhoneId() {
         return mPhoneId;
     }
 
+    /**
+     * Returns the suggestion. {@code null} means that the caller is no longer sure what time it
+     * is.
+     */
     @Nullable
     public TimestampedValue<Long> getUtcTime() {
         return mUtcTime;
     }
 
+    /**
+     * Returns debug metadata for the suggestion. The information is present in {@link #toString()}
+     * but is not considered for {@link #equals(Object)} and {@link #hashCode()}.
+     */
     @NonNull
     public List<String> getDebugInfo() {
         return mDebugInfo == null
@@ -105,7 +124,7 @@
      * information is present in {@link #toString()} but is not considered for
      * {@link #equals(Object)} and {@link #hashCode()}.
      */
-    public void addDebugInfo(String debugInfo) {
+    public void addDebugInfo(@NonNull String debugInfo) {
         if (mDebugInfo == null) {
             mDebugInfo = new ArrayList<>();
         }
@@ -156,16 +175,19 @@
      *
      * @hide
      */
-    public static class Builder {
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final class Builder {
         private final int mPhoneId;
-        private TimestampedValue<Long> mUtcTime;
-        private List<String> mDebugInfo;
+        @Nullable private TimestampedValue<Long> mUtcTime;
+        @Nullable private List<String> mDebugInfo;
 
+        /** Creates a builder with the specified {@code phoneId}. */
         public Builder(int phoneId) {
             mPhoneId = phoneId;
         }
 
         /** Returns the builder for call chaining. */
+        @NonNull
         public Builder setUtcTime(@Nullable TimestampedValue<Long> utcTime) {
             if (utcTime != null) {
                 // utcTime can be null, but the value it holds cannot.
@@ -177,6 +199,7 @@
         }
 
         /** Returns the builder for call chaining. */
+        @NonNull
         public Builder addDebugInfo(@NonNull String debugInfo) {
             if (mDebugInfo == null) {
                 mDebugInfo = new ArrayList<>();
@@ -186,6 +209,7 @@
         }
 
         /** Returns the {@link PhoneTimeSuggestion}. */
+        @NonNull
         public PhoneTimeSuggestion build() {
             return new PhoneTimeSuggestion(this);
         }
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index 54dd1be..7c29f01 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.os.RemoteException;
@@ -29,8 +30,11 @@
 
 /**
  * The interface through which system components can send signals to the TimeDetectorService.
+ *
+ * <p>This class is marked non-final for mockito.
  * @hide
  */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
 @SystemService(Context.TIME_DETECTOR_SERVICE)
 public class TimeDetector {
     private static final String TAG = "timedetector.TimeDetector";
@@ -38,6 +42,7 @@
 
     private final ITimeDetectorService mITimeDetectorService;
 
+    /** @hide */
     public TimeDetector() throws ServiceNotFoundException {
         mITimeDetectorService = ITimeDetectorService.Stub.asInterface(
                 ServiceManager.getServiceOrThrow(Context.TIME_DETECTOR_SERVICE));
@@ -62,6 +67,8 @@
 
     /**
      * Suggests the user's manually entered current time to the detector.
+     *
+     * @hide
      */
     @RequiresPermission(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE)
     public void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion) {
@@ -77,6 +84,8 @@
 
     /**
      * A shared utility method to create a {@link ManualTimeSuggestion}.
+     *
+     * @hide
      */
     public static ManualTimeSuggestion createManualTimeSuggestion(long when, String why) {
         TimestampedValue<Long> utcTime =
@@ -88,6 +97,8 @@
 
     /**
      * Suggests the time according to a network time source like NTP.
+     *
+     * @hide
      */
     @RequiresPermission(android.Manifest.permission.SET_TIME)
     public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) {
diff --git a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java
index e8162488..d71ffcb 100644
--- a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java
+++ b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -30,12 +31,27 @@
 import java.util.Objects;
 
 /**
- * A suggested time zone from a Phone-based signal, e.g. from MCC and NITZ information.
+ * A time zone suggestion from an identified telephony source, e.g. from MCC and NITZ information
+ * associated with a specific radio.
+ *
+ * <p>The time zone ID can be {@code null} to indicate that the telephony source has entered an
+ * "un-opinionated" state and any previous suggestions from that source are being withdrawn.
+ * When not {@code null}, the value consists of a suggested time zone ID and metadata that can be
+ * used to judge quality / certainty of the suggestion.
+ *
+ * <p>{@code matchType} must be set to {@link #MATCH_TYPE_NA} when {@code zoneId} is {@code null},
+ * and one of the other {@code MATCH_TYPE_} values when it is not {@code null}.
+ *
+ * <p>{@code quality} must be set to {@link #QUALITY_NA} when {@code zoneId} is {@code null},
+ * and one of the other {@code QUALITY_} values when it is not {@code null}.
  *
  * @hide
  */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
 public final class PhoneTimeZoneSuggestion implements Parcelable {
 
+    /** @hide */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     @NonNull
     public static final Creator<PhoneTimeZoneSuggestion> CREATOR =
             new Creator<PhoneTimeZoneSuggestion>() {
@@ -58,6 +74,7 @@
         return new Builder(phoneId).addDebugInfo(debugInfo).build();
     }
 
+    /** @hide */
     @IntDef({ MATCH_TYPE_NA, MATCH_TYPE_NETWORK_COUNTRY_ONLY, MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET,
             MATCH_TYPE_EMULATOR_ZONE_ID, MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY })
     @Retention(RetentionPolicy.SOURCE)
@@ -90,6 +107,7 @@
      */
     public static final int MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY = 5;
 
+    /** @hide */
     @IntDef({ QUALITY_NA, QUALITY_SINGLE_ZONE, QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET,
             QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS })
     @Retention(RetentionPolicy.SOURCE)
@@ -115,7 +133,7 @@
 
     /**
      * The ID of the phone this suggestion is associated with. For multiple-sim devices this
-     * helps to establish origin so filtering / stickiness can be implemented.
+     * helps to establish source so filtering / stickiness can be implemented.
      */
     private final int mPhoneId;
 
@@ -123,6 +141,7 @@
      * The suggestion. {@code null} means there is no current suggestion and any previous suggestion
      * should be forgotten.
      */
+    @Nullable
     private final String mZoneId;
 
     /**
@@ -139,9 +158,10 @@
     private final int mQuality;
 
     /**
-     * Free-form debug information about how the signal was derived. Used for debug only,
+     * Free-form debug information about how the suggestion was derived. Used for debug only,
      * intentionally not used in equals(), etc.
      */
+    @Nullable
     private List<String> mDebugInfo;
 
     private PhoneTimeZoneSuggestion(Builder builder) {
@@ -182,25 +202,47 @@
         return 0;
     }
 
+    /**
+     * Returns an identifier for the source of this suggestion. When a device has several "phones",
+     * i.e. sim slots or equivalent, it is used to identify which one.
+     */
     public int getPhoneId() {
         return mPhoneId;
     }
 
+    /**
+     * Returns the suggested time zone Olson ID, e.g. "America/Los_Angeles". {@code null} means that
+     * the caller is no longer sure what the current time zone is. See
+     * {@link PhoneTimeZoneSuggestion} for the associated {@code matchType} / {@code quality} rules.
+     */
     @Nullable
     public String getZoneId() {
         return mZoneId;
     }
 
+    /**
+     * Returns information about how the suggestion was determined which could be used to rank
+     * suggestions when several are available from different sources. See
+     * {@link PhoneTimeZoneSuggestion} for the associated rules.
+     */
     @MatchType
     public int getMatchType() {
         return mMatchType;
     }
 
+    /**
+     * Returns information about the likelihood of the suggested zone being correct.  See
+     * {@link PhoneTimeZoneSuggestion} for the associated rules.
+     */
     @Quality
     public int getQuality() {
         return mQuality;
     }
 
+    /**
+     * Returns debug metadata for the suggestion. The information is present in {@link #toString()}
+     * but is not considered for {@link #equals(Object)} and {@link #hashCode()}.
+     */
     @NonNull
     public List<String> getDebugInfo() {
         return mDebugInfo == null
@@ -267,36 +309,43 @@
      *
      * @hide
      */
-    public static class Builder {
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final class Builder {
         private final int mPhoneId;
-        private String mZoneId;
+        @Nullable private String mZoneId;
         @MatchType private int mMatchType;
         @Quality private int mQuality;
-        private List<String> mDebugInfo;
+        @Nullable private List<String> mDebugInfo;
 
         public Builder(int phoneId) {
             mPhoneId = phoneId;
         }
 
-        /** Returns the builder for call chaining. */
-        public Builder setZoneId(String zoneId) {
+        /**
+         * Returns the builder for call chaining.
+         */
+        @NonNull
+        public Builder setZoneId(@Nullable String zoneId) {
             mZoneId = zoneId;
             return this;
         }
 
         /** Returns the builder for call chaining. */
+        @NonNull
         public Builder setMatchType(@MatchType int matchType) {
             mMatchType = matchType;
             return this;
         }
 
         /** Returns the builder for call chaining. */
+        @NonNull
         public Builder setQuality(@Quality int quality) {
             mQuality = quality;
             return this;
         }
 
         /** Returns the builder for call chaining. */
+        @NonNull
         public Builder addDebugInfo(@NonNull String debugInfo) {
             if (mDebugInfo == null) {
                 mDebugInfo = new ArrayList<>();
@@ -333,6 +382,7 @@
         }
 
         /** Returns the {@link PhoneTimeZoneSuggestion}. */
+        @NonNull
         public PhoneTimeZoneSuggestion build() {
             validate();
             return new PhoneTimeZoneSuggestion(this);
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java
index e165d8a..5b5f311 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetector.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.os.RemoteException;
@@ -28,8 +29,10 @@
 /**
  * The interface through which system components can send signals to the TimeZoneDetectorService.
  *
+ * <p>This class is non-final for mockito.
  * @hide
  */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
 @SystemService(Context.TIME_ZONE_DETECTOR_SERVICE)
 public class TimeZoneDetector {
     private static final String TAG = "timezonedetector.TimeZoneDetector";
@@ -37,6 +40,7 @@
 
     private final ITimeZoneDetectorService mITimeZoneDetectorService;
 
+    /** @hide */
     public TimeZoneDetector() throws ServiceNotFoundException {
         mITimeZoneDetectorService = ITimeZoneDetectorService.Stub.asInterface(
                 ServiceManager.getServiceOrThrow(Context.TIME_ZONE_DETECTOR_SERVICE));
@@ -46,7 +50,10 @@
      * Suggests the current time zone, determined using telephony signals, to the detector. The
      * detector may ignore the signal based on system settings, whether better information is
      * available, and so on.
+     *
+     * @hide
      */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     @RequiresPermission(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE)
     public void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion) {
         if (DEBUG) {
@@ -62,6 +69,8 @@
     /**
      * Suggests the current time zone, determined for the user's manually information, to the
      * detector. The detector may ignore the signal based on system settings.
+     *
+     * @hide
      */
     @RequiresPermission(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE)
     public void suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) {
@@ -77,6 +86,8 @@
 
     /**
      * A shared utility method to create a {@link ManualTimeZoneSuggestion}.
+     *
+     * @hide
      */
     public static ManualTimeZoneSuggestion createManualTimeZoneSuggestion(String tzId, String why) {
         ManualTimeZoneSuggestion suggestion = new ManualTimeZoneSuggestion(tzId);
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 176a181..a60e591 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -163,7 +163,6 @@
     /**
      * The app spent sufficient time in the old bucket without any substantial event so it reached
      * the timeout threshold to have its bucket lowered.
-     *
      * @hide
      */
     public static final int REASON_MAIN_TIMEOUT =   0x0200;
@@ -173,15 +172,25 @@
      */
     public static final int REASON_MAIN_USAGE =     0x0300;
     /**
-     * Forced by a core UID.
+     * Forced by the user/developer, either explicitly or implicitly through some action. If user
+     * action was not involved and this is purely due to the system,
+     * {@link #REASON_MAIN_FORCED_BY_SYSTEM} should be used instead.
      * @hide
      */
-    public static final int REASON_MAIN_FORCED =    0x0400;
+    public static final int REASON_MAIN_FORCED_BY_USER = 0x0400;
     /**
-     * Set by a privileged system app.
+     * Set by a privileged system app. This may be overridden by
+     * {@link #REASON_MAIN_FORCED_BY_SYSTEM} or user action.
      * @hide
      */
     public static final int REASON_MAIN_PREDICTED = 0x0500;
+    /**
+     * Forced by the system, independent of user action. If user action is involved,
+     * {@link #REASON_MAIN_FORCED_BY_USER} should be used instead. When this is used, only
+     * {@link #REASON_MAIN_FORCED_BY_SYSTEM} or user action can change the bucket.
+     * @hide
+     */
+    public static final int REASON_MAIN_FORCED_BY_SYSTEM = 0x0600;
 
     /** @hide */
     public static final int REASON_SUB_MASK = 0x00FF;
@@ -1016,7 +1025,10 @@
             case REASON_MAIN_DEFAULT:
                 sb.append("d");
                 break;
-            case REASON_MAIN_FORCED:
+            case REASON_MAIN_FORCED_BY_SYSTEM:
+                sb.append("s");
+                break;
+            case REASON_MAIN_FORCED_BY_USER:
                 sb.append("f");
                 break;
             case REASON_MAIN_PREDICTED:
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 4bf3e90..c523f65 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -517,7 +517,7 @@
      * The absence of a connection type.
      * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
+    @SystemApi
     public static final int TYPE_NONE        = -1;
 
     /**
@@ -3169,10 +3169,10 @@
     /**
      * @hide
      * Register a NetworkAgent with ConnectivityService.
-     * @return NetID corresponding to NetworkAgent.
+     * @return Network corresponding to NetworkAgent.
      */
     @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
-    public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
+    public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
             NetworkCapabilities nc, int score, NetworkAgentConfig config) {
         return registerNetworkAgent(messenger, ni, lp, nc, score, config, NetworkProvider.ID_NONE);
     }
@@ -3180,10 +3180,10 @@
     /**
      * @hide
      * Register a NetworkAgent with ConnectivityService.
-     * @return NetID corresponding to NetworkAgent.
+     * @return Network corresponding to NetworkAgent.
      */
     @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
-    public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
+    public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
             NetworkCapabilities nc, int score, NetworkAgentConfig config, int providerId) {
         try {
             return mService.registerNetworkAgent(messenger, ni, lp, nc, score, config, providerId);
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 7691beb..186196bd 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -152,7 +152,7 @@
 
     void declareNetworkRequestUnfulfillable(in NetworkRequest request);
 
-    int registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
+    Network registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
             in NetworkCapabilities nc, int score, in NetworkAgentConfig config,
             in int factorySerialNumber);
 
diff --git a/core/java/android/net/NattKeepalivePacketData.java b/core/java/android/net/NattKeepalivePacketData.java
index 3fb52f1..bd39c13 100644
--- a/core/java/android/net/NattKeepalivePacketData.java
+++ b/core/java/android/net/NattKeepalivePacketData.java
@@ -16,9 +16,11 @@
 
 package android.net;
 
-import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
-import static android.net.SocketKeepalive.ERROR_INVALID_PORT;
+import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS;
+import static android.net.InvalidPacketException.ERROR_INVALID_PORT;
 
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.net.util.IpUtils;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -30,20 +32,22 @@
 import java.nio.ByteOrder;
 
 /** @hide */
+@SystemApi
 public final class NattKeepalivePacketData extends KeepalivePacketData implements Parcelable {
     private static final int IPV4_HEADER_LENGTH = 20;
     private static final int UDP_HEADER_LENGTH = 8;
 
     // This should only be constructed via static factory methods, such as
     // nattKeepalivePacket
-    private NattKeepalivePacketData(InetAddress srcAddress, int srcPort,
-            InetAddress dstAddress, int dstPort, byte[] data) throws
+    public NattKeepalivePacketData(@NonNull InetAddress srcAddress, int srcPort,
+            @NonNull InetAddress dstAddress, int dstPort, @NonNull byte[] data) throws
             InvalidPacketException {
         super(srcAddress, srcPort, dstAddress, dstPort, data);
     }
 
     /**
      * Factory method to create Nat-T keepalive packet structure.
+     * @hide
      */
     public static NattKeepalivePacketData nattKeepalivePacket(
             InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort)
@@ -87,7 +91,7 @@
     }
 
     /** Write to parcel */
-    public void writeToParcel(Parcel out, int flags) {
+    public void writeToParcel(@NonNull Parcel out, int flags) {
         out.writeString(srcAddress.getHostAddress());
         out.writeString(dstAddress.getHostAddress());
         out.writeInt(srcPort);
@@ -95,7 +99,7 @@
     }
 
     /** Parcelable Creator */
-    public static final Parcelable.Creator<NattKeepalivePacketData> CREATOR =
+    public static final @NonNull Parcelable.Creator<NattKeepalivePacketData> CREATOR =
             new Parcelable.Creator<NattKeepalivePacketData>() {
                 public NattKeepalivePacketData createFromParcel(Parcel in) {
                     final InetAddress srcAddress =
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index fc72eec..d286204 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -44,9 +44,10 @@
  * @hide
  */
 public abstract class NetworkAgent {
-    // Guaranteed to be valid (not NETID_UNSET), otherwise registerNetworkAgent() would have thrown
-    // an exception.
-    public final int netId;
+    // Guaranteed to be non-null, otherwise registerNetworkAgent() would have thrown
+    // an exception. Be careful in tests when mocking though.
+    @NonNull
+    public final Network network;
 
     private final Handler mHandler;
     private volatile AsyncChannel mAsyncChannel;
@@ -246,7 +247,7 @@
         if (VDBG) log("Registering NetworkAgent");
         ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
                 Context.CONNECTIVITY_SERVICE);
-        netId = cm.registerNetworkAgent(new Messenger(mHandler), new NetworkInfo(ni),
+        network = cm.registerNetworkAgent(new Messenger(mHandler), new NetworkInfo(ni),
                 new LinkProperties(lp), new NetworkCapabilities(nc), score, config,
                 providerId);
     }
diff --git a/core/java/android/net/NetworkAgentConfig.java b/core/java/android/net/NetworkAgentConfig.java
index 3a383a4..abc6b67 100644
--- a/core/java/android/net/NetworkAgentConfig.java
+++ b/core/java/android/net/NetworkAgentConfig.java
@@ -18,22 +18,27 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 
 /**
- * A grab-bag of information (metadata, policies, properties, etc) about a
- * {@link Network}. Since this contains PII, it should not be sent outside the
- * system.
+ * Allows a network transport to provide the system with policy and configuration information about
+ * a particular network when registering a {@link NetworkAgent}. This information cannot change once
+ * the agent is registered.
  *
  * @hide
  */
-public class NetworkAgentConfig implements Parcelable {
+@SystemApi
+public final class NetworkAgentConfig implements Parcelable {
 
     /**
      * If the {@link Network} is a VPN, whether apps are allowed to bypass the
      * VPN. This is set by a {@link VpnService} and used by
      * {@link ConnectivityManager} when creating a VPN.
+     *
+     * @hide
      */
     public boolean allowBypass;
 
@@ -43,6 +48,8 @@
      * ap in the wifi settings to trigger a connection is explicit.  A 3rd party app asking to
      * connect to a particular access point is also explicit, though this may change in the future
      * as we want apps to use the multinetwork apis.
+     *
+     * @hide
      */
     public boolean explicitlySelected;
 
@@ -50,12 +57,16 @@
      * Set if the user desires to use this network even if it is unvalidated. This field has meaning
      * only if {@link explicitlySelected} is true. If it is, this field must also be set to the
      * appropriate value based on previous user choice.
+     *
+     * @hide
      */
     public boolean acceptUnvalidated;
 
     /**
      * Whether the user explicitly set that this network should be validated even if presence of
      * only partial internet connectivity.
+     *
+     * @hide
      */
     public boolean acceptPartialConnectivity;
 
@@ -65,29 +76,62 @@
      * procedure, a carrier specific provisioning notification will be placed.
      * only one notification should be displayed. This field is set based on
      * which notification should be used for provisioning.
+     *
+     * @hide
      */
     public boolean provisioningNotificationDisabled;
 
     /**
+     *
+     * @return whether the sign in to network notification is enabled by this configuration.
+     */
+    public boolean isProvisioningNotificationEnabled() {
+        return !provisioningNotificationDisabled;
+    }
+
+    /**
      * For mobile networks, this is the subscriber ID (such as IMSI).
+     *
+     * @hide
      */
     public String subscriberId;
 
     /**
+     * @return the subscriber ID, or null if none.
+     */
+    @Nullable
+    public String getSubscriberId() {
+        return subscriberId;
+    }
+
+    /**
      * Set to skip 464xlat. This means the device will treat the network as IPv6-only and
      * will not attempt to detect a NAT64 via RFC 7050 DNS lookups.
+     *
+     * @hide
      */
     public boolean skip464xlat;
 
     /**
+     * @return whether NAT64 prefix detection is enabled.
+     */
+    public boolean isNat64DetectionEnabled() {
+        return !skip464xlat;
+    }
+
+    /**
      * Set to true if the PRIVATE_DNS_BROKEN notification has shown for this network.
      * Reset this bit when private DNS mode is changed from strict mode to opportunistic/off mode.
+     *
+     * @hide
      */
     public boolean hasShownBroken;
 
+    /** @hide */
     public NetworkAgentConfig() {
     }
 
+    /** @hide */
     public NetworkAgentConfig(@Nullable NetworkAgentConfig nac) {
         if (nac != null) {
             allowBypass = nac.allowBypass;
@@ -99,13 +143,63 @@
         }
     }
 
+    /**
+     * Builder class to facilitate constructing {@link NetworkAgentConfig} objects.
+     */
+    public static class Builder {
+        private final NetworkAgentConfig mConfig = new NetworkAgentConfig();
+
+        /**
+         * Sets the subscriber ID for this network.
+         *
+         * @return this builder, to facilitate chaining.
+         */
+        @NonNull
+        public Builder setSubscriberId(@Nullable String subscriberId) {
+            mConfig.subscriberId = subscriberId;
+            return this;
+        }
+
+        /**
+         * Disables active detection of NAT64 (e.g., via RFC 7050 DNS lookups). Used to save power
+         * and reduce idle traffic on networks that are known to be IPv6-only without a NAT64.
+         *
+         * @return this builder, to facilitate chaining.
+         */
+        @NonNull
+        public Builder disableNat64Detection() {
+            mConfig.skip464xlat = true;
+            return this;
+        }
+
+        /**
+         * Disables the "Sign in to network" notification. Used if the network transport will
+         * perform its own carrier-specific provisioning procedure.
+         *
+         * @return this builder, to facilitate chaining.
+         */
+        @NonNull
+        public Builder disableProvisioningNotification() {
+            mConfig.provisioningNotificationDisabled = true;
+            return this;
+        }
+
+        /**
+         * Returns the constructed {@link NetworkAgentConfig} object.
+         */
+        @NonNull
+        public NetworkAgentConfig build() {
+            return mConfig;
+        }
+    }
+
     @Override
     public int describeContents() {
         return 0;
     }
 
     @Override
-    public void writeToParcel(Parcel out, int flags) {
+    public void writeToParcel(@NonNull Parcel out, int flags) {
         out.writeInt(allowBypass ? 1 : 0);
         out.writeInt(explicitlySelected ? 1 : 0);
         out.writeInt(acceptUnvalidated ? 1 : 0);
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index f6dc525..428a4ea 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -163,27 +163,26 @@
     public static final String EXTRA_NEW_SCORER = "newScorer";
 
     /** @hide */
-    @IntDef({CACHE_FILTER_NONE, CACHE_FILTER_CURRENT_NETWORK, CACHE_FILTER_SCAN_RESULTS})
+    @IntDef({SCORE_FILTER_NONE, SCORE_FILTER_CURRENT_NETWORK, SCORE_FILTER_SCAN_RESULTS})
     @Retention(RetentionPolicy.SOURCE)
-    public @interface CacheUpdateFilter {}
+    public @interface ScoreUpdateFilter {}
 
     /**
-     * Do not filter updates sent to the cache.
-     * @hide
+     * Do not filter updates sent to the {@link NetworkScoreCallback}].
      */
-    public static final int CACHE_FILTER_NONE = 0;
+    public static final int SCORE_FILTER_NONE = 0;
 
     /**
-     * Only send cache updates when the network matches the connected network.
-     * @hide
+     * Only send updates to the {@link NetworkScoreCallback} when the network matches the connected
+     * network.
      */
-    public static final int CACHE_FILTER_CURRENT_NETWORK = 1;
+    public static final int SCORE_FILTER_CURRENT_NETWORK = 1;
 
     /**
-     * Only send cache updates when the network is part of the current scan result set.
-     * @hide
+     * Only send updates to the {@link NetworkScoreCallback} when the network is part of the
+     * current scan result set.
      */
-    public static final int CACHE_FILTER_SCAN_RESULTS = 2;
+    public static final int SCORE_FILTER_SCAN_RESULTS = 2;
 
     /** @hide */
     @IntDef({RECOMMENDATIONS_ENABLED_FORCED_OFF, RECOMMENDATIONS_ENABLED_OFF,
@@ -410,7 +409,7 @@
     @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
     @Deprecated // migrate to registerNetworkScoreCache(int, INetworkScoreCache, int)
     public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
-        registerNetworkScoreCache(networkType, scoreCache, CACHE_FILTER_NONE);
+        registerNetworkScoreCache(networkType, scoreCache, SCORE_FILTER_NONE);
     }
 
     /**
@@ -418,7 +417,7 @@
      *
      * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}
      * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores
-     * @param filterType the {@link CacheUpdateFilter} to apply
+     * @param filterType the {@link ScoreUpdateFilter} to apply
      * @throws SecurityException if the caller does not hold the
      *         {@link permission#REQUEST_NETWORK_SCORES} permission.
      * @throws IllegalArgumentException if a score cache is already registered for this type.
@@ -426,7 +425,7 @@
      */
     @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
     public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache,
-            @CacheUpdateFilter int filterType) {
+            @ScoreUpdateFilter int filterType) {
         try {
             mService.registerNetworkScoreCache(networkType, scoreCache, filterType);
         } catch (RemoteException e) {
@@ -510,7 +509,7 @@
      * Register a network score callback.
      *
      * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}
-     * @param filterType the {@link CacheUpdateFilter} to apply
+     * @param filterType the {@link ScoreUpdateFilter} to apply
      * @param callback implementation of {@link NetworkScoreCallback} that will be invoked when the
      *                 scores change.
      * @param executor The executor on which to execute the callbacks.
@@ -522,7 +521,7 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
     public void registerNetworkScoreCallback(@NetworkKey.NetworkType int networkType,
-            @CacheUpdateFilter int filterType,
+            @ScoreUpdateFilter int filterType,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull NetworkScoreCallback callback) throws SecurityException {
         if (callback == null || executor == null) {
diff --git a/core/java/android/os/TimestampedValue.java b/core/java/android/os/TimestampedValue.java
index 348574e..f4c87ac 100644
--- a/core/java/android/os/TimestampedValue.java
+++ b/core/java/android/os/TimestampedValue.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 
 import java.util.Objects;
 
@@ -35,19 +36,27 @@
  * @param <T> the type of the value with an associated timestamp
  * @hide
  */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
 public final class TimestampedValue<T> implements Parcelable {
     private final long mReferenceTimeMillis;
+    @Nullable
     private final T mValue;
 
-    public TimestampedValue(long referenceTimeMillis, T value) {
+    public TimestampedValue(long referenceTimeMillis, @Nullable T value) {
         mReferenceTimeMillis = referenceTimeMillis;
         mValue = value;
     }
 
+    /** Returns the reference time value. See {@link TimestampedValue} for more information. */
     public long getReferenceTimeMillis() {
         return mReferenceTimeMillis;
     }
 
+    /**
+     * Returns the value associated with the timestamp. See {@link TimestampedValue} for more
+     * information.
+     */
+    @Nullable
     public T getValue() {
         return mValue;
     }
@@ -86,6 +95,8 @@
         return one.mReferenceTimeMillis - two.mReferenceTimeMillis;
     }
 
+    /** @hide */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final @NonNull Parcelable.Creator<TimestampedValue<?>> CREATOR =
             new Parcelable.ClassLoaderCreator<TimestampedValue<?>>() {
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 548b123..089122d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -523,7 +523,9 @@
      * Input: The Intent's data URI specifies bootstrapping information for authenticating and
      * provisioning the peer, and uses a "DPP" scheme. The URI should be attached to the intent
      * using {@link Intent#setData(Uri)}. The calling app can obtain a DPP URI in any
-     * way, e.g. by scanning a QR code or other out-of-band methods.
+     * way, e.g. by scanning a QR code or other out-of-band methods. The calling app may also
+     * attach the {@link #EXTRA_EASY_CONNECT_BAND_LIST} extra to provide information
+     * about the bands supported by the enrollee device.
      * <p>
      * Output: After calling {@link android.app.Activity#startActivityForResult}, the callback
      * {@code onActivityResult} will have resultCode {@link android.app.Activity#RESULT_OK} if
@@ -595,17 +597,29 @@
     /**
      * Activity Extra: The Band List that the Enrollee supports.
      * <p>
-     * An extra returned on the result intent received when using the {@link
-     * #ACTION_PROCESS_WIFI_EASY_CONNECT_URI} intent to launch the Easy Connect Operation. This
-     * extra contains the bands the Enrollee supports, expressed as the Global Operating Class,
-     * see Table E-4 in IEEE Std 802.11-2016 Global operating classes. This value is populated only
-     * by remote R2 devices, and only for the following error codes: {@link
-     * android.net.wifi.EasyConnectStatusCallback#EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK}
-     * {@link android.net.wifi.EasyConnectStatusCallback#EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION}
+     * This extra contains the bands the Enrollee supports, expressed as the Global Operating
+     * Class, see Table E-4 in IEEE Std 802.11-2016 Global operating classes. It is used both as
+     * input, to configure the Easy Connect operation and as output of the operation.
+     * <p>
+     * As input: an optional extra to be attached to the
+     * {@link #ACTION_PROCESS_WIFI_EASY_CONNECT_URI}. If attached, it indicates the bands which
+     * the remote device (enrollee, device-to-be-configured) supports. The Settings operation
+     * may take this into account when presenting the user with list of networks configurations
+     * to be used. The calling app may obtain this information in any out-of-band method. The
+     * information should be attached as an array of raw integers - using the
+     * {@link Intent#putExtra(String, int[])}.
+     * <p>
+     * As output: an extra returned on the result intent received when using the
+     * {@link #ACTION_PROCESS_WIFI_EASY_CONNECT_URI} intent to launch the Easy Connect Operation
+     * . This value is populated only by remote R2 devices, and only for the following error
+     * codes:
+     * {@link android.net.wifi.EasyConnectStatusCallback#EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK},
+     * {@link android.net.wifi.EasyConnectStatusCallback#EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION},
+     * or
      * {@link android.net.wifi.EasyConnectStatusCallback#EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION}.
-     * Therefore, always check if this extra is available using {@link Intent#hasExtra(String)}. If
-     * there is no error, i.e. if the operation returns {@link android.app.Activity#RESULT_OK}, then
-     * this extra is not attached to the result intent.
+     * Therefore, always check if this extra is available using {@link Intent#hasExtra(String)}.
+     * If there is no error, i.e. if the operation returns {@link android.app.Activity#RESULT_OK}
+     * , then this extra is not attached to the result intent.
      * <p>
      * Use the {@link Intent#getIntArrayExtra(String)} to obtain the list.
      */
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ca8ba4c..e0f6e06 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -826,6 +826,10 @@
                 if (mWindowAttributes.packageName == null) {
                     mWindowAttributes.packageName = mBasePackageName;
                 }
+                if (WindowManagerGlobal.USE_BLAST_ADAPTER) {
+                    mWindowAttributes.privateFlags |=
+                        WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
+                }
                 attrs = mWindowAttributes;
                 setTag();
 
@@ -1308,7 +1312,7 @@
             mWindowAttributes.privateFlags |= compatibleWindowFlag;
 
             if (WindowManagerGlobal.USE_BLAST_ADAPTER) {
-                mWindowAttributes.privateFlags =
+                mWindowAttributes.privateFlags |=
                     WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
             }
 
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 20af76b..f851e10 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -5737,7 +5737,7 @@
         private boolean mIsDraggingCursor;
 
         public void onTouchEvent(MotionEvent event) {
-            if (getSelectionController().isCursorBeingModified()) {
+            if (hasSelectionController() && getSelectionController().isCursorBeingModified()) {
                 return;
             }
             switch (event.getActionMasked()) {
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index 13bfc1b..31b5e49 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -44,21 +44,21 @@
 import com.android.internal.util.XmlUtils;
 import com.android.server.DropboxLogTags;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.FileNotFoundException;
 import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
 /**
  * Performs a number of miscellaneous, non-system-critical actions
  * after the system has finished booting.
@@ -424,7 +424,23 @@
         for (String propPostfix : MOUNT_DURATION_PROPS_POSTFIX) {
             int duration = SystemProperties.getInt("ro.boottime.init.mount_all." + propPostfix, 0);
             if (duration != 0) {
-                MetricsLogger.histogram(null, "boot_mount_all_duration_" + propPostfix, duration);
+                int eventType;
+                switch (propPostfix) {
+                    case "early":
+                        eventType = StatsLog.BOOT_TIME_EVENT_DURATION__EVENT__MOUNT_EARLY_DURATION;
+                        break;
+                    case "default":
+                        eventType =
+                                StatsLog.BOOT_TIME_EVENT_DURATION__EVENT__MOUNT_DEFAULT_DURATION;
+                        break;
+                    case "late":
+                        eventType = StatsLog.BOOT_TIME_EVENT_DURATION__EVENT__MOUNT_LATE_DURATION;
+                        break;
+                    default:
+                        continue;
+                }
+                StatsLog.write(StatsLog.BOOT_TIME_EVENT_DURATION_REPORTED, eventType,
+                        duration);
             }
         }
     }
@@ -555,16 +571,19 @@
         Pattern pattern = Pattern.compile(LAST_SHUTDOWN_TIME_PATTERN, Pattern.MULTILINE);
         Matcher matcher = pattern.matcher(lines);
         if (matcher.find()) {
-            MetricsLogger.histogram(null, "boot_fs_shutdown_duration",
+            StatsLog.write(StatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+                    StatsLog.BOOT_TIME_EVENT_DURATION__EVENT__SHUTDOWN_DURATION,
                     Integer.parseInt(matcher.group(1)));
-            MetricsLogger.histogram(null, "boot_fs_shutdown_umount_stat",
+            StatsLog.write(StatsLog.BOOT_TIME_EVENT_ERROR_CODE_REPORTED,
+                    StatsLog.BOOT_TIME_EVENT_ERROR_CODE__EVENT__SHUTDOWN_UMOUNT_STAT,
                     Integer.parseInt(matcher.group(2)));
             Slog.i(TAG, "boot_fs_shutdown," + matcher.group(1) + "," + matcher.group(2));
         } else { // not found
             // This can happen when a device has too much kernel log after file system unmount
             // ,exceeding maxReadSize. And having that much kernel logging can affect overall
             // performance as well. So it is better to fix the kernel to reduce the amount of log.
-            MetricsLogger.histogram(null, "boot_fs_shutdown_umount_stat",
+            StatsLog.write(StatsLog.BOOT_TIME_EVENT_ERROR_CODE_REPORTED,
+                    StatsLog.BOOT_TIME_EVENT_ERROR_CODE__EVENT__SHUTDOWN_UMOUNT_STAT,
                     UMOUNT_STATUS_NOT_AVAILABLE);
             Slog.w(TAG, "boot_fs_shutdown, string not found");
         }
@@ -674,7 +693,11 @@
             return;
         }
         stat = fixFsckFsStat(partition, stat, lines, startLineNumber, endLineNumber);
-        MetricsLogger.histogram(null, "boot_fs_stat_" + partition, stat);
+        if ("userdata".equals(partition) || "data".equals(partition)) {
+            StatsLog.write(StatsLog.BOOT_TIME_EVENT_ERROR_CODE_REPORTED,
+                    StatsLog.BOOT_TIME_EVENT_ERROR_CODE__EVENT__FS_MGR_FS_STAT_DATA_PARTITION,
+                    stat);
+        }
         Slog.i(TAG, "fs_stat, partition:" + partition + " stat:0x" + Integer.toHexString(stat));
     }
 
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 6e6746f..a2f514a 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -344,7 +344,6 @@
     cppflags: ["-Wno-conversion-null"],
 
     srcs: [
-        "android/graphics/apex/android_bitmap.cpp",
         "android/graphics/apex/android_matrix.cpp",
         "android/graphics/apex/android_paint.cpp",
         "android/graphics/apex/android_region.cpp",
@@ -430,6 +429,7 @@
         android: {
             srcs: [ // sources that depend on android only libraries
                 "android/graphics/apex/android_canvas.cpp",
+                "android/graphics/apex/android_bitmap.cpp",
                 "android/graphics/apex/renderthread.cpp",
                 "android/graphics/apex/jni_runtime.cpp",
 
diff --git a/core/jni/android/graphics/apex/android_bitmap.cpp b/core/jni/android/graphics/apex/android_bitmap.cpp
index 90cc986..6a3c01e 100644
--- a/core/jni/android/graphics/apex/android_bitmap.cpp
+++ b/core/jni/android/graphics/apex/android_bitmap.cpp
@@ -122,6 +122,98 @@
     return getInfo(bitmap->info(), bitmap->rowBytes());
 }
 
+static bool nearlyEqual(float a, float b) {
+    // By trial and error, this is close enough to match for the ADataSpaces we
+    // compare for.
+    return ::fabs(a - b) < .002f;
+}
+
+static bool nearlyEqual(const skcms_TransferFunction& x, const skcms_TransferFunction& y) {
+    return nearlyEqual(x.g, y.g)
+        && nearlyEqual(x.a, y.a)
+        && nearlyEqual(x.b, y.b)
+        && nearlyEqual(x.c, y.c)
+        && nearlyEqual(x.d, y.d)
+        && nearlyEqual(x.e, y.e)
+        && nearlyEqual(x.f, y.f);
+}
+
+static bool nearlyEqual(const skcms_Matrix3x3& x, const skcms_Matrix3x3& y) {
+    for (int i = 0; i < 3; i++) {
+        for (int j = 0; j < 3; j++) {
+            if (!nearlyEqual(x.vals[i][j], y.vals[i][j])) return false;
+        }
+    }
+    return true;
+}
+
+static constexpr skcms_TransferFunction k2Dot6 = {2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
+
+// Skia's SkNamedGamut::kDCIP3 is based on a white point of D65. This gamut
+// matches the white point used by ColorSpace.Named.DCIP3.
+static constexpr skcms_Matrix3x3 kDCIP3 = {{
+        {0.486143, 0.323835, 0.154234},
+        {0.226676, 0.710327, 0.0629966},
+        {0.000800549, 0.0432385, 0.78275},
+}};
+
+ADataSpace ABitmap_getDataSpace(ABitmap* bitmapHandle) {
+    Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle);
+    const SkImageInfo& info = bitmap->info();
+    SkColorSpace* colorSpace = info.colorSpace();
+    if (!colorSpace) {
+        return ADATASPACE_UNKNOWN;
+    }
+
+    if (colorSpace->isSRGB()) {
+        if (info.colorType() == kRGBA_F16_SkColorType) {
+            return ADATASPACE_SCRGB;
+        }
+        return ADATASPACE_SRGB;
+    }
+
+    skcms_TransferFunction fn;
+    LOG_ALWAYS_FATAL_IF(!colorSpace->isNumericalTransferFn(&fn));
+
+    skcms_Matrix3x3 gamut;
+    LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&gamut));
+
+    if (nearlyEqual(gamut, SkNamedGamut::kSRGB)) {
+        if (nearlyEqual(fn, SkNamedTransferFn::kLinear)) {
+            // Skia doesn't differentiate amongst the RANGES. In Java, we associate
+            // LINEAR_EXTENDED_SRGB with F16, and LINEAR_SRGB with other Configs.
+            // Make the same association here.
+            if (info.colorType() == kRGBA_F16_SkColorType) {
+                return ADATASPACE_SCRGB_LINEAR;
+            }
+            return ADATASPACE_SRGB_LINEAR;
+        }
+
+        if (nearlyEqual(fn, SkNamedTransferFn::kRec2020)) {
+            return ADATASPACE_BT709;
+        }
+    }
+
+    if (nearlyEqual(fn, SkNamedTransferFn::kSRGB) && nearlyEqual(gamut, SkNamedGamut::kDCIP3)) {
+        return ADATASPACE_DISPLAY_P3;
+    }
+
+    if (nearlyEqual(fn, SkNamedTransferFn::k2Dot2) && nearlyEqual(gamut, SkNamedGamut::kAdobeRGB)) {
+        return ADATASPACE_ADOBE_RGB;
+    }
+
+    if (nearlyEqual(fn, SkNamedTransferFn::kRec2020) &&
+        nearlyEqual(gamut, SkNamedGamut::kRec2020)) {
+        return ADATASPACE_BT2020;
+    }
+
+    if (nearlyEqual(fn, k2Dot6) && nearlyEqual(gamut, kDCIP3)) {
+        return ADATASPACE_DCI_P3;
+    }
+
+    return ADATASPACE_UNKNOWN;
+}
+
 AndroidBitmapInfo ABitmap_getInfoFromJava(JNIEnv* env, jobject bitmapObj) {
     uint32_t rowBytes = 0;
     SkImageInfo imageInfo = GraphicsJNI::getBitmapInfo(env, bitmapObj, &rowBytes);
diff --git a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
index f231eed..32b8a45 100644
--- a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
+++ b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
@@ -17,6 +17,7 @@
 #define ANDROID_GRAPHICS_BITMAP_H
 
 #include <android/bitmap.h>
+#include <android/data_space.h>
 #include <jni.h>
 #include <sys/cdefs.h>
 
@@ -49,6 +50,7 @@
 void ABitmap_releaseRef(ABitmap* bitmap);
 
 AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmap);
+ADataSpace ABitmap_getDataSpace(ABitmap* bitmap);
 
 void* ABitmap_getPixels(ABitmap* bitmap);
 void ABitmap_notifyPixelsChanged(ABitmap* bitmap);
@@ -106,6 +108,7 @@
         ABitmap* get() const { return mBitmap; }
 
         AndroidBitmapInfo getInfo() const { return ABitmap_getInfo(mBitmap); }
+        ADataSpace getDataSpace() const { return ABitmap_getDataSpace(mBitmap); }
         void* getPixels() const { return ABitmap_getPixels(mBitmap); }
         void notifyPixelsChanged() const { ABitmap_notifyPixelsChanged(mBitmap); }
 
@@ -119,4 +122,4 @@
 }; // namespace android
 #endif // __cplusplus
 
-#endif // ANDROID_GRAPHICS_BITMAP_H
\ No newline at end of file
+#endif // ANDROID_GRAPHICS_BITMAP_H
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 466544c..673772a 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1156,6 +1156,36 @@
   createAndMountAppData(package_name, ce_data_path, mirrorCePath, actualCePath, fail_fn);
 }
 
+// Relabel directory
+static void relabelDir(const char* path, security_context_t context, fail_fn_t fail_fn) {
+  if (setfilecon(path, context) != 0) {
+    fail_fn(CREATE_ERROR("Failed to setfilecon %s %s", path, strerror(errno)));
+  }
+}
+
+// Relabel all directories under a path non-recursively.
+static void relabelAllDirs(const char* path, security_context_t context, fail_fn_t fail_fn) {
+  DIR* dir = opendir(path);
+  if (dir == nullptr) {
+    fail_fn(CREATE_ERROR("Failed to opendir %s", path));
+  }
+  struct dirent* ent;
+  while ((ent = readdir(dir))) {
+    if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue;
+    auto filePath = StringPrintf("%s/%s", path, ent->d_name);
+    if (ent->d_type == DT_DIR) {
+      relabelDir(filePath.c_str(), context, fail_fn);
+    } else if (ent->d_type == DT_LNK) {
+      if (lsetfilecon(filePath.c_str(), context) != 0) {
+        fail_fn(CREATE_ERROR("Failed to lsetfilecon %s %s", filePath.c_str(), strerror(errno)));
+      }
+    } else {
+      fail_fn(CREATE_ERROR("Unexpected type: %d %s", ent->d_type, filePath.c_str()));
+    }
+  }
+  closedir(dir);
+}
+
 /**
  * Make other apps data directory not visible in CE, DE storage.
  *
@@ -1215,10 +1245,36 @@
   snprintf(internalDePath, PATH_MAX, "/data/user_de");
   snprintf(externalPrivateMountPath, PATH_MAX, "/mnt/expand");
 
+  security_context_t dataDataContext = nullptr;
+  if (getfilecon(internalDePath, &dataDataContext) < 0) {
+    fail_fn(CREATE_ERROR("Unable to getfilecon on %s %s", internalDePath,
+        strerror(errno)));
+  }
+
   MountAppDataTmpFs(internalLegacyCePath, fail_fn);
   MountAppDataTmpFs(internalCePath, fail_fn);
   MountAppDataTmpFs(internalDePath, fail_fn);
-  MountAppDataTmpFs(externalPrivateMountPath, fail_fn);
+
+  // Mount tmpfs on all external vols DE and CE storage
+  DIR* dir = opendir(externalPrivateMountPath);
+  if (dir == nullptr) {
+    fail_fn(CREATE_ERROR("Failed to opendir %s", externalPrivateMountPath));
+  }
+  struct dirent* ent;
+  while ((ent = readdir(dir))) {
+    if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue;
+    if (ent->d_type != DT_DIR) {
+      fail_fn(CREATE_ERROR("Unexpected type: %d %s", ent->d_type, ent->d_name));
+    }
+    auto volPath = StringPrintf("%s/%s", externalPrivateMountPath, ent->d_name);
+    auto cePath = StringPrintf("%s/user", volPath.c_str());
+    auto dePath = StringPrintf("%s/user_de", volPath.c_str());
+    MountAppDataTmpFs(cePath.c_str(), fail_fn);
+    MountAppDataTmpFs(dePath.c_str(), fail_fn);
+  }
+  closedir(dir);
+
+  bool legacySymlinkCreated = false;
 
   for (int i = 0; i < size; i += 3) {
     jstring package_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i));
@@ -1266,7 +1322,14 @@
       // If it's user 0, create a symlink /data/user/0 -> /data/data,
       // otherwise create /data/user/$USER
       if (userId == 0) {
-        symlink(internalLegacyCePath, internalCeUserPath);
+        if (!legacySymlinkCreated) {
+          legacySymlinkCreated = true;
+          int result = symlink(internalLegacyCePath, internalCeUserPath);
+          if (result != 0) {
+             fail_fn(CREATE_ERROR("Failed to create symlink %s %s", internalCeUserPath,
+              strerror(errno)));
+          }
+        }
         actualCePath = internalLegacyCePath;
       } else {
         PrepareDirIfNotPresent(internalCeUserPath, DEFAULT_DATA_DIR_PERMISSION,
@@ -1280,6 +1343,43 @@
     isolateAppDataPerPackage(userId, packageName, volUuid, ceDataInode,
         actualCePath, actualDePath, fail_fn);
   }
+  // We set the label AFTER everything is done, as we are applying
+  // the file operations on tmpfs. If we set the label when we mount
+  // tmpfs, SELinux will not happy as we are changing system_data_files.
+  // Relabel dir under /data/user, including /data/user/0
+  relabelAllDirs(internalCePath, dataDataContext, fail_fn);
+
+  // Relabel /data/user
+  relabelDir(internalCePath, dataDataContext, fail_fn);
+
+  // Relabel /data/data
+  relabelDir(internalLegacyCePath, dataDataContext, fail_fn);
+
+  // Relabel dir under /data/user_de
+  relabelAllDirs(internalDePath, dataDataContext, fail_fn);
+
+  // Relabel /data/user_de
+  relabelDir(internalDePath, dataDataContext, fail_fn);
+
+  // Relabel CE and DE dirs under /mnt/expand
+  dir = opendir(externalPrivateMountPath);
+  if (dir == nullptr) {
+    fail_fn(CREATE_ERROR("Failed to opendir %s", externalPrivateMountPath));
+  }
+  while ((ent = readdir(dir))) {
+    if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue;
+    auto volPath = StringPrintf("%s/%s", externalPrivateMountPath, ent->d_name);
+    auto cePath = StringPrintf("%s/user", volPath.c_str());
+    auto dePath = StringPrintf("%s/user_de", volPath.c_str());
+
+    relabelAllDirs(cePath.c_str(), dataDataContext, fail_fn);
+    relabelDir(cePath.c_str(), dataDataContext, fail_fn);
+    relabelAllDirs(dePath.c_str(), dataDataContext, fail_fn);
+    relabelDir(dePath.c_str(), dataDataContext, fail_fn);
+  }
+  closedir(dir);
+
+  freecon(dataDataContext);
 }
 
 // Utility routine to specialize a zygote child process.
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 06040a5..b71e539 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -32,8 +32,8 @@
 import "frameworks/base/core/proto/android/server/job/enums.proto";
 import "frameworks/base/core/proto/android/server/statlogger.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/base/core/proto/android/util/quotatracker.proto";
 
-// Next tag: 21
 message JobSchedulerServiceDumpProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
@@ -160,10 +160,13 @@
     optional JobConcurrencyManagerProto concurrency_manager = 20;
 
     optional JobStorePersistStatsProto persist_stats = 21;
+
+    optional .android.util.quota.CountQuotaTrackerProto quota_tracker = 22;
+
+    // Next tag: 23
 }
 
 // A com.android.server.job.JobSchedulerService.Constants object.
-// Next tag: 29
 message ConstantsProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
@@ -246,6 +249,14 @@
     // Whether to use heartbeats or rolling window for quota management. True
     // will use heartbeats, false will use a rolling window.
     reserved 23; // use_heartbeats
+    // Whether to enable quota limits on APIs.
+    optional bool enable_api_quotas = 31;
+    // The maximum number of schedule() calls an app can make in a set amount of time.
+    optional int32 api_quota_schedule_count = 32;
+    // The time window that {@link #API_QUOTA_SCHEDULE_COUNT} should be evaluated over.
+    optional int64 api_quota_schedule_window_ms = 33;
+    // Whether or not to throw an exception when an app hits its schedule quota limit.
+    optional bool api_quota_schedule_throw_exception = 34;
 
     message QuotaController {
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -331,7 +342,7 @@
     // In this time after screen turns on, we increase job concurrency.
     optional int32 screen_off_job_concurrency_increase_delay_ms = 28;
 
-    // Next tag: 31
+    // Next tag: 35
 }
 
 // Next tag: 4
@@ -651,8 +662,7 @@
             optional bool is_active = 2;
             // The time this timer last became active. Only valid if is_active is true.
             optional int64 start_time_elapsed = 3;
-            // How many background jobs are currently running. Valid only if the device is_active
-            // is true.
+            // How many background jobs are currently running. Valid only if is_active is true.
             optional int32 bg_job_count = 4;
             // All of the jobs that the Timer is currently tracking.
             repeated JobStatusShortInfoProto running_jobs = 5;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b78b181..7ecd9b7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2568,7 +2568,7 @@
 
     <!-- Allows telephony to suggest the time / time zone.
          <p>Not for use by third-party applications.
-         @hide
+         @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @hide
      -->
     <permission android:name="android.permission.SUGGEST_PHONE_TIME_AND_ZONE"
         android:protectionLevel="signature|telephony" />
diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
index 89c2374..8c9b4d0 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
@@ -67,6 +67,7 @@
         mOriginalFlagValue = Editor.FLAG_ENABLE_CURSOR_DRAG;
         Editor.FLAG_ENABLE_CURSOR_DRAG = true;
     }
+
     @After
     public void after() throws Throwable {
         Editor.FLAG_ENABLE_CURSOR_DRAG = mOriginalFlagValue;
@@ -356,6 +357,23 @@
         assertFalse(editor.getSelectionController().isCursorBeingModified());
     }
 
+    @Test // Reproduces b/147366705
+    public void testCursorDrag_nonSelectableTextView() throws Throwable {
+        String text = "Hello world!";
+        TextView tv = mActivity.findViewById(R.id.nonselectable_textview);
+        tv.setText(text);
+        Editor editor = tv.getEditorForTesting();
+
+        // Simulate a tap. No error should be thrown.
+        long event1Time = 1001;
+        MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
+        mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1));
+
+        // Swipe left to right. No error should be thrown.
+        onView(withId(R.id.nonselectable_textview)).perform(
+                dragOnText(text.indexOf("llo"), text.indexOf("!")));
+    }
+
     private static MotionEvent downEvent(long downTime, long eventTime, float x, float y) {
         return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
     }
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
index b411668..aa55e08 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
@@ -19,7 +19,6 @@
 import static android.widget.espresso.ContextMenuUtils.assertContextMenuContainsItemDisabled;
 import static android.widget.espresso.ContextMenuUtils.assertContextMenuContainsItemEnabled;
 import static android.widget.espresso.ContextMenuUtils.assertContextMenuIsNotDisplayed;
-import static android.widget.espresso.DragHandleUtils.assertNoSelectionHandles;
 import static android.widget.espresso.DragHandleUtils.onHandleView;
 import static android.widget.espresso.TextViewActions.mouseClick;
 import static android.widget.espresso.TextViewActions.mouseClickOnTextAtIndex;
@@ -64,7 +63,6 @@
  */
 @RunWith(AndroidJUnit4.class)
 @MediumTest
-@Suppress // Consistently failing. b/29591177
 public class TextViewActivityMouseTest {
 
     @Rule
@@ -86,11 +84,8 @@
         onView(withId(R.id.textview)).perform(mouseClick());
         onView(withId(R.id.textview)).perform(replaceText(helloWorld));
 
-        assertNoSelectionHandles();
-
         onView(withId(R.id.textview)).perform(
                 mouseDragOnText(helloWorld.indexOf("llo"), helloWorld.indexOf("ld!")));
-
         onView(withId(R.id.textview)).check(hasSelection("llo wor"));
 
         onHandleView(com.android.internal.R.id.selection_start_handle)
@@ -100,8 +95,6 @@
 
         onView(withId(R.id.textview)).perform(mouseClickOnTextAtIndex(helloWorld.indexOf("w")));
         onView(withId(R.id.textview)).check(hasSelection(""));
-
-        assertNoSelectionHandles();
     }
 
     @Test
@@ -196,11 +189,11 @@
 
         onView(withId(R.id.textview)).check(matches(withText("abc ghi.def")));
         onView(withId(R.id.textview)).check(hasSelection(""));
-        assertNoSelectionHandles();
         onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex("abc ghi.def".length()));
     }
 
     @Test
+    @Suppress // Consistently failing. b/29591177
     public void testDragAndDrop_longClick() {
         final String text = "abc def ghi.";
         onView(withId(R.id.textview)).perform(mouseClick());
@@ -213,7 +206,6 @@
 
         onView(withId(R.id.textview)).check(matches(withText("abc ghi.def")));
         onView(withId(R.id.textview)).check(hasSelection(""));
-        assertNoSelectionHandles();
         onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex("abc ghi.def".length()));
     }
 
diff --git a/core/tests/coretests/src/android/widget/espresso/MouseUiController.java b/core/tests/coretests/src/android/widget/espresso/MouseUiController.java
index abee736..1928d25 100644
--- a/core/tests/coretests/src/android/widget/espresso/MouseUiController.java
+++ b/core/tests/coretests/src/android/widget/espresso/MouseUiController.java
@@ -70,6 +70,8 @@
         event.setSource(InputDevice.SOURCE_MOUSE);
         if (event.getActionMasked() != MotionEvent.ACTION_UP) {
             event.setButtonState(mButton);
+        } else {
+            event.setButtonState(0);
         }
         return mUiController.injectMotionEvent(event);
     }
diff --git a/media/java/android/media/IMediaRoute2ProviderClient.aidl b/media/java/android/media/IMediaRoute2ProviderClient.aidl
index e8abfdc..0fccb3a 100644
--- a/media/java/android/media/IMediaRoute2ProviderClient.aidl
+++ b/media/java/android/media/IMediaRoute2ProviderClient.aidl
@@ -25,8 +25,10 @@
  * @hide
  */
 oneway interface IMediaRoute2ProviderClient {
-    void updateState(in MediaRoute2ProviderInfo providerInfo,
-            in List<RoutingSessionInfo> sessionInfos);
-    void notifySessionCreated(in @nullable RoutingSessionInfo sessionInfo, long requestId);
-    void notifySessionInfoChanged(in RoutingSessionInfo sessionInfo);
+    // TODO: Change it to updateRoutes?
+    void updateState(in MediaRoute2ProviderInfo providerInfo);
+    void notifySessionCreated(in RoutingSessionInfo sessionInfo, long requestId);
+    void notifySessionCreationFailed(long requestId);
+    void notifySessionUpdated(in RoutingSessionInfo sessionInfo);
+    void notifySessionReleased(in RoutingSessionInfo sessionInfo);
 }
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 1cd5dfa..6d9aea5 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -58,6 +58,16 @@
 
     public static final String SERVICE_INTERFACE = "android.media.MediaRoute2ProviderService";
 
+    /**
+     * The request ID to pass {@link #notifySessionCreated(RoutingSessionInfo, long)}
+     * when {@link MediaRoute2ProviderService} created a session although there was no creation
+     * request.
+     *
+     * @see #notifySessionCreated(RoutingSessionInfo, long)
+     * @hide
+     */
+    public static final long REQUEST_ID_UNKNOWN = 0;
+
     private final Handler mHandler;
     private final Object mSessionLock = new Object();
     private final AtomicBoolean mStatePublishScheduled = new AtomicBoolean(false);
@@ -118,7 +128,7 @@
      *
      * @param sessionId id of the session
      * @return information of the session with the given id.
-     *         null if the session is destroyed or id is not valid.
+     *         null if the session is released or ID is not valid.
      * @hide
      */
     @Nullable
@@ -143,90 +153,39 @@
     }
 
     /**
-     * Updates the information of a session.
-     * If the session is destroyed or not created before, it will be ignored.
-     * Call {@link #updateProviderInfo(MediaRoute2ProviderInfo)} to notify clients of
-     * session info changes.
-     *
-     * @param sessionInfo new session information
-     * @see #notifySessionCreated(RoutingSessionInfo, long)
-     * @hide
-     */
-    public final void updateSessionInfo(@NonNull RoutingSessionInfo sessionInfo) {
-        Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
-        String sessionId = sessionInfo.getId();
-
-        synchronized (mSessionLock) {
-            if (mSessionInfo.containsKey(sessionId)) {
-                mSessionInfo.put(sessionId, sessionInfo);
-                schedulePublishState();
-            } else {
-                Log.w(TAG, "Ignoring unknown session info.");
-                return;
-            }
-        }
-    }
-
-    /**
-     * Notifies the session is changed.
-     *
-     * TODO: This method is temporary, only created for tests. Remove when the alternative is ready.
-     * @hide
-     */
-    public final void notifySessionInfoChanged(@NonNull RoutingSessionInfo sessionInfo) {
-        Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
-
-        String sessionId = sessionInfo.getId();
-        synchronized (mSessionLock) {
-            if (mSessionInfo.containsKey(sessionId)) {
-                mSessionInfo.put(sessionId, sessionInfo);
-            } else {
-                Log.w(TAG, "Ignoring unknown session info.");
-                return;
-            }
-        }
-
-        if (mClient == null) {
-            return;
-        }
-        try {
-            mClient.notifySessionInfoChanged(sessionInfo);
-        } catch (RemoteException ex) {
-            Log.w(TAG, "Failed to notify session info changed.");
-        }
-    }
-
-    /**
-     * Notifies clients of that the session is created and ready for use. If the session can be
-     * controlled, pass a {@link Bundle} that contains how to control it.
+     * Notifies clients of that the session is created and ready for use.
+     * <p>
+     * If this session is created without any creation request, use {@link #REQUEST_ID_UNKNOWN}
+     * as the request ID.
      *
      * @param sessionInfo information of the new session.
-     *                    The {@link RoutingSessionInfo#getId() id} of the session must be
-     *                    unique. Pass {@code null} to reject the request or inform clients that
-     *                    session creation is failed.
-     * @param requestId id of the previous request to create this session
+     *                    The {@link RoutingSessionInfo#getId() id} of the session must be unique.
+     * @param requestId id of the previous request to create this session provided in
+     *                  {@link #onCreateSession(String, String, String, long)}
+     * @see #onCreateSession(String, String, String, long)
      * @hide
      */
-    // TODO: fail reason?
-    // TODO: Maybe better to create notifySessionCreationFailed?
-    public final void notifySessionCreated(@Nullable RoutingSessionInfo sessionInfo,
+    public final void notifySessionCreated(@NonNull RoutingSessionInfo sessionInfo,
             long requestId) {
-        if (sessionInfo != null) {
-            String sessionId = sessionInfo.getId();
-            synchronized (mSessionLock) {
-                if (mSessionInfo.containsKey(sessionId)) {
-                    Log.w(TAG, "Ignoring duplicate session id.");
-                    return;
-                }
-                mSessionInfo.put(sessionInfo.getId(), sessionInfo);
+        Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
+
+        String sessionId = sessionInfo.getId();
+        synchronized (mSessionLock) {
+            if (mSessionInfo.containsKey(sessionId)) {
+                Log.w(TAG, "Ignoring duplicate session id.");
+                return;
             }
-            schedulePublishState();
+            mSessionInfo.put(sessionInfo.getId(), sessionInfo);
         }
+        schedulePublishState();
 
         if (mClient == null) {
             return;
         }
         try {
+            // TODO: Calling binder calls in multiple thread may cause timing issue.
+            //       Consider to change implementations to avoid the problems.
+            //       For example, post binder calls, always send all sessions at once, etc.
             mClient.notifySessionCreated(sessionInfo, requestId);
         } catch (RemoteException ex) {
             Log.w(TAG, "Failed to notify session created.");
@@ -234,70 +193,138 @@
     }
 
     /**
-     * Releases a session with the given id.
-     * {@link #onDestroySession} is called if the session is released.
+     * Notifies clients of that the session could not be created.
      *
-     * @param sessionId id of the session to be released
-     * @see #onDestroySession(String, RoutingSessionInfo)
+     * @param requestId id of the previous request to create the session provided in
+     *                  {@link #onCreateSession(String, String, String, long)}.
+     * @see #onCreateSession(String, String, String, long)
      * @hide
      */
-    public final void releaseSession(@NonNull String sessionId) {
-        if (TextUtils.isEmpty(sessionId)) {
-            throw new IllegalArgumentException("sessionId must not be empty");
+    public final void notifySessionCreationFailed(long requestId) {
+        if (mClient == null) {
+            return;
         }
-        //TODO: notify media router service of release.
-        RoutingSessionInfo sessionInfo;
-        synchronized (mSessionLock) {
-            sessionInfo = mSessionInfo.remove(sessionId);
-        }
-        if (sessionInfo != null) {
-            mHandler.sendMessage(obtainMessage(
-                    MediaRoute2ProviderService::onDestroySession, this, sessionId, sessionInfo));
-            schedulePublishState();
+        try {
+            mClient.notifySessionCreationFailed(requestId);
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Failed to notify session creation failed.");
         }
     }
 
     /**
-     * Called when a session should be created.
+     * Notifies the existing session is updated. For example, when
+     * {@link RoutingSessionInfo#getSelectedRoutes() selected routes} are changed.
+     *
+     * @hide
+     */
+    public final void notifySessionUpdated(@NonNull RoutingSessionInfo sessionInfo) {
+        Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
+
+        String sessionId = sessionInfo.getId();
+        synchronized (mSessionLock) {
+            if (mSessionInfo.containsKey(sessionId)) {
+                mSessionInfo.put(sessionId, sessionInfo);
+            } else {
+                Log.w(TAG, "Ignoring unknown session info.");
+                return;
+            }
+        }
+
+        if (mClient == null) {
+            return;
+        }
+        try {
+            mClient.notifySessionUpdated(sessionInfo);
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Failed to notify session info changed.");
+        }
+    }
+
+    /**
+     * Notifies that the session is released.
+     *
+     * @param sessionId id of the released session.
+     * @see #onReleaseSession(String)
+     * @hide
+     */
+    public final void notifySessionReleased(@NonNull String sessionId) {
+        if (TextUtils.isEmpty(sessionId)) {
+            throw new IllegalArgumentException("sessionId must not be empty");
+        }
+        RoutingSessionInfo sessionInfo;
+        synchronized (mSessionLock) {
+            sessionInfo = mSessionInfo.remove(sessionId);
+        }
+
+        if (sessionInfo == null) {
+            Log.w(TAG, "Ignoring unknown session info.");
+            return;
+        }
+
+        if (mClient == null) {
+            return;
+        }
+        try {
+            mClient.notifySessionReleased(sessionInfo);
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Failed to notify session info changed.");
+        }
+    }
+
+    /**
+     * Called when the service receives a request to create a session.
+     * <p>
      * You should create and maintain your own session and notifies the client of
      * session info. Call {@link #notifySessionCreated(RoutingSessionInfo, long)}
      * with the given {@code requestId} to notify the information of a new session.
-     * If you can't create the session or want to reject the request, pass {@code null}
-     * as session info in {@link #notifySessionCreated(RoutingSessionInfo, long)}
-     * with the given {@code requestId}.
+     * The created session must have the same route feature and must include the given route
+     * specified by {@code routeId}.
+     * <p>
+     * If the session can be controlled, you can optionally pass the control hints to
+     * {@link RoutingSessionInfo.Builder#setControlHints(Bundle)}. Control hints is a
+     * {@link Bundle} which contains how to control the session.
+     * <p>
+     * If you can't create the session or want to reject the request, call
+     * {@link #notifySessionCreationFailed(long)} with the given {@code requestId}.
      *
      * @param packageName the package name of the application that selected the route
      * @param routeId the id of the route initially being connected
      * @param routeFeature the route feature of the new session
      * @param requestId the id of this session creation request
+     *
+     * @see RoutingSessionInfo.Builder#Builder(String, String, String)
+     * @see RoutingSessionInfo.Builder#addSelectedRoute(String)
+     * @see RoutingSessionInfo.Builder#setControlHints(Bundle)
      * @hide
      */
     public abstract void onCreateSession(@NonNull String packageName, @NonNull String routeId,
             @NonNull String routeFeature, long requestId);
 
     /**
-     * Called when a session is about to be destroyed.
-     * You can clean up your session here. This can happen by the
-     * client or provider itself.
+     * Called when the session should be released. A client of the session or system can request
+     * a session to be released.
+     * <p>
+     * After releasing the session, call {@link #notifySessionReleased(String)}
+     * with the ID of the released session.
      *
-     * @param sessionId id of the session being destroyed.
-     * @param lastSessionInfo information of the session being destroyed.
-     * @see #releaseSession(String)
+     * Note: Calling {@link #notifySessionReleased(String)} will <em>NOT</em> trigger
+     * this method to be called.
+     *
+     * @param sessionId id of the session being released.
+     * @see #notifySessionReleased(String)
+     * @see #getSessionInfo(String)
      * @hide
      */
-    public abstract void onDestroySession(@NonNull String sessionId,
-            @NonNull RoutingSessionInfo lastSessionInfo);
+    public abstract void onReleaseSession(@NonNull String sessionId);
 
     //TODO: make a way to reject the request
     /**
      * Called when a client requests selecting a route for the session.
-     * After the route is selected, call {@link #updateSessionInfo(RoutingSessionInfo)} to update
-     * session info and call {@link #updateProviderInfo(MediaRoute2ProviderInfo)} to notify
-     * clients of updated session info.
+     * After the route is selected, call {@link #notifySessionUpdated(RoutingSessionInfo)}
+     * to update session info.
      *
      * @param sessionId id of the session
      * @param routeId id of the route
-     * @see #updateSessionInfo(RoutingSessionInfo)
      * @hide
      */
     public abstract void onSelectRoute(@NonNull String sessionId, @NonNull String routeId);
@@ -305,9 +332,8 @@
     //TODO: make a way to reject the request
     /**
      * Called when a client requests deselecting a route from the session.
-     * After the route is deselected, call {@link #updateSessionInfo(RoutingSessionInfo)} to update
-     * session info and call {@link #updateProviderInfo(MediaRoute2ProviderInfo)} to notify
-     * clients of updated session info.
+     * After the route is deselected, call {@link #notifySessionUpdated(RoutingSessionInfo)}
+     * to update session info.
      *
      * @param sessionId id of the session
      * @param routeId id of the route
@@ -318,9 +344,8 @@
     //TODO: make a way to reject the request
     /**
      * Called when a client requests transferring a session to a route.
-     * After the transfer is finished, call {@link #updateSessionInfo(RoutingSessionInfo)} to update
-     * session info and call {@link #updateProviderInfo(MediaRoute2ProviderInfo)} to notify
-     * clients of updated session info.
+     * After the transfer is finished, call {@link #notifySessionUpdated(RoutingSessionInfo)}
+     * to update session info.
      *
      * @param sessionId id of the session
      * @param routeId id of the route
@@ -344,6 +369,8 @@
      * </p>
      *
      * @param preference the new discovery preference
+     *
+     * TODO: This method needs tests.
      */
     public void onDiscoveryPreferenceChanged(@NonNull RouteDiscoveryPreference preference) {}
 
@@ -383,7 +410,7 @@
             sessionInfos = new ArrayList<>(mSessionInfo.values());
         }
         try {
-            mClient.updateState(mProviderInfo, sessionInfos);
+            mClient.updateState(mProviderInfo);
         } catch (RemoteException ex) {
             Log.w(TAG, "Failed to send onProviderInfoUpdated");
         }
@@ -415,6 +442,7 @@
                     MediaRoute2ProviderService.this, packageName, routeId, routeFeature,
                     requestId));
         }
+
         @Override
         public void releaseSession(@NonNull String sessionId) {
             if (!checkCallerisSystem()) {
@@ -424,7 +452,7 @@
                 Log.w(TAG, "releaseSession: Ignoring empty sessionId from system service.");
                 return;
             }
-            mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::releaseSession,
+            mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onReleaseSession,
                     MediaRoute2ProviderService.this, sessionId));
         }
 
diff --git a/media/java/android/media/MediaTranscodeManager.java b/media/java/android/media/MediaTranscodeManager.java
new file mode 100644
index 0000000..2c431b9
--- /dev/null
+++ b/media/java/android/media/MediaTranscodeManager.java
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.net.Uri;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * MediaTranscodeManager provides an interface to the system's media transcode service.
+ * Transcode requests are put in a queue and processed in order. When a transcode operation is
+ * completed the caller is notified via its OnTranscodingFinishedListener. In the meantime the
+ * caller may use the returned TranscodingJob object to cancel or check the status of a specific
+ * transcode operation.
+ * The currently supported media types are video and still images.
+ *
+ * TODO(lnilsson): Add sample code when API is settled.
+ *
+ * @hide
+ */
+public final class MediaTranscodeManager {
+    private static final String TAG = "MediaTranscodeManager";
+
+    // Invalid ID passed from native means the request was never enqueued.
+    private static final long ID_INVALID = -1;
+
+    // Events passed from native.
+    private static final int EVENT_JOB_STARTED = 1;
+    private static final int EVENT_JOB_PROGRESSED = 2;
+    private static final int EVENT_JOB_FINISHED = 3;
+
+    @IntDef(prefix = { "EVENT_" }, value = {
+            EVENT_JOB_STARTED,
+            EVENT_JOB_PROGRESSED,
+            EVENT_JOB_FINISHED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Event {}
+
+    private static MediaTranscodeManager sMediaTranscodeManager;
+    private final ConcurrentMap<Long, TranscodingJob> mPendingTranscodingJobs =
+            new ConcurrentHashMap<>();
+    private final Context mContext;
+
+    /**
+     * Listener that gets notified when a transcoding operation has finished.
+     * This listener gets notified regardless of how the operation finished. It is up to the
+     * listener implementation to check the result and take appropriate action.
+     */
+    @FunctionalInterface
+    public interface OnTranscodingFinishedListener {
+        /**
+         * Called when the transcoding operation has finished. The receiver may use the
+         * TranscodingJob to check the result, i.e. whether the operation succeeded, was canceled or
+         * if an error occurred.
+         * @param transcodingJob The TranscodingJob instance for the finished transcoding operation.
+         */
+        void onTranscodingFinished(@NonNull TranscodingJob transcodingJob);
+    }
+
+    /**
+     * Class describing a transcode operation to be performed. The caller uses this class to
+     * configure a transcoding operation that can then be enqueued using MediaTranscodeManager.
+     */
+    public static final class TranscodingRequest {
+        private Uri mSrcUri;
+        private Uri mDstUri;
+        private MediaFormat mDstFormat;
+
+        private TranscodingRequest(Builder b) {
+            mSrcUri = b.mSrcUri;
+            mDstUri = b.mDstUri;
+            mDstFormat = b.mDstFormat;
+        }
+
+        /** TranscodingRequest builder class. */
+        public static class Builder {
+            private Uri mSrcUri;
+            private Uri mDstUri;
+            private MediaFormat mDstFormat;
+
+            /**
+             * Specifies the source media file.
+             * @param uri Content uri for the source media file.
+             * @return The builder instance.
+             */
+            public Builder setSourceUri(Uri uri) {
+                mSrcUri = uri;
+                return this;
+            }
+
+            /**
+             * Specifies the destination media file.
+             * @param uri Content uri for the destination media file.
+             * @return The builder instance.
+             */
+            public Builder setDestinationUri(Uri uri) {
+                mDstUri = uri;
+                return this;
+            }
+
+            /**
+             * Specifies the media format of the transcoded media file.
+             * @param dstFormat MediaFormat containing the desired destination format.
+             * @return The builder instance.
+             */
+            public Builder setDestinationFormat(MediaFormat dstFormat) {
+                mDstFormat = dstFormat;
+                return this;
+            }
+
+            /**
+             * Builds a new TranscodingRequest with the configuration set on this builder.
+             * @return A new TranscodingRequest.
+             */
+            public TranscodingRequest build() {
+                return new TranscodingRequest(this);
+            }
+        }
+    }
+
+    /**
+     * Handle to an enqueued transcoding operation. An instance of this class represents a single
+     * enqueued transcoding operation. The caller can use that instance to query the status or
+     * progress, and to get the result once the operation has completed.
+     */
+    public static final class TranscodingJob {
+        /** The job is enqueued but not yet running. */
+        public static final int STATUS_PENDING = 1;
+        /** The job is currently running. */
+        public static final int STATUS_RUNNING = 2;
+        /** The job is finished. */
+        public static final int STATUS_FINISHED = 3;
+
+        @IntDef(prefix = { "STATUS_" }, value = {
+                STATUS_PENDING,
+                STATUS_RUNNING,
+                STATUS_FINISHED,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface Status {}
+
+        /** The job does not have a result yet. */
+        public static final int RESULT_NONE = 1;
+        /** The job completed successfully. */
+        public static final int RESULT_SUCCESS = 2;
+        /** The job encountered an error while running. */
+        public static final int RESULT_ERROR = 3;
+        /** The job was canceled by the caller. */
+        public static final int RESULT_CANCELED = 4;
+
+        @IntDef(prefix = { "RESULT_" }, value = {
+                RESULT_NONE,
+                RESULT_SUCCESS,
+                RESULT_ERROR,
+                RESULT_CANCELED,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface Result {}
+
+        /** Listener that gets notified when the progress changes. */
+        @FunctionalInterface
+        public interface OnProgressChangedListener {
+
+            /**
+             * Called when the progress changes. The progress is between 0 and 1, where 0 means
+             * that the job has not yet started and 1 means that it has finished.
+             * @param progress The new progress.
+             */
+            void onProgressChanged(float progress);
+        }
+
+        private final Executor mExecutor;
+        private final OnTranscodingFinishedListener mListener;
+        private final ReentrantLock mStatusChangeLock = new ReentrantLock();
+        private Executor mProgressChangedExecutor;
+        private OnProgressChangedListener mProgressChangedListener;
+        private long mID;
+        private float mProgress = 0.0f;
+        private @Status int mStatus = STATUS_PENDING;
+        private @Result int mResult = RESULT_NONE;
+
+        private TranscodingJob(long id, @NonNull @CallbackExecutor Executor executor,
+                @NonNull OnTranscodingFinishedListener listener) {
+            mID = id;
+            mExecutor = executor;
+            mListener = listener;
+        }
+
+        /**
+         * Set a progress listener.
+         * @param listener The progress listener.
+         */
+        public void setOnProgressChangedListener(@NonNull @CallbackExecutor Executor executor,
+                @Nullable OnProgressChangedListener listener) {
+            mProgressChangedExecutor = executor;
+            mProgressChangedListener = listener;
+        }
+
+        /**
+         * Cancels the transcoding job and notify the listener. If the job happened to finish before
+         * being canceled this call is effectively a no-op and will not update the result in that
+         * case.
+         */
+        public void cancel() {
+            setJobFinished(RESULT_CANCELED);
+            sMediaTranscodeManager.native_cancelTranscodingRequest(mID);
+        }
+
+        /**
+         * Gets the progress of the transcoding job. The progress is between 0 and 1, where 0 means
+         * that the job has not yet started and 1 means that it is finished.
+         * @return The progress.
+         */
+        public float getProgress() {
+            return mProgress;
+        }
+
+        /**
+         * Gets the status of the transcoding job.
+         * @return The status.
+         */
+        public @Status int getStatus() {
+            return mStatus;
+        }
+
+        /**
+         * Gets the result of the transcoding job.
+         * @return The result.
+         */
+        public @Result int getResult() {
+            return mResult;
+        }
+
+        private void setJobStarted() {
+            mStatus = STATUS_RUNNING;
+        }
+
+        private void setJobProgress(float newProgress) {
+            mProgress = newProgress;
+
+            // Notify listener.
+            OnProgressChangedListener onProgressChangedListener = mProgressChangedListener;
+            if (onProgressChangedListener != null) {
+                mProgressChangedExecutor.execute(
+                        () -> onProgressChangedListener.onProgressChanged(mProgress));
+            }
+        }
+
+        private void setJobFinished(int result) {
+            boolean doNotifyListener = false;
+
+            // Prevent conflicting simultaneous status updates from native (finished) and from the
+            // caller (cancel).
+            try {
+                mStatusChangeLock.lock();
+                if (mStatus != STATUS_FINISHED) {
+                    mStatus = STATUS_FINISHED;
+                    mResult = result;
+                    doNotifyListener = true;
+                }
+            } finally {
+                mStatusChangeLock.unlock();
+            }
+
+            if (doNotifyListener) {
+                mExecutor.execute(() -> mListener.onTranscodingFinished(this));
+            }
+        }
+
+        private void processJobEvent(@Event int event, int arg) {
+            switch (event) {
+                case EVENT_JOB_STARTED:
+                    setJobStarted();
+                    break;
+                case EVENT_JOB_PROGRESSED:
+                    setJobProgress((float) arg / 100);
+                    break;
+                case EVENT_JOB_FINISHED:
+                    setJobFinished(arg);
+                    break;
+                default:
+                    Log.e(TAG, "Unsupported event: " + event);
+                    break;
+            }
+        }
+    }
+
+    // Initializes the native library.
+    private static native void native_init();
+    // Requests a new job ID from the native service.
+    private native long native_requestUniqueJobID();
+    // Enqueues a transcoding request to the native service.
+    private native boolean native_enqueueTranscodingRequest(
+            long id, @NonNull TranscodingRequest transcodingRequest, @NonNull Context context);
+    // Cancels an enqueued transcoding request.
+    private native void native_cancelTranscodingRequest(long id);
+
+    // Private constructor.
+    private MediaTranscodeManager(@NonNull Context context) {
+        mContext = context;
+    }
+
+    // Events posted from the native service.
+    @SuppressWarnings("unused")
+    private void postEventFromNative(@Event int event, long id, int arg) {
+        Log.d(TAG, String.format("postEventFromNative. Event %d, ID %d, arg %d", event, id, arg));
+
+        TranscodingJob transcodingJob = mPendingTranscodingJobs.get(id);
+
+        // Job IDs are added to the tracking set before the job is enqueued so it should never
+        // be null unless the service misbehaves.
+        if (transcodingJob == null) {
+            Log.e(TAG, "No matching transcode job found for id " + id);
+            return;
+        }
+
+        transcodingJob.processJobEvent(event, arg);
+    }
+
+    /**
+     * Gets the MediaTranscodeManager singleton instance.
+     * @param context The application context.
+     * @return the {@link MediaTranscodeManager} singleton instance.
+     */
+    public static MediaTranscodeManager getInstance(@NonNull Context context) {
+        Preconditions.checkNotNull(context);
+        synchronized (MediaTranscodeManager.class) {
+            if (sMediaTranscodeManager == null) {
+                sMediaTranscodeManager = new MediaTranscodeManager(context.getApplicationContext());
+            }
+            return sMediaTranscodeManager;
+        }
+    }
+
+    /**
+     * Enqueues a TranscodingRequest for execution.
+     * @param transcodingRequest The TranscodingRequest to enqueue.
+     * @param listenerExecutor Executor on which the listener is notified.
+     * @param listener Listener to get notified when the transcoding job is finished.
+     * @return A TranscodingJob for this operation.
+     */
+    public @Nullable TranscodingJob enqueueTranscodingRequest(
+            @NonNull TranscodingRequest transcodingRequest,
+            @NonNull @CallbackExecutor Executor listenerExecutor,
+            @NonNull OnTranscodingFinishedListener listener) {
+        Log.i(TAG, "enqueueTranscodingRequest called.");
+        Preconditions.checkNotNull(transcodingRequest);
+        Preconditions.checkNotNull(listenerExecutor);
+        Preconditions.checkNotNull(listener);
+
+        // Reserve a job ID.
+        long jobID = native_requestUniqueJobID();
+        if (jobID == ID_INVALID) {
+            return null;
+        }
+
+        // Add the job to the tracking set.
+        TranscodingJob transcodingJob = new TranscodingJob(jobID, listenerExecutor, listener);
+        mPendingTranscodingJobs.put(jobID, transcodingJob);
+
+        // Enqueue the request with the native service.
+        boolean enqueued = native_enqueueTranscodingRequest(jobID, transcodingRequest, mContext);
+        if (!enqueued) {
+            mPendingTranscodingJobs.remove(jobID);
+            return null;
+        }
+
+        return transcodingJob;
+    }
+
+    static {
+        System.loadLibrary("media_jni");
+        native_init();
+    }
+}
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 01f1250..27f02fe 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -719,9 +719,14 @@
                     if (track == null) {
                         break;
                     }
-                    // TODO: add synchronous versions
-                    track.stop();
-                    track.flush();
+                    try {
+                        // TODO: add synchronous versions
+                        track.stop();
+                        track.flush();
+                    } catch (IllegalStateException e) {
+                        // ignore exception, AudioTrack could have already been stopped or
+                        // released by the user of the AudioPolicy
+                    }
                 }
             }
             if (mCaptors != null) {
@@ -730,8 +735,13 @@
                     if (record == null) {
                         break;
                     }
-                    // TODO: if needed: implement an invalidate method
-                    record.stop();
+                    try {
+                        // TODO: if needed: implement an invalidate method
+                        record.stop();
+                    } catch (IllegalStateException e) {
+                        // ignore exception, AudioRecord could have already been stopped or
+                        // released by the user of the AudioPolicy
+                    }
                 }
             }
         }
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 862489f..e3dfaeb 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -16,6 +16,7 @@
 
 package android.media.tv.tuner;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -32,11 +33,13 @@
 import android.media.tv.tuner.frontend.FrontendCallback;
 import android.media.tv.tuner.frontend.FrontendInfo;
 import android.media.tv.tuner.frontend.FrontendStatus;
+import android.media.tv.tuner.frontend.ScanCallback;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 
 import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
  * This class is used to interact with hardware tuners devices.
@@ -70,6 +73,10 @@
 
     private List<Integer> mLnbIds;
     private Lnb mLnb;
+    @Nullable
+    private ScanCallback mScanCallback;
+    @Nullable
+    private Executor mScanCallbackExecutor;
 
     /**
      * Constructs a Tuner instance.
@@ -231,29 +238,6 @@
         private Frontend(int id) {
             mId = id;
         }
-
-        public void setCallback(@Nullable FrontendCallback callback, @Nullable Handler handler) {
-            mCallback = callback;
-
-            if (mCallback == null) {
-                return;
-            }
-
-            if (handler == null) {
-                // use default looper if handler is null
-                if (mHandler == null) {
-                    mHandler = createEventHandler();
-                }
-                return;
-            }
-
-            Looper looper = handler.getLooper();
-            if (mHandler != null && mHandler.getLooper() == looper) {
-                // the same looper. reuse mHandler
-                return;
-            }
-            mHandler = new EventHandler(looper);
-        }
     }
 
     /**
@@ -286,18 +270,32 @@
      * Scan channels.
      * @hide
      */
-    public int scan(@NonNull FrontendSettings settings, @FrontendScanType int scanType) {
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    public int scan(@NonNull FrontendSettings settings, @FrontendScanType int scanType,
+            @NonNull @CallbackExecutor Executor executor, @NonNull ScanCallback scanCallback) {
+        mScanCallback = scanCallback;
+        mScanCallbackExecutor = executor;
         return nativeScan(settings.getType(), settings, scanType);
     }
 
     /**
      * Stops a previous scanning.
      *
-     * If the method completes successfully, the frontend stop previous scanning.
+     * <p>
+     * The {@link ScanCallback} and it's {@link Executor} will be removed.
+     *
+     * <p>
+     * If the method completes successfully, the frontend stopped previous scanning.
+     *
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     public int stopScan() {
-        return nativeStopScan();
+        TunerUtils.checkTunerPermission(mContext);
+        int retVal = nativeStopScan();
+        mScanCallback = null;
+        mScanCallbackExecutor = null;
+        return retVal;
     }
 
     /**
diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java
index c2d6c58c..4532122 100644
--- a/media/java/android/media/tv/tuner/TunerConstants.java
+++ b/media/java/android/media/tv/tuner/TunerConstants.java
@@ -1015,10 +1015,13 @@
             Constants.FrontendAtsc3DemodOutputFormat.BASEBAND_PACKET;
 
     /** @hide */
-    @IntDef({FRONTEND_DVBS_STANDARD_AUTO, FRONTEND_DVBS_STANDARD_S, FRONTEND_DVBS_STANDARD_S2,
-            FRONTEND_DVBS_STANDARD_S2X})
+    @IntDef(prefix = "FRONTEND_DVBS_STANDARD",
+            value = {FRONTEND_DVBS_STANDARD_AUTO, FRONTEND_DVBS_STANDARD_S,
+                    FRONTEND_DVBS_STANDARD_S2,
+                    FRONTEND_DVBS_STANDARD_S2X})
     @Retention(RetentionPolicy.SOURCE)
-    public @interface FrontendDvbsStandard {}
+    public @interface FrontendDvbsStandard {
+    }
     /** @hide */
     public static final int FRONTEND_DVBS_STANDARD_AUTO = Constants.FrontendDvbsStandard.AUTO;
     /** @hide */
@@ -1210,6 +1213,20 @@
             Constants.FrontendDvbtGuardInterval.INTERVAL_19_256;
 
     /** @hide */
+    @IntDef(prefix = "FRONTEND_DVBT_STANDARD",
+            value = {FRONTEND_DVBT_STANDARD_AUTO, FRONTEND_DVBT_STANDARD_T,
+                    FRONTEND_DVBT_STANDARD_T2}
+    )
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface FrontendDvbtStandard {}
+    /** @hide */
+    public static final int FRONTEND_DVBT_STANDARD_AUTO = Constants.FrontendDvbtStandard.AUTO;
+    /** @hide */
+    public static final int FRONTEND_DVBT_STANDARD_T = Constants.FrontendDvbtStandard.T;
+    /** @hide */
+    public static final int FRONTEND_DVBT_STANDARD_T2 = Constants.FrontendDvbtStandard.T2;
+
+    /** @hide */
     @IntDef({FRONTEND_ISDBS_CODERATE_UNDEFINED, FRONTEND_ISDBS_CODERATE_AUTO,
             FRONTEND_ISDBS_CODERATE_1_2, FRONTEND_ISDBS_CODERATE_2_3, FRONTEND_ISDBS_CODERATE_3_4,
             FRONTEND_ISDBS_CODERATE_5_6, FRONTEND_ISDBS_CODERATE_7_8})
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendCallback.java b/media/java/android/media/tv/tuner/frontend/FrontendCallback.java
index 0992eb6..9c4f460 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendCallback.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendCallback.java
@@ -27,10 +27,4 @@
      * Invoked when there is a frontend event.
      */
     void onEvent(int frontendEventType);
-
-    /**
-     * Invoked when there is a scan message.
-     * @param msg
-     */
-    void onScanMessage(ScanMessage msg);
 }
diff --git a/media/java/android/media/tv/tuner/frontend/ScanCallback.java b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
new file mode 100644
index 0000000..8118fcc
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.frontend;
+
+import android.media.tv.tuner.TunerConstants;
+
+/**
+ * Scan callback.
+ *
+ * @hide
+ */
+public interface ScanCallback {
+    /** Scan locked the signal. */
+    void onLocked(boolean isLocked);
+
+    /** Scan stopped. */
+    void onEnd(boolean isEnd);
+
+    /** scan progress percent (0..100) */
+    void onProgress(int percent);
+
+    /** Signal frequency in Hertz */
+    void onFrequencyReport(int frequency);
+
+    /** Symbols per second */
+    void onSymbolRate(int rate);
+
+    /** Locked Plp Ids for DVBT2 frontend. */
+    void onPlpIds(int[] plpIds);
+
+    /** Locked group Ids for DVBT2 frontend. */
+    void onGroupIds(int[] groupIds);
+
+    /** Stream Ids. */
+    void onInputStreamIds(int[] inputStreamIds);
+
+    /** Locked signal standard. */
+    void onDvbsStandard(@TunerConstants.FrontendDvbsStandard int dvbsStandandard);
+
+    /** Locked signal standard. */
+    void onDvbtStandard(@TunerConstants.FrontendDvbtStandard int dvbtStandard);
+
+    /** PLP status in a tuned frequency band for ATSC3 frontend. */
+    void onAtsc3PlpInfos(Atsc3PlpInfo[] atsc3PlpInfos);
+
+    /** PLP information for ATSC3. */
+    class Atsc3PlpInfo {
+        private final int mPlpId;
+        private final boolean mLlsFlag;
+
+        private Atsc3PlpInfo(int plpId, boolean llsFlag) {
+            mPlpId = plpId;
+            mLlsFlag = llsFlag;
+        }
+
+        /** Gets PLP IDs. */
+        public int getPlpId() {
+            return mPlpId;
+        }
+
+        /** Gets LLS flag. */
+        public boolean getLlsFlag() {
+            return mLlsFlag;
+        }
+    }
+}
diff --git a/media/java/android/media/tv/tuner/frontend/ScanMessage.java b/media/java/android/media/tv/tuner/frontend/ScanMessage.java
deleted file mode 100644
index dd687dd..0000000
--- a/media/java/android/media/tv/tuner/frontend/ScanMessage.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.tv.tuner.frontend;
-
-import android.annotation.IntDef;
-import android.hardware.tv.tuner.V1_0.Constants;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Message from frontend during scan operations.
- *
- * @hide
- */
-public class ScanMessage {
-
-    /** @hide */
-    @IntDef({
-        LOCKED,
-        END,
-        PROGRESS_PERCENT,
-        FREQUENCY,
-        SYMBOL_RATE,
-        PLP_IDS,
-        GROUP_IDS,
-        INPUT_STREAM_IDS,
-        STANDARD,
-        ATSC3_PLP_INFO
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Type {}
-    /** @hide */
-    public static final int LOCKED = Constants.FrontendScanMessageType.LOCKED;
-    /** @hide */
-    public static final int END = Constants.FrontendScanMessageType.END;
-    /** @hide */
-    public static final int PROGRESS_PERCENT = Constants.FrontendScanMessageType.PROGRESS_PERCENT;
-    /** @hide */
-    public static final int FREQUENCY = Constants.FrontendScanMessageType.FREQUENCY;
-    /** @hide */
-    public static final int SYMBOL_RATE = Constants.FrontendScanMessageType.SYMBOL_RATE;
-    /** @hide */
-    public static final int PLP_IDS = Constants.FrontendScanMessageType.PLP_IDS;
-    /** @hide */
-    public static final int GROUP_IDS = Constants.FrontendScanMessageType.GROUP_IDS;
-    /** @hide */
-    public static final int INPUT_STREAM_IDS = Constants.FrontendScanMessageType.INPUT_STREAM_IDS;
-    /** @hide */
-    public static final int STANDARD = Constants.FrontendScanMessageType.STANDARD;
-    /** @hide */
-    public static final int ATSC3_PLP_INFO = Constants.FrontendScanMessageType.ATSC3_PLP_INFO;
-
-    private final int mType;
-    private final Object mValue;
-
-    private ScanMessage(int type, Object value) {
-        mType = type;
-        mValue = value;
-    }
-
-    /** Gets scan message type. */
-    @Type
-    public int getMessageType() {
-        return mType;
-    }
-    /** Message indicates whether frontend is locked or not. */
-    public boolean getIsLocked() {
-        if (mType != LOCKED) {
-            throw new IllegalStateException();
-        }
-        return (Boolean) mValue;
-    }
-    /** Message indicates whether the scan has reached the end or not. */
-    public boolean getIsEnd() {
-        if (mType != END) {
-            throw new IllegalStateException();
-        }
-        return (Boolean) mValue;
-    }
-    /** Progress message in percent. */
-    public int getProgressPercent() {
-        if (mType != PROGRESS_PERCENT) {
-            throw new IllegalStateException();
-        }
-        return (Integer) mValue;
-    }
-    /** Gets frequency. */
-    public int getFrequency() {
-        if (mType != FREQUENCY) {
-            throw new IllegalStateException();
-        }
-        return (Integer) mValue;
-    }
-    /** Gets symbol rate. */
-    public int getSymbolRate() {
-        if (mType != SYMBOL_RATE) {
-            throw new IllegalStateException();
-        }
-        return (Integer) mValue;
-    }
-    /** Gets PLP IDs. */
-    public int[] getPlpIds() {
-        if (mType != PLP_IDS) {
-            throw new IllegalStateException();
-        }
-        return (int[]) mValue;
-    }
-    /** Gets group IDs. */
-    public int[] getGroupIds() {
-        if (mType != GROUP_IDS) {
-            throw new IllegalStateException();
-        }
-        return (int[]) mValue;
-    }
-    /** Gets Input stream IDs. */
-    public int[] getInputStreamIds() {
-        if (mType != INPUT_STREAM_IDS) {
-            throw new IllegalStateException();
-        }
-        return (int[]) mValue;
-    }
-    /** Gets the DVB-T or DVB-S standard. */
-    public int getStandard() {
-        if (mType != STANDARD) {
-            throw new IllegalStateException();
-        }
-        return (int) mValue;
-    }
-
-    /** Gets PLP information for ATSC3. */
-    public Atsc3PlpInfo[] getAtsc3PlpInfos() {
-        if (mType != ATSC3_PLP_INFO) {
-            throw new IllegalStateException();
-        }
-        return (Atsc3PlpInfo[]) mValue;
-    }
-
-    /** PLP information for ATSC3. */
-    public static class Atsc3PlpInfo {
-        private final int mPlpId;
-        private final boolean mLlsFlag;
-
-        private Atsc3PlpInfo(int plpId, boolean llsFlag) {
-            mPlpId = plpId;
-            mLlsFlag = llsFlag;
-        }
-
-        /** Gets PLP IDs. */
-        public int getPlpId() {
-            return mPlpId;
-        }
-        /** Gets LLS flag. */
-        public boolean getLlsFlag() {
-            return mLlsFlag;
-        }
-    }
-}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 536a061..aeacd8f 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -19,6 +19,7 @@
         "android_media_MediaProfiles.cpp",
         "android_media_MediaRecorder.cpp",
         "android_media_MediaSync.cpp",
+        "android_media_MediaTranscodeManager.cpp",
         "android_media_ResampleInputStream.cpp",
         "android_media_Streams.cpp",
         "android_media_SyncParams.cpp",
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 963b650..5cb42a9a 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1453,6 +1453,7 @@
 extern int register_android_mtp_MtpDatabase(JNIEnv *env);
 extern int register_android_mtp_MtpDevice(JNIEnv *env);
 extern int register_android_mtp_MtpServer(JNIEnv *env);
+extern int register_android_media_MediaTranscodeManager(JNIEnv *env);
 
 jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
 {
@@ -1565,6 +1566,11 @@
         goto bail;
     }
 
+    if (register_android_media_MediaTranscodeManager(env) < 0) {
+        ALOGE("ERROR: MediaTranscodeManager native registration failed");
+        goto bail;
+    }
+
     /* success -- return valid version number */
     result = JNI_VERSION_1_4;
 
diff --git a/media/jni/android_media_MediaTranscodeManager.cpp b/media/jni/android_media_MediaTranscodeManager.cpp
new file mode 100644
index 0000000..0b4048c
--- /dev/null
+++ b/media/jni/android_media_MediaTranscodeManager.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaTranscodeManager_JNI"
+
+#include "android_runtime/AndroidRuntime.h"
+#include "jni.h"
+
+#include <nativehelper/JNIHelp.h>
+#include <utils/Log.h>
+
+namespace {
+
+// NOTE: Keep these enums in sync with their equivalents in MediaTranscodeManager.java.
+enum {
+    ID_INVALID = -1
+};
+
+enum {
+    EVENT_JOB_STARTED = 1,
+    EVENT_JOB_PROGRESSED = 2,
+    EVENT_JOB_FINISHED = 3,
+};
+
+enum {
+    RESULT_NONE = 1,
+    RESULT_SUCCESS = 2,
+    RESULT_ERROR = 3,
+    RESULT_CANCELED = 4,
+};
+
+struct {
+    jmethodID postEventFromNative;
+} gMediaTranscodeManagerClassInfo;
+
+using namespace android;
+
+void android_media_MediaTranscodeManager_native_init(JNIEnv *env, jclass clazz) {
+    ALOGV("android_media_MediaTranscodeManager_native_init");
+
+    gMediaTranscodeManagerClassInfo.postEventFromNative = env->GetMethodID(
+            clazz, "postEventFromNative", "(IJI)V");
+    LOG_ALWAYS_FATAL_IF(gMediaTranscodeManagerClassInfo.postEventFromNative == NULL,
+                        "can't find android/media/MediaTranscodeManager.postEventFromNative");
+}
+
+jlong android_media_MediaTranscodeManager_requestUniqueJobID(
+        JNIEnv *env __unused, jobject thiz __unused) {
+    ALOGV("android_media_MediaTranscodeManager_reserveUniqueJobID");
+    static std::atomic_int32_t sJobIDCounter{0};
+    jlong id = (jlong)++sJobIDCounter;
+    return id;
+}
+
+jboolean android_media_MediaTranscodeManager_enqueueTranscodingRequest(
+        JNIEnv *env, jobject thiz, jlong id, jobject request, jobject context __unused) {
+    ALOGV("android_media_MediaTranscodeManager_enqueueTranscodingRequest");
+    if (!request) {
+        return ID_INVALID;
+    }
+
+    env->CallVoidMethod(thiz, gMediaTranscodeManagerClassInfo.postEventFromNative,
+                        EVENT_JOB_FINISHED, id, RESULT_ERROR);
+    return true;
+}
+
+void android_media_MediaTranscodeManager_cancelTranscodingRequest(
+        JNIEnv *env __unused, jobject thiz __unused, jlong jobID __unused) {
+    ALOGV("android_media_MediaTranscodeManager_cancelTranscodingRequest");
+}
+
+const JNINativeMethod gMethods[] = {
+    { "native_init", "()V",
+        (void *)android_media_MediaTranscodeManager_native_init },
+    { "native_requestUniqueJobID", "()J",
+        (void *)android_media_MediaTranscodeManager_requestUniqueJobID },
+    { "native_enqueueTranscodingRequest",
+        "(JLandroid/media/MediaTranscodeManager$TranscodingRequest;Landroid/content/Context;)Z",
+        (void *)android_media_MediaTranscodeManager_enqueueTranscodingRequest },
+    { "native_cancelTranscodingRequest", "(J)V",
+        (void *)android_media_MediaTranscodeManager_cancelTranscodingRequest },
+};
+
+} // namespace anonymous
+
+int register_android_media_MediaTranscodeManager(JNIEnv *env) {
+    return AndroidRuntime::registerNativeMethods(env,
+                "android/media/MediaTranscodeManager", gMethods, NELEM(gMethods));
+}
diff --git a/media/tests/MediaFrameworkTest/Android.bp b/media/tests/MediaFrameworkTest/Android.bp
index f0fbc50..ecbe2b3 100644
--- a/media/tests/MediaFrameworkTest/Android.bp
+++ b/media/tests/MediaFrameworkTest/Android.bp
@@ -7,6 +7,7 @@
     ],
     static_libs: [
         "mockito-target-minus-junit4",
+        "androidx.test.ext.junit",
         "androidx.test.rules",
         "android-ex-camera2",
     ],
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediatranscodemanager/MediaTranscodeManagerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediatranscodemanager/MediaTranscodeManagerTest.java
new file mode 100644
index 0000000..eeda50e
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediatranscodemanager/MediaTranscodeManagerTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 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.mediaframeworktest.functional.mediatranscodemanager;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.media.MediaTranscodeManager;
+import android.util.Log;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class MediaTranscodeManagerTest {
+    private static final String TAG = "MediaTranscodeManagerTest";
+
+    /**  The time to wait for the transcode operation to complete before failing the test. */
+    private static final int TRANSCODE_TIMEOUT_SECONDS = 2;
+
+    @Test
+    public void testMediaTranscodeManager() throws InterruptedException {
+        Log.d(TAG, "Starting: testMediaTranscodeManager");
+
+        Semaphore transcodeCompleteSemaphore = new Semaphore(0);
+        MediaTranscodeManager.TranscodingRequest request =
+                new MediaTranscodeManager.TranscodingRequest.Builder().build();
+        Executor listenerExecutor = Executors.newSingleThreadExecutor();
+
+        MediaTranscodeManager mediaTranscodeManager =
+                MediaTranscodeManager.getInstance(ApplicationProvider.getApplicationContext());
+        assertNotNull(mediaTranscodeManager);
+
+        MediaTranscodeManager.TranscodingJob job;
+        job = mediaTranscodeManager.enqueueTranscodingRequest(request, listenerExecutor,
+                transcodingJob -> {
+                Log.d(TAG, "Transcoding completed with result: " + transcodingJob.getResult());
+                transcodeCompleteSemaphore.release();
+            });
+        assertNotNull(job);
+
+        job.setOnProgressChangedListener(
+                listenerExecutor, progress -> Log.d(TAG, "Progress: " + progress));
+
+        if (job != null) {
+            Log.d(TAG, "testMediaTranscodeManager - Waiting for transcode to complete.");
+            boolean finishedOnTime = transcodeCompleteSemaphore.tryAcquire(
+                    TRANSCODE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+            assertTrue("Transcode failed to complete in time.", finishedOnTime);
+        }
+    }
+}
diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
index 221783b..ed93112 100644
--- a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
@@ -172,7 +172,7 @@
         MediaRoute2Info route = mRoutes.get(routeId);
         if (route == null || TextUtils.equals(ROUTE_ID3_SESSION_CREATION_FAILED, routeId)) {
             // Tell the router that session cannot be created by passing null as sessionInfo.
-            notifySessionCreated(/* sessionInfo= */ null, requestId);
+            notifySessionCreationFailed(requestId);
             return;
         }
         maybeDeselectRoute(routeId);
@@ -196,8 +196,13 @@
     }
 
     @Override
-    public void onDestroySession(String sessionId, RoutingSessionInfo lastSessionInfo) {
-        for (String routeId : lastSessionInfo.getSelectedRoutes()) {
+    public void onReleaseSession(String sessionId) {
+        RoutingSessionInfo sessionInfo = getSessionInfo(sessionId);
+        if (sessionInfo == null) {
+            return;
+        }
+
+        for (String routeId : sessionInfo.getSelectedRoutes()) {
             mRouteIdToSessionId.remove(routeId);
             MediaRoute2Info route = mRoutes.get(routeId);
             if (route != null) {
@@ -206,6 +211,7 @@
                         .build());
             }
         }
+        notifySessionReleased(sessionId);
     }
 
     @Override
@@ -227,8 +233,7 @@
                 .removeSelectableRoute(routeId)
                 .addDeselectableRoute(routeId)
                 .build();
-        updateSessionInfo(newSessionInfo);
-        notifySessionInfoChanged(newSessionInfo);
+        notifySessionUpdated(newSessionInfo);
     }
 
     @Override
@@ -247,7 +252,7 @@
                 .build());
 
         if (sessionInfo.getSelectedRoutes().size() == 1) {
-            releaseSession(sessionId);
+            notifySessionReleased(sessionId);
             return;
         }
 
@@ -256,8 +261,7 @@
                 .addSelectableRoute(routeId)
                 .removeDeselectableRoute(routeId)
                 .build();
-        updateSessionInfo(newSessionInfo);
-        notifySessionInfoChanged(newSessionInfo);
+        notifySessionUpdated(newSessionInfo);
     }
 
     @Override
@@ -269,8 +273,7 @@
                 .removeDeselectableRoute(routeId)
                 .removeTransferrableRoute(routeId)
                 .build();
-        updateSessionInfo(newSessionInfo);
-        notifySessionInfoChanged(newSessionInfo);
+        notifySessionUpdated(newSessionInfo);
     }
 
     void maybeDeselectRoute(String routeId) {
diff --git a/native/graphics/jni/bitmap.cpp b/native/graphics/jni/bitmap.cpp
index 1aebeaf..26c7f8d 100644
--- a/native/graphics/jni/bitmap.cpp
+++ b/native/graphics/jni/bitmap.cpp
@@ -16,6 +16,7 @@
 
 #include <android/bitmap.h>
 #include <android/graphics/bitmap.h>
+#include <android/data_space.h>
 
 int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
                           AndroidBitmapInfo* info) {
@@ -29,6 +30,15 @@
     return ANDROID_BITMAP_RESULT_SUCCESS;
 }
 
+int32_t AndroidBitmap_getDataSpace(JNIEnv* env, jobject jbitmap) {
+    if (NULL == env || NULL == jbitmap) {
+        return ADATASPACE_UNKNOWN; // Or return a real error?
+    }
+
+    android::graphics::Bitmap bitmap(env, jbitmap);
+    return bitmap.getDataSpace();
+}
+
 int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr) {
     if (NULL == env || NULL == jbitmap) {
         return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
diff --git a/native/graphics/jni/libjnigraphics.map.txt b/native/graphics/jni/libjnigraphics.map.txt
index bdd7f63..832770f 100644
--- a/native/graphics/jni/libjnigraphics.map.txt
+++ b/native/graphics/jni/libjnigraphics.map.txt
@@ -18,6 +18,7 @@
     AImageDecoderHeaderInfo_isAnimated;
     AImageDecoderHeaderInfo_getAndroidBitmapFormat;
     AndroidBitmap_getInfo;
+    AndroidBitmap_getDataSpace;
     AndroidBitmap_lockPixels;
     AndroidBitmap_unlockPixels;
   local:
diff --git a/packages/CarSystemUI/res/layout/sysui_primary_window.xml b/packages/CarSystemUI/res/layout/sysui_primary_window.xml
index 309d9ef..cc36e87 100644
--- a/packages/CarSystemUI/res/layout/sysui_primary_window.xml
+++ b/packages/CarSystemUI/res/layout/sysui_primary_window.xml
@@ -15,9 +15,16 @@
   ~ limitations under the License.
   -->
 
+<!-- Fullscreen views in sysui should be listed here in increasing Z order. -->
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:background="@android:color/transparent"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
+
+    <ViewStub android:id="@+id/fullscreen_user_switcher_stub"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:layout="@layout/car_fullscreen_user_switcher"/>
+
 </FrameLayout>
\ No newline at end of file
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
index 6ec3854..cfe1c70 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
@@ -22,7 +22,7 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
-import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.util.leak.LeakDetector;
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java b/packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java
index e3e9ab7..c7e14d6 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java
@@ -54,6 +54,7 @@
     private ViewGroup mBaseLayout;
     private WindowManager.LayoutParams mLp;
     private WindowManager.LayoutParams mLpChanged;
+    private boolean mIsAttached = false;
 
     @Inject
     public SystemUIPrimaryWindowController(
@@ -86,8 +87,17 @@
         return mBaseLayout;
     }
 
+    /** Returns {@code true} if the window is already attached. */
+    public boolean isAttached() {
+        return mIsAttached;
+    }
+
     /** Attaches the window to the window manager. */
     public void attach() {
+        if (mIsAttached) {
+            return;
+        }
+        mIsAttached = true;
         // Now that the status bar window encompasses the sliding panel and its
         // translucent backdrop, the entire thing is made TRANSLUCENT and is
         // hardware-accelerated.
@@ -98,13 +108,14 @@
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                         | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                         | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
+                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
                 PixelFormat.TRANSLUCENT);
         mLp.token = new Binder();
         mLp.gravity = Gravity.TOP;
         mLp.setFitWindowInsetsTypes(/* types= */ 0);
         mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-        mLp.setTitle("NotificationShade");
+        mLp.setTitle("SystemUIPrimaryWindow");
         mLp.packageName = mContext.getPackageName();
         mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 
@@ -118,8 +129,11 @@
             // TODO: Update this so that the windowing type gets the full height of the display
             //  when we use MATCH_PARENT.
             mLpChanged.height = mDisplayHeight + mNavBarHeight;
+            mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
         } else {
             mLpChanged.height = mStatusBarHeight;
+            // TODO: Allow touches to go through to the status bar to handle notification panel.
+            mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
         }
         updateWindow();
     }
@@ -131,7 +145,9 @@
 
     private void updateWindow() {
         if (mLp != null && mLp.copyFrom(mLpChanged) != 0) {
-            mWindowManager.updateViewLayout(mBaseLayout, mLp);
+            if (isAttached()) {
+                mWindowManager.updateViewLayout(mBaseLayout, mLp);
+            }
         }
     }
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 4521f5f..18485dc 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -67,6 +67,7 @@
 import com.android.systemui.car.CarDeviceProvisionedController;
 import com.android.systemui.car.CarDeviceProvisionedListener;
 import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.car.SystemUIPrimaryWindowController;
 import com.android.systemui.classifier.FalsingLog;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -106,8 +107,8 @@
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.phone.AutoHideController;
@@ -168,6 +169,7 @@
     // acceleration rate for the fling animation
     private static final float FLING_SPEED_UP_FACTOR = 0.6f;
 
+    private final UserSwitcherController mUserSwitcherController;
     private final ScrimController mScrimController;
     private final LockscreenLockIconController mLockscreenLockIconController;
 
@@ -177,17 +179,16 @@
     private float mBackgroundAlphaDiff;
     private float mInitialBackgroundAlpha;
 
-    private final Lazy<FullscreenUserSwitcher> mFullscreenUserSwitcherLazy;
-    private FullscreenUserSwitcher mFullscreenUserSwitcher;
-
     private CarBatteryController mCarBatteryController;
     private BatteryMeterView mBatteryMeterView;
     private Drawable mNotificationPanelBackground;
 
     private final Object mQueueLock = new Object();
+    private final SystemUIPrimaryWindowController mSystemUIPrimaryWindowController;
     private final CarNavigationBarController mCarNavigationBarController;
     private final FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
     private final Lazy<PowerManagerHelper> mPowerManagerHelperLazy;
+    private final FullscreenUserSwitcher mFullscreenUserSwitcher;
     private final ShadeController mShadeController;
     private final CarServiceProvider mCarServiceProvider;
     private final CarDeviceProvisionedController mCarDeviceProvisionedController;
@@ -268,7 +269,7 @@
             HeadsUpManagerPhone headsUpManagerPhone,
             DynamicPrivacyController dynamicPrivacyController,
             BypassHeadsUpNotifier bypassHeadsUpNotifier,
-            Lazy<NewNotifPipeline> newNotifPipeline,
+            Lazy<NotifPipelineInitializer> notifPipelineInitializer,
             FalsingManager falsingManager,
             BroadcastDispatcher broadcastDispatcher,
             RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
@@ -338,7 +339,8 @@
             /* Car Settings injected components. */
             CarServiceProvider carServiceProvider,
             Lazy<PowerManagerHelper> powerManagerHelperLazy,
-            Lazy<FullscreenUserSwitcher> fullscreenUserSwitcherLazy,
+            FullscreenUserSwitcher fullscreenUserSwitcher,
+            SystemUIPrimaryWindowController systemUIPrimaryWindowController,
             CarNavigationBarController carNavigationBarController,
             FlingAnimationUtils.Builder flingAnimationUtilsBuilder) {
         super(
@@ -355,7 +357,7 @@
                 headsUpManagerPhone,
                 dynamicPrivacyController,
                 bypassHeadsUpNotifier,
-                newNotifPipeline,
+                notifPipelineInitializer,
                 falsingManager,
                 broadcastDispatcher,
                 remoteInputQuickSettingsDisabler,
@@ -422,6 +424,7 @@
                 userInfoControllerImpl,
                 notificationRowBinder,
                 dismissCallbackRegistry);
+        mUserSwitcherController = userSwitcherController;
         mScrimController = scrimController;
         mLockscreenLockIconController = lockscreenLockIconController;
         mCarDeviceProvisionedController =
@@ -429,7 +432,8 @@
         mShadeController = shadeController;
         mCarServiceProvider = carServiceProvider;
         mPowerManagerHelperLazy = powerManagerHelperLazy;
-        mFullscreenUserSwitcherLazy = fullscreenUserSwitcherLazy;
+        mFullscreenUserSwitcher = fullscreenUserSwitcher;
+        mSystemUIPrimaryWindowController = systemUIPrimaryWindowController;
         mCarNavigationBarController = carNavigationBarController;
         mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
     }
@@ -444,6 +448,13 @@
         mScreenLifecycle = Dependency.get(ScreenLifecycle.class);
         mScreenLifecycle.addObserver(mScreenObserver);
 
+        // TODO: Remove the setup of user switcher from Car Status Bar.
+        mSystemUIPrimaryWindowController.attach();
+        mFullscreenUserSwitcher.setStatusBar(this);
+        mFullscreenUserSwitcher.setContainer(
+                mSystemUIPrimaryWindowController.getBaseLayout().findViewById(
+                        R.id.fullscreen_user_switcher_stub));
+
         // Notification bar related setup.
         mInitialBackgroundAlpha = (float) mContext.getResources().getInteger(
                 R.integer.config_initialNotificationBackgroundAlpha) / 100;
@@ -510,16 +521,6 @@
                 });
     }
 
-    /**
-     * Allows for showing or hiding just the navigation bars. This is indented to be used when
-     * the full screen user selector is shown.
-     */
-    void setNavBarVisibility(@View.Visibility int visibility) {
-        mCarNavigationBarController.setBottomWindowVisibility(visibility);
-        mCarNavigationBarController.setLeftWindowVisibility(visibility);
-        mCarNavigationBarController.setRightWindowVisibility(visibility);
-    }
-
     @Override
     public boolean hideKeyguard() {
         boolean result = super.hideKeyguard();
@@ -924,9 +925,6 @@
                     + " scroll " + mStackScroller.getScrollX()
                     + "," + mStackScroller.getScrollY());
         }
-
-        pw.print("  mFullscreenUserSwitcher=");
-        pw.println(mFullscreenUserSwitcher);
         pw.print("  mCarBatteryController=");
         pw.println(mCarBatteryController);
         pw.print("  mBatteryMeterView=");
@@ -972,14 +970,7 @@
 
     @Override
     protected void createUserSwitcher() {
-        UserSwitcherController userSwitcherController =
-                Dependency.get(UserSwitcherController.class);
-        if (userSwitcherController.useFullscreenUserSwitcher()) {
-            mFullscreenUserSwitcher = mFullscreenUserSwitcherLazy.get();
-            mFullscreenUserSwitcher.setStatusBar(this);
-            mFullscreenUserSwitcher.setContainer(
-                    mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub));
-        } else {
+        if (!mUserSwitcherController.useFullscreenUserSwitcher()) {
             super.createUserSwitcher();
         }
     }
@@ -996,25 +987,12 @@
         super.onStateChanged(newState);
 
         if (newState != StatusBarState.FULLSCREEN_USER_SWITCHER) {
-            hideUserSwitcher();
+            mFullscreenUserSwitcher.hide();
         } else {
             dismissKeyguardWhenUserSwitcherNotDisplayed();
         }
     }
 
-    /** Makes the full screen user switcher visible, if applicable. */
-    public void showUserSwitcher() {
-        if (mFullscreenUserSwitcher != null && mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
-            mFullscreenUserSwitcher.show(); // Makes the switcher visible.
-        }
-    }
-
-    private void hideUserSwitcher() {
-        if (mFullscreenUserSwitcher != null) {
-            mFullscreenUserSwitcher.hide();
-        }
-    }
-
     final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
         @Override
         public void onScreenTurnedOn() {
@@ -1024,7 +1002,7 @@
 
     // We automatically dismiss keyguard unless user switcher is being shown on the keyguard.
     private void dismissKeyguardWhenUserSwitcherNotDisplayed() {
-        if (mFullscreenUserSwitcher == null) {
+        if (!mUserSwitcherController.useFullscreenUserSwitcher()) {
             return; // Not using the full screen user switcher.
         }
 
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
index 0ad0992..2a2eb69 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
@@ -24,6 +24,7 @@
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.R;
 import com.android.systemui.dock.DockManager;
+import com.android.systemui.navigationbar.car.CarNavigationBarController;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.phone.NavigationModeController;
@@ -40,6 +41,8 @@
 public class CarStatusBarKeyguardViewManager extends StatusBarKeyguardViewManager {
 
     protected boolean mShouldHideNavBar;
+    private final CarNavigationBarController mCarNavigationBarController;
+    private final FullscreenUserSwitcher mFullscreenUserSwitcher;
 
     @Inject
     public CarStatusBarKeyguardViewManager(Context context,
@@ -52,13 +55,17 @@
             DockManager dockManager,
             StatusBarWindowController statusBarWindowController,
             KeyguardStateController keyguardStateController,
-            NotificationMediaManager notificationMediaManager) {
+            NotificationMediaManager notificationMediaManager,
+            CarNavigationBarController carNavigationBarController,
+            FullscreenUserSwitcher fullscreenUserSwitcher) {
         super(context, callback, lockPatternUtils, sysuiStatusBarStateController,
                 configurationController, keyguardUpdateMonitor, navigationModeController,
                 dockManager, statusBarWindowController, keyguardStateController,
                 notificationMediaManager);
         mShouldHideNavBar = context.getResources()
                 .getBoolean(R.bool.config_hideNavWhenKeyguardBouncerShown);
+        mCarNavigationBarController = carNavigationBarController;
+        mFullscreenUserSwitcher = fullscreenUserSwitcher;
     }
 
     @Override
@@ -66,8 +73,10 @@
         if (!mShouldHideNavBar) {
             return;
         }
-        CarStatusBar statusBar = (CarStatusBar) mStatusBar;
-        statusBar.setNavBarVisibility(navBarVisible ? View.VISIBLE : View.GONE);
+        int visibility = navBarVisible ? View.VISIBLE : View.GONE;
+        mCarNavigationBarController.setBottomWindowVisibility(visibility);
+        mCarNavigationBarController.setLeftWindowVisibility(visibility);
+        mCarNavigationBarController.setRightWindowVisibility(visibility);
     }
 
     /**
@@ -86,8 +95,7 @@
      */
     @Override
     public void onCancelClicked() {
-        CarStatusBar statusBar = (CarStatusBar) mStatusBar;
-        statusBar.showUserSwitcher();
+        mFullscreenUserSwitcher.show();
     }
 
     /**
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index e5a091f..3abbe32 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -31,6 +31,7 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.car.SystemUIPrimaryWindowController;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
@@ -66,8 +67,8 @@
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.phone.AutoHideController;
@@ -138,7 +139,7 @@
             HeadsUpManagerPhone headsUpManagerPhone,
             DynamicPrivacyController dynamicPrivacyController,
             BypassHeadsUpNotifier bypassHeadsUpNotifier,
-            Lazy<NewNotifPipeline> newNotifPipeline,
+            Lazy<NotifPipelineInitializer> notifPipelineInitializer,
             FalsingManager falsingManager,
             BroadcastDispatcher broadcastDispatcher,
             RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
@@ -207,7 +208,8 @@
             DismissCallbackRegistry dismissCallbackRegistry,
             CarServiceProvider carServiceProvider,
             Lazy<PowerManagerHelper> powerManagerHelperLazy,
-            Lazy<FullscreenUserSwitcher> fullscreenUserSwitcherLazy,
+            FullscreenUserSwitcher fullscreenUserSwitcher,
+            SystemUIPrimaryWindowController systemUIPrimaryWindowController,
             CarNavigationBarController carNavigationBarController,
             FlingAnimationUtils.Builder flingAnimationUtilsBuilder) {
         return new CarStatusBar(
@@ -224,7 +226,7 @@
                 headsUpManagerPhone,
                 dynamicPrivacyController,
                 bypassHeadsUpNotifier,
-                newNotifPipeline,
+                notifPipelineInitializer,
                 falsingManager,
                 broadcastDispatcher,
                 remoteInputQuickSettingsDisabler,
@@ -292,7 +294,8 @@
                 dismissCallbackRegistry,
                 carServiceProvider,
                 powerManagerHelperLazy,
-                fullscreenUserSwitcherLazy,
+                fullscreenUserSwitcher,
+                systemUIPrimaryWindowController,
                 carNavigationBarController,
                 flingAnimationUtilsBuilder);
     }
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index f8fc3bb..3cd66c2 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -38,6 +38,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.R;
 import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.car.SystemUIPrimaryWindowController;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.statusbar.car.CarTrustAgentUnlockDialogHelper.OnHideListener;
 import com.android.systemui.statusbar.car.UserGridRecyclerView.UserRecord;
@@ -56,9 +57,10 @@
     private final UserManager mUserManager;
     private final CarServiceProvider mCarServiceProvider;
     private final CarTrustAgentUnlockDialogHelper mUnlockDialogHelper;
+    private final SystemUIPrimaryWindowController mSystemUIPrimaryWindowController;
+    private CarStatusBar mCarStatusBar;
     private final int mShortAnimDuration;
 
-    private CarStatusBar mStatusBar;
     private View mParent;
     private UserGridRecyclerView mUserGridView;
     private CarTrustAgentEnrollmentManager mEnrollmentManager;
@@ -81,23 +83,35 @@
             @Main Resources resources,
             UserManager userManager,
             CarServiceProvider carServiceProvider,
-            CarTrustAgentUnlockDialogHelper carTrustAgentUnlockDialogHelper) {
+            CarTrustAgentUnlockDialogHelper carTrustAgentUnlockDialogHelper,
+            SystemUIPrimaryWindowController systemUIPrimaryWindowController) {
         mContext = context;
         mResources = resources;
         mUserManager = userManager;
         mCarServiceProvider = carServiceProvider;
         mUnlockDialogHelper = carTrustAgentUnlockDialogHelper;
+        mSystemUIPrimaryWindowController = systemUIPrimaryWindowController;
 
         mShortAnimDuration = mResources.getInteger(android.R.integer.config_shortAnimTime);
     }
 
-    /** Sets the status bar which controls the keyguard. */
+    /** Sets the status bar which gives an entry point to dismiss the keyguard. */
+    // TODO: Remove this in favor of a keyguard controller.
     public void setStatusBar(CarStatusBar statusBar) {
-        mStatusBar = statusBar;
+        mCarStatusBar = statusBar;
+    }
+
+    /** Returns {@code true} if the user switcher already has a parent view. */
+    public boolean isAttached() {
+        return mParent != null;
     }
 
     /** Sets the {@link ViewStub} to show the user switcher. */
     public void setContainer(ViewStub containerStub) {
+        if (isAttached()) {
+            return;
+        }
+
         mParent = containerStub.inflate();
 
         View container = mParent.findViewById(R.id.container);
@@ -148,20 +162,31 @@
      * Makes user grid visible.
      */
     public void show() {
+        if (!isAttached()) {
+            return;
+        }
         mParent.setVisibility(View.VISIBLE);
+        mSystemUIPrimaryWindowController.setWindowExpanded(true);
     }
 
     /**
      * Hides the user grid.
      */
     public void hide() {
+        if (!isAttached()) {
+            return;
+        }
         mParent.setVisibility(View.INVISIBLE);
+        mSystemUIPrimaryWindowController.setWindowExpanded(false);
     }
 
     /**
      * @return {@code true} if user grid is visible, {@code false} otherwise.
      */
     public boolean isVisible() {
+        if (!isAttached()) {
+            return false;
+        }
         return mParent.getVisibility() == View.VISIBLE;
     }
 
@@ -196,7 +221,7 @@
         }
         if (mSelectedUser.mType == UserRecord.FOREGROUND_USER) {
             hide();
-            mStatusBar.dismissKeyguard();
+            mCarStatusBar.dismissKeyguard();
             return;
         }
         // Switching is about to happen, since it takes time, fade out the switcher gradually.
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
index cdabeeb..8c756ec 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
@@ -43,6 +43,9 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowInsets;
+import android.view.WindowManager;
 import android.widget.ImageView;
 import android.widget.TextView;
 
@@ -53,7 +56,6 @@
 
 import com.android.internal.util.UserIcons;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.SystemUIDialog;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -337,7 +339,7 @@
                     .setPositiveButton(android.R.string.ok, null)
                     .create();
             // Sets window flags for the SysUI dialog
-            SystemUIDialog.applyFlags(maxUsersDialog);
+            applyCarSysUIDialogFlags(maxUsersDialog);
             maxUsersDialog.show();
         }
 
@@ -356,10 +358,19 @@
                     .setOnCancelListener(this)
                     .create();
             // Sets window flags for the SysUI dialog
-            SystemUIDialog.applyFlags(addUserDialog);
+            applyCarSysUIDialogFlags(addUserDialog);
             addUserDialog.show();
         }
 
+        private void applyCarSysUIDialogFlags(AlertDialog dialog) {
+            final Window window = dialog.getWindow();
+            window.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
+            window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+                    | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+            window.setFitWindowInsetsTypes(
+                    window.getFitWindowInsetsTypes() & ~WindowInsets.Type.statusBars());
+        }
+
         private void notifyUserSelected(UserRecord userRecord) {
             // Notify the listener which user was selected
             if (mUserSelectionListener != null) {
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
index 2697a10..cb062a6 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
@@ -30,8 +30,6 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import com.android.internal.telephony.PhoneConstants;
-
 /**
  * This util class provides common logic for carrier actions
  */
@@ -103,7 +101,7 @@
     }
 
     private static void onDisableAllMeteredApns(Intent intent, Context context) {
-        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+        int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
                 SubscriptionManager.getDefaultVoiceSubscriptionId());
         logd("onDisableAllMeteredApns subId: " + subId);
         final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
@@ -111,7 +109,7 @@
     }
 
     private static void onEnableAllMeteredApns(Intent intent, Context context) {
-        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+        int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
                 SubscriptionManager.getDefaultVoiceSubscriptionId());
         logd("onEnableAllMeteredApns subId: " + subId);
         final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
@@ -135,7 +133,7 @@
     }
 
     private static void onRegisterDefaultNetworkAvail(Intent intent, Context context) {
-        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+        int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
                 SubscriptionManager.getDefaultVoiceSubscriptionId());
         logd("onRegisterDefaultNetworkAvail subId: " + subId);
         final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
@@ -143,7 +141,7 @@
     }
 
     private static void onDeregisterDefaultNetworkAvail(Intent intent, Context context) {
-        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+        int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
                 SubscriptionManager.getDefaultVoiceSubscriptionId());
         logd("onDeregisterDefaultNetworkAvail subId: " + subId);
         final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
@@ -151,7 +149,7 @@
     }
 
     private static void onDisableRadio(Intent intent, Context context) {
-        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+        int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
                 SubscriptionManager.getDefaultVoiceSubscriptionId());
         logd("onDisableRadio subId: " + subId);
         final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
@@ -159,7 +157,7 @@
     }
 
     private static void onEnableRadio(Intent intent, Context context) {
-        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+        int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
                 SubscriptionManager.getDefaultVoiceSubscriptionId());
         logd("onEnableRadio subId: " + subId);
         final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
@@ -202,7 +200,7 @@
     }
 
     private static void onResetAllCarrierActions(Intent intent, Context context) {
-        int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+        int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
                 SubscriptionManager.getDefaultVoiceSubscriptionId());
         logd("onResetAllCarrierActions subId: " + subId);
         final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java
index 086a287..6229434 100644
--- a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java
+++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java
@@ -15,6 +15,7 @@
  */
 package com.android.carrierdefaultapp;
 
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.times;
@@ -26,11 +27,10 @@
 import android.content.Intent;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.test.InstrumentationTestCase;
 
-import com.android.internal.telephony.PhoneConstants;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -69,6 +69,7 @@
         mContext.injectSystemService(NotificationManager.class, mNotificationMgr);
         mContext.injectSystemService(TelephonyManager.class, mTelephonyMgr);
         mContext.injectSystemService(CarrierConfigManager.class, mCarrierConfigMgr);
+        doReturn(mTelephonyMgr).when(mTelephonyMgr).createForSubscriptionId(anyInt());
 
         mReceiver = new CarrierDefaultBroadcastReceiver();
     }
@@ -88,7 +89,7 @@
         doReturn(b).when(mCarrierConfigMgr).getConfig();
 
         Intent intent = new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_REDIRECTED);
-        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
+        intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
         mReceiver.onReceive(mContext, intent);
 
         mContext.waitForMs(100);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 81739e0..9d4c24e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -211,13 +211,6 @@
     private static final int EAP_WPA = 1; // WPA-EAP
     private static final int EAP_WPA2_WPA3 = 2; // RSN-EAP
 
-    /**
-     * The number of distinct wifi levels.
-     *
-     * <p>Must keep in sync with {@link R.array.wifi_signal} and {@link WifiManager#RSSI_LEVELS}.
-     */
-    public static final int SIGNAL_LEVELS = 5;
-
     public static final int UNREACHABLE_RSSI = Integer.MIN_VALUE;
 
     public static final String KEY_PREFIX_AP = "AP:";
@@ -453,9 +446,10 @@
             return other.getSpeed() - getSpeed();
         }
 
+        WifiManager wifiManager = getWifiManager();
         // Sort by signal strength, bucketed by level
-        int difference = WifiManager.calculateSignalLevel(other.mRssi, SIGNAL_LEVELS)
-                - WifiManager.calculateSignalLevel(mRssi, SIGNAL_LEVELS);
+        int difference = wifiManager.calculateSignalLevel(other.mRssi)
+                - wifiManager.calculateSignalLevel(mRssi);
         if (difference != 0) {
             return difference;
         }
@@ -869,13 +863,14 @@
     }
 
     /**
-     * Returns the number of levels to show for a Wifi icon, from 0 to {@link #SIGNAL_LEVELS}-1.
+     * Returns the number of levels to show for a Wifi icon, from 0 to
+     * {@link WifiManager#getMaxSignalLevel()}.
      *
-     * <p>Use {@#isReachable()} to determine if an AccessPoint is in range, as this method will
+     * <p>Use {@link #isReachable()} to determine if an AccessPoint is in range, as this method will
      * always return at least 0.
      */
     public int getLevel() {
-        return WifiManager.calculateSignalLevel(mRssi, SIGNAL_LEVELS);
+        return getWifiManager().calculateSignalLevel(mRssi);
     }
 
     public int getRssi() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java b/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
index 4a4f0e6..f21e466 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
@@ -22,6 +22,7 @@
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.os.Parcelable;
 
@@ -126,13 +127,15 @@
     @Keep
     public TestAccessPointBuilder setLevel(int level) {
         // Reversal of WifiManager.calculateSignalLevels
+        WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
+        int maxSignalLevel = wifiManager.getMaxSignalLevel();
         if (level == 0) {
             mRssi = MIN_RSSI;
-        } else if (level >= AccessPoint.SIGNAL_LEVELS) {
+        } else if (level > maxSignalLevel) {
             mRssi = MAX_RSSI;
         } else {
             float inputRange = MAX_RSSI - MIN_RSSI;
-            float outputRange = AccessPoint.SIGNAL_LEVELS - 1;
+            float outputRange = maxSignalLevel;
             mRssi = (int) (level * inputRange / outputRange + MIN_RSSI);
         }
         return this;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 8591116..3f55cea 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -89,7 +89,7 @@
     public void setListening(boolean listening) {
         if (listening) {
             mNetworkScoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
-                    mWifiNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK);
+                    mWifiNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_CURRENT_NETWORK);
             mWifiNetworkScoreCache.registerListener(mCacheListener);
             mConnectivityManager.registerNetworkCallback(
                     mNetworkRequest, mNetworkCallback, mHandler);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index ba6a8ea..ed4ff08 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -361,7 +361,7 @@
         mNetworkScoreManager.registerNetworkScoreCache(
                 NetworkKey.TYPE_WIFI,
                 mScoreCache,
-                NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS);
+                NetworkScoreManager.SCORE_FILTER_SCAN_RESULTS);
     }
 
     private void requestScoresForNetworkKeys(Collection<NetworkKey> keys) {
diff --git a/packages/SettingsLib/tests/integ/Android.bp b/packages/SettingsLib/tests/integ/Android.bp
index 4600793..2ccff1e 100644
--- a/packages/SettingsLib/tests/integ/Android.bp
+++ b/packages/SettingsLib/tests/integ/Android.bp
@@ -14,7 +14,10 @@
 
 android_test {
     name: "SettingsLibTests",
-    defaults: ["SettingsLibDefaults"],
+    defaults: [
+        "SettingsLibDefaults",
+        "framework-wifi-test-defaults"
+    ],
 
     certificate: "platform",
 
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 61cbbd3..03201ae 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -83,7 +83,6 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class AccessPointTest {
-
     private static final String TEST_SSID = "\"test_ssid\"";
     private static final String ROAMING_SSID = "\"roaming_ssid\"";
     private static final String OSU_FRIENDLY_NAME = "osu_friendly_name";
@@ -98,6 +97,7 @@
             20 * DateUtils.MINUTE_IN_MILLIS;
 
     private Context mContext;
+    private int mMaxSignalLevel;
     private WifiInfo mWifiInfo;
     @Mock private Context mMockContext;
     @Mock private WifiManager mMockWifiManager;
@@ -128,6 +128,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = InstrumentationRegistry.getTargetContext();
+        mMaxSignalLevel = mContext.getSystemService(WifiManager.class).getMaxSignalLevel();
         mWifiInfo = new WifiInfo();
         mWifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(TEST_SSID));
         mWifiInfo.setBSSID(TEST_BSSID);
@@ -180,7 +181,7 @@
 
     @Test
     public void testCompareTo_GivesHighLevelBeforeLowLevel() {
-        final int highLevel = AccessPoint.SIGNAL_LEVELS - 1;
+        final int highLevel = mMaxSignalLevel;
         final int lowLevel = 1;
         assertThat(highLevel).isGreaterThan(lowLevel);
 
@@ -226,7 +227,7 @@
                 .setReachable(true).build();
         AccessPoint saved = new TestAccessPointBuilder(mContext).setSaved(true).build();
         AccessPoint highLevelAndReachable = new TestAccessPointBuilder(mContext)
-                .setLevel(AccessPoint.SIGNAL_LEVELS - 1).build();
+                .setLevel(mMaxSignalLevel).build();
         AccessPoint firstName = new TestAccessPointBuilder(mContext).setSsid("a").build();
         AccessPoint lastname = new TestAccessPointBuilder(mContext).setSsid("z").build();
 
@@ -520,6 +521,8 @@
         when(packageManager.getApplicationInfoAsUser(eq(appPackageName), anyInt(), anyInt()))
                 .thenReturn(applicationInfo);
         when(applicationInfo.loadLabel(packageManager)).thenReturn(appLabel);
+        when(context.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
+        when(mMockWifiManager.calculateSignalLevel(rssi)).thenReturn(4);
 
         NetworkInfo networkInfo =
                 new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
@@ -636,14 +639,14 @@
     public void testBuilder_setLevel() {
         AccessPoint testAp;
 
-        for (int i = 0; i < AccessPoint.SIGNAL_LEVELS; i++) {
+        for (int i = 0; i <= mMaxSignalLevel; i++) {
             testAp = new TestAccessPointBuilder(mContext).setLevel(i).build();
             assertThat(testAp.getLevel()).isEqualTo(i);
         }
 
         // numbers larger than the max level should be set to max
-        testAp = new TestAccessPointBuilder(mContext).setLevel(AccessPoint.SIGNAL_LEVELS).build();
-        assertThat(testAp.getLevel()).isEqualTo(AccessPoint.SIGNAL_LEVELS - 1);
+        testAp = new TestAccessPointBuilder(mContext).setLevel(mMaxSignalLevel + 1).build();
+        assertThat(testAp.getLevel()).isEqualTo(mMaxSignalLevel);
 
         // numbers less than 0 should give level 0
         testAp = new TestAccessPointBuilder(mContext).setLevel(-100).build();
@@ -653,7 +656,7 @@
     @Test
     public void testBuilder_settingReachableAfterLevelDoesNotAffectLevel() {
         int level = 1;
-        assertThat(level).isLessThan(AccessPoint.SIGNAL_LEVELS - 1);
+        assertThat(level).isLessThan(mMaxSignalLevel);
 
         AccessPoint testAp =
                 new TestAccessPointBuilder(mContext).setLevel(level).setReachable(true).build();
diff --git a/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml
new file mode 100644
index 0000000..50aa212
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<!-- RelativeLayouts have an issue enforcing minimum heights, so just
+     work around this for now with LinearLayouts. -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="center"
+    android:paddingTop="@dimen/global_actions_grid_item_vertical_margin"
+    android:paddingBottom="@dimen/global_actions_grid_item_vertical_margin"
+    android:paddingLeft="@dimen/global_actions_grid_item_side_margin"
+    android:paddingRight="@dimen/global_actions_grid_item_side_margin"
+    android:layout_marginRight="3dp"
+    android:layout_marginLeft="3dp"
+    android:background="@drawable/rounded_bg_full">
+    <LinearLayout
+        android:layout_width="@dimen/global_actions_grid_item_width"
+        android:layout_height="@dimen/global_actions_grid_item_height"
+        android:gravity="top|center_horizontal"
+        android:orientation="vertical">
+        <ImageView
+            android:id="@*android:id/icon"
+            android:layout_width="@dimen/global_actions_grid_item_icon_width"
+            android:layout_height="@dimen/global_actions_grid_item_icon_height"
+            android:layout_marginTop="@dimen/global_actions_grid_item_icon_top_margin"
+            android:layout_marginBottom="@dimen/global_actions_grid_item_icon_bottom_margin"
+            android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin"
+            android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin"
+            android:scaleType="centerInside"
+            android:tint="@color/global_actions_text" />
+
+        <TextView
+            android:id="@*android:id/message"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:ellipsize="marquee"
+            android:marqueeRepeatLimit="marquee_forever"
+            android:singleLine="true"
+            android:gravity="center"
+            android:textSize="12dp"
+            android:textColor="@color/global_actions_text"
+            android:textAppearance="?android:attr/textAppearanceSmall" />
+
+        <TextView
+            android:visibility="gone"
+            android:id="@*android:id/status"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:textColor="@color/global_actions_text"
+            android:textAppearance="?android:attr/textAppearanceSmall" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
new file mode 100644
index 0000000..4cfb47e
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+  <androidx.constraintlayout.widget.ConstraintLayout
+      android:id="@+id/global_actions_grid_root"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:clipChildren="false"
+      android:clipToPadding="false"
+      android:layout_marginBottom="@dimen/global_actions_grid_container_negative_shadow_offset">
+
+    <com.android.systemui.globalactions.GlobalActionsFlatLayout
+        android:id="@id/global_actions_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:theme="@style/qs_theme"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        android:gravity="top | center_horizontal"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:paddingBottom="@dimen/global_actions_grid_container_shadow_offset"
+        android:layout_marginTop="@dimen/global_actions_top_margin"
+        android:layout_marginBottom="@dimen/global_actions_grid_container_negative_shadow_offset">
+      <LinearLayout
+          android:layout_height="wrap_content"
+          android:layout_width="wrap_content"
+          android:layoutDirection="ltr"
+          android:clipChildren="false"
+          android:clipToPadding="false"
+          android:layout_marginBottom="@dimen/global_actions_grid_container_bottom_margin">
+        <!-- For separated items-->
+        <LinearLayout
+            android:id="@+id/separated_button"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_marginLeft="@dimen/global_actions_grid_side_margin"
+            android:layout_marginRight="@dimen/global_actions_grid_side_margin"
+            android:paddingLeft="@dimen/global_actions_grid_horizontal_padding"
+            android:paddingRight="@dimen/global_actions_grid_horizontal_padding"
+            android:paddingTop="@dimen/global_actions_grid_vertical_padding"
+            android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
+            android:orientation="vertical"
+            android:gravity="center"
+            android:translationZ="@dimen/global_actions_translate"
+            />
+        <!-- Grid of action items -->
+        <com.android.systemui.globalactions.ListGridLayout
+            android:id="@android:id/list"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:gravity="right"
+            android:layout_marginRight="@dimen/global_actions_grid_side_margin"
+            android:translationZ="@dimen/global_actions_translate"
+            android:paddingLeft="@dimen/global_actions_grid_horizontal_padding"
+            android:paddingRight="@dimen/global_actions_grid_horizontal_padding"
+            android:paddingTop="@dimen/global_actions_grid_vertical_padding"
+            android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
+            >
+          <LinearLayout
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:visibility="gone"
+              android:layoutDirection="locale"
+              />
+          <LinearLayout
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:visibility="gone"
+              android:layoutDirection="locale"
+              />
+          <LinearLayout
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:visibility="gone"
+              android:layoutDirection="locale"
+              />
+        </com.android.systemui.globalactions.ListGridLayout>
+      </LinearLayout>
+    </com.android.systemui.globalactions.GlobalActionsFlatLayout>
+
+    <LinearLayout
+        android:id="@+id/global_actions_panel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/global_actions_view">
+
+      <FrameLayout
+          android:translationY="@dimen/global_actions_plugin_offset"
+          android:id="@+id/global_actions_panel_container"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:translationY="@dimen/global_actions_plugin_offset"
+        android:id="@+id/global_actions_controls"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/global_actions_panel">
+      <TextView
+          android:text="Home"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+          android:singleLine="true"
+          android:gravity="center"
+          android:textSize="25dp"
+          android:textColor="?android:attr/textColorPrimary"
+          android:fontFamily="@*android:string/config_headlineFontFamily" />
+    <LinearLayout
+        android:id="@+id/global_actions_controls_list"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical" />
+    </LinearLayout>
+  </androidx.constraintlayout.widget.ConstraintLayout>
+</ScrollView>
diff --git a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
index 6b42400..366abaa 100644
--- a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
@@ -14,12 +14,27 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-          android:id="@+id/global_screenshot_action_chip"
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:layout_marginHorizontal="@dimen/screenshot_action_chip_margin_horizontal"
-          android:paddingVertical="@dimen/screenshot_action_chip_padding_vertical"
-          android:paddingHorizontal="@dimen/screenshot_action_chip_padding_horizontal"
-          android:background="@drawable/action_chip_background"
-          android:textColor="@color/global_screenshot_button_text"/>
+<com.android.systemui.screenshot.ScreenshotActionChip
+    xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/global_screenshot_action_chip"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:layout_marginHorizontal="@dimen/screenshot_action_chip_margin_horizontal"
+              android:layout_gravity="center"
+              android:paddingVertical="@dimen/screenshot_action_chip_padding_vertical"
+              android:background="@drawable/action_chip_background"
+              android:gravity="center">
+    <ImageView
+        android:id="@+id/screenshot_action_chip_icon"
+        android:layout_width="@dimen/screenshot_action_chip_icon_size"
+        android:layout_height="@dimen/screenshot_action_chip_icon_size"
+        android:layout_marginStart="@dimen/screenshot_action_chip_padding_start"
+        android:layout_marginEnd="@dimen/screenshot_action_chip_padding_middle"/>
+    <TextView
+        android:id="@+id/screenshot_action_chip_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/screenshot_action_chip_padding_end"
+        android:textSize="@dimen/screenshot_action_chip_text_size"
+        android:textColor="@color/global_screenshot_button_text"/>
+</com.android.systemui.screenshot.ScreenshotActionChip>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5a1151e..c26cb9a 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -291,12 +291,17 @@
     <dimen name="global_screenshot_legacy_bg_padding">20dp</dimen>
     <dimen name="global_screenshot_bg_padding">20dp</dimen>
     <dimen name="screenshot_action_container_corner_radius">10dp</dimen>
-    <dimen name="screenshot_action_container_padding">20dp</dimen>
+    <dimen name="screenshot_action_container_padding">10dp</dimen>
     <!-- Radius of the chip background on global screenshot actions -->
     <dimen name="screenshot_button_corner_radius">20dp</dimen>
-    <dimen name="screenshot_action_chip_margin_horizontal">10dp</dimen>
+    <dimen name="screenshot_action_chip_margin_horizontal">4dp</dimen>
     <dimen name="screenshot_action_chip_padding_vertical">10dp</dimen>
-    <dimen name="screenshot_action_chip_padding_horizontal">15dp</dimen>
+    <dimen name="screenshot_action_chip_icon_size">20dp</dimen>
+    <dimen name="screenshot_action_chip_padding_start">4dp</dimen>
+    <!-- Padding between icon and text -->
+    <dimen name="screenshot_action_chip_padding_middle">8dp</dimen>
+    <dimen name="screenshot_action_chip_padding_end">12dp</dimen>
+    <dimen name="screenshot_action_chip_text_size">14sp</dimen>
 
 
     <!-- The width of the view containing navigation buttons -->
@@ -951,6 +956,9 @@
     <dimen name="cell_overlay_padding">18dp</dimen>
 
     <!-- Global actions power menu -->
+    <dimen name="global_actions_top_margin">12dp</dimen>
+    <dimen name="global_actions_plugin_offset">-145dp</dimen>
+
     <dimen name="global_actions_panel_width">120dp</dimen>
     <dimen name="global_actions_padding">12dp</dimen>
     <dimen name="global_actions_translate">9dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
index 8105faa..eab9706 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
@@ -27,9 +27,9 @@
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotifCollection;
-import com.android.systemui.statusbar.notification.collection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -49,7 +49,7 @@
     public ForegroundServiceNotificationListener(Context context,
             ForegroundServiceController foregroundServiceController,
             NotificationEntryManager notificationEntryManager,
-            NotifCollection notifCollection) {
+            NotifPipeline notifPipeline) {
         mContext = context;
         mForegroundServiceController = foregroundServiceController;
 
@@ -77,7 +77,7 @@
         });
         mEntryManager.addNotificationLifetimeExtender(new ForegroundServiceLifetimeExtender());
 
-        notifCollection.addCollectionListener(new NotifCollectionListener() {
+        notifPipeline.addCollectionListener(new NotifCollectionListener() {
             @Override
             public void onEntryAdded(NotificationEntry entry) {
                 addNotification(entry, entry.getImportance());
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
index 563a0a7..31656a0 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
@@ -961,6 +961,13 @@
             if (view != null) {
                 final SpringAnimation animation =
                         (SpringAnimation) view.getTag(getTagIdForProperty(property));
+
+                // If the animation is null, the view was probably removed from the layout before
+                // the animation started.
+                if (animation == null) {
+                    return;
+                }
+
                 if (afterCallbacks != null) {
                     animation.addEndListener(new OneTimeEndListener() {
                         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index b195238..a6fa414 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -30,10 +30,8 @@
 import com.android.systemui.recents.Recents;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
-import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
-import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
 import com.android.systemui.statusbar.notification.people.PeopleHubModule;
 import com.android.systemui.statusbar.phone.KeyguardLiftController;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -113,9 +111,4 @@
     @Singleton
     @Binds
     abstract SystemClock bindSystemClock(SystemClockImpl systemClock);
-
-    @Singleton
-    @Binds
-    abstract NotifListBuilder bindNotifListBuilder(NotifListBuilderImpl impl);
-
 }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 91bb80c..c138462 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -59,7 +59,6 @@
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
-import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.FeatureFlagUtils;
 import android.util.Log;
@@ -444,7 +443,8 @@
                                 mKeyguardManager.isDeviceLocked())
                         : null;
 
-        ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, panelViewController);
+        ActionsDialog dialog = new ActionsDialog(
+                mContext, mAdapter, panelViewController, isControlsEnabled(mContext));
         dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
         dialog.setKeyguardShowing(mKeyguardShowing);
 
@@ -518,7 +518,7 @@
 
         @Override
         public boolean shouldBeSeparated() {
-            return shouldUseSeparatedView();
+            return !isControlsEnabled(mContext);
         }
 
         @Override
@@ -1154,6 +1154,9 @@
         }
 
         protected int getActionLayoutId(Context context) {
+            if (isControlsEnabled(context)) {
+                return com.android.systemui.R.layout.global_actions_grid_item_v2;
+            }
             return com.android.systemui.R.layout.global_actions_grid_item;
         }
 
@@ -1415,8 +1418,8 @@
             } else if (TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
                 // Airplane mode can be changed after ECM exits if airplane toggle button
                 // is pressed during ECM mode
-                if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) &&
-                        mIsWaitingForEcmExit) {
+                if (!(intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false))
+                        && mIsWaitingForEcmExit) {
                     mIsWaitingForEcmExit = false;
                     changeAirplaneModeSystemSetting(true);
                 }
@@ -1526,15 +1529,18 @@
         private ResetOrientationData mResetOrientationData;
         private boolean mHadTopUi;
         private final StatusBarWindowController mStatusBarWindowController;
+        private boolean mControlsEnabled;
 
         ActionsDialog(Context context, MyAdapter adapter,
-                GlobalActionsPanelPlugin.PanelViewController plugin) {
+                GlobalActionsPanelPlugin.PanelViewController plugin,
+                boolean controlsEnabled) {
             super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
             mContext = context;
             mAdapter = adapter;
             mColorExtractor = Dependency.get(SysuiColorExtractor.class);
             mStatusBarService = Dependency.get(IStatusBarService.class);
             mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
+            mControlsEnabled = controlsEnabled;
 
             // Window initialization
             Window window = getWindow();
@@ -1651,6 +1657,10 @@
         }
 
         private int getGlobalActionsLayoutId(Context context) {
+            if (mControlsEnabled) {
+                return com.android.systemui.R.layout.global_actions_grid_v2;
+            }
+
             int rotation = RotationUtils.getRotation(context);
             boolean useGridLayout = isForceGridEnabled(context)
                     || (shouldUsePanel() && rotation == RotationUtils.ROTATION_NONE);
@@ -1854,4 +1864,9 @@
     private static boolean shouldUseSeparatedView() {
         return true;
     }
+
+    private static boolean isControlsEnabled(Context context) {
+        return Settings.Secure.getInt(
+                context.getContentResolver(), "systemui.controls_available", 0) == 1;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java
new file mode 100644
index 0000000..6749f1d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.globalactions;
+
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Single row implementation of the button layout created by the global actions dialog.
+ */
+public class GlobalActionsFlatLayout extends GlobalActionsLayout {
+    public GlobalActionsFlatLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        mBackgroundsSet = true;
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        // backgrounds set only once, the first time onMeasure is called after inflation
+        // if (getListView() != null && !mBackgroundsSet) {
+        //     setBackgrounds();
+        //     mBackgroundsSet = true;
+        // }
+    }
+
+    @VisibleForTesting
+    protected void setupListView() {
+        ListGridLayout listView = getListView();
+        listView.setExpectedCount(Math.min(2, mAdapter.countListItems()));
+        listView.setReverseSublists(shouldReverseSublists());
+        listView.setReverseItems(shouldReverseListItems());
+        listView.setSwapRowsAndColumns(shouldSwapRowsAndColumns());
+    }
+
+    @Override
+    public void onUpdateList() {
+        setupListView();
+        super.onUpdateList();
+        updateSeparatedItemSize();
+    }
+
+    /**
+     * If the separated view contains only one item, expand the bounds of that item to take up the
+     * entire view, so that the whole thing is touch-able.
+     */
+    @VisibleForTesting
+    protected void updateSeparatedItemSize() {
+        ViewGroup separated = getSeparatedView();
+        if (separated.getChildCount() == 0) {
+            return;
+        }
+        View firstChild = separated.getChildAt(0);
+        ViewGroup.LayoutParams childParams = firstChild.getLayoutParams();
+
+        if (separated.getChildCount() == 1) {
+            childParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
+            childParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
+        } else {
+            childParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
+            childParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        }
+    }
+
+    @Override
+    protected ListGridLayout getListView() {
+        return (ListGridLayout) super.getListView();
+    }
+
+    @Override
+    protected void removeAllListViews() {
+        ListGridLayout list = getListView();
+        if (list != null) {
+            list.removeAllItems();
+        }
+    }
+
+    @Override
+    protected void addToListView(View v, boolean reverse) {
+        ListGridLayout list = getListView();
+        if (list != null) {
+            list.addItem(v);
+        }
+    }
+
+    @Override
+    public void removeAllItems() {
+        ViewGroup separatedList = getSeparatedView();
+        ListGridLayout list = getListView();
+        if (separatedList != null) {
+            separatedList.removeAllViews();
+        }
+        if (list != null) {
+            list.removeAllItems();
+        }
+    }
+
+    /**
+     * Determines whether the ListGridLayout should fill sublists in the reverse order.
+     * Used to account for sublist ordering changing between landscape and seascape views.
+     */
+    @VisibleForTesting
+    protected boolean shouldReverseSublists() {
+        if (getCurrentRotation() == ROTATION_SEASCAPE) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Determines whether the ListGridLayout should fill rows first instead of columns.
+     * Used to account for vertical/horizontal changes due to landscape or seascape rotations.
+     */
+    @VisibleForTesting
+    protected boolean shouldSwapRowsAndColumns() {
+        if (getCurrentRotation() == ROTATION_NONE) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    protected boolean shouldReverseListItems() {
+        int rotation = getCurrentRotation();
+        boolean reverse = false; // should we add items to parents in the reverse order?
+        if (rotation == ROTATION_NONE
+                || rotation == ROTATION_SEASCAPE) {
+            reverse = !reverse; // if we're in portrait or seascape, reverse items
+        }
+        if (getCurrentLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+            reverse = !reverse; // if we're in an RTL language, reverse items (again)
+        }
+        return reverse;
+    }
+
+    @VisibleForTesting
+    protected float getAnimationDistance() {
+        int rows = getListView().getRowCount();
+        float gridItemSize = getContext().getResources().getDimension(
+                com.android.systemui.R.dimen.global_actions_grid_item_height);
+        return rows * gridItemSize / 2;
+    }
+
+    @Override
+    public float getAnimationOffsetX() {
+        switch (getCurrentRotation()) {
+            case ROTATION_LANDSCAPE:
+                return getAnimationDistance();
+            case ROTATION_SEASCAPE:
+                return -getAnimationDistance();
+            default: // Portrait
+                return 0;
+        }
+    }
+
+    @Override
+    public float getAnimationOffsetY() {
+        if (getCurrentRotation() == ROTATION_NONE) {
+            return getAnimationDistance();
+        }
+        return 0;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 9f2bbc6..27c9555 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -64,7 +64,6 @@
 import android.view.animation.Interpolator;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.TextView;
 import android.widget.Toast;
 
 import com.android.systemui.R;
@@ -529,9 +528,10 @@
         mActionsView.removeAllViews();
 
         for (Notification.Action action : actions) {
-            TextView actionChip = (TextView) inflater.inflate(
+            ScreenshotActionChip actionChip = (ScreenshotActionChip) inflater.inflate(
                     R.layout.global_screenshot_action_chip, mActionsView, false);
             actionChip.setText(action.title);
+            actionChip.setIcon(action.getIcon(), true);
             actionChip.setOnClickListener(v -> {
                 try {
                     action.actionIntent.send();
@@ -545,11 +545,11 @@
         }
 
         if (DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, SCREENSHOT_SCROLLING_ENABLED, false)) {
-            TextView scrollChip = (TextView) inflater.inflate(
+            ScreenshotActionChip scrollChip = (ScreenshotActionChip) inflater.inflate(
                     R.layout.global_screenshot_action_chip, mActionsView, false);
             Toast scrollNotImplemented = Toast.makeText(
                     mContext, "Not implemented", Toast.LENGTH_SHORT);
-            scrollChip.setText("Scroll"); // TODO (mkephart): add resource and translate
+            scrollChip.setText("Extend"); // TODO (mkephart): add resource and translate
             scrollChip.setOnClickListener(v -> scrollNotImplemented.show());
             mActionsView.addView(scrollChip);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionChip.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionChip.java
new file mode 100644
index 0000000..6edacd1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionChip.java
@@ -0,0 +1,73 @@
+/*
+ * 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.systemui.screenshot;
+
+import android.annotation.ColorInt;
+import android.content.Context;
+import android.graphics.drawable.Icon;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+
+/**
+ * View for a chip with an icon and text.
+ */
+public class ScreenshotActionChip extends LinearLayout {
+
+    private ImageView mIcon;
+    private TextView mText;
+    private @ColorInt int mIconColor;
+
+    public ScreenshotActionChip(Context context) {
+        this(context, null);
+    }
+
+    public ScreenshotActionChip(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ScreenshotActionChip(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public ScreenshotActionChip(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+
+        mIconColor = context.getColor(R.color.global_screenshot_button_text);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        mIcon = findViewById(R.id.screenshot_action_chip_icon);
+        mText = findViewById(R.id.screenshot_action_chip_text);
+    }
+
+    void setIcon(Icon icon, boolean tint) {
+        if (tint) {
+            icon.setTint(mIconColor);
+        }
+        mIcon.setImageIcon(icon);
+    }
+
+    void setText(CharSequence text) {
+        mText.setText(text);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 36dcaac..4a22831 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -43,7 +43,7 @@
 import com.android.systemui.statusbar.NotificationUiAdjustment;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
-import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.logging.NotifEvent;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
index e1268f6..73bfe25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
@@ -16,13 +16,11 @@
 
 package com.android.systemui.statusbar.notification.collection;
 
-import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
-
 import java.util.List;
 
 
 /**
- * Utility class for dumping the results of a {@link NotifListBuilder} to a debug string.
+ * Utility class for dumping the results of a {@link ShadeListBuilder} to a debug string.
  */
 public class ListDumper {
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 856b75b..4b15b7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -47,9 +47,13 @@
 import android.util.Log;
 
 import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.statusbar.notification.collection.notifcollection.CoalescedEvent;
-import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer;
-import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer.BatchableNotificationHandler;
+import com.android.systemui.statusbar.notification.collection.coalescer.CoalescedEvent;
+import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer;
+import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer.BatchableNotificationHandler;
+import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
+import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
 import com.android.systemui.util.Assert;
 
 import java.lang.annotation.Retention;
@@ -123,36 +127,25 @@
      * Sets the class responsible for converting the collection into the list of currently-visible
      * notifications.
      */
-    public void setBuildListener(CollectionReadyForBuildListener buildListener) {
+    void setBuildListener(CollectionReadyForBuildListener buildListener) {
         Assert.isMainThread();
         mBuildListener = buildListener;
     }
 
-    /**
-     * Returns the list of "active" notifications, i.e. the notifications that are currently posted
-     * to the phone. In general, this tracks closely to the list maintained by NotificationManager,
-     * but it can diverge slightly due to lifetime extenders.
-     *
-     * The returned list is read-only, unsorted, unfiltered, and ungrouped.
-     */
-    public Collection<NotificationEntry> getNotifs() {
+    /** @see NotifPipeline#getActiveNotifs() */
+    Collection<NotificationEntry> getActiveNotifs() {
         Assert.isMainThread();
         return mReadOnlyNotificationSet;
     }
 
-    /**
-     * Registers a listener to be informed when notifications are added, removed or updated.
-     */
-    public void addCollectionListener(NotifCollectionListener listener) {
+    /** @see NotifPipeline#addCollectionListener(NotifCollectionListener) */
+    void addCollectionListener(NotifCollectionListener listener) {
         Assert.isMainThread();
         mNotifCollectionListeners.add(listener);
     }
 
-    /**
-     * Registers a lifetime extender. Lifetime extenders can cause notifications that have been
-     * dismissed or retracted to be temporarily retained in the collection.
-     */
-    public void addNotificationLifetimeExtender(NotifLifetimeExtender extender) {
+    /** @see NotifPipeline#addNotificationLifetimeExtender(NotifLifetimeExtender) */
+    void addNotificationLifetimeExtender(NotifLifetimeExtender extender) {
         Assert.isMainThread();
         checkForReentrantCall();
         if (mLifetimeExtenders.contains(extender)) {
@@ -165,7 +158,7 @@
     /**
      * Dismiss a notification on behalf of the user.
      */
-    public void dismissNotification(
+    void dismissNotification(
             NotificationEntry entry,
             @CancellationReason int reason,
             @NonNull DismissedByUserStats stats) {
@@ -446,7 +439,7 @@
             REASON_TIMEOUT,
     })
     @Retention(RetentionPolicy.SOURCE)
-    @interface CancellationReason {}
+    public @interface CancellationReason {}
 
     public static final int REASON_UNKNOWN = 0;
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
index 0d17557..e7b772f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
@@ -25,6 +25,9 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.statusbar.notification.InflationException;
+import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
 
@@ -107,7 +110,7 @@
                                 DISMISS_SENTIMENT_NEUTRAL,
                                 NotificationVisibility.obtain(entry.getKey(),
                                         entry.getRanking().getRank(),
-                                        mNotifCollection.getNotifs().size(),
+                                        mNotifCollection.getActiveNotifs().size(),
                                         true,
                                         NotificationLogger.getNotificationLocation(entry))
                         ));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
new file mode 100644
index 0000000..7124517
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
@@ -0,0 +1,191 @@
+/*
+ * 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.systemui.statusbar.notification.collection;
+
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.SectionsProvider;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
+
+import java.util.Collection;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * The system that constructs the "shade list", the filtered, grouped, and sorted list of
+ * notifications that are currently being displayed to the user in the notification shade.
+ *
+ * The pipeline proceeds through a series of stages in order to produce the final list (see below).
+ * Each stage exposes hooks and listeners to allow other code to participate.
+ *
+ * This list differs from the canonical one we receive from system server in a few ways:
+ * - Filtered: Some notifications are filtered out. For example, we filter out notifications whose
+ *   views haven't been inflated yet. We also filter out some notifications if we're on the lock
+ *   screen and notifications for other users. So participate, see
+ *   {@link #addPreGroupFilter} and similar methods.
+ * - Grouped: Notifications that are part of the same group are clustered together into a single
+ *   GroupEntry. These groups are then transformed in order to remove children or completely split
+ *   them apart. To participate, see {@link #addPromoter}.
+ * - Sorted: All top-level notifications are sorted. To participate, see
+ *   {@link #setSectionsProvider} and {@link #setComparators}
+ *
+ * The exact order of all hooks is as follows:
+ *  0. Collection listeners are fired ({@link #addCollectionListener}).
+ *  1. Pre-group filters are fired on each notification ({@link #addPreGroupFilter}).
+ *  2. Initial grouping is performed (NotificationEntries will have their parents set
+ *     appropriately).
+ *  3. OnBeforeTransformGroupListeners are fired ({@link #addOnBeforeTransformGroupsListener})
+ *  4. NotifPromoters are called on each notification with a parent ({@link #addPromoter})
+ *  5. OnBeforeSortListeners are fired ({@link #addOnBeforeSortListener})
+ *  6. SectionsProvider is called on each top-level entry in the list ({@link #setSectionsProvider})
+ *  7. Top-level entries within the same section are sorted by NotifComparators
+ *     ({@link #setComparators})
+ *  8. Pre-render filters are fired on each notification ({@link #addPreRenderFilter})
+ *  9. OnBeforeRenderListListeners are fired ({@link #addOnBeforeRenderListListener})
+ *  9. The list is handed off to the view layer to be rendered
+ */
+@Singleton
+public class NotifPipeline {
+    private final NotifCollection mNotifCollection;
+    private final ShadeListBuilder mShadeListBuilder;
+
+    @Inject
+    public NotifPipeline(
+            NotifCollection notifCollection,
+            ShadeListBuilder shadeListBuilder) {
+        mNotifCollection = notifCollection;
+        mShadeListBuilder = shadeListBuilder;
+    }
+
+    /**
+     * Returns the list of "active" notifications, i.e. the notifications that are currently posted
+     * to the phone. In general, this tracks closely to the list maintained by NotificationManager,
+     * but it can diverge slightly due to lifetime extenders.
+     *
+     * The returned collection is read-only, unsorted, unfiltered, and ungrouped.
+     */
+    public Collection<NotificationEntry> getActiveNotifs() {
+        return mNotifCollection.getActiveNotifs();
+    }
+
+    /**
+     * Registers a listener to be informed when notifications are added, removed or updated.
+     */
+    public void addCollectionListener(NotifCollectionListener listener) {
+        mNotifCollection.addCollectionListener(listener);
+    }
+
+    /**
+     * Registers a lifetime extender. Lifetime extenders can cause notifications that have been
+     * dismissed or retracted to be temporarily retained in the collection.
+     */
+    public void addNotificationLifetimeExtender(NotifLifetimeExtender extender) {
+        mNotifCollection.addNotificationLifetimeExtender(extender);
+    }
+
+    /**
+     * Registers a filter with the pipeline before grouping, promoting and sorting occurs. Filters
+     * are called on each notification in the order that they were registered. If any filter
+     * returns true, the notification is removed from the pipeline (and no other filters are
+     * called on that notif).
+     */
+    public void addPreGroupFilter(NotifFilter filter) {
+        mShadeListBuilder.addPreGroupFilter(filter);
+    }
+
+    /**
+     * Called after notifications have been filtered and after the initial grouping has been
+     * performed but before NotifPromoters have had a chance to promote children out of groups.
+     */
+    public void addOnBeforeTransformGroupsListener(OnBeforeTransformGroupsListener listener) {
+        mShadeListBuilder.addOnBeforeTransformGroupsListener(listener);
+    }
+
+    /**
+     * Registers a promoter with the pipeline. Promoters are able to promote child notifications to
+     * top-level, i.e. move a notification that would be a child of a group and make it appear
+     * ungrouped. Promoters are called on each child notification in the order that they are
+     * registered. If any promoter returns true, the notification is removed from the group (and no
+     * other promoters are called on it).
+     */
+    public void addPromoter(NotifPromoter promoter) {
+        mShadeListBuilder.addPromoter(promoter);
+    }
+
+    /**
+     * Called after notifs have been filtered and groups have been determined but before sections
+     * have been determined or the notifs have been sorted.
+     */
+    public void addOnBeforeSortListener(OnBeforeSortListener listener) {
+        mShadeListBuilder.addOnBeforeSortListener(listener);
+    }
+
+    /**
+     * Assigns sections to each top-level entry, where a section is simply an integer. Sections are
+     * the primary metric by which top-level entries are sorted; NotifComparators are only consulted
+     * when two entries are in the same section. The pipeline doesn't assign any particular meaning
+     * to section IDs -- from it's perspective they're just numbers and it sorts them by a simple
+     * numerical comparison.
+     */
+    public void setSectionsProvider(SectionsProvider provider) {
+        mShadeListBuilder.setSectionsProvider(provider);
+    }
+
+    /**
+     * Comparators that are used to sort top-level entries that share the same section. The
+     * comparators are executed in order until one of them returns a non-zero result. If all return
+     * zero, the pipeline falls back to sorting by rank (and, failing that, Notification.when).
+     */
+    public void setComparators(List<NotifComparator> comparators) {
+        mShadeListBuilder.setComparators(comparators);
+    }
+
+    /**
+     * Registers a filter with the pipeline to filter right before rendering the list (after
+     * pre-group filtering, grouping, promoting and sorting occurs). Filters are
+     * called on each notification in the order that they were registered. If any filter returns
+     * true, the notification is removed from the pipeline (and no other filters are called on that
+     * notif).
+     */
+    public void addPreRenderFilter(NotifFilter filter) {
+        mShadeListBuilder.addPreRenderFilter(filter);
+    }
+
+    /**
+     * Called at the end of the pipeline after the notif list has been finalized but before it has
+     * been handed off to the view layer.
+     */
+    public void addOnBeforeRenderListListener(OnBeforeRenderListListener listener) {
+        mShadeListBuilder.addOnBeforeRenderListListener(listener);
+    }
+
+    /**
+     * Returns a read-only view in to the current shade list, i.e. the list of notifications that
+     * are currently present in the shade. If this method is called during pipeline execution it
+     * will return the current state of the list, which will likely be only partially-generated.
+     */
+    public List<ListEntry> getShadeList() {
+        return mShadeListBuilder.getShadeList();
+    }
+}
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 7301fe1..2fcfb8c 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
@@ -59,6 +59,7 @@
 import com.android.systemui.statusbar.notification.InflationException;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationGuts;
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 19d90f0..76c524b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -32,7 +32,6 @@
 import android.annotation.Nullable;
 import android.util.ArrayMap;
 
-import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
 import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
 import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
 import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener;
@@ -41,6 +40,7 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.SectionsProvider;
+import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
 import com.android.systemui.statusbar.notification.logging.NotifEvent;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
 import com.android.systemui.util.Assert;
@@ -57,11 +57,13 @@
 import javax.inject.Singleton;
 
 /**
- * The implementation of {@link NotifListBuilder}.
+ * The second half of {@link NotifPipeline}. Sits downstream of the NotifCollection and transforms
+ * its "notification set" into the "shade list", the filtered, grouped, and sorted list of
+ * notifications that are currently present in the notification shade.
  */
 @MainThread
 @Singleton
-public class NotifListBuilderImpl implements NotifListBuilder {
+public class ShadeListBuilder {
     private final SystemClock mSystemClock;
     private final NotifLog mNotifLog;
 
@@ -90,7 +92,7 @@
     private final List<ListEntry> mReadOnlyNotifList = Collections.unmodifiableList(mNotifList);
 
     @Inject
-    public NotifListBuilderImpl(SystemClock systemClock, NotifLog notifLog) {
+    public ShadeListBuilder(SystemClock systemClock, NotifLog notifLog) {
         Assert.isMainThread();
         mSystemClock = systemClock;
         mNotifLog = notifLog;
@@ -116,32 +118,28 @@
         mOnRenderListListener = onRenderListListener;
     }
 
-    @Override
-    public void addOnBeforeTransformGroupsListener(OnBeforeTransformGroupsListener listener) {
+    void addOnBeforeTransformGroupsListener(OnBeforeTransformGroupsListener listener) {
         Assert.isMainThread();
 
         mPipelineState.requireState(STATE_IDLE);
         mOnBeforeTransformGroupsListeners.add(listener);
     }
 
-    @Override
-    public void addOnBeforeSortListener(OnBeforeSortListener listener) {
+    void addOnBeforeSortListener(OnBeforeSortListener listener) {
         Assert.isMainThread();
 
         mPipelineState.requireState(STATE_IDLE);
         mOnBeforeSortListeners.add(listener);
     }
 
-    @Override
-    public void addOnBeforeRenderListListener(OnBeforeRenderListListener listener) {
+    void addOnBeforeRenderListListener(OnBeforeRenderListListener listener) {
         Assert.isMainThread();
 
         mPipelineState.requireState(STATE_IDLE);
         mOnBeforeRenderListListeners.add(listener);
     }
 
-    @Override
-    public void addPreGroupFilter(NotifFilter filter) {
+    void addPreGroupFilter(NotifFilter filter) {
         Assert.isMainThread();
         mPipelineState.requireState(STATE_IDLE);
 
@@ -149,8 +147,7 @@
         filter.setInvalidationListener(this::onPreGroupFilterInvalidated);
     }
 
-    @Override
-    public void addPreRenderFilter(NotifFilter filter) {
+    void addPreRenderFilter(NotifFilter filter) {
         Assert.isMainThread();
         mPipelineState.requireState(STATE_IDLE);
 
@@ -158,8 +155,7 @@
         filter.setInvalidationListener(this::onPreRenderFilterInvalidated);
     }
 
-    @Override
-    public void addPromoter(NotifPromoter promoter) {
+    void addPromoter(NotifPromoter promoter) {
         Assert.isMainThread();
         mPipelineState.requireState(STATE_IDLE);
 
@@ -167,8 +163,7 @@
         promoter.setInvalidationListener(this::onPromoterInvalidated);
     }
 
-    @Override
-    public void setSectionsProvider(SectionsProvider provider) {
+    void setSectionsProvider(SectionsProvider provider) {
         Assert.isMainThread();
         mPipelineState.requireState(STATE_IDLE);
 
@@ -176,8 +171,7 @@
         provider.setInvalidationListener(this::onSectionsProviderInvalidated);
     }
 
-    @Override
-    public void setComparators(List<NotifComparator> comparators) {
+    void setComparators(List<NotifComparator> comparators) {
         Assert.isMainThread();
         mPipelineState.requireState(STATE_IDLE);
 
@@ -188,8 +182,7 @@
         }
     }
 
-    @Override
-    public List<ListEntry> getActiveNotifs() {
+    List<ListEntry> getShadeList() {
         Assert.isMainThread();
         return mReadOnlyNotifList;
     }
@@ -275,7 +268,7 @@
     }
 
     /**
-     * The core algorithm of the pipeline. See the top comment in {@link NotifListBuilder} for
+     * The core algorithm of the pipeline. See the top comment in {@link NotifPipeline} for
      * details on our contracts with other code.
      *
      * Once the build starts we are very careful to protect against reentrant code. Anything that
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CoalescedEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/CoalescedEvent.kt
similarity index 87%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CoalescedEvent.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/CoalescedEvent.kt
index b6218b4..143de8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CoalescedEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/CoalescedEvent.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification.collection.notifcollection
+package com.android.systemui.statusbar.notification.collection.coalescer
 
 import android.service.notification.NotificationListenerService.Ranking
 import android.service.notification.StatusBarNotification
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/EventBatch.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java
similarity index 89%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/EventBatch.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java
index ac51178..2c6a165 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/EventBatch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification.collection.notifcollection;
+package com.android.systemui.statusbar.notification.collection.coalescer;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescer.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
index c3e3c53..8076616 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification.collection.notifcollection;
+package com.android.systemui.statusbar.notification.collection.coalescer;
 
 import static com.android.systemui.statusbar.notification.logging.NotifEvent.COALESCED_EVENT;
 import static com.android.systemui.statusbar.notification.logging.NotifEvent.EARLY_BATCH_EMIT;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java
index 898918e..c1a11b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java
@@ -16,27 +16,16 @@
 
 package com.android.systemui.statusbar.notification.collection.coordinator;
 
-import com.android.systemui.statusbar.notification.collection.NotifCollection;
-import com.android.systemui.statusbar.notification.collection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender;
-import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
-import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
 
 /**
- * Interface for registering callbacks to the {@link NewNotifPipeline}.
- *
- * This includes registering:
- *  {@link Pluggable}s to the {@link NotifListBuilder}
- *  {@link NotifCollectionListener}s and {@link NotifLifetimeExtender}s to {@link NotifCollection}
+ * Interface for registering callbacks to the {@link NotifPipeline}.
  */
 public interface Coordinator {
-
     /**
      * Called after the NewNotifPipeline is initialized.
-     * Coordinators should register their {@link Pluggable}s to the notifListBuilder
-     * and their {@link NotifCollectionListener}s and {@link NotifLifetimeExtender}s
-     * to the notifCollection in this method.
+     * Coordinators should register their listeners and {@link Pluggable}s to the pipeline.
      */
-    void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder);
+    void attach(NotifPipeline pipeline);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
index 5e7dd98..625d1b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
@@ -23,9 +23,8 @@
 import android.os.RemoteException;
 import android.service.notification.StatusBarNotification;
 
-import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 
@@ -52,10 +51,10 @@
     }
 
     @Override
-    public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
+    public void attach(NotifPipeline pipeline) {
         mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
 
-        notifListBuilder.addPreGroupFilter(mNotifFilter);
+        pipeline.addPreGroupFilter(mNotifFilter);
     }
 
     private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java
index 62342b1..da119c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java
@@ -25,12 +25,11 @@
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.appops.AppOpsController;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.statusbar.notification.collection.NotifCollection;
-import com.android.systemui.statusbar.notification.collection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -57,7 +56,7 @@
     private final AppOpsController mAppOpsController;
     private final Handler mMainHandler;
 
-    private NotifCollection mNotifCollection;
+    private NotifPipeline mNotifPipeline;
 
     @Inject
     public ForegroundCoordinator(
@@ -70,20 +69,20 @@
     }
 
     @Override
-    public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
-        mNotifCollection = notifCollection;
+    public void attach(NotifPipeline pipeline) {
+        mNotifPipeline = pipeline;
 
         // extend the lifetime of foreground notification services to show for at least 5 seconds
-        mNotifCollection.addNotificationLifetimeExtender(mForegroundLifetimeExtender);
+        mNotifPipeline.addNotificationLifetimeExtender(mForegroundLifetimeExtender);
 
         // listen for new notifications to add appOps
-        mNotifCollection.addCollectionListener(mNotifCollectionListener);
+        mNotifPipeline.addCollectionListener(mNotifCollectionListener);
 
         // when appOps change, update any relevant notifications to update appOps for
         mAppOpsController.addCallback(ForegroundServiceController.APP_OPS, this::onAppOpsChanged);
 
         // filter out foreground service notifications that aren't necessary anymore
-        notifListBuilder.addPreGroupFilter(mNotifFilter);
+        mNotifPipeline.addPreGroupFilter(mNotifFilter);
     }
 
     /**
@@ -230,7 +229,7 @@
     }
 
     private NotificationEntry findNotificationEntryWithKey(String key) {
-        for (NotificationEntry entry : mNotifCollection.getNotifs()) {
+        for (NotificationEntry entry : mNotifPipeline.getActiveNotifs()) {
             if (entry.getKey().equals(key)) {
                 return entry;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index db107f5..a26ee545 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -39,9 +39,8 @@
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.collection.GroupEntry;
 import com.android.systemui.statusbar.notification.collection.ListEntry;
-import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -86,9 +85,9 @@
     }
 
     @Override
-    public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
+    public void attach(NotifPipeline pipeline) {
         setupInvalidateNotifListCallbacks();
-        notifListBuilder.addPreRenderFilter(mNotifFilter);
+        pipeline.addPreRenderFilter(mNotifFilter);
     }
 
     private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index 2436bb9..562a618 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -18,11 +18,10 @@
 
 import com.android.systemui.Dumpable;
 import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.notification.collection.NotifCollection;
-import com.android.systemui.statusbar.notification.collection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender;
-import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -33,8 +32,8 @@
 import javax.inject.Singleton;
 
 /**
- * Handles the attachment of the {@link NotifListBuilder} and {@link NotifCollection} to the
- * {@link Coordinator}s, so that the Coordinators can register their respective callbacks.
+ * Handles the attachment of {@link Coordinator}s to the {@link NotifPipeline} so that the
+ * Coordinators can register their respective callbacks.
  */
 @Singleton
 public class NotifCoordinators implements Dumpable {
@@ -63,14 +62,12 @@
     }
 
     /**
-     * Sends the initialized notifListBuilder and notifCollection to each
-     * coordinator to indicate the notifListBuilder is ready to accept {@link Pluggable}s
-     * and the notifCollection is ready to accept {@link NotifCollectionListener}s and
-     * {@link NotifLifetimeExtender}s.
+     * Sends the pipeline to each coordinator when the pipeline is ready to accept
+     * {@link Pluggable}s, {@link NotifCollectionListener}s and {@link NotifLifetimeExtender}s.
      */
-    public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
+    public void attach(NotifPipeline pipeline) {
         for (Coordinator c : mCoordinators) {
-            c.attach(notifCollection, notifListBuilder);
+            c.attach(pipeline);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
index a14f0e1..20c9cbc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
@@ -16,13 +16,12 @@
 
 package com.android.systemui.statusbar.notification.collection.coordinator;
 
-import com.android.systemui.statusbar.notification.collection.NotifCollection;
-import com.android.systemui.statusbar.notification.collection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.collection.NotifInflater;
 import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
 import com.android.systemui.statusbar.notification.logging.NotifEvent;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
 
@@ -55,10 +54,10 @@
     }
 
     @Override
-    public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
-        notifCollection.addCollectionListener(mNotifCollectionListener);
-        notifListBuilder.addPreRenderFilter(mNotifInflationErrorFilter);
-        notifListBuilder.addPreRenderFilter(mNotifInflatingFilter);
+    public void attach(NotifPipeline pipeline) {
+        pipeline.addCollectionListener(mNotifCollectionListener);
+        pipeline.addPreRenderFilter(mNotifInflationErrorFilter);
+        pipeline.addPreRenderFilter(mNotifInflatingFilter);
     }
 
     private final NotifCollectionListener mNotifCollectionListener = new NotifCollectionListener() {
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 0751aa8..7e9e760 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
@@ -17,9 +17,8 @@
 package com.android.systemui.statusbar.notification.collection.coordinator;
 
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 
 import javax.inject.Inject;
@@ -43,10 +42,10 @@
     }
 
     @Override
-    public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
+    public void attach(NotifPipeline pipeline) {
         mStatusBarStateController.addCallback(mStatusBarStateCallback);
 
-        notifListBuilder.addPreGroupFilter(mNotifFilter);
+        pipeline.addPreGroupFilter(mNotifFilter);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.java
similarity index 92%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflater.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.java
index fc04827..ea0ece4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.java
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification.collection;
+package com.android.systemui.statusbar.notification.collection.inflation;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.coordinator.PreparationCoordinator;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
similarity index 90%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinder.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
index 7504e86..3f500644 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification.collection;
+package com.android.systemui.statusbar.notification.collection.inflation;
 
 import android.annotation.Nullable;
 
 import com.android.systemui.statusbar.NotificationUiAdjustment;
 import com.android.systemui.statusbar.notification.InflationException;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 /**
  * Used by the {@link NotificationEntryManager}. When notifications are added or updated, the binder
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 80b5b8a..1ab20a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification.collection;
+package com.android.systemui.statusbar.notification.collection.inflation;
 
 import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
 import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
@@ -39,6 +39,7 @@
 import com.android.systemui.statusbar.notification.InflationException;
 import com.android.systemui.statusbar.notification.NotificationClicker;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/FakePipelineConsumer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/FakePipelineConsumer.java
index 986ee17..15f312d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/FakePipelineConsumer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/FakePipelineConsumer.java
@@ -19,8 +19,8 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.statusbar.notification.collection.GroupEntry;
 import com.android.systemui.statusbar.notification.collection.ListEntry;
-import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.ShadeListBuilder;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -36,7 +36,7 @@
     private List<ListEntry> mEntries = Collections.emptyList();
 
     /** Attach the consumer to the pipeline. */
-    public void attach(NotifListBuilderImpl listBuilder) {
+    public void attach(ShadeListBuilder listBuilder) {
         listBuilder.setOnRenderListListener(this::onBuildComplete);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
similarity index 78%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
index 8d3d0ff..959b002 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
@@ -24,10 +24,11 @@
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
-import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
-import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.ShadeListBuilder;
+import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer;
 import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators;
-import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer;
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -39,10 +40,11 @@
  * Initialization code for the new notification pipeline.
  */
 @Singleton
-public class NewNotifPipeline implements Dumpable {
+public class NotifPipelineInitializer implements Dumpable {
+    private final NotifPipeline mPipelineWrapper;
     private final GroupCoalescer mGroupCoalescer;
     private final NotifCollection mNotifCollection;
-    private final NotifListBuilderImpl mNotifPipeline;
+    private final ShadeListBuilder mListBuilder;
     private final NotifCoordinators mNotifPluggableCoordinators;
     private final NotifInflaterImpl mNotifInflater;
     private final DumpController mDumpController;
@@ -51,17 +53,19 @@
     private final FakePipelineConsumer mFakePipelineConsumer = new FakePipelineConsumer();
 
     @Inject
-    public NewNotifPipeline(
+    public NotifPipelineInitializer(
+            NotifPipeline pipelineWrapper,
             GroupCoalescer groupCoalescer,
             NotifCollection notifCollection,
-            NotifListBuilderImpl notifPipeline,
+            ShadeListBuilder listBuilder,
             NotifCoordinators notifCoordinators,
             NotifInflaterImpl notifInflater,
             DumpController dumpController,
             FeatureFlags featureFlags) {
+        mPipelineWrapper = pipelineWrapper;
         mGroupCoalescer = groupCoalescer;
         mNotifCollection = notifCollection;
-        mNotifPipeline = notifPipeline;
+        mListBuilder = listBuilder;
         mNotifPluggableCoordinators = notifCoordinators;
         mDumpController = dumpController;
         mNotifInflater = notifInflater;
@@ -81,11 +85,11 @@
         }
 
         // Wire up coordinators
-        mFakePipelineConsumer.attach(mNotifPipeline);
-        mNotifPluggableCoordinators.attach(mNotifCollection, mNotifPipeline);
+        mNotifPluggableCoordinators.attach(mPipelineWrapper);
 
         // Wire up pipeline
-        mNotifPipeline.attach(mNotifCollection);
+        mFakePipelineConsumer.attach(mListBuilder);
+        mListBuilder.attach(mNotifCollection);
         mNotifCollection.attach(mGroupCoalescer);
         mGroupCoalescer.attach(notificationService);
 
@@ -99,5 +103,5 @@
         mGroupCoalescer.dump(fd, pw, args);
     }
 
-    private static final String TAG = "NewNotifPipeline";
+    private static final String TAG = "NotifPipeline";
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifListBuilder.java
deleted file mode 100644
index 7580924..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifListBuilder.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.collection.listbuilder;
-
-import com.android.systemui.statusbar.notification.collection.ListEntry;
-import com.android.systemui.statusbar.notification.collection.NotifCollection;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.SectionsProvider;
-
-import java.util.List;
-
-/**
- * The system that constructs the current "notification list", the list of notifications that are
- * currently being displayed to the user.
- *
- * The pipeline proceeds through a series of stages in order to produce the final list (see below).
- * Each stage exposes hooks and listeners for other code to participate.
- *
- * This list differs from the canonical one we receive from system server in a few ways:
- * - Filtered: Some notifications are filtered out. For example, we filter out notifications whose
- *   views haven't been inflated yet. We also filter out some notifications if we're on the lock
- *   screen. To participate, see {@link #addFilter(NotifFilter)}.
- * - Grouped: Notifications that are part of the same group are clustered together into a single
- *   GroupEntry. These groups are then transformed in order to remove children or completely split
- *   them apart. To participate, see {@link #addPromoter(NotifPromoter)}.
- * - Sorted: All top-level notifications are sorted. To participate, see
- *   {@link #setSectionsProvider(SectionsProvider)} and {@link #setComparators(List)}
- *
- * The exact order of all hooks is as follows:
- *  0. Collection listeners are fired (see {@link NotifCollection}).
- *  1. NotifFilters are called on each notification currently in NotifCollection.
- *  2. Initial grouping is performed (NotificationEntries will have their parents set
- *     appropriately).
- *  3. OnBeforeTransformGroupListeners are fired
- *  4. NotifPromoters are called on each notification with a parent
- *  5. OnBeforeSortListeners are fired
- *  6. SectionsProvider is called on each top-level entry in the list
- *  7. The top-level entries are sorted using the provided NotifComparators (plus some additional
- *     built-in logic).
- *  8. OnBeforeRenderListListeners are fired
- *  9. The list is handed off to the view layer to be rendered.
- */
-public interface NotifListBuilder {
-
-    /**
-     * Registers a filter with the pipeline before grouping, promoting and sorting occurs. Filters
-     * are called on each notification in the order that they were registered. If any filter
-     * returns true, the notification is removed from the pipeline (and no other filters are
-     * called on that notif).
-     */
-    void addPreGroupFilter(NotifFilter filter);
-
-    /**
-     * Registers a promoter with the pipeline. Promoters are able to promote child notifications to
-     * top-level, i.e. move a notification that would be a child of a group and make it appear
-     * ungrouped. Promoters are called on each child notification in the order that they are
-     * registered. If any promoter returns true, the notification is removed from the group (and no
-     * other promoters are called on it).
-     */
-    void addPromoter(NotifPromoter promoter);
-
-    /**
-     * Assigns sections to each top-level entry, where a section is simply an integer. Sections are
-     * the primary metric by which top-level entries are sorted; NotifComparators are only consulted
-     * when two entries are in the same section. The pipeline doesn't assign any particular meaning
-     * to section IDs -- from it's perspective they're just numbers and it sorts them by a simple
-     * numerical comparison.
-     */
-    void setSectionsProvider(SectionsProvider provider);
-
-    /**
-     * Comparators that are used to sort top-level entries that share the same section. The
-     * comparators are executed in order until one of them returns a non-zero result. If all return
-     * zero, the pipeline falls back to sorting by rank (and, failing that, Notification.when).
-     */
-    void setComparators(List<NotifComparator> comparators);
-
-    /**
-     * Registers a filter with the pipeline to filter right before rendering the list (after
-     * pre-group filtering, grouping, promoting and sorting occurs). Filters are
-     * called on each notification in the order that they were registered. If any filter returns
-     * true, the notification is removed from the pipeline (and no other filters are called on that
-     * notif).
-     */
-    void addPreRenderFilter(NotifFilter filter);
-
-    /**
-     * Called after notifications have been filtered and after the initial grouping has been
-     * performed but before NotifPromoters have had a chance to promote children out of groups.
-     */
-    void addOnBeforeTransformGroupsListener(OnBeforeTransformGroupsListener listener);
-
-    /**
-     * Called after notifs have been filtered and groups have been determined but before sections
-     * have been determined or the notifs have been sorted.
-     */
-    void addOnBeforeSortListener(OnBeforeSortListener listener);
-
-    /**
-     * Called at the end of the pipeline after the notif list has been finalized but before it has
-     * been handed off to the view layer.
-     */
-    void addOnBeforeRenderListListener(OnBeforeRenderListListener listener);
-
-    /**
-     * Returns a read-only view in to the current notification list. If this method is called
-     * during pipeline execution it will return the current state of the list, which will likely
-     * be only partially-generated.
-     */
-    List<ListEntry> getActiveNotifs();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeRenderListListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeRenderListListener.java
index f6ca12d..44a27a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeRenderListListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeRenderListListener.java
@@ -17,10 +17,11 @@
 package com.android.systemui.statusbar.notification.collection.listbuilder;
 
 import com.android.systemui.statusbar.notification.collection.ListEntry;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 
 import java.util.List;
 
-/** See {@link NotifListBuilder#addOnBeforeRenderListListener(OnBeforeRenderListListener)} */
+/** See {@link NotifPipeline#addOnBeforeRenderListListener(OnBeforeRenderListListener)} */
 public interface OnBeforeRenderListListener {
     /**
      * Called at the end of the pipeline after the notif list has been finalized but before it has
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeSortListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeSortListener.java
index 7be7ac0..56cfe5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeSortListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeSortListener.java
@@ -17,10 +17,11 @@
 package com.android.systemui.statusbar.notification.collection.listbuilder;
 
 import com.android.systemui.statusbar.notification.collection.ListEntry;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 
 import java.util.List;
 
-/** See {@link NotifListBuilder#addOnBeforeSortListener(OnBeforeSortListener)} */
+/** See {@link NotifPipeline#addOnBeforeSortListener(OnBeforeSortListener)} */
 public interface OnBeforeSortListener {
     /**
      * Called after the notif list has been filtered and grouped but before sections have been
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeTransformGroupsListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeTransformGroupsListener.java
index d7a0815..0dc4df0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeTransformGroupsListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeTransformGroupsListener.java
@@ -17,13 +17,14 @@
 package com.android.systemui.statusbar.notification.collection.listbuilder;
 
 import com.android.systemui.statusbar.notification.collection.ListEntry;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
 
 import java.util.List;
 
 /**
  * See
- * {@link NotifListBuilder#addOnBeforeTransformGroupsListener(OnBeforeTransformGroupsListener)}
+ * {@link NotifPipeline#addOnBeforeTransformGroupsListener(OnBeforeTransformGroupsListener)}
  */
 public interface OnBeforeTransformGroupsListener {
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
index 084d038..1897ba2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
@@ -18,13 +18,13 @@
 
 import android.annotation.IntDef;
 
-import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.ShadeListBuilder;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * Used by {@link NotifListBuilderImpl} to track its internal state machine.
+ * Used by {@link ShadeListBuilder} to track its internal state machine.
  */
 public class PipelineState {
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifComparator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifComparator.java
index a191c83..0d150ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifComparator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifComparator.java
@@ -17,13 +17,13 @@
 package com.android.systemui.statusbar.notification.collection.listbuilder.pluggable;
 
 import com.android.systemui.statusbar.notification.collection.ListEntry;
-import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 
 import java.util.Comparator;
 import java.util.List;
 
 /**
- * Pluggable for participating in notif sorting. See {@link NotifListBuilder#setComparators(List)}.
+ * Pluggable for participating in notif sorting. See {@link NotifPipeline#setComparators(List)}.
  */
 public abstract class NotifComparator
         extends Pluggable<NotifComparator>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java
index e6189ed..8f575cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java
@@ -16,12 +16,12 @@
 
 package com.android.systemui.statusbar.notification.collection.listbuilder.pluggable;
 
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
 
 /**
  * Pluggable for participating in notif filtering.
- * See {@link NotifListBuilder#addPreGroupFilter} and {@link NotifListBuilder#addPreRenderFilter}.
+ * See {@link NotifPipeline#addPreGroupFilter} and {@link NotifPipeline#addPreRenderFilter}.
  */
 public abstract class NotifFilter extends Pluggable<NotifFilter> {
     protected NotifFilter(String name) {
@@ -35,9 +35,9 @@
      * however. If another filter returns true before yours, we'll skip straight to the next notif.
      *
      * @param entry The entry in question.
-     *              If this filter is registered via {@link NotifListBuilder#addPreGroupFilter},
+     *              If this filter is registered via {@link NotifPipeline#addPreGroupFilter},
      *              this entry will not have any grouping nor sorting information.
-     *              If this filter is registered via {@link NotifListBuilder#addPreRenderFilter},
+     *              If this filter is registered via {@link NotifPipeline#addPreRenderFilter},
      *              this entry will have grouping and sorting information.
      * @param now A timestamp in SystemClock.uptimeMillis that represents "now" for the purposes of
      *            pipeline execution. This value will be the same for all pluggable calls made
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifPromoter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifPromoter.java
index 84e16f4..5fce446 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifPromoter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifPromoter.java
@@ -16,13 +16,13 @@
 
 package com.android.systemui.statusbar.notification.collection.listbuilder.pluggable;
 
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
 
 /**
  *  Pluggable for participating in notif promotion. Notif promoters can upgrade notifications
  *  from being children of a group to top-level notifications. See
- *  {@link NotifListBuilder#addPromoter(NotifPromoter)}.
+ *  {@link NotifPipeline#addPromoter}.
  */
 public abstract class NotifPromoter extends Pluggable<NotifPromoter> {
     protected NotifPromoter(String name) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
index f9ce197..4270408 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
@@ -18,10 +18,10 @@
 
 import android.annotation.Nullable;
 
-import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 
 /**
- * Generic superclass for chunks of code that can plug into the {@link NotifListBuilder}.
+ * Generic superclass for chunks of code that can plug into the {@link NotifPipeline}.
  *
  * A pluggable is fundamentally three things:
  * 1. A name (for debugging purposes)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/CollectionReadyForBuildListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CollectionReadyForBuildListener.java
similarity index 82%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/CollectionReadyForBuildListener.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CollectionReadyForBuildListener.java
index 87aaea0..4023474 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/CollectionReadyForBuildListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CollectionReadyForBuildListener.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification.collection;
+package com.android.systemui.statusbar.notification.collection.notifcollection;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 import java.util.Collection;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/DismissedByUserStats.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/DismissedByUserStats.java
similarity index 91%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/DismissedByUserStats.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/DismissedByUserStats.java
index ecce6ea..b268686 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/DismissedByUserStats.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/DismissedByUserStats.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification.collection;
+package com.android.systemui.statusbar.notification.collection.notifcollection;
 
 import android.service.notification.NotificationStats.DismissalSentiment;
 import android.service.notification.NotificationStats.DismissalSurface;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollectionListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
similarity index 71%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollectionListener.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
index 032620e..9cbc7d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollectionListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,9 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification.collection;
+package com.android.systemui.statusbar.notification.collection.notifcollection;
 
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 /**
  * Listener interface for {@link NotifCollection}.
@@ -36,7 +38,9 @@
     }
 
     /**
-     * Called immediately after a notification has been removed from the collection.
+     * Called whenever a notification is retracted by system server. This method is not called
+     * immediately after a user dismisses a notification: we wait until we receive confirmation from
+     * system server before considering the notification removed.
      */
     default void onEntryRemoved(
             NotificationEntry entry,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java
similarity index 89%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifLifetimeExtender.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java
index 2c7b138..05f5ea8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifLifetimeExtender.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,9 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification.collection;
+package com.android.systemui.statusbar.notification.collection.notifcollection;
 
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 /**
  * A way for other code to temporarily extend the lifetime of a notification after it has been
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
index c6c36ee..02acc81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
@@ -22,8 +22,8 @@
 
 import com.android.systemui.log.RichEvent;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
-import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer;
+import com.android.systemui.statusbar.notification.collection.ShadeListBuilder;
+import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -67,7 +67,7 @@
     }
 
     /**
-     * @return if this event occurred in {@link NotifListBuilder}
+     * @return if this event occurred in {@link ShadeListBuilder}
      */
     static boolean isListBuilderEvent(@EventType int type) {
         return isBetweenInclusive(type, 0, TOTAL_LIST_BUILDER_EVENT_TYPES);
@@ -161,7 +161,7 @@
     private static final int TOTAL_EVENT_LABELS = EVENT_LABELS.length;
 
     /**
-     * Events related to {@link NotifListBuilder}
+     * Events related to {@link ShadeListBuilder}
      */
     public static final int WARN = 0;
     public static final int ON_BUILD_LIST = 1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 189d3b6..ba70cf4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -199,8 +199,8 @@
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -364,7 +364,7 @@
     private final HeadsUpManagerPhone mHeadsUpManager;
     private final DynamicPrivacyController mDynamicPrivacyController;
     private final BypassHeadsUpNotifier mBypassHeadsUpNotifier;
-    private final Lazy<NewNotifPipeline> mNewNotifPipeline;
+    private final Lazy<NotifPipelineInitializer> mNewNotifPipeline;
     private final FalsingManager mFalsingManager;
     private final BroadcastDispatcher mBroadcastDispatcher;
     private final ConfigurationController mConfigurationController;
@@ -625,7 +625,7 @@
             HeadsUpManagerPhone headsUpManagerPhone,
             DynamicPrivacyController dynamicPrivacyController,
             BypassHeadsUpNotifier bypassHeadsUpNotifier,
-            Lazy<NewNotifPipeline> newNotifPipeline,
+            Lazy<NotifPipelineInitializer> newNotifPipeline,
             FalsingManager falsingManager,
             BroadcastDispatcher broadcastDispatcher,
             RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
index be7f0a0..b4d5dad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
@@ -65,8 +65,8 @@
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
@@ -117,7 +117,7 @@
             HeadsUpManagerPhone headsUpManagerPhone,
             DynamicPrivacyController dynamicPrivacyController,
             BypassHeadsUpNotifier bypassHeadsUpNotifier,
-            Lazy<NewNotifPipeline> newNotifPipeline,
+            Lazy<NotifPipelineInitializer> newNotifPipeline,
             FalsingManager falsingManager,
             BroadcastDispatcher broadcastDispatcher,
             RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 12a6516..720f229 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -66,7 +66,7 @@
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index 9c9a627..8d11b54 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -48,7 +48,7 @@
 import com.android.systemui.appops.AppOpsController;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 
@@ -71,7 +71,7 @@
     @Mock private NotificationEntryManager mEntryManager;
     @Mock private AppOpsController mAppOpsController;
     @Mock private Handler mMainHandler;
-    @Mock private NotifCollection mNotifCollection;
+    @Mock private NotifPipeline mNotifPipeline;
 
     @Before
     public void setUp() throws Exception {
@@ -81,7 +81,7 @@
         MockitoAnnotations.initMocks(this);
         mFsc = new ForegroundServiceController(mEntryManager, mAppOpsController, mMainHandler);
         mListener = new ForegroundServiceNotificationListener(
-                mContext, mFsc, mEntryManager, mNotifCollection);
+                mContext, mFsc, mEntryManager, mNotifPipeline);
         ArgumentCaptor<NotificationEntryListener> entryListenerCaptor =
                 ArgumentCaptor.forClass(NotificationEntryListener.class);
         verify(mEntryManager).addNotificationEntryListener(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 1e0179d..cc5514f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -78,7 +78,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
-import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
index bf84f2b..29ce920 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
@@ -21,7 +21,7 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.NotificationRankingManager
-import com.android.systemui.statusbar.notification.collection.NotificationRowBinder
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder
 import com.android.systemui.statusbar.notification.logging.NotifLog
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index 28feaca..09cc5ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -52,9 +52,13 @@
 import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent;
 import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
-import com.android.systemui.statusbar.notification.collection.notifcollection.CoalescedEvent;
-import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer;
-import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer.BatchableNotificationHandler;
+import com.android.systemui.statusbar.notification.collection.coalescer.CoalescedEvent;
+import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer;
+import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer.BatchableNotificationHandler;
+import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
+import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
 import com.android.systemui.util.Assert;
 
 import org.junit.Before;
@@ -377,7 +381,7 @@
         verify(mExtender3).shouldExtendLifetime(entry2, REASON_UNKNOWN);
 
         // THEN the entry is not removed
-        assertTrue(mCollection.getNotifs().contains(entry2));
+        assertTrue(mCollection.getActiveNotifs().contains(entry2));
 
         // THEN the entry properly records all extenders that returned true
         assertEquals(Arrays.asList(mExtender1, mExtender2), entry2.mLifetimeExtenders);
@@ -398,7 +402,7 @@
 
         // GIVEN a notification gets lifetime-extended by one of them
         mNoMan.retractNotif(notif2.sbn, REASON_APP_CANCEL);
-        assertTrue(mCollection.getNotifs().contains(entry2));
+        assertTrue(mCollection.getActiveNotifs().contains(entry2));
         clearInvocations(mExtender1, mExtender2, mExtender3);
 
         // WHEN the last active extender expires (but new ones become active)
@@ -413,7 +417,7 @@
         verify(mExtender3).shouldExtendLifetime(entry2, REASON_UNKNOWN);
 
         // THEN the entry is not removed
-        assertTrue(mCollection.getNotifs().contains(entry2));
+        assertTrue(mCollection.getActiveNotifs().contains(entry2));
 
         // THEN the entry properly records all extenders that returned true
         assertEquals(Arrays.asList(mExtender1, mExtender3), entry2.mLifetimeExtenders);
@@ -435,7 +439,7 @@
 
         // GIVEN a notification gets lifetime-extended by a couple of them
         mNoMan.retractNotif(notif2.sbn, REASON_APP_CANCEL);
-        assertTrue(mCollection.getNotifs().contains(entry2));
+        assertTrue(mCollection.getActiveNotifs().contains(entry2));
         clearInvocations(mExtender1, mExtender2, mExtender3);
 
         // WHEN one (but not all) of the extenders expires
@@ -443,7 +447,7 @@
         mExtender2.callback.onEndLifetimeExtension(mExtender2, entry2);
 
         // THEN the entry is not removed
-        assertTrue(mCollection.getNotifs().contains(entry2));
+        assertTrue(mCollection.getActiveNotifs().contains(entry2));
 
         // THEN we don't re-query the extenders
         verify(mExtender1, never()).shouldExtendLifetime(eq(entry2), anyInt());
@@ -470,7 +474,7 @@
 
         // GIVEN a notification gets lifetime-extended by a couple of them
         mNoMan.retractNotif(notif2.sbn, REASON_UNKNOWN);
-        assertTrue(mCollection.getNotifs().contains(entry2));
+        assertTrue(mCollection.getActiveNotifs().contains(entry2));
         clearInvocations(mExtender1, mExtender2, mExtender3);
 
         // WHEN all of the active extenders expire
@@ -480,7 +484,7 @@
         mExtender1.callback.onEndLifetimeExtension(mExtender1, entry2);
 
         // THEN the entry removed
-        assertFalse(mCollection.getNotifs().contains(entry2));
+        assertFalse(mCollection.getActiveNotifs().contains(entry2));
         verify(mCollectionListener).onEntryRemoved(entry2, REASON_UNKNOWN, false);
     }
 
@@ -500,7 +504,7 @@
 
         // GIVEN a notification gets lifetime-extended by a couple of them
         mNoMan.retractNotif(notif2.sbn, REASON_UNKNOWN);
-        assertTrue(mCollection.getNotifs().contains(entry2));
+        assertTrue(mCollection.getActiveNotifs().contains(entry2));
         clearInvocations(mExtender1, mExtender2, mExtender3);
 
         // WHEN the notification is reposted
@@ -511,7 +515,7 @@
         verify(mExtender2).cancelLifetimeExtension(entry2);
 
         // THEN the notification is still present
-        assertTrue(mCollection.getNotifs().contains(entry2));
+        assertTrue(mCollection.getActiveNotifs().contains(entry2));
     }
 
     @Test(expected = IllegalStateException.class)
@@ -530,7 +534,7 @@
 
         // GIVEN a notification gets lifetime-extended by a couple of them
         mNoMan.retractNotif(notif2.sbn, REASON_UNKNOWN);
-        assertTrue(mCollection.getNotifs().contains(entry2));
+        assertTrue(mCollection.getActiveNotifs().contains(entry2));
         clearInvocations(mExtender1, mExtender2, mExtender3);
 
         // WHEN a lifetime extender makes a reentrant call during cancelLifetimeExtension()
@@ -559,7 +563,7 @@
 
         // GIVEN a notification gets lifetime-extended by a couple of them
         mNoMan.retractNotif(notif2.sbn, REASON_UNKNOWN);
-        assertTrue(mCollection.getNotifs().contains(entry2));
+        assertTrue(mCollection.getActiveNotifs().contains(entry2));
         clearInvocations(mExtender1, mExtender2, mExtender3);
 
         // WHEN the notification is reposted
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 3e4068b..be06748 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -38,7 +38,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl.OnRenderListListener;
+import com.android.systemui.statusbar.notification.collection.ShadeListBuilder.OnRenderListListener;
 import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
 import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
 import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener;
@@ -46,6 +46,7 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.SectionsProvider;
+import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
 import com.android.systemui.util.Assert;
 import com.android.systemui.util.time.FakeSystemClock;
@@ -72,9 +73,9 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
-public class NotifListBuilderImplTest extends SysuiTestCase {
+public class ShadeListBuilderTest extends SysuiTestCase {
 
-    private NotifListBuilderImpl mListBuilder;
+    private ShadeListBuilder mListBuilder;
     private FakeSystemClock mSystemClock = new FakeSystemClock();
 
     @Mock private NotifLog mNotifLog;
@@ -99,7 +100,7 @@
         MockitoAnnotations.initMocks(this);
         Assert.sMainLooper = TestableLooper.get(this).getLooper();
 
-        mListBuilder = new NotifListBuilderImpl(mSystemClock, mNotifLog);
+        mListBuilder = new ShadeListBuilder(mSystemClock, mNotifLog);
         mListBuilder.setOnRenderListListener(mOnRenderListListener);
 
         mListBuilder.attach(mNotifCollection);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescerTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
index 7ff3240..5e0baf2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification.collection.notifcollection;
+package com.android.systemui.statusbar.notification.collection.coalescer;
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
index ea6c70a..701cf95 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
@@ -36,7 +36,7 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.RankingBuilder;
-import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
@@ -65,7 +65,7 @@
     @Mock private ActivityManagerInternal mActivityMangerInternal;
     @Mock private IPackageManager mIPackageManager;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
-    @Mock private NotifListBuilderImpl mNotifListBuilder;
+    @Mock private NotifPipeline mNotifPipeline;
     private Notification mNotification;
     private NotificationEntry mEntry;
     private DeviceProvisionedCoordinator mDeviceProvisionedCoordinator;
@@ -84,8 +84,8 @@
                 .build();
 
         ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
-        mDeviceProvisionedCoordinator.attach(null, mNotifListBuilder);
-        verify(mNotifListBuilder, times(1)).addPreGroupFilter(filterCaptor.capture());
+        mDeviceProvisionedCoordinator.attach(mNotifPipeline);
+        verify(mNotifPipeline, times(1)).addPreGroupFilter(filterCaptor.capture());
         mDeviceProvisionedFilter = filterCaptor.getValue();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java
index 01bca0d..6cc8dd9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java
@@ -36,12 +36,11 @@
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.appops.AppOpsController;
-import com.android.systemui.statusbar.notification.collection.NotifCollection;
-import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender;
-import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -59,8 +58,7 @@
     @Mock private Handler mMainHandler;
     @Mock private ForegroundServiceController mForegroundServiceController;
     @Mock private AppOpsController mAppOpsController;
-    @Mock private NotifListBuilderImpl mNotifListBuilder;
-    @Mock private NotifCollection mNotifCollection;
+    @Mock private NotifPipeline mNotifPipeline;
 
     private NotificationEntry mEntry;
     private Notification mNotification;
@@ -84,9 +82,9 @@
         ArgumentCaptor<NotifLifetimeExtender> lifetimeExtenderCaptor =
                 ArgumentCaptor.forClass(NotifLifetimeExtender.class);
 
-        mForegroundCoordinator.attach(mNotifCollection, mNotifListBuilder);
-        verify(mNotifListBuilder, times(1)).addPreGroupFilter(filterCaptor.capture());
-        verify(mNotifCollection, times(1)).addNotificationLifetimeExtender(
+        mForegroundCoordinator.attach(mNotifPipeline);
+        verify(mNotifPipeline, times(1)).addPreGroupFilter(filterCaptor.capture());
+        verify(mNotifPipeline, times(1)).addNotificationLifetimeExtender(
                 lifetimeExtenderCaptor.capture());
 
         mForegroundFilter = filterCaptor.getValue();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
index f921cf9..5866d90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
@@ -41,7 +41,7 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.notification.collection.GroupEntry;
-import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
@@ -68,7 +68,7 @@
     @Mock private StatusBarStateController mStatusBarStateController;
     @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock private HighPriorityProvider mHighPriorityProvider;
-    @Mock private NotifListBuilderImpl mNotifListBuilder;
+    @Mock private NotifPipeline mNotifPipeline;
 
     private NotificationEntry mEntry;
     private KeyguardCoordinator mKeyguardCoordinator;
@@ -87,8 +87,8 @@
                 .build();
 
         ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
-        mKeyguardCoordinator.attach(null, mNotifListBuilder);
-        verify(mNotifListBuilder, times(1)).addPreRenderFilter(filterCaptor.capture());
+        mKeyguardCoordinator.attach(mNotifPipeline);
+        verify(mNotifPipeline, times(1)).addPreRenderFilter(filterCaptor.capture());
         mKeyguardFilter = filterCaptor.getValue();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
index d3b16c3..e84f9cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
@@ -33,7 +33,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.RankingBuilder;
-import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
@@ -50,7 +50,7 @@
 public class RankingCoordinatorTest extends SysuiTestCase {
 
     @Mock private StatusBarStateController mStatusBarStateController;
-    @Mock private NotifListBuilderImpl mNotifListBuilder;
+    @Mock private NotifPipeline mNotifPipeline;
     private NotificationEntry mEntry;
     private RankingCoordinator mRankingCoordinator;
     private NotifFilter mRankingFilter;
@@ -62,8 +62,8 @@
         mEntry = new NotificationEntryBuilder().build();
 
         ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
-        mRankingCoordinator.attach(null, mNotifListBuilder);
-        verify(mNotifListBuilder, times(1)).addPreGroupFilter(filterCaptor.capture());
+        mRankingCoordinator.attach(mNotifPipeline);
+        verify(mNotifPipeline, times(1)).addPreGroupFilter(filterCaptor.capture());
         mRankingFilter = filterCaptor.getValue();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 9bd3914..d9939f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -71,7 +71,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
-import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
 import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewAdapter;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index 5ac7bfb..782e14c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -54,7 +54,7 @@
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 560aadb..fee4852 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -120,8 +120,8 @@
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
@@ -214,7 +214,7 @@
     @Mock private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
     @Mock private KeyguardBypassController mKeyguardBypassController;
     @Mock private DynamicPrivacyController mDynamicPrivacyController;
-    @Mock private NewNotifPipeline mNewNotifPipeline;
+    @Mock private NotifPipelineInitializer mNewNotifPipeline;
     @Mock private ZenModeController mZenModeController;
     @Mock private AutoHideController mAutoHideController;
     @Mock private NotificationViewHierarchyManager mNotificationViewHierarchyManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 4103d71..cd89d3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -30,12 +30,12 @@
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 
-import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.settingslib.graph.SignalDrawable;
 import com.android.settingslib.net.DataUsageController;
@@ -418,7 +418,7 @@
 
         intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn);
         intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn);
-        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, mSubId);
+        SubscriptionManager.putSubscriptionIdExtra(intent, mSubId);
 
         return intent;
     }
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index e1fe3bf..900c671 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -501,13 +501,15 @@
         p2pInfo.groupFormed = isGroupFormed;
         p2pInfo.isGroupOwner = isGroupOwner;
 
-        WifiP2pGroup group = new WifiP2pGroup();
-        group.setIsGroupOwner(isGroupOwner);
-        group.setInterface(ifname);
+        WifiP2pGroup group = mock(WifiP2pGroup.class);
+        when(group.isGroupOwner()).thenReturn(isGroupOwner);
+        when(group.getInterface()).thenReturn(ifname);
 
-        final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
-        intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, p2pInfo);
-        intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, group);
+        final Intent intent = mock(Intent.class);
+        when(intent.getAction()).thenReturn(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
+        when(intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO)).thenReturn(p2pInfo);
+        when(intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP)).thenReturn(group);
+
         mServiceContext.sendBroadcastAsUserMultiplePermissions(intent, UserHandle.ALL,
                 P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST);
     }
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index eb62620..b06fc52 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -21,12 +21,10 @@
 import static com.android.server.backup.BackupManagerService.TAG;
 
 import android.app.backup.RestoreSet;
-import android.content.Intent;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.util.EventLog;
 import android.util.Pair;
 import android.util.Slog;
@@ -40,7 +38,6 @@
 import com.android.server.backup.TransportManager;
 import com.android.server.backup.UserBackupManagerService;
 import com.android.server.backup.fullbackup.PerformAdbBackupTask;
-import com.android.server.backup.fullbackup.PerformFullTransportBackupTask;
 import com.android.server.backup.keyvalue.BackupRequest;
 import com.android.server.backup.keyvalue.KeyValueBackupTask;
 import com.android.server.backup.params.AdbBackupParams;
@@ -73,10 +70,7 @@
     public static final int MSG_RESTORE_SESSION_TIMEOUT = 8;
     public static final int MSG_FULL_CONFIRMATION_TIMEOUT = 9;
     public static final int MSG_RUN_ADB_RESTORE = 10;
-    public static final int MSG_RETRY_INIT = 11;
     public static final int MSG_RETRY_CLEAR = 12;
-    public static final int MSG_WIDGET_BROADCAST = 13;
-    public static final int MSG_RUN_FULL_TRANSPORT_BACKUP = 14;
     public static final int MSG_REQUEST_BACKUP = 15;
     public static final int MSG_SCHEDULE_BACKUP_PACKAGE = 16;
     public static final int MSG_BACKUP_OPERATION_TIMEOUT = 17;
@@ -279,12 +273,6 @@
                 break;
             }
 
-            case MSG_RUN_FULL_TRANSPORT_BACKUP: {
-                PerformFullTransportBackupTask task = (PerformFullTransportBackupTask) msg.obj;
-                (new Thread(task, "transport-backup")).start();
-                break;
-            }
-
             case MSG_RUN_RESTORE: {
                 RestoreParams params = (RestoreParams) msg.obj;
                 Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
@@ -445,12 +433,6 @@
                 break;
             }
 
-            case MSG_WIDGET_BROADCAST: {
-                final Intent intent = (Intent) msg.obj;
-                backupManagerService.getContext().sendBroadcastAsUser(intent, UserHandle.SYSTEM);
-                break;
-            }
-
             case MSG_REQUEST_BACKUP: {
                 BackupParams params = (BackupParams) msg.obj;
                 if (MORE_DEBUG) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index f4962e5..5435cba 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5505,7 +5505,10 @@
     // changes that would conflict throughout the automerger graph. Having this method temporarily
     // helps with the process of going through with all these dependent changes across the entire
     // tree.
-    public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
+    /**
+     * Register a new agent. {@see #registerNetworkAgent} below.
+     */
+    public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
             LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
             int currentScore, NetworkAgentConfig networkAgentConfig) {
         return registerNetworkAgent(messenger, networkInfo, linkProperties, networkCapabilities,
@@ -5526,8 +5529,9 @@
      *         {@link NetworkAgentInfo#getCurrentScore}.
      * @param networkAgentConfig metadata about the network. This is never updated.
      * @param providerId the ID of the provider owning this NetworkAgent.
+     * @return the network created for this agent.
      */
-    public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
+    public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
             LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
             int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
         enforceNetworkFactoryPermission();
@@ -5560,7 +5564,7 @@
         // If the network disconnects or sends any other event before that, messages are deferred by
         // NetworkAgent until nai.asyncChannel.connect(), which will be called when finalizing the
         // registration.
-        return nai.network.netId;
+        return nai.network;
     }
 
     private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) {
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index b26ef92..d1d1cb3 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -523,7 +523,7 @@
 
         @Override
         public void accept(INetworkScoreCache networkScoreCache, Object cookie) {
-            int filterType = NetworkScoreManager.CACHE_FILTER_NONE;
+            int filterType = NetworkScoreManager.SCORE_FILTER_NONE;
             if (cookie instanceof Integer) {
                 filterType = (Integer) cookie;
             }
@@ -547,17 +547,17 @@
         private List<ScoredNetwork> filterScores(List<ScoredNetwork> scoredNetworkList,
                 int filterType) {
             switch (filterType) {
-                case NetworkScoreManager.CACHE_FILTER_NONE:
+                case NetworkScoreManager.SCORE_FILTER_NONE:
                     return scoredNetworkList;
 
-                case NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK:
+                case NetworkScoreManager.SCORE_FILTER_CURRENT_NETWORK:
                     if (mCurrentNetworkFilter == null) {
                         mCurrentNetworkFilter =
                                 new CurrentNetworkScoreCacheFilter(new WifiInfoSupplier(mContext));
                     }
                     return mCurrentNetworkFilter.apply(scoredNetworkList);
 
-                case NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS:
+                case NetworkScoreManager.SCORE_FILTER_SCAN_RESULTS:
                     if (mScanResultsFilter == null) {
                         mScanResultsFilter = new ScanResultsScoreCacheFilter(
                                 new ScanResultsSupplier(mContext));
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index c27b0da..ed3bab9 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -218,7 +218,7 @@
             // Has to be in TestNetworkAgent to ensure all teardown codepaths properly clean up
             // resources, even for binder death or unwanted calls.
             synchronized (mTestNetworkTracker) {
-                mTestNetworkTracker.remove(netId);
+                mTestNetworkTracker.remove(network.netId);
             }
         }
     }
@@ -337,7 +337,7 @@
                                             callingUid,
                                             binder);
 
-                            mTestNetworkTracker.put(agent.netId, agent);
+                            mTestNetworkTracker.put(agent.network.netId, agent);
                         }
                     } catch (SocketException e) {
                         throw new UncheckedIOException(e);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index a372fca0..debc2a1 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -2129,16 +2129,6 @@
     }
 
     @Override
-    public void removeAccount(IAccountManagerResponse response, Account account,
-            boolean expectActivityLaunch) {
-        removeAccountAsUser(
-                response,
-                account,
-                expectActivityLaunch,
-                UserHandle.getCallingUserId());
-    }
-
-    @Override
     public void removeAccountAsUser(IAccountManagerResponse response, Account account,
             boolean expectActivityLaunch, int userId) {
         final int callingUid = Binder.getCallingUid();
@@ -4454,12 +4444,6 @@
 
     @Override
     @NonNull
-    public Account[] getAccounts(String type, String opPackageName) {
-        return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
-    }
-
-    @Override
-    @NonNull
     public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
         int callingUid = Binder.getCallingUid();
         if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c21adb0..8f6d981 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16408,6 +16408,22 @@
     }
 
     @Override
+    public boolean updateMccMncConfiguration(String mcc, String mnc) {
+        int mccInt, mncInt;
+        try {
+            mccInt = Integer.parseInt(mcc);
+            mncInt = Integer.parseInt(mnc);
+        } catch (NumberFormatException | StringIndexOutOfBoundsException ex) {
+            Slog.e(TAG, "Error parsing mcc: " + mcc + " mnc: " + mnc + ". ex=" + ex);
+            return false;
+        }
+        Configuration config = new Configuration();
+        config.mcc = mccInt;
+        config.mnc = mncInt == 0 ? Configuration.MNC_ZERO : mncInt;
+        return mActivityTaskManager.updateConfiguration(config);
+    }
+
+    @Override
     public int getLaunchedFromUid(IBinder activityToken) {
         return mActivityTaskManager.getLaunchedFromUid(activityToken);
     }
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index f15d999..8d26176 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -367,6 +367,8 @@
         CompatConfig config = new CompatConfig(androidBuildClassifier, context);
         config.initConfigFromLib(Environment.buildPath(
                 Environment.getRootDirectory(), "etc", "compatconfig"));
+        config.initConfigFromLib(Environment.buildPath(
+                Environment.getRootDirectory(), "system_ext", "etc", "compatconfig"));
         return config;
     }
 
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 476f3f8..1d2a905 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -848,7 +848,7 @@
     }
 
     public int getNetId() {
-        return mNetworkAgent != null ? mNetworkAgent.netId : NETID_UNSET;
+        return mNetworkAgent != null ? mNetworkAgent.network.netId : NETID_UNSET;
     }
 
     private LinkProperties makeLinkProperties() {
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 0d315cd..408c1c9 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -23,18 +23,22 @@
 import android.media.MediaRoute2ProviderInfo;
 import android.media.RoutingSessionInfo;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 
 abstract class MediaRoute2Provider {
     final ComponentName mComponentName;
     final String mUniqueId;
+    final Object mLock = new Object();
 
     Callback mCallback;
     private volatile MediaRoute2ProviderInfo mProviderInfo;
-    private volatile List<RoutingSessionInfo> mSessionInfos = Collections.emptyList();
+
+    @GuardedBy("mLock")
+    final List<RoutingSessionInfo> mSessionInfos = new ArrayList<>();
 
     MediaRoute2Provider(@NonNull ComponentName componentName) {
         mComponentName = Objects.requireNonNull(componentName, "Component name must not be null.");
@@ -69,11 +73,12 @@
 
     @NonNull
     public List<RoutingSessionInfo> getSessionInfos() {
-        return mSessionInfos;
+        synchronized (mLock) {
+            return mSessionInfos;
+        }
     }
 
-    void setProviderState(MediaRoute2ProviderInfo providerInfo,
-            List<RoutingSessionInfo> sessionInfos) {
+    void setProviderState(MediaRoute2ProviderInfo providerInfo) {
         if (providerInfo == null) {
             mProviderInfo = null;
         } else {
@@ -81,14 +86,6 @@
                     .setUniqueId(mUniqueId)
                     .build();
         }
-        List<RoutingSessionInfo> sessionInfoWithProviderId = new ArrayList<RoutingSessionInfo>();
-        for (RoutingSessionInfo sessionInfo : sessionInfos) {
-            sessionInfoWithProviderId.add(
-                    new RoutingSessionInfo.Builder(sessionInfo)
-                            .setProviderId(mUniqueId)
-                            .build());
-        }
-        mSessionInfos = sessionInfoWithProviderId;
     }
 
     void notifyProviderState() {
@@ -97,9 +94,8 @@
         }
     }
 
-    void setAndNotifyProviderState(MediaRoute2ProviderInfo providerInfo,
-            List<RoutingSessionInfo> sessionInfos) {
-        setProviderState(providerInfo, sessionInfos);
+    void setAndNotifyProviderState(MediaRoute2ProviderInfo providerInfo) {
+        setProviderState(providerInfo);
         notifyProviderState();
     }
 
@@ -112,10 +108,9 @@
         void onProviderStateChanged(@Nullable MediaRoute2Provider provider);
         void onSessionCreated(@NonNull MediaRoute2Provider provider,
                 @Nullable RoutingSessionInfo sessionInfo, long requestId);
-        // TODO: Remove this when MediaRouter2ServiceImpl notifies clients of session changes.
-        void onSessionInfoChanged(@NonNull MediaRoute2Provider provider,
+        void onSessionCreationFailed(@NonNull MediaRoute2Provider provider, long requestId);
+        void onSessionUpdated(@NonNull MediaRoute2Provider provider,
                 @NonNull RoutingSessionInfo sessionInfo);
-        // TODO: Call this when service actually notifies of session release.
         void onSessionReleased(@NonNull MediaRoute2Provider provider,
                 @NonNull RoutingSessionInfo sessionInfo);
     }
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
index c0ad46f..3840d02 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
@@ -17,7 +17,6 @@
 package com.android.server.media;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -37,8 +36,6 @@
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
-import java.util.Collections;
-import java.util.List;
 import java.util.Objects;
 
 /**
@@ -270,35 +267,69 @@
     }
 
     private void onProviderStateUpdated(Connection connection,
-            MediaRoute2ProviderInfo providerInfo, List<RoutingSessionInfo> sessionInfos) {
+            MediaRoute2ProviderInfo providerInfo) {
         if (mActiveConnection != connection) {
             return;
         }
         if (DEBUG) {
             Slog.d(TAG, this + ": State changed ");
         }
-        setAndNotifyProviderState(providerInfo, sessionInfos);
+        setAndNotifyProviderState(providerInfo);
     }
 
-    private void onSessionCreated(Connection connection, @Nullable RoutingSessionInfo sessionInfo,
+    private void onSessionCreated(Connection connection, RoutingSessionInfo sessionInfo,
             long requestId) {
         if (mActiveConnection != connection) {
             return;
         }
-        if (sessionInfo != null) {
-            sessionInfo = new RoutingSessionInfo.Builder(sessionInfo)
-                    .setProviderId(getUniqueId())
-                    .build();
+
+        if (sessionInfo == null) {
+            Slog.w(TAG, "onSessionCreated: Ignoring null sessionInfo sent from " + mComponentName);
+            return;
         }
+
+        sessionInfo = new RoutingSessionInfo.Builder(sessionInfo)
+                .setProviderId(getUniqueId())
+                .build();
+
+        boolean duplicateSessionAlreadyExists = false;
+        synchronized (mLock) {
+            for (int i = 0; i < mSessionInfos.size(); i++) {
+                if (mSessionInfos.get(i).getId().equals(sessionInfo.getId())) {
+                    duplicateSessionAlreadyExists = true;
+                    break;
+                }
+            }
+            mSessionInfos.add(sessionInfo);
+        }
+
+        if (duplicateSessionAlreadyExists) {
+            Slog.w(TAG, "onSessionCreated: Duplicate session already exists. Ignoring.");
+            return;
+        }
+
         mCallback.onSessionCreated(this, sessionInfo, requestId);
     }
 
-    private void onSessionInfoChanged(Connection connection, RoutingSessionInfo sessionInfo) {
+    private void onSessionCreationFailed(Connection connection, long requestId) {
+        if (mActiveConnection != connection) {
+            return;
+        }
+
+        if (requestId == MediaRoute2ProviderService.REQUEST_ID_UNKNOWN) {
+            Slog.w(TAG, "onSessionCreationFailed: Ignoring requestId REQUEST_ID_UNKNOWN");
+            return;
+        }
+
+        mCallback.onSessionCreationFailed(this, requestId);
+    }
+
+    private void onSessionUpdated(Connection connection, RoutingSessionInfo sessionInfo) {
         if (mActiveConnection != connection) {
             return;
         }
         if (sessionInfo == null) {
-            Slog.w(TAG, "onSessionInfoChanged: Ignoring null sessionInfo sent from "
+            Slog.w(TAG, "onSessionUpdated: Ignoring null sessionInfo sent from "
                     + mComponentName);
             return;
         }
@@ -307,7 +338,55 @@
                 .setProviderId(getUniqueId())
                 .build();
 
-        mCallback.onSessionInfoChanged(this, sessionInfo);
+        boolean found = false;
+        synchronized (mLock) {
+            for (int i = 0; i < mSessionInfos.size(); i++) {
+                if (mSessionInfos.get(i).getId().equals(sessionInfo.getId())) {
+                    mSessionInfos.set(i, sessionInfo);
+                    found = true;
+                    break;
+                }
+            }
+        }
+
+        if (!found) {
+            Slog.w(TAG, "onSessionUpdated: Matching session info not found");
+            return;
+        }
+
+        mCallback.onSessionUpdated(this, sessionInfo);
+    }
+
+    private void onSessionReleased(Connection connection, RoutingSessionInfo sessionInfo) {
+        if (mActiveConnection != connection) {
+            return;
+        }
+        if (sessionInfo == null) {
+            Slog.w(TAG, "onSessionReleased: Ignoring null sessionInfo sent from " + mComponentName);
+            return;
+        }
+
+        sessionInfo = new RoutingSessionInfo.Builder(sessionInfo)
+                .setProviderId(getUniqueId())
+                .build();
+
+        boolean found = false;
+        synchronized (mLock) {
+            for (int i = 0; i < mSessionInfos.size(); i++) {
+                if (mSessionInfos.get(i).getId().equals(sessionInfo.getId())) {
+                    mSessionInfos.remove(i);
+                    found = true;
+                    break;
+                }
+            }
+        }
+
+        if (!found) {
+            Slog.w(TAG, "onSessionReleased: Matching session info not found");
+            return;
+        }
+
+        mCallback.onSessionReleased(this, sessionInfo);
     }
 
     private void disconnect() {
@@ -315,7 +394,7 @@
             mConnectionReady = false;
             mActiveConnection.dispose();
             mActiveConnection = null;
-            setAndNotifyProviderState(null, Collections.emptyList());
+            setAndNotifyProviderState(null);
         }
     }
 
@@ -421,19 +500,24 @@
             mHandler.post(() -> onConnectionDied(Connection.this));
         }
 
-        void postProviderStateUpdated(MediaRoute2ProviderInfo providerInfo,
-                List<RoutingSessionInfo> sessionInfos) {
-            mHandler.post(() -> onProviderStateUpdated(Connection.this,
-                    providerInfo, sessionInfos));
+        void postProviderStateUpdated(MediaRoute2ProviderInfo providerInfo) {
+            mHandler.post(() -> onProviderStateUpdated(Connection.this, providerInfo));
         }
 
-        void postSessionCreated(@Nullable RoutingSessionInfo sessionInfo, long requestId) {
-            mHandler.post(() -> onSessionCreated(Connection.this, sessionInfo,
-                    requestId));
+        void postSessionCreated(RoutingSessionInfo sessionInfo, long requestId) {
+            mHandler.post(() -> onSessionCreated(Connection.this, sessionInfo, requestId));
         }
 
-        void postSessionInfoChanged(RoutingSessionInfo sessionInfo) {
-            mHandler.post(() -> onSessionInfoChanged(Connection.this, sessionInfo));
+        void postSessionCreationFailed(long requestId) {
+            mHandler.post(() -> onSessionCreationFailed(Connection.this, requestId));
+        }
+
+        void postSessionUpdated(RoutingSessionInfo sessionInfo) {
+            mHandler.post(() -> onSessionUpdated(Connection.this, sessionInfo));
+        }
+
+        void postSessionReleased(RoutingSessionInfo sessionInfo) {
+            mHandler.post(() -> onSessionReleased(Connection.this, sessionInfo));
         }
     }
 
@@ -449,16 +533,15 @@
         }
 
         @Override
-        public void updateState(MediaRoute2ProviderInfo providerInfo,
-                List<RoutingSessionInfo> sessionInfos) {
+        public void updateState(MediaRoute2ProviderInfo providerInfo) {
             Connection connection = mConnectionRef.get();
             if (connection != null) {
-                connection.postProviderStateUpdated(providerInfo, sessionInfos);
+                connection.postProviderStateUpdated(providerInfo);
             }
         }
 
         @Override
-        public void notifySessionCreated(@Nullable RoutingSessionInfo sessionInfo, long requestId) {
+        public void notifySessionCreated(RoutingSessionInfo sessionInfo, long requestId) {
             Connection connection = mConnectionRef.get();
             if (connection != null) {
                 connection.postSessionCreated(sessionInfo, requestId);
@@ -466,10 +549,26 @@
         }
 
         @Override
-        public void notifySessionInfoChanged(RoutingSessionInfo sessionInfo) {
+        public void notifySessionCreationFailed(long requestId) {
             Connection connection = mConnectionRef.get();
             if (connection != null) {
-                connection.postSessionInfoChanged(sessionInfo);
+                connection.postSessionCreationFailed(requestId);
+            }
+        }
+
+        @Override
+        public void notifySessionUpdated(RoutingSessionInfo sessionInfo) {
+            Connection connection = mConnectionRef.get();
+            if (connection != null) {
+                connection.postSessionUpdated(sessionInfo);
+            }
+        }
+
+        @Override
+        public void notifySessionReleased(RoutingSessionInfo sessionInfo) {
+            Connection connection = mConnectionRef.get();
+            if (connection != null) {
+                connection.postSessionReleased(sessionInfo);
             }
         }
     }
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index c48c90d..d940e35 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -22,7 +22,6 @@
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.Intent;
@@ -31,6 +30,7 @@
 import android.media.IMediaRouter2Manager;
 import android.media.MediaRoute2Info;
 import android.media.MediaRoute2ProviderInfo;
+import android.media.MediaRoute2ProviderService;
 import android.media.RouteDiscoveryPreference;
 import android.media.RoutingSessionInfo;
 import android.os.Binder;
@@ -876,13 +876,19 @@
 
         @Override
         public void onSessionCreated(@NonNull MediaRoute2Provider provider,
-                @Nullable RoutingSessionInfo sessionInfo, long requestId) {
+                @NonNull RoutingSessionInfo sessionInfo, long requestId) {
             sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionCreatedOnHandler,
                     this, provider, sessionInfo, requestId));
         }
 
         @Override
-        public void onSessionInfoChanged(@NonNull MediaRoute2Provider provider,
+        public void onSessionCreationFailed(@NonNull MediaRoute2Provider provider, long requestId) {
+            sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionCreationFailedOnHandler,
+                    this, provider, requestId));
+        }
+
+        @Override
+        public void onSessionUpdated(@NonNull MediaRoute2Provider provider,
                 @NonNull RoutingSessionInfo sessionInfo) {
             sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionInfoChangedOnHandler,
                     this, provider, sessionInfo));
@@ -1132,7 +1138,14 @@
         }
 
         private void onSessionCreatedOnHandler(@NonNull MediaRoute2Provider provider,
-                @Nullable RoutingSessionInfo sessionInfo, long requestId) {
+                @NonNull RoutingSessionInfo sessionInfo, long requestId) {
+
+            if (requestId == MediaRoute2ProviderService.REQUEST_ID_UNKNOWN) {
+                // The session is created without any matching request.
+                // TODO: Tell managers for the session creation
+                return;
+            }
+
             SessionCreationRequest matchingRequest = null;
 
             for (SessionCreationRequest request : mSessionCreationRequests) {
@@ -1182,6 +1195,30 @@
             // TODO: Tell managers for the session creation
         }
 
+        private void onSessionCreationFailedOnHandler(@NonNull MediaRoute2Provider provider,
+                long requestId) {
+            SessionCreationRequest matchingRequest = null;
+
+            for (SessionCreationRequest request : mSessionCreationRequests) {
+                if (request.mRequestId == requestId
+                        && TextUtils.equals(
+                                request.mRoute.getProviderId(), provider.getUniqueId())) {
+                    matchingRequest = request;
+                    break;
+                }
+            }
+
+            if (matchingRequest == null) {
+                Slog.w(TAG, "Ignoring session creation failed result for unknown request. "
+                        + "requestId=" + requestId);
+                return;
+            }
+
+            mSessionCreationRequests.remove(matchingRequest);
+            notifySessionCreationFailed(matchingRequest.mClientRecord,
+                    toClientRequestId(requestId));
+        }
+
         private void onSessionInfoChangedOnHandler(@NonNull MediaRoute2Provider provider,
                 @NonNull RoutingSessionInfo sessionInfo) {
 
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 961d3d0..6695227 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -169,7 +169,7 @@
         for (MediaRoute2Info route : mBluetoothRoutes) {
             builder.addRoute(route);
         }
-        setProviderState(builder.build(), Collections.emptyList());
+        setProviderState(builder.build());
         mHandler.post(() -> notifyProviderState());
     }
 
@@ -212,6 +212,6 @@
         for (MediaRoute2Info route : mBluetoothRoutes) {
             builder.addRoute(route);
         }
-        setAndNotifyProviderState(builder.build(), Collections.emptyList());
+        setAndNotifyProviderState(builder.build());
     }
 }
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index ffcd6cf..bcfe577 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -338,9 +338,8 @@
     }
 
     @GuardedBy("mService.mLock")
-    public void onPackageUninstalledLPw(@NonNull AndroidPackage pkg,
+    public void onPackageUninstalledLPw(@NonNull AndroidPackage pkg, @Nullable PackageSetting ps,
             @NonNull int[] userIds) {
-        PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
         if (ps == null) {
             return;
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index dad32cd..159b4e4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -17502,7 +17502,8 @@
             synchronized (mLock) {
                 if (res) {
                     if (pkg != null) {
-                        mInstantAppRegistry.onPackageUninstalledLPw(pkg, info.removedUsers);
+                        mInstantAppRegistry.onPackageUninstalledLPw(pkg, uninstalledPs,
+                                info.removedUsers);
                     }
                     updateSequenceNumberLP(uninstalledPs, info.removedUsers);
                     updateInstantAppInstallerLocked(packageName);
diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
index 5271493..6daf516 100644
--- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java
+++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
@@ -743,8 +743,8 @@
             } else if (TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
                 // Airplane mode can be changed after ECM exits if airplane toggle button
                 // is pressed during ECM mode
-                if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) &&
-                        mIsWaitingForEcmExit) {
+                if (!(intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false))
+                        && mIsWaitingForEcmExit) {
                     mIsWaitingForEcmExit = false;
                     changeAirplaneModeSystemSetting(true);
                 }
diff --git a/services/core/java/com/android/server/stats/StatsPullAtomService.java b/services/core/java/com/android/server/stats/StatsPullAtomService.java
index bb910b2..5ee7eff 100644
--- a/services/core/java/com/android/server/stats/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/StatsPullAtomService.java
@@ -911,11 +911,26 @@
     }
 
     private void registerPowerProfile() {
-        // No op.
+        int tagId = StatsLog.POWER_PROFILE;
+        mStatsManager.registerPullAtomCallback(
+                tagId,
+                /* PullAtomMetadata */ null,
+                (atomTag, data) -> pullPowerProfile(atomTag, data),
+                Executors.newSingleThreadExecutor()
+        );
     }
 
-    private void pullPowerProfile() {
-        // No op.
+    private int pullPowerProfile(int atomTag, List<StatsEvent> pulledData) {
+        PowerProfile powerProfile = new PowerProfile(mContext);
+        ProtoOutputStream proto = new ProtoOutputStream();
+        powerProfile.dumpDebug(proto);
+        proto.flush();
+        StatsEvent e = StatsEvent.newBuilder()
+                .setAtomId(atomTag)
+                .writeByteArray(proto.getBytes())
+                .build();
+        pulledData.add(e);
+        return StatsManager.PULL_SUCCESS;
     }
 
     private void registerProcessCpuTime() {
diff --git a/services/core/java/com/android/server/utils/quota/QuotaTracker.java b/services/core/java/com/android/server/utils/quota/QuotaTracker.java
index ef1f426..a8cf9f6 100644
--- a/services/core/java/com/android/server/utils/quota/QuotaTracker.java
+++ b/services/core/java/com/android/server/utils/quota/QuotaTracker.java
@@ -172,6 +172,16 @@
 
     // Exposed API to users.
 
+    /** Remove all saved events from the tracker. */
+    public void clear() {
+        synchronized (mLock) {
+            mInQuotaAlarmListener.clearLocked();
+            mFreeQuota.clear();
+
+            dropEverythingLocked();
+        }
+    }
+
     /**
      * @return true if the UPTC is within quota, false otherwise.
      * @throws IllegalStateException if given categorizer returns a Category that's not recognized.
@@ -245,10 +255,7 @@
             mIsEnabled = enable;
 
             if (!mIsEnabled) {
-                mInQuotaAlarmListener.clearLocked();
-                mFreeQuota.clear();
-
-                dropEverythingLocked();
+                clear();
             }
         }
     }
diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
index 4696dd0..0275f3e 100644
--- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp
+++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
@@ -33,7 +33,6 @@
 #include "bpf/BpfUtils.h"
 #include "netdbpf/BpfNetworkStats.h"
 
-using android::bpf::Stats;
 using android::bpf::bpfGetUidStats;
 using android::bpf::bpfGetIfaceStats;
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6b81fdd..485899e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -23,7 +23,6 @@
 import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
 import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY;
-import static android.app.admin.DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED;
 import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE;
 import static android.app.admin.DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED;
 import static android.app.admin.DevicePolicyManager.CODE_HAS_DEVICE_OWNER;
@@ -4118,6 +4117,12 @@
         if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER, userHandle)) {
             mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false, userHandle);
         }
+        // When a device owner is set, the system automatically restricts adding a managed profile.
+        // Remove this restriction when the device owner is cleared.
+        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, userHandle)) {
+            mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, false,
+                    userHandle);
+        }
     }
 
     /**
@@ -8056,10 +8061,19 @@
             updateDeviceOwnerLocked();
             setDeviceOwnerSystemPropertyLocked();
 
-            // TODO Send to system too?
-            mInjector.binderWithCleanCallingIdentity(
-                    () -> sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED,
-                            userId));
+            mInjector.binderWithCleanCallingIdentity(() -> {
+                // Restrict adding a managed profile when a device owner is set on the device.
+                // That is to prevent the co-existence of a managed profile and a device owner
+                // on the same device.
+                // Instead, the device may be provisioned with an organization-owned managed
+                // profile, such that the admin on that managed profile has extended management
+                // capabilities that can affect the entire device (but not access private data
+                // on the primary profile).
+                mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true,
+                        UserHandle.of(userId));
+                // TODO Send to system too?
+                sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED, userId);
+            });
             mDeviceAdminServiceController.startServiceForOwner(
                     admin.getPackageName(), userId, "set-device-owner");
 
@@ -8322,6 +8336,17 @@
                 throw new IllegalArgumentException("Not active admin: " + who);
             }
 
+            final int parentUserId = getProfileParentId(userHandle);
+            // When trying to set a profile owner on a new user, it may be that this user is
+            // a profile - but it may not be a managed profile if there's a restriction on the
+            // parent to add managed profiles (e.g. if the device has a device owner).
+            if (parentUserId != userHandle && mUserManager.hasUserRestriction(
+                    UserManager.DISALLOW_ADD_MANAGED_PROFILE,
+                    UserHandle.of(parentUserId))) {
+                Slog.i(LOG_TAG, "Cannot set profile owner because of restriction.");
+                return false;
+            }
+
             if (isAdb()) {
                 // Log profile owner provisioning was started using adb.
                 MetricsLogger.action(mContext, PROVISIONING_ENTRY_POINT_ADB, LOG_TAG_PROFILE_OWNER);
@@ -12387,25 +12412,41 @@
         final long ident = mInjector.binderClearCallingIdentity();
         try {
             final UserHandle callingUserHandle = UserHandle.of(callingUserId);
-            final ComponentName ownerAdmin = getOwnerComponent(packageName, callingUserId);
-            if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE,
-                    callingUserHandle)) {
-                // An admin can initiate provisioning if it has set the restriction.
-                if (ownerAdmin == null || isAdminAffectedByRestriction(ownerAdmin,
-                        UserManager.DISALLOW_ADD_MANAGED_PROFILE, callingUserId)) {
-                    return CODE_ADD_MANAGED_PROFILE_DISALLOWED;
-                }
+            final boolean hasDeviceOwner;
+            synchronized (getLockObject()) {
+                hasDeviceOwner = getDeviceOwnerAdminLocked() != null;
             }
-            boolean canRemoveProfile = true;
-            if (mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
-                    callingUserHandle)) {
-                // We can remove a profile if the admin itself has set the restriction.
-                if (ownerAdmin == null || isAdminAffectedByRestriction(ownerAdmin,
-                        UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
-                        callingUserId)) {
-                    canRemoveProfile = false;
-                }
+
+            final boolean addingProfileRestricted = mUserManager.hasUserRestriction(
+                    UserManager.DISALLOW_ADD_MANAGED_PROFILE, callingUserHandle);
+
+            UserInfo parentUser = mUserManager.getProfileParent(callingUserId);
+            final boolean addingProfileRestrictedOnParent = (parentUser != null)
+                    && mUserManager.hasUserRestriction(
+                            UserManager.DISALLOW_ADD_MANAGED_PROFILE,
+                            UserHandle.of(parentUser.id));
+
+            Slog.i(LOG_TAG, String.format(
+                    "When checking for managed profile provisioning: Has device owner? %b, adding"
+                            + " profile restricted? %b, adding profile restricted on parent? %b",
+                    hasDeviceOwner, addingProfileRestricted, addingProfileRestrictedOnParent));
+
+            // If there's a device owner, the restriction on adding a managed profile must be set
+            // somewhere.
+            if (hasDeviceOwner && !addingProfileRestricted && !addingProfileRestrictedOnParent) {
+                Slog.wtf(LOG_TAG, "Has a device owner but no restriction on adding a profile.");
             }
+
+            // Do not allow adding a managed profile if there's a restriction, either on the current
+            // user or its parent user.
+            if (addingProfileRestricted || addingProfileRestrictedOnParent) {
+                return CODE_CANNOT_ADD_MANAGED_PROFILE;
+            }
+            // If there's a restriction on removing the managed profile then we have to take it
+            // into account when checking whether more profiles can be added.
+            boolean canRemoveProfile =
+                    !mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
+                    callingUserHandle);
             if (!mUserManager.canAddMoreManagedProfiles(callingUserId, canRemoveProfile)) {
                 return CODE_CANNOT_ADD_MANAGED_PROFILE;
             }
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 2fb2021..e609adc 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -16,7 +16,7 @@
 
 package com.android.server;
 
-import static android.net.NetworkScoreManager.CACHE_FILTER_NONE;
+import static android.net.NetworkScoreManager.SCORE_FILTER_NONE;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
@@ -306,7 +306,7 @@
         bindToScorer(true /*callerIsScorer*/);
 
         mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
-                mNetworkScoreCache, CACHE_FILTER_NONE);
+                mNetworkScoreCache, SCORE_FILTER_NONE);
 
         mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
 
@@ -321,9 +321,9 @@
         bindToScorer(true /*callerIsScorer*/);
 
         mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
-                mNetworkScoreCache, CACHE_FILTER_NONE);
+                mNetworkScoreCache, SCORE_FILTER_NONE);
         mNetworkScoreService.registerNetworkScoreCache(
-                NetworkKey.TYPE_WIFI, mNetworkScoreCache2, CACHE_FILTER_NONE);
+                NetworkKey.TYPE_WIFI, mNetworkScoreCache2, SCORE_FILTER_NONE);
 
         // updateScores should update both caches
         mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
@@ -378,7 +378,7 @@
         bindToScorer(true /*callerIsScorer*/);
 
         mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
-                CACHE_FILTER_NONE);
+                SCORE_FILTER_NONE);
         mNetworkScoreService.clearScores();
 
         verify(mNetworkScoreCache).clearScores();
@@ -392,7 +392,7 @@
                 .thenReturn(PackageManager.PERMISSION_GRANTED);
 
         mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
-                CACHE_FILTER_NONE);
+                SCORE_FILTER_NONE);
         mNetworkScoreService.clearScores();
 
         verify(mNetworkScoreCache).clearScores();
@@ -472,7 +472,7 @@
 
         try {
             mNetworkScoreService.registerNetworkScoreCache(
-                NetworkKey.TYPE_WIFI, mNetworkScoreCache, CACHE_FILTER_NONE);
+                    NetworkKey.TYPE_WIFI, mNetworkScoreCache, SCORE_FILTER_NONE);
             fail("SecurityException expected");
         } catch (SecurityException e) {
             // expected
@@ -615,7 +615,7 @@
                 new ArrayList<>(scoredNetworkList),
                 NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
 
-        consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE);
+        consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_NONE);
 
         verify(mNetworkScoreCache).updateScores(scoredNetworkList);
         verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
@@ -656,7 +656,7 @@
                 Collections.emptyList(),
                 NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
 
-        consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE);
+        consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_NONE);
 
         verifyZeroInteractions(mNetworkScoreCache, mCurrentNetworkFilter, mScanResultsFilter);
     }
@@ -673,7 +673,7 @@
         List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList);
         filteredList.remove(SCORED_NETWORK);
         when(mCurrentNetworkFilter.apply(scoredNetworkList)).thenReturn(filteredList);
-        consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK);
+        consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_CURRENT_NETWORK);
 
         verify(mNetworkScoreCache).updateScores(filteredList);
         verifyZeroInteractions(mScanResultsFilter);
@@ -691,7 +691,7 @@
         List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList);
         filteredList.remove(SCORED_NETWORK);
         when(mScanResultsFilter.apply(scoredNetworkList)).thenReturn(filteredList);
-        consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS);
+        consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_SCAN_RESULTS);
 
         verify(mNetworkScoreCache).updateScores(filteredList);
         verifyZeroInteractions(mCurrentNetworkFilter);
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 0f11566..39a3aae 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -212,7 +212,8 @@
 
         String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
         when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
-        Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
+        Account[] accounts = mAms.getAccountsAsUser(null,
+                UserHandle.getCallingUserId(), mContext.getOpPackageName());
         Arrays.sort(accounts, new AccountSorter());
         assertEquals(6, accounts.length);
         assertEquals(a11, accounts[0]);
@@ -222,8 +223,8 @@
         assertEquals(a22, accounts[4]);
         assertEquals(a32, accounts[5]);
 
-        accounts = mAms.getAccounts(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
-                mContext.getOpPackageName());
+        accounts = mAms.getAccountsAsUser(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+                UserHandle.getCallingUserId(), mContext.getOpPackageName());
         Arrays.sort(accounts, new AccountSorter());
         assertEquals(3, accounts.length);
         assertEquals(a11, accounts[0]);
@@ -232,8 +233,8 @@
 
         mAms.removeAccountInternal(a21);
 
-        accounts = mAms.getAccounts(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
-                mContext.getOpPackageName());
+        accounts = mAms.getAccountsAsUser(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+                UserHandle.getCallingUserId(), mContext.getOpPackageName());
         Arrays.sort(accounts, new AccountSorter());
         assertEquals(2, accounts.length);
         assertEquals(a11, accounts[0]);
@@ -373,7 +374,8 @@
         unlockSystemUser();
         String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
         when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
-        Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
+        Account[] accounts = mAms.getAccountsAsUser(null, UserHandle.getCallingUserId(),
+                mContext.getOpPackageName());
         assertEquals("1 account should be migrated", 1, accounts.length);
         assertEquals(PreNTestDatabaseHelper.ACCOUNT_NAME, accounts[0].name);
         assertEquals(PreNTestDatabaseHelper.ACCOUNT_PASSWORD, mAms.getPassword(accounts[0]));
@@ -2980,7 +2982,8 @@
                     Log.d(TAG, logPrefix + " getAccounts started");
                     long ti = System.currentTimeMillis();
                     try {
-                        Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
+                        Account[] accounts = mAms.getAccountsAsUser(null,
+                                UserHandle.getCallingUserId(), mContext.getOpPackageName());
                         if (accounts == null || accounts.length != 1
                                 || !AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1.equals(
                                 accounts[0].type)) {
@@ -3051,7 +3054,8 @@
                     Log.d(TAG, logPrefix + " getAccounts started");
                     long ti = System.currentTimeMillis();
                     try {
-                        Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
+                        Account[] accounts = mAms.getAccountsAsUser(null,
+                                UserHandle.getCallingUserId(), mContext.getOpPackageName());
                         if (accounts == null || accounts.length != 1
                                 || !AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1.equals(
                                 accounts[0].type)) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 21034d3..45729e5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -34,6 +34,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.anyObject;
@@ -275,6 +276,29 @@
         }).when(getServices().userManager).getApplicationRestrictions(
                 anyString(), any(UserHandle.class));
 
+        // Emulate UserManager.setUserRestriction/getUserRestrictions
+        final Map<UserHandle, Bundle> userRestrictions = new HashMap<>();
+
+        doAnswer((Answer<Void>) invocation -> {
+            String key = (String) invocation.getArguments()[0];
+            boolean value = (Boolean) invocation.getArguments()[1];
+            UserHandle user = (UserHandle) invocation.getArguments()[2];
+            Bundle userBundle = userRestrictions.getOrDefault(user, new Bundle());
+            userBundle.putBoolean(key, value);
+
+            userRestrictions.put(user, userBundle);
+            return null;
+        }).when(getServices().userManager).setUserRestriction(
+                anyString(), anyBoolean(), any(UserHandle.class));
+
+        doAnswer((Answer<Boolean>) invocation -> {
+            String key = (String) invocation.getArguments()[0];
+            UserHandle user = (UserHandle) invocation.getArguments()[1];
+            Bundle userBundle = userRestrictions.getOrDefault(user, new Bundle());
+            return userBundle.getBoolean(key);
+        }).when(getServices().userManager).hasUserRestriction(
+                anyString(), any(UserHandle.class));
+
         // Add the first secondary user.
         getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0,
                 UserManager.USER_TYPE_FULL_SECONDARY);
@@ -822,10 +846,8 @@
         final int MANAGED_PROFILE_ADMIN_UID =
                 UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID);
 
-        // Setup device owner.
         mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
         mContext.packageName = admin1.getPackageName();
-        setupDeviceOwner();
 
         // Add a managed profile belonging to the system user.
         addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
@@ -833,18 +855,13 @@
         // Change the parent user's password.
         dpm.reportPasswordChanged(UserHandle.USER_SYSTEM);
 
-        // Both the device owner and the managed profile owner should receive this broadcast.
+        // The managed profile owner should receive this broadcast.
         final Intent intent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED);
         intent.setComponent(admin1);
         intent.putExtra(Intent.EXTRA_USER, UserHandle.of(UserHandle.USER_SYSTEM));
 
         verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                 MockUtils.checkIntent(intent),
-                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM),
-                eq(null),
-                any(Bundle.class));
-        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
-                MockUtils.checkIntent(intent),
                 MockUtils.checkUserHandle(MANAGED_PROFILE_USER_ID),
                 eq(null),
                 any(Bundle.class));
@@ -864,12 +881,11 @@
         final int MANAGED_PROFILE_ADMIN_UID =
                 UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID);
 
-        // Setup device owner.
+        // Configure system as having separate profile challenge.
         mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
         mContext.packageName = admin1.getPackageName();
         doReturn(true).when(getServices().lockPatternUtils)
                 .isSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID);
-        setupDeviceOwner();
 
         // Add a managed profile belonging to the system user.
         addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
@@ -954,6 +970,10 @@
         verify(getServices().iactivityManager, times(1)).updateDeviceOwner(
                 eq(admin1.getPackageName()));
 
+        verify(getServices().userManager, times(1)).setUserRestriction(
+                eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE),
+                eq(true), eq(UserHandle.SYSTEM));
+
         verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                 MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
                 MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
@@ -2005,12 +2025,11 @@
 
         assertNoDeviceOwnerRestrictions();
 
-        // Initialize DPMS again and check that the user restriction wasn't enabled again.
         reset(getServices().userManagerInternal);
-        initializeDpms();
-        assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
-        assertNotNull(dpms.getDeviceOwnerAdminLocked());
 
+        // Ensure the DISALLOW_REMOVE_MANAGED_PROFILES restriction doesn't show up as a
+        // restriction to the device owner.
+        dpm.addUserRestriction(admin1, UserManager.DISALLOW_REMOVE_MANAGED_PROFILE);
         assertNoDeviceOwnerRestrictions();
     }
 
@@ -3106,7 +3125,6 @@
         setup_nonSplitUser_withDo_primaryUser();
         final int MANAGED_PROFILE_USER_ID = 18;
         final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 1308);
-        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
         when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM,
                 false /* we can't remove a managed profile */)).thenReturn(false);
         when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM,
@@ -3158,41 +3176,16 @@
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE, false);
 
-        // COMP mode is allowed.
+        // COMP mode NOT is allowed.
         assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
-                DevicePolicyManager.CODE_OK);
-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
 
-        // And other DPCs can also provision a managed profile (DO + BYOD case).
+        // And other DPCs can NOT provision a managed profile.
         assertCheckProvisioningPreCondition(
                 DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                 DpmMockContext.ANOTHER_PACKAGE_NAME,
-                DevicePolicyManager.CODE_OK);
-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true,
-                DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID);
-    }
-
-    public void testProvisioning_nonSplitUser_withDo_primaryUser_restrictedByDo() throws Exception {
-        setup_nonSplitUser_withDo_primaryUser();
-        mContext.packageName = admin1.getPackageName();
-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
-        // The DO should be allowed to initiate provisioning if it set the restriction itself, but
-        // other packages should be forbidden.
-        when(getServices().userManager.hasUserRestriction(
-                eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE),
-                eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
-                .thenReturn(true);
-        when(getServices().userManager.getUserRestrictionSource(
-                eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE),
-                eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
-                .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);
-        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
-                DevicePolicyManager.CODE_OK);
-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
-        assertCheckProvisioningPreCondition(
-                DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
-                DpmMockContext.ANOTHER_PACKAGE_NAME,
-                DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED);
+                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false,
                 DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID);
     }
@@ -3213,31 +3206,46 @@
                 eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
                 .thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM);
         assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
-                DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED);
+                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
 
         assertCheckProvisioningPreCondition(
                 DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                 DpmMockContext.ANOTHER_PACKAGE_NAME,
-                DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED);
+                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false,
                 DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID);
     }
 
-    public void testCheckProvisioningPreCondition_nonSplitUser_comp() throws Exception {
+    public void testCheckCannotSetProfileOwnerWithDeviceOwner() throws Exception {
+        setup_nonSplitUser_withDo_primaryUser();
+        final int managedProfileUserId = 18;
+        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 1308);
+
+        final int userId = UserHandle.getUserId(managedProfileAdminUid);
+        getServices().addUser(userId, 0, UserManager.USER_TYPE_PROFILE_MANAGED,
+                UserHandle.USER_SYSTEM);
+        mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);
+        setUpPackageManagerForFakeAdmin(admin1, managedProfileAdminUid, admin1);
+        dpm.setActiveAdmin(admin1, false, userId);
+        assertFalse(dpm.setProfileOwner(admin1, null, userId));
+        mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
+    }
+
+    public void testCheckProvisioningPreCondition_nonSplitUser_attemptingComp() throws Exception {
         setup_nonSplitUser_withDo_primaryUser_ManagedProfile();
         mContext.packageName = admin1.getPackageName();
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
 
         // We can delete the managed profile to create a new one, so provisioning is allowed.
         assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
-                DevicePolicyManager.CODE_OK);
-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
         assertCheckProvisioningPreCondition(
                 DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                 DpmMockContext.ANOTHER_PACKAGE_NAME,
-                DevicePolicyManager.CODE_OK);
-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true,
+                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false,
                 DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID);
     }
 
@@ -3265,8 +3273,8 @@
 
         // But the device owner can still do it because it has set the restriction itself.
         assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
-                DevicePolicyManager.CODE_OK);
-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
     }
 
     private void setup_splitUser_firstBoot_systemUser() throws Exception {
@@ -3475,6 +3483,8 @@
         when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                 .thenReturn(true);
         when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        when(getServices().userManager.getProfileParent(DpmMockContext.CALLER_USER_HANDLE))
+            .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
         when(getServices().userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
                 true)).thenReturn(true);
         setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
@@ -3487,7 +3497,7 @@
         setup_provisionManagedProfileWithDeviceOwner_primaryUser();
         setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
         mContext.packageName = admin1.getPackageName();
-        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
     }
 
     public void testCheckProvisioningPreCondition_provisionManagedProfileWithDeviceOwner_primaryUser()
@@ -3495,9 +3505,9 @@
         setup_provisionManagedProfileWithDeviceOwner_primaryUser();
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
 
-        // COMP mode is allowed.
+        // COMP mode is NOT allowed.
         assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
-                DevicePolicyManager.CODE_OK);
+                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
     }
 
     private void setup_provisionManagedProfileCantRemoveUser_primaryUser() throws Exception {
@@ -4014,11 +4024,6 @@
         List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
         MoreAsserts.assertEmpty(targetUsers);
 
-        // Setup a managed profile managed by the same admin.
-        final int MANAGED_PROFILE_USER_ID = 15;
-        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456);
-        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
-
         // Add a secondary user, it should never talk with.
         final int ANOTHER_USER_ID = 36;
         getServices().addUser(ANOTHER_USER_ID, 0, UserManager.USER_TYPE_FULL_SECONDARY);
@@ -4028,30 +4033,11 @@
         targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
         MoreAsserts.assertEmpty(targetUsers);
 
-        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
-        targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
-        MoreAsserts.assertEmpty(targetUsers);
-
         // Setting affiliation ids
         final Set<String> userAffiliationIds = Collections.singleton("some.affiliation-id");
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         dpm.setAffiliationIds(admin1, userAffiliationIds);
 
-        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
-        dpm.setAffiliationIds(admin1, userAffiliationIds);
-
-        // Calling from device owner admin, the result list should just contain the managed
-        // profile user id.
-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
-        targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
-        MoreAsserts.assertContentsInAnyOrder(targetUsers, UserHandle.of(MANAGED_PROFILE_USER_ID));
-
-        // Calling from managed profile admin, the result list should just contain the system
-        // user id.
-        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
-        targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
-        MoreAsserts.assertContentsInAnyOrder(targetUsers, UserHandle.SYSTEM);
-
         // Changing affiliation ids in one
         dpm.setAffiliationIds(admin1, Collections.singleton("some-different-affiliation-id"));
 
@@ -4065,38 +4051,6 @@
         MoreAsserts.assertEmpty(targetUsers);
     }
 
-    public void testGetBindDeviceAdminTargetUsers_differentPackage() throws Exception {
-        // Setup a device owner.
-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
-        setupDeviceOwner();
-
-        // Set up a managed profile managed by different package.
-        final int MANAGED_PROFILE_USER_ID = 15;
-        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456);
-        final ComponentName adminDifferentPackage =
-                new ComponentName("another.package", "whatever.class");
-        addManagedProfile(adminDifferentPackage, MANAGED_PROFILE_ADMIN_UID, admin2);
-
-        // Setting affiliation ids
-        final Set<String> userAffiliationIds = Collections.singleton("some-affiliation-id");
-        dpm.setAffiliationIds(admin1, userAffiliationIds);
-
-        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
-        dpm.setAffiliationIds(adminDifferentPackage, userAffiliationIds);
-
-        // Calling from device owner admin, we should get zero bind device admin target users as
-        // their packages are different.
-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
-        List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
-        MoreAsserts.assertEmpty(targetUsers);
-
-        // Calling from managed profile admin, we should still get zero target users for the same
-        // reason.
-        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
-        targetUsers = dpm.getBindDeviceAdminTargetUsers(adminDifferentPackage);
-        MoreAsserts.assertEmpty(targetUsers);
-    }
-
     private void verifyLockTaskState(int userId) throws Exception {
         verifyLockTaskState(userId, new String[0],
                 DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS);
@@ -4133,79 +4087,6 @@
                 () -> dpm.setLockTaskFeatures(who, flags));
     }
 
-    public void testLockTaskPolicyAllowedForAffiliatedUsers() throws Exception {
-        // Setup a device owner.
-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
-        setupDeviceOwner();
-        // Lock task policy is updated when loading user data.
-        verifyLockTaskState(UserHandle.USER_SYSTEM);
-
-        // Set up a managed profile managed by different package (package name shouldn't matter)
-        final int MANAGED_PROFILE_USER_ID = 15;
-        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456);
-        final ComponentName adminDifferentPackage =
-                new ComponentName("another.package", "whatever.class");
-        addManagedProfile(adminDifferentPackage, MANAGED_PROFILE_ADMIN_UID, admin2);
-        verifyLockTaskState(MANAGED_PROFILE_USER_ID);
-
-        // Setup a PO on the secondary user
-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
-        setAsProfileOwner(admin3);
-        verifyLockTaskState(DpmMockContext.CALLER_USER_HANDLE);
-
-        // The DO can still set lock task packages
-        final String[] doPackages = {"doPackage1", "doPackage2"};
-        final int flags = DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS
-                | DevicePolicyManager.LOCK_TASK_FEATURE_HOME
-                | DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
-        verifyCanSetLockTask(DpmMockContext.CALLER_SYSTEM_USER_UID, UserHandle.USER_SYSTEM, admin1, doPackages, flags);
-
-        final String[] secondaryPoPackages = {"secondaryPoPackage1", "secondaryPoPackage2"};
-        final int secondaryPoFlags = DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS
-                | DevicePolicyManager.LOCK_TASK_FEATURE_HOME
-                | DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
-        verifyCanNotSetLockTask(DpmMockContext.CALLER_UID, admin3, secondaryPoPackages, secondaryPoFlags);
-
-        // Managed profile is unaffiliated - shouldn't be able to setLockTaskPackages.
-        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
-        final String[] poPackages = {"poPackage1", "poPackage2"};
-        final int poFlags = DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS
-                | DevicePolicyManager.LOCK_TASK_FEATURE_HOME
-                | DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
-        verifyCanNotSetLockTask(MANAGED_PROFILE_ADMIN_UID, adminDifferentPackage, poPackages, poFlags);
-
-        // Setting same affiliation ids
-        final Set<String> userAffiliationIds = Collections.singleton("some-affiliation-id");
-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
-        dpm.setAffiliationIds(admin1, userAffiliationIds);
-
-        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
-        dpm.setAffiliationIds(adminDifferentPackage, userAffiliationIds);
-
-        // Now the managed profile can set lock task packages.
-        dpm.setLockTaskPackages(adminDifferentPackage, poPackages);
-        MoreAsserts.assertEquals(poPackages, dpm.getLockTaskPackages(adminDifferentPackage));
-        assertTrue(dpm.isLockTaskPermitted("poPackage1"));
-        assertFalse(dpm.isLockTaskPermitted("doPackage2"));
-        // And it can set lock task features.
-        dpm.setLockTaskFeatures(adminDifferentPackage, poFlags);
-        verifyLockTaskState(MANAGED_PROFILE_USER_ID, poPackages, poFlags);
-
-        // Unaffiliate the profile, lock task mode no longer available on the profile.
-        dpm.setAffiliationIds(adminDifferentPackage, Collections.emptySet());
-        assertFalse(dpm.isLockTaskPermitted("poPackage1"));
-        // Lock task packages cleared when loading user data and when the user becomes unaffiliated.
-        verify(getServices().iactivityManager, times(2)).updateLockTaskPackages(
-                MANAGED_PROFILE_USER_ID, new String[0]);
-        verify(getServices().iactivityTaskManager, times(2)).updateLockTaskFeatures(
-                MANAGED_PROFILE_USER_ID, DevicePolicyManager.LOCK_TASK_FEATURE_NONE);
-
-        // Verify that lock task packages were not cleared for the DO
-        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
-        assertTrue(dpm.isLockTaskPermitted("doPackage1"));
-
-    }
-
     public void testLockTaskPolicyForProfileOwner() throws Exception {
         // Setup a PO
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 1dd7e64..6aca58f 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -23,7 +23,8 @@
 import static android.app.usage.UsageEvents.Event.SYSTEM_INTERACTION;
 import static android.app.usage.UsageEvents.Event.USER_INTERACTION;
 import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
-import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED;
+import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM;
+import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_USER;
 import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED;
 import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT;
 import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
@@ -501,12 +502,18 @@
         // Can force to NEVER
         mInjector.mElapsedRealtime = HOUR_MS;
         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
-                REASON_MAIN_FORCED);
+                REASON_MAIN_FORCED_BY_USER);
         assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1));
 
-        // Prediction can't override FORCED reason
+        // Prediction can't override FORCED reasons
+        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
+                REASON_MAIN_FORCED_BY_SYSTEM);
+        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
+                REASON_MAIN_PREDICTED);
+        assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
+
         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
-                REASON_MAIN_FORCED);
+                REASON_MAIN_FORCED_BY_USER);
         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
                 REASON_MAIN_PREDICTED);
         assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController, PACKAGE_1));
@@ -631,7 +638,7 @@
         mInjector.mElapsedRealtime = 1 * RARE_THRESHOLD + 100;
         // Make sure app is in NEVER bucket
         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
-                REASON_MAIN_FORCED);
+                REASON_MAIN_FORCED_BY_USER);
         mController.checkIdleStates(USER_ID);
         assertBucket(STANDBY_BUCKET_NEVER);
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 8617833..5a7c3b3 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -16,8 +16,6 @@
 
 package android.telephony;
 
-import com.android.telephony.Rlog;
-
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -36,6 +34,7 @@
 import android.telephony.ims.ImsReasonInfo;
 
 import com.android.internal.telephony.ICarrierConfigLoader;
+import com.android.telephony.Rlog;
 
 /**
  * Provides access to telephony configuration values that are carrier-specific.
@@ -300,7 +299,6 @@
 
     /**
      * A string array containing numbers that shouldn't be included in the call log.
-     * @hide
      */
     public static final String KEY_UNLOGGABLE_NUMBERS_STRING_ARRAY =
             "unloggable_numbers_string_array";
@@ -313,12 +311,11 @@
             KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";
 
     /**
-     * Do only allow auto selection in Advanced Network Settings when in home network.
+     * Only allow auto selection in Advanced Network Settings when in home network.
      * Manual selection is allowed when in roaming network.
-     * @hide
      */
-    public static final String
-            KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL = "only_auto_select_in_home_network";
+    public static final String KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL =
+            "only_auto_select_in_home_network";
 
     /**
      * Control whether users receive a simplified network settings UI and improved network
@@ -582,9 +579,6 @@
      * registration state to change.  That is, turning on or off mobile data will not cause VT to be
      * enabled or disabled.
      * When {@code false}, disabling mobile data will cause VT to be de-registered.
-     * <p>
-     * See also {@link #KEY_VILTE_DATA_IS_METERED_BOOL}.
-     * @hide
      */
     public static final String KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS =
             "ignore_data_enabled_changed_for_video_calls";
@@ -648,7 +642,6 @@
     /**
      * Default WFC_IMS_enabled: true VoWiFi by default is on
      *                          false VoWiFi by default is off
-     * @hide
      */
     public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL =
             "carrier_default_wfc_ims_enabled_bool";
@@ -720,9 +713,7 @@
      *
      * As of now, Verizon is the only carrier enforcing this dependency in their
      * WFC awareness and activation requirements.
-     *
-     * @hide
-     *  */
+     */
     public static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL
             = "carrier_volte_override_wfc_provisioning_bool";
 
@@ -1083,7 +1074,6 @@
      *
      * When {@code false}, the old behavior is used, where the toggle in accessibility settings is
      * used to set the IMS stack's RTT enabled state.
-     * @hide
      */
     public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL =
             "ignore_rtt_mode_setting_bool";
@@ -1124,7 +1114,6 @@
      * Determines whether the IMS conference merge process supports and returns its participants
      * data. When {@code true}, on merge complete, conference call would have a list of its
      * participants returned in XML format, {@code false otherwise}.
-     * @hide
      */
     public static final String KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL =
             "support_ims_conference_event_package_bool";
@@ -1197,20 +1186,18 @@
     public static final String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
 
     /**
-     * Determine whether user can switch Wi-Fi preferred or Cellular preferred in calling preference.
+     * Determine whether user can switch Wi-Fi preferred or Cellular preferred
+     * in calling preference.
      * Some operators support Wi-Fi Calling only, not VoLTE.
      * They don't need "Cellular preferred" option.
-     * In this case, set uneditalbe attribute for preferred preference.
-     * @hide
+     * In this case, set uneditable attribute for preferred preference.
      */
     public static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool";
 
-     /**
-      * Flag to indicate if Wi-Fi needs to be disabled in ECBM
-      * @hide
-      **/
-     public static final String
-              KEY_CONFIG_WIFI_DISABLE_IN_ECBM = "config_wifi_disable_in_ecbm";
+    /**
+     * Flag to indicate if Wi-Fi needs to be disabled in ECBM.
+     */
+    public static final String KEY_CONFIG_WIFI_DISABLE_IN_ECBM = "config_wifi_disable_in_ecbm";
 
     /**
      * List operator-specific error codes and indices of corresponding error strings in
@@ -1274,9 +1261,8 @@
     public static final String KEY_WFC_SPN_USE_ROOT_LOCALE = "wfc_spn_use_root_locale";
 
     /**
-     * The Component Name of the activity that can setup the emergency addrees for WiFi Calling
+     * The Component Name of the activity that can setup the emergency address for WiFi Calling
      * as per carrier requirement.
-     * @hide
      */
      public static final String KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING =
             "wfc_emergency_address_carrier_app_string";
@@ -1440,22 +1426,19 @@
     public static final String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
 
     /**
-     * APN types that user is not allowed to modify
-     * @hide
+     * APN types that user is not allowed to modify.
      */
     public static final String KEY_READ_ONLY_APN_TYPES_STRING_ARRAY =
             "read_only_apn_types_string_array";
 
     /**
-     * APN fields that user is not allowed to modify
-     * @hide
+     * APN fields that user is not allowed to modify.
      */
     public static final String KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY =
             "read_only_apn_fields_string_array";
 
     /**
      * Default value of APN types field if not specified by user when adding/modifying an APN.
-     * @hide
      */
     public static final String KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY =
             "apn_settings_default_apn_types_string_array";
@@ -1486,29 +1469,25 @@
             "hide_digits_helper_text_on_stk_input_screen_bool";
 
     /**
-     * Boolean indicating if show data RAT icon on status bar even when data is disabled
-     * @hide
+     * Boolean indicating if show data RAT icon on status bar even when data is disabled.
      */
     public static final String KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL =
             "always_show_data_rat_icon_bool";
 
     /**
-     * Boolean indicating if default data account should show LTE or 4G icon
-     * @hide
+     * Boolean indicating if default data account should show LTE or 4G icon.
      */
     public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL =
             "show_4g_for_lte_data_icon_bool";
 
     /**
      * Boolean indicating if default data account should show 4G icon when in 3G.
-     * @hide
      */
     public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL =
             "show_4g_for_3g_data_icon_bool";
 
     /**
-     * Boolean indicating if lte+ icon should be shown if available
-     * @hide
+     * Boolean indicating if LTE+ icon should be shown if available.
      */
     public static final String KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL =
             "hide_lte_plus_data_icon_bool";
@@ -1523,10 +1502,8 @@
             "operator_name_filter_pattern_string";
 
     /**
-     * The string is used to compare with operator name. If it matches the pattern then show
-     * specific data icon.
-     *
-     * @hide
+     * The string is used to compare with operator name.
+     * If it matches the pattern then show specific data icon.
      */
     public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING =
             "show_carrier_data_icon_pattern_string";
@@ -1539,33 +1516,28 @@
             "show_precise_failed_cause_bool";
 
     /**
-     * Boolean to decide whether lte is enabled.
-     * @hide
+     * Boolean to decide whether LTE is enabled.
      */
     public static final String KEY_LTE_ENABLED_BOOL = "lte_enabled_bool";
 
     /**
      * Boolean to decide whether TD-SCDMA is supported.
-     * @hide
      */
     public static final String KEY_SUPPORT_TDSCDMA_BOOL = "support_tdscdma_bool";
 
     /**
      * A list of mcc/mnc that support TD-SCDMA for device when connect to the roaming network.
-     * @hide
      */
     public static final String KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY =
             "support_tdscdma_roaming_networks_string_array";
 
     /**
      * Boolean to decide whether world mode is enabled.
-     * @hide
      */
     public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool";
 
     /**
      * Flatten {@link android.content.ComponentName} of the carrier's settings activity.
-     * @hide
      */
     public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING =
             "carrier_settings_activity_component_name_string";
@@ -1619,25 +1591,23 @@
     /**
      * Defines carrier-specific actions which act upon
      * com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED, used for customization of the
-     * default carrier app
+     * default carrier app.
      * Format: "CARRIER_ACTION_IDX, ..."
      * Where {@code CARRIER_ACTION_IDX} is an integer defined in
-     * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils}
+     * com.android.carrierdefaultapp.CarrierActionUtils
      * Example:
-     * {@link com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS
-     * disable_metered_apns}
-     * @hide
+     * com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS
+     * disables metered APNs
      */
-    @UnsupportedAppUsage
+    @SuppressLint("IntentName")
     public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY =
             "carrier_default_actions_on_redirection_string_array";
 
     /**
-     * Defines carrier-specific actions which act upon
-     * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+     * Defines carrier-specific actions which act upon CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
      * and configured signal args:
-     * {@link TelephonyManager#EXTRA_APN_TYPE apnType},
-     * {@link TelephonyManager#EXTRA_ERROR_CODE errorCode}
+     * android.telephony.TelephonyManager#EXTRA_APN_TYPE,
+     * android.telephony.TelephonyManager#EXTRA_ERROR_CODE
      * used for customization of the default carrier app
      * Format:
      * {
@@ -1645,42 +1615,41 @@
      *     "APN_1, ERROR_CODE_2 : CARRIER_ACTION_IDX_1 "
      * }
      * Where {@code APN_1} is a string defined in
-     * {@link com.android.internal.telephony.PhoneConstants PhoneConstants}
+     * com.android.internal.telephony.PhoneConstants
      * Example: "default"
      *
-     * {@code ERROR_CODE_1} is an integer defined in
-     * {@link DataFailCause DcFailure}
+     * {@code ERROR_CODE_1} is an integer defined in android.telephony.DataFailCause
      * Example:
-     * {@link DataFailCause#MISSING_UNKNOWN_APN}
+     * android.telephony.DataFailCause#MISSING_UNKNOWN_APN
      *
      * {@code CARRIER_ACTION_IDX_1} is an integer defined in
-     * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils}
+     * com.android.carrierdefaultapp.CarrierActionUtils
      * Example:
-     * {@link com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS}
-     * @hide
+     * com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS
+     * disables metered APNs
      */
+    @SuppressLint("IntentName")
     public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DCFAILURE_STRING_ARRAY =
             "carrier_default_actions_on_dcfailure_string_array";
 
     /**
-     * Defines carrier-specific actions which act upon
-     * com.android.internal.telephony.CARRIER_SIGNAL_RESET, used for customization of the
-     * default carrier app
+     * Defines carrier-specific actions which act upon CARRIER_SIGNAL_RESET,
+     * used for customization of the default carrier app.
      * Format: "CARRIER_ACTION_IDX, ..."
      * Where {@code CARRIER_ACTION_IDX} is an integer defined in
-     * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils}
+     * com.android.carrierdefaultapp.CarrierActionUtils
      * Example:
-     * {@link com.android.carrierdefaultapp.CarrierActionUtils
-     * #CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS clear all notifications on reset}
-     * @hide
+     * com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS
+     * clears all notifications on reset
      */
+    @SuppressLint("IntentName")
     public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET =
             "carrier_default_actions_on_reset_string_array";
 
     /**
      * Defines carrier-specific actions which act upon
      * com.android.internal.telephony.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE,
-     * used for customization of the default carrier app
+     * used for customization of the default carrier app.
      * Format:
      * {
      *     "true : CARRIER_ACTION_IDX_1",
@@ -1688,17 +1657,17 @@
      * }
      * Where {@code true} is a boolean indicates default network available/unavailable
      * Where {@code CARRIER_ACTION_IDX} is an integer defined in
-     * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils}
+     * com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils
      * Example:
-     * {@link com.android.carrierdefaultapp.CarrierActionUtils
-     * #CARRIER_ACTION_ENABLE_DEFAULT_URL_HANDLER enable the app as the default URL handler}
-     * @hide
+     * com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_ENABLE_DEFAULT_URL_HANDLER
+     * enables the app as the default URL handler
      */
+    @SuppressLint("IntentName")
     public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DEFAULT_NETWORK_AVAILABLE =
             "carrier_default_actions_on_default_network_available_string_array";
+
     /**
-     * Defines a list of acceptable redirection url for default carrier app
-     * @hides
+     * Defines a list of acceptable redirection url for default carrier app.
      */
     public static final String KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY =
             "carrier_default_redirection_url_string_array";
@@ -1826,10 +1795,10 @@
 
     /**
      * Determines whether to enable enhanced call blocking feature on the device.
-     * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED
-     * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_PRIVATE
-     * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_PAYPHONE
-     * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNKNOWN
+     * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED
+     * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_PRIVATE
+     * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_PAYPHONE
+     * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNKNOWN
      *
      * <p>
      * 1. For Single SIM(SS) device, it can be customized in both carrier_config_mccmnc.xml
@@ -1839,7 +1808,6 @@
      *    function is used regardless of SIM.
      * <p>
      * If {@code true} enable enhanced call blocking feature on the device, {@code false} otherwise.
-     * @hide
      */
     public static final String KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL =
             "support_enhanced_call_blocking_bool";
@@ -1950,7 +1918,6 @@
 
     /**
      * Flag indicating whether the carrier supports call deflection for an incoming IMS call.
-     * @hide
      */
     public static final String KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL =
             "carrier_allow_deflect_ims_call_bool";
@@ -2015,8 +1982,6 @@
     /**
      * Whether system apps are allowed to use fallback if carrier video call is not available.
      * Defaults to {@code true}.
-     *
-     * @hide
      */
     public static final String KEY_ALLOW_VIDEO_CALLING_FALLBACK_BOOL =
             "allow_video_calling_fallback_bool";
@@ -2054,9 +2019,8 @@
             "enhanced_4g_lte_title_variant_bool";
 
     /**
-     * The index indicates the carrier specified title string of Enahnce 4G LTE Mode settings.
+     * The index indicates the carrier specified title string of Enhanced 4G LTE Mode settings.
      * Default value is 0, which indicates the default title string.
-     * @hide
      */
     public static final String KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT =
             "enhanced_4g_lte_title_variant_int";
@@ -2100,15 +2064,13 @@
      *                 {@link #KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL} is false. If
      *                 {@link #KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL} is true, this
      *                 configuration is ignored and roaming preference cannot be changed.
-     * @hide
      */
     public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL =
             "editable_wfc_roaming_mode_bool";
 
     /**
-     * Flag specifying wether to show blocking pay phone option in blocked numbers screen. Only show
-     * the option if payphone call presentation represents in the carrier's region.
-     * @hide
+     * Flag specifying whether to show blocking pay phone option in blocked numbers screen.
+     * Only show the option if payphone call presentation is present in the carrier's region.
      */
     public static final java.lang.String KEY_SHOW_BLOCKING_PAY_PHONE_OPTION_BOOL =
             "show_blocking_pay_phone_option_bool";
@@ -2118,7 +2080,6 @@
      * {@code false} - roaming preference can be selected separately from the home preference.
      * {@code true}  - roaming preference is the same as home preference and
      *                 {@link #KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT} is used as the default value.
-     * @hide
      */
     public static final String KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL =
             "use_wfc_home_network_mode_in_roaming_network_bool";
@@ -2146,7 +2107,6 @@
      * while the device is registered over WFC. Default value is -1, which indicates
      * that this notification is not pertinent for a particular carrier. We've added a delay
      * to prevent false positives.
-     * @hide
      */
     public static final String KEY_EMERGENCY_NOTIFICATION_DELAY_INT =
             "emergency_notification_delay_int";
@@ -2197,7 +2157,6 @@
     /**
      * Flag specifying whether to show an alert dialog for video call charges.
      * By default this value is {@code false}.
-     * @hide
      */
     public static final String KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL =
             "show_video_call_charges_alert_dialog_bool";
@@ -2484,10 +2443,9 @@
     /**
      * Identifies if the key is available for WLAN or EPDG or both. The value is a bitmask.
      * 0 indicates that neither EPDG or WLAN is enabled.
-     * 1 indicates that key type {@link TelephonyManager#KEY_TYPE_EPDG} is enabled.
-     * 2 indicates that key type {@link TelephonyManager#KEY_TYPE_WLAN} is enabled.
+     * 1 indicates that key type TelephonyManager#KEY_TYPE_EPDG is enabled.
+     * 2 indicates that key type TelephonyManager#KEY_TYPE_WLAN is enabled.
      * 3 indicates that both are enabled.
-     * @hide
      */
     public static final String IMSI_KEY_AVAILABILITY_INT = "imsi_key_availability_int";
 
@@ -2505,7 +2463,6 @@
     /**
      * Flag specifying whether IMS registration state menu is shown in Status Info setting,
      * default to false.
-     * @hide
      */
     public static final String KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL =
             "show_ims_registration_status_bool";
@@ -2561,7 +2518,6 @@
 
     /**
      * The flag to disable the popup dialog which warns the user of data charges.
-     * @hide
      */
     public static final String KEY_DISABLE_CHARGE_INDICATION_BOOL =
             "disable_charge_indication_bool";
@@ -2626,15 +2582,13 @@
     /**
      * Determines whether any carrier has been identified and its specific config has been applied,
      * default to false.
-     * @hide
      */
     public static final String KEY_CARRIER_CONFIG_APPLIED_BOOL = "carrier_config_applied_bool";
 
     /**
      * Determines whether we should show a warning asking the user to check with their carrier
-     * on pricing when the user enabled data roaming.
+     * on pricing when the user enabled data roaming,
      * default to false.
-     * @hide
      */
     public static final String KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL =
             "check_pricing_with_carrier_data_roaming_bool";
@@ -2786,10 +2740,10 @@
      * Specifies a carrier-defined {@link android.telecom.CallRedirectionService} which Telecom
      * will bind to for outgoing calls.  An empty string indicates that no carrier-defined
      * {@link android.telecom.CallRedirectionService} is specified.
-     * @hide
      */
     public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING =
             "call_redirection_service_component_name_string";
+
     /**
      * Support for the original string display of CDMA MO call.
      * By default, it is disabled.
@@ -2902,8 +2856,8 @@
             "call_waiting_service_class_int";
 
     /**
-     * This configuration allow the system UI to display different 5G icon for different 5G
-     * scenario.
+     * This configuration allows the system UI to display different 5G icons for different 5G
+     * scenarios.
      *
      * There are five 5G scenarios:
      * 1. connected_mmwave: device currently connected to 5G cell as the secondary cell and using
@@ -2920,24 +2874,22 @@
      *    5G cell as a secondary cell) but the use of 5G is restricted.
      *
      * The configured string contains multiple key-value pairs separated by comma. For each pair,
-     * the key and value is separated by a colon. The key is corresponded to a 5G status above and
+     * the key and value are separated by a colon. The key corresponds to a 5G status above and
      * the value is the icon name. Use "None" as the icon name if no icon should be shown in a
      * specific 5G scenario. If the scenario is "None", config can skip this key and value.
      *
      * Icon name options: "5G_Plus", "5G".
      *
      * Here is an example:
-     * UE want to display 5G_Plus icon for scenario#1, and 5G icon for scenario#2; otherwise no
+     * UE wants to display 5G_Plus icon for scenario#1, and 5G icon for scenario#2; otherwise not
      * define.
      * The configuration is: "connected_mmwave:5G_Plus,connected:5G"
-     *
-     * @hide
      */
     public static final String KEY_5G_ICON_CONFIGURATION_STRING =
             "5g_icon_configuration_string";
 
     /**
-     * Timeout in second for displaying 5G icon, default value is 0 which means the timer is
+     * Timeout in seconds for displaying 5G icon, default value is 0 which means the timer is
      * disabled.
      *
      * System UI will show the 5G icon and start a timer with the timeout from this config when the
@@ -2946,8 +2898,6 @@
      *
      * If 5G is reacquired during this timer, the timer is canceled and restarted when 5G is next
      * lost. Allows us to momentarily lose 5G without blinking the icon.
-     *
-     * @hide
      */
     public static final String KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT =
             "5g_icon_display_grace_period_sec_int";
@@ -3112,8 +3062,6 @@
      * signal bar of primary network. By default it will be false, meaning whenever data
      * is going over opportunistic network, signal bar will reflect signal strength and rat
      * icon of that network.
-     *
-     * @hide
      */
     public static final String KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN =
             "always_show_primary_signal_bar_in_opportunistic_network_boolean";
@@ -3335,8 +3283,6 @@
 
     /**
      * Determines whether wifi calling location privacy policy is shown.
-     *
-     * @hide
      */
     public static final String KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL =
             "show_wfc_location_privacy_policy_bool";
@@ -3447,8 +3393,8 @@
             "support_wps_over_ims_bool";
 
     /**
-     * Holds the list of carrier certificate hashes. Note that each carrier has its own certificates
-     * @hide
+     * Holds the list of carrier certificate hashes.
+     * Note that each carrier has its own certificates.
      */
     public static final String KEY_CARRIER_CERTIFICATE_STRING_ARRAY =
             "carrier_certificate_string_array";
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 1dbc8b1..8ed4ee5 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -780,7 +780,11 @@
                     "Invalid pdu format. format must be either 3gpp or 3gpp2");
         }
         try {
-            ISms iSms = TelephonyManager.getSmsService();
+            ISms iSms = ISms.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSmsServiceRegisterer()
+                            .get());
             if (iSms != null) {
                 iSms.injectSmsPduForSubscriber(
                         getSubscriptionId(), pdu, format, receivedIntent);
@@ -1603,7 +1607,7 @@
      * the service does not exist.
      */
     private static ISms getISmsServiceOrThrow() {
-        ISms iSms = TelephonyManager.getSmsService();
+        ISms iSms = getISmsService();
         if (iSms == null) {
             throw new UnsupportedOperationException("Sms is not supported");
         }
@@ -1611,7 +1615,11 @@
     }
 
     private static ISms getISmsService() {
-        return TelephonyManager.getSmsService();
+        return ISms.Stub.asInterface(
+                TelephonyFrameworkInitializer
+                        .getTelephonyServiceManager()
+                        .getSmsServiceRegisterer()
+                        .get());
     }
 
     /**
@@ -2045,7 +2053,11 @@
     public boolean isSMSPromptEnabled() {
         ISms iSms = null;
         try {
-            iSms = TelephonyManager.getSmsService();
+            iSms = ISms.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSmsServiceRegisterer()
+                            .get());
             return iSms.isSMSPromptEnabled();
         } catch (RemoteException ex) {
             return false;
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index cb4462f..36f541f 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -16,8 +16,6 @@
 
 package android.telephony;
 
-import com.android.telephony.Rlog;
-
 import static android.net.NetworkPolicyManager.OVERRIDE_CONGESTED;
 import static android.net.NetworkPolicyManager.OVERRIDE_UNMETERED;
 
@@ -67,6 +65,7 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.util.HandlerExecutor;
 import com.android.internal.util.Preconditions;
+import com.android.telephony.Rlog;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -1146,7 +1145,11 @@
         SubscriptionInfo subInfo = null;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 subInfo = iSub.getActiveSubscriptionInfo(subId, mContext.getOpPackageName(),
                         mContext.getFeatureId());
@@ -1180,7 +1183,11 @@
         SubscriptionInfo result = null;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 result = iSub.getActiveSubscriptionInfoForIccId(iccId, mContext.getOpPackageName(),
                         mContext.getFeatureId());
@@ -1214,7 +1221,11 @@
         SubscriptionInfo result = null;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIndex,
                         mContext.getOpPackageName(), mContext.getFeatureId());
@@ -1238,7 +1249,11 @@
         List<SubscriptionInfo> result = null;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 result = iSub.getAllSubInfoList(mContext.getOpPackageName(),
                         mContext.getFeatureId());
@@ -1319,7 +1334,11 @@
         List<SubscriptionInfo> activeList = null;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 activeList = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName(),
                         mContext.getFeatureId());
@@ -1370,7 +1389,11 @@
         List<SubscriptionInfo> result = null;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 result = iSub.getAvailableSubscriptionInfoList(mContext.getOpPackageName(),
                         mContext.getFeatureId());
@@ -1409,7 +1432,11 @@
         List<SubscriptionInfo> result = null;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 result = iSub.getAccessibleSubscriptionInfoList(mContext.getOpPackageName());
             }
@@ -1438,7 +1465,11 @@
     public void requestEmbeddedSubscriptionInfoListRefresh() {
         int cardId = TelephonyManager.from(mContext).getCardIdForDefaultEuicc();
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 iSub.requestEmbeddedSubscriptionInfoListRefresh(cardId);
             }
@@ -1467,7 +1498,11 @@
     @SystemApi
     public void requestEmbeddedSubscriptionInfoListRefresh(int cardId) {
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 iSub.requestEmbeddedSubscriptionInfoListRefresh(cardId);
             }
@@ -1488,7 +1523,11 @@
         int result = 0;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 result = iSub.getAllSubInfoCount(mContext.getOpPackageName(),
                         mContext.getFeatureId());
@@ -1517,7 +1556,11 @@
         int result = 0;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 result = iSub.getActiveSubInfoCount(mContext.getOpPackageName(),
                         mContext.getFeatureId());
@@ -1538,7 +1581,11 @@
         int result = 0;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 result = iSub.getActiveSubInfoCountMax();
             }
@@ -1595,7 +1642,11 @@
         }
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub == null) {
                 Log.e(LOG_TAG, "[addSubscriptionInfoRecord]- ISub service is null");
                 return;
@@ -1629,7 +1680,11 @@
         }
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub == null) {
                 Log.e(LOG_TAG, "[removeSubscriptionInfoRecord]- ISub service is null");
                 return;
@@ -1732,7 +1787,11 @@
         int result = INVALID_SIM_SLOT_INDEX;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 result = iSub.getSlotIndex(subscriptionId);
             }
@@ -1766,7 +1825,11 @@
         int[] subId = null;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 subId = iSub.getSubId(slotIndex);
             }
@@ -1790,7 +1853,11 @@
         int result = INVALID_PHONE_INDEX;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 result = iSub.getPhoneId(subId);
             }
@@ -1824,7 +1891,11 @@
         int subId = INVALID_SUBSCRIPTION_ID;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 subId = iSub.getDefaultSubId();
             }
@@ -1847,7 +1918,11 @@
         int subId = INVALID_SUBSCRIPTION_ID;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 subId = iSub.getDefaultVoiceSubId();
             }
@@ -1877,7 +1952,11 @@
     public void setDefaultVoiceSubscriptionId(int subscriptionId) {
         if (VDBG) logd("setDefaultVoiceSubId sub id = " + subscriptionId);
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 iSub.setDefaultVoiceSubId(subscriptionId);
             }
@@ -1925,7 +2004,11 @@
         int subId = INVALID_SUBSCRIPTION_ID;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 subId = iSub.getDefaultSmsSubId();
             }
@@ -1951,7 +2034,11 @@
     public void setDefaultSmsSubId(int subscriptionId) {
         if (VDBG) logd("setDefaultSmsSubId sub id = " + subscriptionId);
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 iSub.setDefaultSmsSubId(subscriptionId);
             }
@@ -1989,7 +2076,11 @@
         int subId = INVALID_SUBSCRIPTION_ID;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 subId = iSub.getDefaultDataSubId();
             }
@@ -2015,7 +2106,11 @@
     public void setDefaultDataSubId(int subscriptionId) {
         if (VDBG) logd("setDataSubscription sub id = " + subscriptionId);
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 iSub.setDefaultDataSubId(subscriptionId);
             }
@@ -2046,7 +2141,11 @@
     /** @hide */
     public void clearSubscriptionInfo() {
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 iSub.clearSubInfo();
             }
@@ -2140,10 +2239,9 @@
     @UnsupportedAppUsage
     public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId, int subId) {
         if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId);
-        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
-        intent.putExtra(EXTRA_SUBSCRIPTION_INDEX, subId);
         intent.putExtra(EXTRA_SLOT_INDEX, phoneId);
         intent.putExtra(PhoneConstants.PHONE_KEY, phoneId);
+        putSubscriptionIdExtra(intent, subId);
     }
 
     /**
@@ -2182,7 +2280,11 @@
      */
     public @NonNull int[] getActiveSubscriptionIdList(boolean visibleOnly) {
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 int[] subId = iSub.getActiveSubIdList(visibleOnly);
                 if (subId != null) return subId;
@@ -2233,7 +2335,11 @@
         int simState = TelephonyManager.SIM_STATE_UNKNOWN;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 simState = iSub.getSimStateForSlotIndex(slotIndex);
             }
@@ -2252,7 +2358,11 @@
      */
     public static void setSubscriptionProperty(int subId, String propKey, String propValue) {
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 iSub.setSubscriptionProperty(subId, propKey, propValue);
             }
@@ -2272,7 +2382,11 @@
             Context context) {
         String resultValue = null;
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 resultValue = iSub.getSubscriptionProperty(subId, propKey,
                         context.getOpPackageName(), context.getFeatureId());
@@ -2414,7 +2528,11 @@
     @UnsupportedAppUsage
     public boolean isActiveSubId(int subId) {
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 return iSub.isActiveSubId(subId, mContext.getOpPackageName(),
                         mContext.getFeatureId());
@@ -2717,7 +2835,11 @@
             @TelephonyManager.SetOpportunisticSubscriptionResult Consumer<Integer> callback) {
         if (VDBG) logd("[setPreferredDataSubscriptionId]+ subId:" + subId);
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub == null) return;
 
             ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() {
@@ -2760,7 +2882,11 @@
     public int getPreferredDataSubscriptionId() {
         int preferredSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 preferredSubId = iSub.getPreferredDataSubscriptionId();
             }
@@ -2791,7 +2917,11 @@
         List<SubscriptionInfo> subInfoList = null;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 subInfoList = iSub.getOpportunisticSubscriptions(contextPkg, contextFeature);
             }
@@ -2892,7 +3022,11 @@
         ParcelUuid groupUuid = null;
         int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 groupUuid = iSub.createSubscriptionGroup(subIdArray, pkgForDebug);
             } else {
@@ -2942,7 +3076,11 @@
         int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 iSub.addSubscriptionsIntoGroup(subIdArray, groupUuid, pkgForDebug);
             } else {
@@ -2994,7 +3132,11 @@
         int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 iSub.removeSubscriptionsFromGroup(subIdArray, groupUuid, pkgForDebug);
             } else {
@@ -3039,7 +3181,11 @@
 
         List<SubscriptionInfo> result = null;
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 result = iSub.getSubscriptionsInGroup(groupUuid, contextPkg, contextFeature);
             } else {
@@ -3152,7 +3298,11 @@
             logd("setSubscriptionActivated subId= " + subscriptionId + " enable " + enable);
         }
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 return iSub.setSubscriptionEnabled(enable, subscriptionId);
             }
@@ -3241,7 +3391,11 @@
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public boolean isSubscriptionEnabled(int subscriptionId) {
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 return iSub.isSubscriptionEnabled(subscriptionId);
             }
@@ -3264,7 +3418,11 @@
         int subId = INVALID_SUBSCRIPTION_ID;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 subId = iSub.getEnabledSubscriptionId(slotIndex);
             }
@@ -3290,7 +3448,11 @@
         int result = 0;
 
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 result = helper.callMethod(iSub);
             }
@@ -3313,7 +3475,11 @@
      */
     public static int getActiveDataSubscriptionId() {
         try {
-            ISub iSub = TelephonyManager.getSubscriptionService();
+            ISub iSub = ISub.Stub.asInterface(
+                    TelephonyFrameworkInitializer
+                            .getTelephonyServiceManager()
+                            .getSubscriptionServiceRegisterer()
+                            .get());
             if (iSub != null) {
                 return iSub.getActiveDataSubscriptionId();
             }
@@ -3321,4 +3487,19 @@
         }
         return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
     }
+
+    /**
+     * Helper method that puts a subscription id on an intent with the constants:
+     * PhoneConstant.SUBSCRIPTION_KEY and SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX.
+     * Both constants are used to support backwards compatibility.  Once we know we got all places,
+     * we can remove PhoneConstants.SUBSCRIPTION_KEY.
+     * @param intent Intent to put sub id on.
+     * @param subId SubscriptionId to put on intent.
+     *
+     * @hide
+     */
+    public static void putSubscriptionIdExtra(Intent intent, int subId) {
+        intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
+    }
 }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d15a531..0ffeccf 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -57,7 +57,6 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
@@ -95,15 +94,12 @@
 import android.util.Pair;
 
 import com.android.ims.internal.IImsServiceFeatureCallback;
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.CellNetworkScanResult;
 import com.android.internal.telephony.INumberVerificationCallback;
 import com.android.internal.telephony.IOns;
 import com.android.internal.telephony.IPhoneSubInfo;
 import com.android.internal.telephony.ISetOpportunisticDataCallback;
-import com.android.internal.telephony.ISms;
-import com.android.internal.telephony.ISub;
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.ITelephonyRegistry;
 import com.android.internal.telephony.IUpdateAvailableNetworksCallback;
@@ -303,21 +299,6 @@
     private SubscriptionManager mSubscriptionManager;
     private TelephonyScanManager mTelephonyScanManager;
 
-    /** Cached service handles, cleared by resetServiceHandles() at death */
-    private static final Object sCacheLock = new Object();
-
-    /** @hide */
-    private static boolean sServiceHandleCacheEnabled = true;
-
-    @GuardedBy("sCacheLock")
-    private static IPhoneSubInfo sIPhoneSubInfo;
-    @GuardedBy("sCacheLock")
-    private static ISub sISub;
-    @GuardedBy("sCacheLock")
-    private static ISms sISms;
-    @GuardedBy("sCacheLock")
-    private static final DeathRecipient sServiceDeath = new DeathRecipient();
-
     /** Enum indicating multisim variants
      *  DSDS - Dual SIM Dual Standby
      *  DSDA - Dual SIM Dual Active
@@ -1463,7 +1444,8 @@
     /**
      * <p>Broadcast Action: The emergency callback mode is changed.
      * <ul>
-     *   <li><em>phoneinECMState</em> - A boolean value,true=phone in ECM, false=ECM off</li>
+     *   <li><em>EXTRA_PHONE_IN_ECM_STATE</em> - A boolean value,true=phone in ECM,
+     *   false=ECM off</li>
      * </ul>
      * <p class="note">
      * You can <em>not</em> receive this through components declared
@@ -1473,12 +1455,25 @@
      *
      * <p class="note">This is a protected intent that can only be sent by the system.
      *
+     * @see #EXTRA_PHONE_IN_ECM_STATE
+     *
      * @hide
      */
     @SystemApi
     @SuppressLint("ActionValue")
-    public static final String ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
-            = "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED";
+    public static final String ACTION_EMERGENCY_CALLBACK_MODE_CHANGED =
+            "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED";
+
+
+    /**
+     * Extra included in {@link #ACTION_EMERGENCY_CALLBACK_MODE_CHANGED}.
+     * Indicates whether the phone is in an emergency phone state.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_PHONE_IN_ECM_STATE =
+            "android.telephony.extra.PHONE_IN_ECM_STATE";
 
     /**
      * <p>Broadcast Action: when data connections get redirected with validation failure.
@@ -1670,8 +1665,8 @@
     /**
      * <p>Broadcast Action: The emergency call state is changed.
      * <ul>
-     *   <li><em>phoneInEmergencyCall</em> - A boolean value, true if phone in emergency call,
-     *   false otherwise</li>
+     *   <li><em>EXTRA_PHONE_IN_EMERGENCY_CALL</em> - A boolean value, true if phone in emergency
+     *   call, false otherwise</li>
      * </ul>
      * <p class="note">
      * You can <em>not</em> receive this through components declared
@@ -1681,12 +1676,25 @@
      *
      * <p class="note">This is a protected intent that can only be sent by the system.
      *
+     * @see #EXTRA_PHONE_IN_EMERGENCY_CALL
+     *
      * @hide
      */
     @SystemApi
     @SuppressLint("ActionValue")
-    public static final String ACTION_EMERGENCY_CALL_STATE_CHANGED
-            = "android.intent.action.EMERGENCY_CALL_STATE_CHANGED";
+    public static final String ACTION_EMERGENCY_CALL_STATE_CHANGED =
+            "android.intent.action.EMERGENCY_CALL_STATE_CHANGED";
+
+
+    /**
+     * Extra included in {@link #ACTION_EMERGENCY_CALL_STATE_CHANGED}.
+     * It indicates whether the phone is making an emergency call.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_PHONE_IN_EMERGENCY_CALL =
+            "android.telephony.extra.PHONE_IN_EMERGENCY_CALL";
 
     /**
      * <p>Broadcast Action: It indicates the Emergency callback mode blocks datacall/sms
@@ -1699,8 +1707,8 @@
      * @hide
      */
     @SystemApi
-    public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS
-            = "android.telephony.action.SHOW_NOTICE_ECM_BLOCK_OTHERS";
+    public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS =
+            "android.telephony.action.SHOW_NOTICE_ECM_BLOCK_OTHERS";
 
     /**
      * Broadcast Action: The default data subscription has changed in a multi-SIM device.
@@ -1713,8 +1721,8 @@
      */
     @SystemApi
     @SuppressLint("ActionValue")
-    public static final String ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED
-            = "android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED";
+    public static final String ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED =
+            "android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED";
 
     /**
      * Broadcast Action: The default voice subscription has changed in a mult-SIm device.
@@ -1727,8 +1735,8 @@
      */
     @SystemApi
     @SuppressLint("ActionValue")
-    public static final String ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED
-            = "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED";
+    public static final String ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED =
+            "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED";
 
     /**
      * Broadcast Action: This triggers a client initiated OMA-DM session to the OMA server.
@@ -1741,8 +1749,8 @@
      */
     @SystemApi
     @SuppressLint("ActionValue")
-    public static final String ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE
-            = "com.android.omadm.service.CONFIGURATION_UPDATE";
+    public static final String ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE =
+            "com.android.omadm.service.CONFIGURATION_UPDATE";
 
     //
     //
@@ -1866,7 +1874,7 @@
     public String getDeviceId(int slotIndex) {
         // FIXME this assumes phoneId == slotIndex
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
             return info.getDeviceIdForPhone(slotIndex, mContext.getOpPackageName(),
@@ -2120,7 +2128,7 @@
 
     private String getNaiBySubscriberId(int subId) {
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
             String nai = info.getNaiForSubscriber(subId, mContext.getOpPackageName(),
@@ -3809,7 +3817,7 @@
     @UnsupportedAppUsage
     public String getSimSerialNumber(int subId) {
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
             return info.getIccSerialNumberForSubscriber(subId, mContext.getOpPackageName(),
@@ -4083,7 +4091,7 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getSubscriberId(int subId) {
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
             return info.getSubscriberIdForSubscriber(subId, mContext.getOpPackageName(),
@@ -4119,7 +4127,7 @@
     @Nullable
     public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(@KeyType int keyType) {
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null) {
                 Rlog.e(TAG,"IMSI error: Subscriber Info is null");
                 return null;
@@ -4162,7 +4170,7 @@
     @SystemApi
     public void resetCarrierKeysForImsiEncryption() {
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null) {
                 Rlog.e(TAG, "IMSI error: Subscriber Info is null");
                 if (!isSystemProcess()) {
@@ -4227,7 +4235,7 @@
      */
     public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo) {
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null) return;
             info.setCarrierInfoForImsiEncryption(mSubId, mContext.getOpPackageName(),
                     imsiEncryptionInfo);
@@ -4251,7 +4259,7 @@
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getGroupIdLevel1() {
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
             return info.getGroupIdLevel1ForSubscriber(getSubId(), mContext.getOpPackageName(),
@@ -4275,7 +4283,7 @@
     @UnsupportedAppUsage
     public String getGroupIdLevel1(int subId) {
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
             return info.getGroupIdLevel1ForSubscriber(subId, mContext.getOpPackageName(),
@@ -4338,7 +4346,7 @@
             return number;
         }
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
             return info.getLine1NumberForSubscriber(subId, mContext.getOpPackageName(),
@@ -4429,7 +4437,7 @@
             return alphaTag;
         }
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
             return info.getLine1AlphaTagForSubscriber(subId, getOpPackageName(),
@@ -4517,7 +4525,7 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getMsisdn(int subId) {
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
             return info.getMsisdnForSubscriber(subId, getOpPackageName(), getFeatureId());
@@ -4551,7 +4559,7 @@
     @UnsupportedAppUsage
     public String getVoiceMailNumber(int subId) {
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
             return info.getVoiceMailNumberForSubscriber(subId, getOpPackageName(),
@@ -5150,7 +5158,7 @@
     @UnsupportedAppUsage
     public String getVoiceMailAlphaTag(int subId) {
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
             return info.getVoiceMailAlphaTagForSubscriber(subId, getOpPackageName(),
@@ -5198,7 +5206,7 @@
     @UnsupportedAppUsage
     public String getIsimImpi() {
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
             //get the Isim Impi based on subId
@@ -5225,7 +5233,7 @@
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getIsimDomain() {
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
             //get the Isim Domain based on subId
@@ -5249,7 +5257,7 @@
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String[] getIsimImpu() {
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
             //get the Isim Impu based on subId
@@ -5262,6 +5270,19 @@
         }
     }
 
+   /**
+    * @hide
+    */
+    @UnsupportedAppUsage
+    private IPhoneSubInfo getSubscriberInfo() {
+        // get it each time because that process crashes a lot
+        return IPhoneSubInfo.Stub.asInterface(
+                TelephonyFrameworkInitializer
+                        .getTelephonyServiceManager()
+                        .getPhoneSubServiceRegisterer()
+                        .get());
+    }
+
     /**
      * Device call state: No activity.
      */
@@ -7012,7 +7033,7 @@
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getIsimIst() {
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
             //get the Isim Ist based on subId
@@ -7034,7 +7055,7 @@
     @UnsupportedAppUsage
     public String[] getIsimPcscf() {
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
             //get the Isim Pcscf based on subId
@@ -7115,7 +7136,7 @@
     @UnsupportedAppUsage
     public String getIccAuthentication(int subId, int appType, int authType, String data) {
         try {
-            IPhoneSubInfo info = getSubscriberInfoService();
+            IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
             return info.getIccSimChallengeResponse(subId, appType, authType, data);
@@ -12391,150 +12412,4 @@
         }
         return false;
     }
-
-    private static class DeathRecipient implements IBinder.DeathRecipient {
-        @Override
-        public void binderDied() {
-            resetServiceCache();
-        }
-    }
-
-   /**
-    * Reset everything in the service cache; if one handle died then they are
-    * all probably broken.
-    * @hide
-    */
-    private static void resetServiceCache() {
-        synchronized (sCacheLock) {
-            if (sISub != null) {
-                sISub.asBinder().unlinkToDeath(sServiceDeath, 0);
-                sISub = null;
-            }
-            if (sISms != null) {
-                sISms.asBinder().unlinkToDeath(sServiceDeath, 0);
-                sISms = null;
-            }
-            if (sIPhoneSubInfo != null) {
-                sIPhoneSubInfo.asBinder().unlinkToDeath(sServiceDeath, 0);
-                sIPhoneSubInfo = null;
-            }
-        }
-    }
-
-   /**
-    * @hide
-    */
-    static IPhoneSubInfo getSubscriberInfoService() {
-        if (!sServiceHandleCacheEnabled) {
-            return IPhoneSubInfo.Stub.asInterface(
-                TelephonyFrameworkInitializer
-                        .getTelephonyServiceManager()
-                        .getPhoneSubServiceRegisterer()
-                        .get());
-        }
-
-        if (sIPhoneSubInfo == null) {
-            IPhoneSubInfo temp = IPhoneSubInfo.Stub.asInterface(
-                    TelephonyFrameworkInitializer
-                        .getTelephonyServiceManager()
-                        .getPhoneSubServiceRegisterer()
-                        .get());
-            synchronized (sCacheLock) {
-                if (sIPhoneSubInfo == null && temp != null) {
-                    try {
-                        sIPhoneSubInfo = temp;
-                        sIPhoneSubInfo.asBinder().linkToDeath(sServiceDeath, 0);
-                    } catch (Exception e) {
-                        // something has gone horribly wrong
-                        sIPhoneSubInfo = null;
-                    }
-                }
-            }
-        }
-        return sIPhoneSubInfo;
-    }
-
-   /**
-    * @hide
-    */
-    static ISub getSubscriptionService() {
-        if (!sServiceHandleCacheEnabled) {
-            return ISub.Stub.asInterface(
-                    TelephonyFrameworkInitializer
-                            .getTelephonyServiceManager()
-                            .getSubscriptionServiceRegisterer()
-                            .get());
-        }
-
-        if (sISub == null) {
-            ISub temp = ISub.Stub.asInterface(
-                    TelephonyFrameworkInitializer
-                            .getTelephonyServiceManager()
-                            .getSubscriptionServiceRegisterer()
-                            .get());
-            synchronized (sCacheLock) {
-                if (sISub == null && temp != null) {
-                    try {
-                        sISub = temp;
-                        sISub.asBinder().linkToDeath(sServiceDeath, 0);
-                    } catch (Exception e) {
-                        // something has gone horribly wrong
-                        sISub = null;
-                    }
-                }
-            }
-        }
-        return sISub;
-    }
-
-    /**
-    * @hide
-    */
-    static ISms getSmsService() {
-        if (!sServiceHandleCacheEnabled) {
-            return ISms.Stub.asInterface(
-                    TelephonyFrameworkInitializer
-                            .getTelephonyServiceManager()
-                            .getSmsServiceRegisterer()
-                            .get());
-        }
-
-        if (sISms == null) {
-            ISms temp = ISms.Stub.asInterface(
-                    TelephonyFrameworkInitializer
-                            .getTelephonyServiceManager()
-                            .getSmsServiceRegisterer()
-                            .get());
-            synchronized (sCacheLock) {
-                if (sISms == null && temp != null) {
-                    try {
-                        sISms = temp;
-                        sISms.asBinder().linkToDeath(sServiceDeath, 0);
-                    } catch (Exception e) {
-                        // something has gone horribly wrong
-                        sISms = null;
-                    }
-                }
-            }
-        }
-        return sISms;
-    }
-
-    /**
-     * Disables service handle caching for tests that utilize mock services.
-     * @hide
-     */
-    @VisibleForTesting
-    public static void disableServiceHandleCaching() {
-        sServiceHandleCacheEnabled = false;
-    }
-
-    /**
-     * Reenables service handle caching.
-     * @hide
-     */
-    @VisibleForTesting
-    public static void enableServiceHandleCaching() {
-        sServiceHandleCacheEnabled = true;
-    }
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 51701eb..db8c845 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -100,9 +100,6 @@
     public static final String DATA_APN_TYPE_KEY = "apnType";
     public static final String DATA_APN_KEY = "apn";
 
-    public static final String PHONE_IN_ECM_STATE = "phoneinECMState";
-    public static final String PHONE_IN_EMERGENCY_CALL = "phoneInEmergencyCall";
-
     /**
      * Return codes for supplyPinReturnResult and
      * supplyPukReturnResult APIs
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index 0ab5c97..11d5b25 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -222,7 +222,7 @@
 
     @Override
     public Network getNetwork() {
-        return new Network(mNetworkAgent.netId);
+        return mNetworkAgent.network;
     }
 
     public void expectPreventReconnectReceived(long timeoutMs) {
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index b2d363e..1901a1d 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -575,7 +575,7 @@
                 }
             };
 
-            assertEquals(na.netId, nmNetworkCaptor.getValue().netId);
+            assertEquals(na.network.netId, nmNetworkCaptor.getValue().netId);
             mNmCallbacks = nmCbCaptor.getValue();
 
             mNmCallbacks.onNetworkMonitorCreated(mNetworkMonitor);
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 9e915ae..e863266 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -35,7 +35,6 @@
 import android.net.IDnsResolver;
 import android.net.INetd;
 import android.net.Network;
-import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkProvider;
@@ -75,7 +74,6 @@
     @Mock INetd mNetd;
     @Mock INetworkManagementService mNMS;
     @Mock Context mCtx;
-    @Mock NetworkAgentConfig mAgentConfig;
     @Mock NetworkNotificationManager mNotifier;
     @Mock Resources mResources;
 
@@ -358,7 +356,7 @@
         NetworkScore ns = new NetworkScore();
         ns.putIntExtension(NetworkScore.LEGACY_SCORE, 50);
         NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
-                caps, ns, mCtx, null, mAgentConfig, mConnService, mNetd, mDnsResolver, mNMS,
+                caps, ns, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS,
                 NetworkProvider.ID_NONE);
         nai.everValidated = true;
         return nai;
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index cf70f5d..9b24887 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -63,7 +63,6 @@
     static final int NETID = 42;
 
     @Mock ConnectivityService mConnectivity;
-    @Mock NetworkAgentConfig mAgentConfig;
     @Mock IDnsResolver mDnsResolver;
     @Mock INetd mNetd;
     @Mock INetworkManagementService mNms;
@@ -72,6 +71,7 @@
 
     TestLooper mLooper;
     Handler mHandler;
+    NetworkAgentConfig mAgentConfig = new NetworkAgentConfig();
 
     Nat464Xlat makeNat464Xlat() {
         return new Nat464Xlat(mNai, mNetd, mDnsResolver, mNms) {
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 6326f14..70c9bef 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -50,6 +50,8 @@
 
     "//frameworks/opt/net/wifi/libs/WifiTrackerLib/tests",
     "//external/robolectric-shadows:__subpackages__",
+    "//frameworks/base/packages/SettingsLib/tests/integ",
+    "//external/sl4a:__subpackages__",
 ]
 
 // wifi-service needs pre-jarjared version of framework-wifi so it can reference copied utility
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index c6aca07..3413305 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -23,6 +23,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -793,10 +795,19 @@
         }
     }
 
-    /** empty scan result
+    /**
+     * Construct an empty scan result.
      *
-     * {@hide}
-     * */
+     * Test code has a need to construct a ScanResult in a specific state.
+     * (Note that mocking using Mockito does not work if the object needs to be parceled and
+     * unparceled.)
+     * Export a @SystemApi default constructor to allow tests to construct an empty ScanResult
+     * object. The test can then directly set the fields it cares about.
+     *
+     * @hide
+     */
+    @SystemApi
+    @VisibleForTesting
     public ScanResult() {
     }
 
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index f4c5b91..ee2b575 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -39,6 +39,8 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
@@ -1208,22 +1210,27 @@
      */
     @SystemApi
     public static class NetworkSelectionStatus {
-        // Quality Network Selection Status enable, temporary disabled, permanently disabled
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(prefix = "NETWORK_SELECTION_",
+                value = {
+                NETWORK_SELECTION_ENABLED,
+                NETWORK_SELECTION_TEMPORARY_DISABLED,
+                NETWORK_SELECTION_PERMANENTLY_DISABLED})
+        public @interface NetworkEnabledStatus {}
         /**
-         * This network is allowed to join Quality Network Selection
-         * @hide
+         * This network will be considered as a potential candidate to connect to during network
+         * selection.
          */
         public static final int NETWORK_SELECTION_ENABLED = 0;
         /**
-         * network was temporary disabled. Can be re-enabled after a time period expire
-         * @hide
+         * This network was temporary disabled. May be re-enabled after a time out.
          */
-        public static final int NETWORK_SELECTION_TEMPORARY_DISABLED  = 1;
+        public static final int NETWORK_SELECTION_TEMPORARY_DISABLED = 1;
         /**
-         * network was permanently disabled.
-         * @hide
+         * This network was permanently disabled.
          */
-        public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED  = 2;
+        public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED = 2;
         /**
          * Maximum Network selection status
          * @hide
@@ -1455,6 +1462,7 @@
          * Network selection status, should be in one of three status: enable, temporaily disabled
          * or permanently disabled
          */
+        @NetworkEnabledStatus
         private int mStatus;
 
         /**
@@ -1635,6 +1643,56 @@
         }
 
         /**
+         * NetworkSelectionStatus exports an immutable public API.
+         * However, test code has a need to construct a NetworkSelectionStatus in a specific state.
+         * (Note that mocking using Mockito does not work if the object needs to be parceled and
+         * unparceled.)
+         * Export a @SystemApi Builder to allow tests to construct a NetworkSelectionStatus object
+         * in the desired state, without sacrificing NetworkSelectionStatus's immutability.
+         */
+        @VisibleForTesting
+        public static final class Builder {
+            private final NetworkSelectionStatus mNetworkSelectionStatus =
+                    new NetworkSelectionStatus();
+
+            /**
+             * Set the current network selection status.
+             * One of:
+             * {@link #NETWORK_SELECTION_ENABLED},
+             * {@link #NETWORK_SELECTION_TEMPORARY_DISABLED},
+             * {@link #NETWORK_SELECTION_PERMANENTLY_DISABLED}
+             * @see NetworkSelectionStatus#getNetworkSelectionStatus()
+             */
+            @NonNull
+            public Builder setNetworkSelectionStatus(@NetworkEnabledStatus int status) {
+                mNetworkSelectionStatus.setNetworkSelectionStatus(status);
+                return this;
+            }
+
+            /**
+             *
+             * Set the current network's disable reason.
+             * One of the {@link #NETWORK_SELECTION_ENABLE} or DISABLED_* constants.
+             * e.g. {@link #DISABLED_ASSOCIATION_REJECTION}.
+             * @see NetworkSelectionStatus#getNetworkSelectionDisableReason()
+             */
+            @NonNull
+            public Builder setNetworkSelectionDisableReason(
+                    @NetworkSelectionDisableReason int reason) {
+                mNetworkSelectionStatus.setNetworkSelectionDisableReason(reason);
+                return this;
+            }
+
+            /**
+             * Build a NetworkSelectionStatus object.
+             */
+            @NonNull
+            public NetworkSelectionStatus build() {
+                return mNetworkSelectionStatus;
+            }
+        }
+
+        /**
          * Get the network disable reason string for a reason code (for debugging).
          * @param reason specific error reason. One of the {@link #NETWORK_SELECTION_ENABLE} or
          *               DISABLED_* constants e.g. {@link #DISABLED_ASSOCIATION_REJECTION}.
@@ -1660,10 +1718,13 @@
         }
 
         /**
-         * get current network network selection status
-         * @return return current network network selection status
-         * @hide
+         * Get the current network network selection status.
+         * One of:
+         * {@link #NETWORK_SELECTION_ENABLED},
+         * {@link #NETWORK_SELECTION_TEMPORARY_DISABLED},
+         * {@link #NETWORK_SELECTION_PERMANENTLY_DISABLED}
          */
+        @NetworkEnabledStatus
         public int getNetworkSelectionStatus() {
             return mStatus;
         }
@@ -1965,10 +2026,11 @@
     }
 
     /**
-     * Set the network selection status
+     * Set the network selection status.
      * @hide
      */
-    public void setNetworkSelectionStatus(NetworkSelectionStatus status) {
+    @SystemApi
+    public void setNetworkSelectionStatus(@NonNull NetworkSelectionStatus status) {
         mNetworkSelectionStatus = status;
     }
 
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 41f7c6e..5edcc2d 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -1028,8 +1028,10 @@
     }
 
     /**
-     * @hide
+     * Get the client private key as supplied in {@link #setClientKeyEntryWithCertificateChain}, or
+     * null if unset.
      */
+    @Nullable
     public PrivateKey getClientPrivateKey() {
         return mClientPrivateKey;
     }
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 62337cb..51b15af 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -17,6 +17,7 @@
 package android.net.wifi;
 
 import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -27,6 +28,8 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.net.Inet4Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
@@ -356,6 +359,72 @@
         }
     }
 
+    /**
+     * WifiInfo exports an immutable public API.
+     * However, test code has a need to construct a WifiInfo in a specific state.
+     * (Note that mocking using Mockito does not work if the object needs to be parceled and
+     * unparceled.)
+     * Export a @SystemApi Builder to allow tests to construct a WifiInfo object
+     * in the desired state, without sacrificing WifiInfo's immutability.
+     *
+     * @hide
+     */
+    // This builder was not made public to reduce confusion for external developers as there are
+    // no legitimate uses for this builder except for testing.
+    @SystemApi
+    @VisibleForTesting
+    public static final class Builder {
+        private final WifiInfo mWifiInfo = new WifiInfo();
+
+        /**
+         * Set the SSID, in the form of a raw byte array.
+         * @see WifiInfo#getSSID()
+         */
+        @NonNull
+        public Builder setSsid(@NonNull byte[] ssid) {
+            mWifiInfo.setSSID(WifiSsid.createFromByteArray(ssid));
+            return this;
+        }
+
+        /**
+         * Set the BSSID.
+         * @see WifiInfo#getBSSID()
+         */
+        @NonNull
+        public Builder setBssid(@NonNull String bssid) {
+            mWifiInfo.setBSSID(bssid);
+            return this;
+        }
+
+        /**
+         * Set the RSSI, in dBm.
+         * @see WifiInfo#getRssi()
+         */
+        @NonNull
+        public Builder setRssi(int rssi) {
+            mWifiInfo.setRssi(rssi);
+            return this;
+        }
+
+        /**
+         * Set the network ID.
+         * @see WifiInfo#getNetworkId()
+         */
+        @NonNull
+        public Builder setNetworkId(int networkId) {
+            mWifiInfo.setNetworkId(networkId);
+            return this;
+        }
+
+        /**
+         * Build a WifiInfo object.
+         */
+        @NonNull
+        public WifiInfo build() {
+            return mWifiInfo;
+        }
+    }
+
     /** @hide */
     public void setSSID(WifiSsid wifiSsid) {
         mWifiSsid = wifiSsid;
diff --git a/wifi/tests/Android.bp b/wifi/tests/Android.bp
new file mode 100644
index 0000000..6a39959
--- /dev/null
+++ b/wifi/tests/Android.bp
@@ -0,0 +1,50 @@
+// 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.
+
+// Make test APK
+// ============================================================
+
+android_test {
+    name: "FrameworksWifiApiTests",
+
+    defaults: ["framework-wifi-test-defaults"],
+
+    srcs: ["**/*.java"],
+
+    jacoco: {
+        include_filter: ["android.net.wifi.*"],
+        // TODO(b/147521214) need to exclude test classes
+        exclude_filter: [],
+    },
+
+    static_libs: [
+        "androidx.test.rules",
+        "core-test-rules",
+        "guava",
+        "mockito-target-minus-junit4",
+        "net-tests-utils",
+        "frameworks-base-testutils",
+        "truth-prebuilt",
+    ],
+
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+    ],
+
+    test_suites: [
+        "device-tests",
+        "mts",
+    ],
+}
diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk
deleted file mode 100644
index d2c385b4..0000000
--- a/wifi/tests/Android.mk
+++ /dev/null
@@ -1,66 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-# Make test APK
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-# This list is generated from the java source files in this module
-# The list is a comma separated list of class names with * matching zero or more characters.
-# Example:
-#   Input files: src/com/android/server/wifi/Test.java src/com/android/server/wifi/AnotherTest.java
-#   Generated exclude list: com.android.server.wifi.Test*,com.android.server.wifi.AnotherTest*
-
-# Filter all src files to just java files
-local_java_files := $(filter %.java,$(LOCAL_SRC_FILES))
-# Transform java file names into full class names.
-# This only works if the class name matches the file name and the directory structure
-# matches the package.
-local_classes := $(subst /,.,$(patsubst src/%.java,%,$(local_java_files)))
-# Convert class name list to jacoco exclude list
-# This appends a * to all classes and replace the space separators with commas.
-# These patterns will match all classes in this module and their inner classes.
-jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes)))
-
-jacoco_include := android.net.wifi.*
-
-LOCAL_JACK_COVERAGE_INCLUDE_FILTER := $(jacoco_include)
-LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.test.rules \
-    core-test-rules \
-    guava \
-    mockito-target-minus-junit4 \
-    net-tests-utils \
-    frameworks-base-testutils \
-    truth-prebuilt \
-
-LOCAL_JAVA_LIBRARIES := \
-    android.test.runner \
-    android.test.base \
-
-LOCAL_PACKAGE_NAME := FrameworksWifiApiTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := \
-    device-tests \
-    mts \
-
-include $(BUILD_PACKAGE)